diff --git a/_windows/git.xml b/_windows/git.xml
deleted file mode 100644
index a8092bd..0000000
--- a/_windows/git.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/_windows/laf.xml b/_windows/laf.xml
deleted file mode 100644
index dbf49b4..0000000
--- a/_windows/laf.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/card/named/cellar.py b/card/named/cellar.py
index da3d5d5..b58d106 100644
--- a/card/named/cellar.py
+++ b/card/named/cellar.py
@@ -23,5 +23,5 @@ class Cellar(Action):
self._Card__owner.draw_cards(cards_discarded)
def __get_index(self, message):
- return self.__Card_owner.get_general_input(message, int)
+ return self.__Card_owner.take_input(message, int)
diff --git a/card/named/merchant.py b/card/named/merchant.py
index cf0b9b4..2e9fed4 100644
--- a/card/named/merchant.py
+++ b/card/named/merchant.py
@@ -13,5 +13,5 @@ class Merchant(Action):
self._Card__owner.add_purchase_power(3)
def __get_Merchant_input(self, message):
- return self.__Card_owner.get_general_input("Player " + str(self._Card__owner.get_player_index()) + ", " +
- message, str)
+ return self.__Card_owner.take_input("Player " + str(self._Card__owner.get_player_index()) + ", " +
+ message, str)
diff --git a/card/named/militia.py b/card/named/militia.py
index 6711e1b..00ae47c 100644
--- a/card/named/militia.py
+++ b/card/named/militia.py
@@ -11,9 +11,9 @@ class Militia(Action, Attack):
def __force_discard(self, chances, player):
if player.get_hand().get_remaining() > 3 and chances > 0:
- hand_index = player.militia_input("\nPlease provide an index to identify a card from hand you would like to"
- " discard (0 to " + str(player.get_hand().get_remaining() - 1) + "): "
- , int)
+ hand_index = player.get_response_input("\nPlease provide an index to identify a card from hand you would "
+ "like to discard (0 to " + str(player.get_hand().get_remaining() - 1)
+ + "): ", int, self.__class__)
self.__check_discard(hand_index, player, chances)
elif self.get_owner().get_hand().get_remaining() > 3 and chances <= 0:
print("You're out of chances to select a valid card to discard, randomly selecting for you.")
diff --git a/card/named/moat.py b/card/named/moat.py
index d15679b..204bd8b 100644
--- a/card/named/moat.py
+++ b/card/named/moat.py
@@ -5,6 +5,6 @@ from card.basic.card_reaction import Reaction
class Moat(Action, Reaction):
def react(self, what_attack):
owner = self.get_owner()
- return "Y" == owner.get_general_input("Player " + str(owner.get_player_index()) + ", enter 'Y' if you'd "
+ return "Y" == owner.take_input("Player " + str(owner.get_player_index()) + ", enter 'Y' if you'd "
"like to reveal " + str(self) + " to block the " + str(what_attack) +
" attack: ", str)
diff --git a/card/special/card_gain.py b/card/special/card_gain.py
index bf724c4..0238416 100644
--- a/card/special/card_gain.py
+++ b/card/special/card_gain.py
@@ -26,7 +26,7 @@ class CardGain(Card):
chances = 0
def __get_gain_card(self):
- return self.get_owner().get_general_input("\nPlease identify the index of which card you would like to "
+ return self.get_owner().take_input("\nPlease identify the index of which card you would like to "
"obtain: ", int)
def __get_gainable_cards(self, spending_limit):
diff --git a/card/special/card_trash.py b/card/special/card_trash.py
index 8925171..8684259 100644
--- a/card/special/card_trash.py
+++ b/card/special/card_trash.py
@@ -29,7 +29,7 @@ class CardTrash(Card):
self.trash_card_get_cost()
def __get_card_to_trash(self):
- return self.get_owner().get_general_input("\nPlease identify the index of the desired card to trash: ", int)
+ return self.get_owner().take_input("\nPlease identify the index of the desired card to trash: ", int)
def __get_trashable_cards(self):
result = list()
diff --git a/editor.xml b/editor.xml
deleted file mode 100644
index 19bd26a..0000000
--- a/editor.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/game.py b/game.py
index 91c1d80..a47cb49 100644
--- a/game.py
+++ b/game.py
@@ -1,6 +1,8 @@
from table.table import Table
from player.human import Human
from player.bots.pure_big_money import Pure_Big_Money
+from player.bots.smithy_big_money import Smithy_Big_Money
+from player.bots.militia_big_money import Militia_Big_Money
from card.basic.card_action import Action
from card.basic.card_curse import Curse
from card.basic.card_victory import Victory
@@ -56,7 +58,12 @@ def setup_new_game(game_list, parameter, card_info):
t.add_player(human)
for i in range(bots):
- bot = Pure_Big_Money(t)
+ if i % 3 == 0:
+ bot = Militia_Big_Money(t)
+ elif i % 3 == 1:
+ bot = Smithy_Big_Money(t)
+ else:
+ bot = Pure_Big_Money(t)
bot.draw_deck(t, get_starting_deck())
bot.draw_hand()
t.add_player(bot)
@@ -66,7 +73,7 @@ def setup_new_game(game_list, parameter, card_info):
def get_game_parameters():
# humans, bots, card #1, card #2, ... etc
- return [2, 1, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True]
+ return [0, 3, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True]
def get_card_info():
diff --git a/player/bot.py b/player/bot.py
new file mode 100644
index 0000000..f7ef929
--- /dev/null
+++ b/player/bot.py
@@ -0,0 +1,105 @@
+from player.player import Player
+from card.basic.card_action import Action
+from card.basic.card_treasure import Treasure
+from card.named.militia import Militia
+
+
+class Bot(Player):
+ target_card = None
+ target_card_threshold = 0
+
+ def get_play_input(self, message, target_type, restriction):
+ if restriction == Treasure:
+ choice = self.get_subclass_input(Treasure)
+ elif restriction == Action:
+ choice = self.get_subclass_input(Action)
+ else:
+ choice = -1
+
+ print(message + str(choice))
+ return choice
+
+ def get_response_input(self, message, target_type, restriction):
+ if restriction == Militia:
+ choice = self.get_militia_input()
+ else:
+ choice = -1
+ return choice
+
+ def can_afford_on_avg(self, card_name):
+ card_cost = self.get_table().get_piles()[self.get_table().get_pile_index_of_card(card_name)].get_card_group()\
+ .get_cost()
+ total_coin = 0
+ hand = self.get_hand().get_supply()
+ deck = self.get_deck().get_supply()
+ discard = self.get_discard().get_supply()
+ supplies = hand + deck + discard
+
+ for c in supplies:
+ total_coin += c.get_purchase_power()
+ return card_cost <= total_coin/(len(hand) + len(deck) + len(discard))
+
+ def has_how_many_of_card(self, card_name):
+ total = 0
+ hand = self.get_hand().get_supply()
+ deck = self.get_deck().get_supply()
+ discard = self.get_discard().get_supply()
+ supplies = hand + deck + discard
+
+ for c in supplies:
+ if c.get_name() == card_name:
+ total += 1
+ return total
+
+ #This will pick either the first or the first least effective purchasing card as this bot doesn't care about that
+ def get_militia_input(self):
+ choice = self.__get_first_non_Treasure()
+ min_coin = self.get_hand().get_supply()[choice].get_purchase_power()
+
+ for c in self.get_hand().get_supply():
+ # We want to do isinstance rather than not isinstance because we only want to evaluate this loop when we are
+ # evaluating an all treasure card hand as at that point the choice will be a treasure card, otherwise the
+ # choice will already be non-treasure and we don't need to check anything since this bot doesn't do action
+ if c.get_purchase_power() < min_coin and isinstance(c, Treasure):
+ min_coin = c.get_purchase_power()
+ choice = self.get_hand().get_supply().index(c)
+ return choice
+
+ # This method will only be called when it is time to buy things, a very simple logic will decide its action.
+ def get_buy_input(self, message, target_type):
+ coin = self.get_coin()
+ choice = -1
+
+ if coin >= self.target_card_threshold and not self.get_table().pile_is_empty(self.target_card) and \
+ self.has_how_many_of_card(self.target_card) < 3:
+ choice = self.get_table().get_pile_index_of_card(self.target_card)
+ elif coin >= 8 and not self.get_table().pile_is_empty("Province"):
+ choice = self.get_table().get_pile_index_of_card("Province")
+ elif coin >= 8 and not self.get_table().pile_is_empty("Dutchy"):
+ choice = self.get_table().get_pile_index_of_card("Dutchy")
+ elif coin >= 6 and not self.get_table().pile_is_empty("Gold") and not \
+ self.get_table().pile_is_empty("Province"):
+ choice = self.get_table().get_pile_index_of_card("Gold")
+ elif coin >= 5 and not self.get_table().pile_is_empty("Dutchy") and \
+ (self.can_afford_on_avg("Province") or self.get_table().pile_is_empty("Province")):
+ choice = self.get_table().get_pile_index_of_card("Dutchy")
+ elif coin >= 3 and not self.get_table().pile_is_empty("Silver"):
+ choice = self.get_table().get_pile_index_of_card("Silver")
+
+ print(message + str(choice))
+ return choice
+
+ def get_subclass_input(self, subclass):
+ choice = -1
+ hand = self.get_hand().get_supply()
+
+ for c in hand:
+ if isinstance(c, subclass):
+ choice = hand.index(c)
+ return choice
+
+ def __get_first_non_Treasure(self):
+ for c in self.get_hand().get_supply():
+ if not isinstance(c, Treasure):
+ return self.get_hand().get_supply().index(c)
+ return 0
\ No newline at end of file
diff --git a/player/bots/militia_big_money.py b/player/bots/militia_big_money.py
new file mode 100644
index 0000000..0add0c2
--- /dev/null
+++ b/player/bots/militia_big_money.py
@@ -0,0 +1,9 @@
+from player.bot import Bot
+
+
+class Militia_Big_Money(Bot):
+ target_card = "Militia"
+ target_card_threshold = 4
+
+ def __str__(self):
+ return "Player " + str(self.get_player_index()) + " (militia big money bot)"
\ No newline at end of file
diff --git a/player/bots/pure_big_money.py b/player/bots/pure_big_money.py
index 8513dd3..c427cc7 100644
--- a/player/bots/pure_big_money.py
+++ b/player/bots/pure_big_money.py
@@ -1,59 +1,12 @@
-from player.player import Player
-from card.basic.card_treasure import Treasure
+from player.bot import Bot
-class Pure_Big_Money(Player):
+class Pure_Big_Money(Bot):
+ target_card = "Province"
+ target_card_threshold = 8
+
def take_action(self):
print("\nAs a BIG MONEY BOT, I'm skipping this unnecessary action phase. Beep-boop, bow to me humans!")
- #This method will only be called for this bot when it is time to play treasures, it will play all of them always.
- def get_play_input(self, message, target_type):
- choice = -1
- hand = self.get_hand().get_supply()
-
- for c in hand:
- if isinstance(c, Treasure):
- choice = hand.index(c)
-
- print(message + str(choice))
- return choice
-
- #This method will only be called when it is time to buy things, a very simple logic will decide its action.
- def get_buy_input(self, message, target_type):
- coin = self.get_coin()
- choice = -1
-
- if coin >= 8:
- choice = self.get_table().get_pile_index_of_card("Province")
- elif coin >= 6:
- choice = self.get_table().get_pile_index_of_card("Gold")
- elif coin >= 3:
- choice = self.get_table().get_pile_index_of_card("Silver")
-
- print(message + str(choice))
- return choice
-
- #This will pick either the first or the first least effective purchasing card as this bot doesn't care about that
- def militia_input(self, message, target_type):
- choice = self.__get_first_non_Treasure()
- min_coin = self.get_hand().get_supply()[choice].get_purchase_power()
-
- for c in self.get_hand().get_supply():
- # We want to do isinstance rather than not isinstance because we only want to evaluate this loop when we are
- # evaluating an all treasure card hand as at that point the choice will be a treasure card, otherwise the
- # choice will already be non-treasure and we don't need to check anything since this bot doesn't do action
- if c.get_purchase_power() < min_coin and isinstance(c, Treasure):
- min_coin = c.get_purchase_power()
- choice = self.get_hand().get_supply().index(c)
-
- print(message + str(choice))
- return choice
-
- def __get_first_non_Treasure(self):
- for c in self.get_hand().get_supply():
- if not isinstance(c, Treasure):
- return self.get_hand().get_supply().index(c)
- return 0
-
def __str__(self):
return "Player " + str(self.get_player_index()) + " (pure big money bot)"
diff --git a/player/bots/smithy_big_money.py b/player/bots/smithy_big_money.py
new file mode 100644
index 0000000..b73d175
--- /dev/null
+++ b/player/bots/smithy_big_money.py
@@ -0,0 +1,9 @@
+from player.bot import Bot
+
+
+class Smithy_Big_Money(Bot):
+ target_card = "Smithy"
+ target_card_threshold = 5
+
+ def __str__(self):
+ return "Player " + str(self.get_player_index()) + " (smithy big money bot)"
\ No newline at end of file
diff --git a/player/hand.py b/player/hand.py
index 87d1959..e946a28 100644
--- a/player/hand.py
+++ b/player/hand.py
@@ -22,7 +22,11 @@ class Hand(Supply):
attack_blocked = False
for c in self.get_supply():
attack_blocked |= c.react(what_attack)
- return attack_blocked
+ if attack_blocked:
+ print(str(c.get_owner()) + " has " + str(c) + " as the " + str(self.get_supply().index(c)) +
+ ' and blocked the ' + what_attack + " attack.")
+ return True
+ return False
def __get_unique_class_instances(self):
unique_class_instances = list()
diff --git a/player/human.py b/player/human.py
index b06cb39..dd43e68 100644
--- a/player/human.py
+++ b/player/human.py
@@ -5,5 +5,3 @@ class Human(Player):
def __str__(self):
return "Player " + str(self.get_player_index()) + " (human)"
- def militia_input(self, message, target_type):
- return self.get_general_input(message, target_type)
diff --git a/player/player.py b/player/player.py
index 0c492e1..9bcb466 100644
--- a/player/player.py
+++ b/player/player.py
@@ -39,6 +39,9 @@ class Player:
def get_discard(self):
return self.__discard
+ def get_deck(self):
+ return self.__deck
+
def get_player_index(self):
return self.__table.get_players().index(self)
@@ -103,18 +106,30 @@ class Player:
def discard_from_hand(self, n):
self.__hand.transfer_card_by_index(n, self.__discard)
- def play_card(self, acceptable_card_class, chances, counter):
- if chances > 0 and self.__hand.contains_one_of(acceptable_card_class):
- hand_index = self.get_play_input("\nPlease identify a card from hand to play by providing its index: ", int)
- self.__check_play_card(hand_index, counter, acceptable_card_class, chances)
- elif chances <= 0:
- print("You have used up all of your chances to enter a valid integer; forfeiting remaining plays.")
- if counter is not None:
- counter.int = 0
- else:
- print("There are no more acceptable card in hand, moving to next phase.")
- if counter is not None:
- counter.int = 0
+ def claim_top_card(self, supply):
+ supply.get_top_card().set_owner(self)
+
+ def print_hand(self):
+ print("\nPlayer " + str(self.__table.get_players().index(self)) + " Hand:")
+ self.__hand.print()
+
+ def take_turn(self):
+ self.__turn_setup()
+ self.__print()
+ self.take_action()
+ self.take_buy()
+ self.discard_remaining_hand()
+ self.draw_hand()
+
+ # The following two methods are identical under different names so they can be overridden by bot classes later
+ def get_play_input(self, message, target_type, card_restriction):
+ return self.__get_input(self.__std_chances, target_type, message)
+
+ def get_buy_input(self, message, target_type):
+ return self.__get_input(self.__std_chances, target_type, message)
+
+ def get_response_input(self, message, target_type, card_restriction):
+ return self.__get_input(self.__std_chances, target_type, message)
def take_action(self):
print("\nPlease play an Action card until you have no remaining actions.")
@@ -130,6 +145,20 @@ class Player:
self.play_card(Treasure, self.__std_chances, play_another)
self.buy_card(self.__std_chances)
+ def play_card(self, acceptable_card_class, chances, counter):
+ if chances > 0 and self.__hand.contains_one_of(acceptable_card_class):
+ hand_index = self.get_play_input("\nPlease identify a card from hand to play by providing its index: ", int,
+ acceptable_card_class)
+ self.__check_play_card(hand_index, counter, acceptable_card_class, chances)
+ elif chances <= 0:
+ print("You have used up all of your chances to enter a valid integer; forfeiting remaining plays.")
+ if counter is not None:
+ counter.int = 0
+ else:
+ print("There are no more acceptable card in hand, moving to next phase.")
+ if counter is not None:
+ counter.int = 0
+
def buy_card(self, chances):
self.__table.print()
while self.__buys > 0 and not self.__table.are_there_three_empty_piles() and chances > 0:
@@ -156,22 +185,6 @@ class Player:
self.claim_top_card(self.__discard)
chances = self.get_std_chances()
- def take_turn(self):
- self.__turn_setup()
- self.__print()
- self.take_action()
- self.take_buy()
- self.discard_remaining_hand()
- self.draw_hand()
- self.print_hand()
-
- def claim_top_card(self, supply):
- supply.get_top_card().set_owner(self)
-
- def print_hand(self):
- print("\nPlayer " + str(self.__table.get_players().index(self)) + " Hand:")
- self.__hand.print()
-
def __check_play_card(self, hand_index, counter, acceptable_card_class, chances):
if hand_index < 0:
print("You have elected to forfeit any remaining plays.")
@@ -192,19 +205,6 @@ class Player:
print("Index in bounds but not an acceptable card type. Chance to get it right reduced.")
self.play_card(acceptable_card_class, chances - 1, counter)
- # The following two methods are identical under different names so they can be overridden by bot classes later
- def get_play_input(self, message, target_type):
- return self.get_general_input(message, target_type)
-
- def get_buy_input(self, message, target_type):
- return self.get_general_input(message, target_type)
-
- def militia_input(self, message, target_type):
- return self.get_general_input(message, target_type)
-
- def get_general_input(self, message, target_type):
- return self.__get_input(self.__std_chances, target_type, message)
-
def __get_input(self, chances, target_type, message):
value = input(message)
if chances > 0:
diff --git a/table/supply.py b/table/supply.py
index 6157e7a..67c1cc7 100644
--- a/table/supply.py
+++ b/table/supply.py
@@ -9,6 +9,9 @@ class Supply:
for i in range(n):
self.add_card(card)
+ def is_empty(self):
+ return len(self.__card) <= 0
+
def get_supply(self):
return self.__card
diff --git a/table/table.py b/table/table.py
index 2adb2dd..1ed4d0d 100644
--- a/table/table.py
+++ b/table/table.py
@@ -46,6 +46,9 @@ class Table:
result = self.__pile.index(p)
return result
+ def pile_is_empty(self, card_name):
+ return self.__pile[self.get_pile_index_of_card(card_name)].is_empty()
+
def are_there_three_empty_piles(self):
count = 0
for p in self.__pile:
@@ -67,7 +70,7 @@ class Table:
should_continue = True
while should_continue:
# game ends after
- should_continue = not self.should_game_end() or player_turn % len(self.__player) != 0
+ should_continue = not self.should_game_end() or player_turn % len(self.__player) != len(self.__player) - 1
self.print()
self.__player[player_turn % len(self.__player)].take_turn()
player_turn += 1