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) self._Card__owner.draw_cards(cards_discarded)
def __get_index(self, message): 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) self._Card__owner.add_purchase_power(3)
def __get_Merchant_input(self, message): def __get_Merchant_input(self, message):
return self.__Card_owner.get_general_input("Player " + str(self._Card__owner.get_player_index()) + ", " + return self.__Card_owner.take_input("Player " + str(self._Card__owner.get_player_index()) + ", " +
message, str) message, str)

View File

@ -11,9 +11,9 @@ class Militia(Action, Attack):
def __force_discard(self, chances, player): def __force_discard(self, chances, player):
if player.get_hand().get_remaining() > 3 and chances > 0: 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" hand_index = player.get_response_input("\nPlease provide an index to identify a card from hand you would "
" discard (0 to " + str(player.get_hand().get_remaining() - 1) + "): " "like to discard (0 to " + str(player.get_hand().get_remaining() - 1)
, int) + "): ", int, self.__class__)
self.__check_discard(hand_index, player, chances) self.__check_discard(hand_index, player, chances)
elif self.get_owner().get_hand().get_remaining() > 3 and chances <= 0: 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.") 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): class Moat(Action, Reaction):
def react(self, what_attack): def react(self, what_attack):
owner = self.get_owner() 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) + "like to reveal " + str(self) + " to block the " + str(what_attack) +
" attack: ", str) " attack: ", str)

View File

@ -26,7 +26,7 @@ class CardGain(Card):
chances = 0 chances = 0
def __get_gain_card(self): 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) "obtain: ", int)
def __get_gainable_cards(self, spending_limit): def __get_gainable_cards(self, spending_limit):

View File

@ -29,7 +29,7 @@ class CardTrash(Card):
self.trash_card_get_cost() self.trash_card_get_cost()
def __get_card_to_trash(self): 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): def __get_trashable_cards(self):
result = list() 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>

View File

@ -1,6 +1,8 @@
from table.table import Table from table.table import Table
from player.human import Human from player.human import Human
from player.bots.pure_big_money import Pure_Big_Money 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_action import Action
from card.basic.card_curse import Curse from card.basic.card_curse import Curse
from card.basic.card_victory import Victory from card.basic.card_victory import Victory
@ -56,6 +58,11 @@ def setup_new_game(game_list, parameter, card_info):
t.add_player(human) t.add_player(human)
for i in range(bots): for i in range(bots):
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 = Pure_Big_Money(t)
bot.draw_deck(t, get_starting_deck()) bot.draw_deck(t, get_starting_deck())
bot.draw_hand() bot.draw_hand()
@ -66,7 +73,7 @@ def setup_new_game(game_list, parameter, card_info):
def get_game_parameters(): def get_game_parameters():
# humans, bots, card #1, card #2, ... etc # 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(): 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 player.bot import Bot
from card.basic.card_treasure import Treasure
class Pure_Big_Money(Player): class Pure_Big_Money(Bot):
target_card = "Province"
target_card_threshold = 8
def take_action(self): def take_action(self):
print("\nAs a BIG MONEY BOT, I'm skipping this unnecessary action phase. Beep-boop, bow to me humans!") 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): def __str__(self):
return "Player " + str(self.get_player_index()) + " (pure big money bot)" 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 attack_blocked = False
for c in self.get_supply(): for c in self.get_supply():
attack_blocked |= c.react(what_attack) 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): def __get_unique_class_instances(self):
unique_class_instances = list() unique_class_instances = list()

View File

@ -5,5 +5,3 @@ class Human(Player):
def __str__(self): def __str__(self):
return "Player " + str(self.get_player_index()) + " (human)" 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): def get_discard(self):
return self.__discard return self.__discard
def get_deck(self):
return self.__deck
def get_player_index(self): def get_player_index(self):
return self.__table.get_players().index(self) return self.__table.get_players().index(self)
@ -103,18 +106,30 @@ class Player:
def discard_from_hand(self, n): def discard_from_hand(self, n):
self.__hand.transfer_card_by_index(n, self.__discard) self.__hand.transfer_card_by_index(n, self.__discard)
def play_card(self, acceptable_card_class, chances, counter): def claim_top_card(self, supply):
if chances > 0 and self.__hand.contains_one_of(acceptable_card_class): supply.get_top_card().set_owner(self)
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) def print_hand(self):
elif chances <= 0: print("\nPlayer " + str(self.__table.get_players().index(self)) + " Hand:")
print("You have used up all of your chances to enter a valid integer; forfeiting remaining plays.") self.__hand.print()
if counter is not None:
counter.int = 0 def take_turn(self):
else: self.__turn_setup()
print("There are no more acceptable card in hand, moving to next phase.") self.__print()
if counter is not None: self.take_action()
counter.int = 0 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): def take_action(self):
print("\nPlease play an Action card until you have no remaining actions.") 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.play_card(Treasure, self.__std_chances, play_another)
self.buy_card(self.__std_chances) 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): def buy_card(self, chances):
self.__table.print() self.__table.print()
while self.__buys > 0 and not self.__table.are_there_three_empty_piles() and chances > 0: 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) self.claim_top_card(self.__discard)
chances = self.get_std_chances() 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): def __check_play_card(self, hand_index, counter, acceptable_card_class, chances):
if hand_index < 0: if hand_index < 0:
print("You have elected to forfeit any remaining plays.") 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.") 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) 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): def __get_input(self, chances, target_type, message):
value = input(message) value = input(message)
if chances > 0: if chances > 0:

View File

@ -9,6 +9,9 @@ class Supply:
for i in range(n): for i in range(n):
self.add_card(card) self.add_card(card)
def is_empty(self):
return len(self.__card) <= 0
def get_supply(self): def get_supply(self):
return self.__card return self.__card

View File

@ -46,6 +46,9 @@ class Table:
result = self.__pile.index(p) result = self.__pile.index(p)
return result 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): def are_there_three_empty_piles(self):
count = 0 count = 0
for p in self.__pile: for p in self.__pile:
@ -67,7 +70,7 @@ class Table:
should_continue = True should_continue = True
while should_continue: while should_continue:
# game ends after # 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.print()
self.__player[player_turn % len(self.__player)].take_turn() self.__player[player_turn % len(self.__player)].take_turn()
player_turn += 1 player_turn += 1