PY-2017.3.2 <Brad@Libra Merge branch 'master'

This commit is contained in:
bradstein 2018-01-25 08:21:04 -06:00
commit f0f87b4a89
19 changed files with 199 additions and 124 deletions

View File

@ -1,5 +0,0 @@
<application>
<component name="Git.Application.Settings">
<option name="SSH_EXECUTABLE" value="IDEA_SSH" />
</component>
</application>

View File

@ -1,5 +0,0 @@
<application>
<component name="LafManager">
<laf class-name="com.intellij.ide.ui.laf.IntelliJLaf" />
</component>
</application>

View File

@ -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)

View File

@ -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)

View File

@ -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.")

View File

@ -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)

View File

@ -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):

View File

@ -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()

View File

@ -1,6 +0,0 @@
<application>
<component name="DefaultFont">
<option name="FONT_SIZE" value="18" />
<option name="FONT_SCALE" value="1.5" />
</component>
</application>

11
game.py
View File

@ -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():

105
player/bot.py Normal file
View File

@ -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

View File

@ -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)"

View File

@ -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)"

View File

@ -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)"

View File

@ -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()

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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