From e3ff6416ff28dd1770c8bd7e147529b587c5af8e Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Wed, 10 Jan 2018 23:30:39 -0500 Subject: [PATCH] Add files via upload Generalized out attack cards. Fixed bugs. --- card/basic/card_attack.py | 8 +++++++- card/basic/card_curse.py | 14 +++++++------- card/basic/card_kingdom.py | 6 +++--- card/basic/card_treasure.py | 2 +- card/card.py | 4 +++- card/named/militia.py | 21 ++++++++++----------- card/named/moat.py | 6 +++++- card/named/province.py | 5 +++++ game.py | 5 +++-- player/bots/pure_big_money.py | 2 +- player/discard.py | 6 ++++++ player/hand.py | 17 ++++------------- player/human.py | 4 ++-- player/player.py | 9 ++++++--- table/supply.py | 3 ++- table/table.py | 33 +++++++++++++++++++++++---------- 16 files changed, 88 insertions(+), 57 deletions(-) create mode 100644 card/named/province.py diff --git a/card/basic/card_attack.py b/card/basic/card_attack.py index af4c9e8..d3acc68 100644 --- a/card/basic/card_attack.py +++ b/card/basic/card_attack.py @@ -2,4 +2,10 @@ from card.basic.card_kingdom import Kingdom class Attack(Kingdom): - pass + def effect(self): + for player in self.get_owner().get_table().get_players(): + if self.get_owner() != player and not player.get_hand().reaction_blocks_attack(self.get_name()): + self.attack(player) + + def attack(self, player): + pass diff --git a/card/basic/card_curse.py b/card/basic/card_curse.py index daa9f83..185531c 100644 --- a/card/basic/card_curse.py +++ b/card/basic/card_curse.py @@ -1,10 +1,10 @@ -from card.card import Card +from card.basic.card_victory import Victory -class Curse(Card): - @staticmethod - def pile_setup(player_count): - if player_count % Card.normal_full_table < Card.normal_full_table/2: - return Card.pile_player_rate +class Curse(Victory): + @classmethod + def pile_setup(cls, player_count): + if player_count % cls.normal_full_table < cls.normal_full_table/2: + return Victory.pile_player_rate else: - return (player_count - 1) * Card.pile_player_rate + return (player_count - 1) * cls.pile_player_rate diff --git a/card/basic/card_kingdom.py b/card/basic/card_kingdom.py index 46b670e..77b6075 100644 --- a/card/basic/card_kingdom.py +++ b/card/basic/card_kingdom.py @@ -5,6 +5,6 @@ from math import floor class Kingdom(Card): pile_player_rate = 10 - @staticmethod - def pile_setup(player_count): - return (floor(player_count/Card.normal_full_table) + 1) * Card.pile_player_rate + @classmethod + def pile_setup(cls, player_count): + return (floor(player_count/cls.normal_full_table) + 1) * cls.pile_player_rate diff --git a/card/basic/card_treasure.py b/card/basic/card_treasure.py index 4206a6a..f16fdce 100644 --- a/card/basic/card_treasure.py +++ b/card/basic/card_treasure.py @@ -5,4 +5,4 @@ from math import floor class Treasure(Card): @classmethod def pile_setup(cls, player_count): - return (floor(player_count/Card.normal_full_table) + 1) * cls.pile_player_rate + return (floor(player_count/cls.normal_full_table) + 1) * cls.pile_player_rate diff --git a/card/card.py b/card/card.py index 35c41b3..6dcffa7 100644 --- a/card/card.py +++ b/card/card.py @@ -1,5 +1,4 @@ class Card: - prevent_attack = False normal_full_table = 6 pile_player_rate = 10 @@ -24,6 +23,9 @@ class Card: # This is here so that 'special' card can override this function so that unique card effects can happen. pass + def react(self, what_attack): + return False + @classmethod def pile_setup(cls, player_count): # This is here so that each card can override this function so that the right number of . diff --git a/card/named/militia.py b/card/named/militia.py index ffc8783..6711e1b 100644 --- a/card/named/militia.py +++ b/card/named/militia.py @@ -4,12 +4,10 @@ from random import randint class Militia(Action, Attack): - def effect(self): - for player in self._Card__owner.get_table().get_players(): - if self._Card__owner != player and not player.get_hand().blocks_attack(self.get_name()): - player.print_hand() - print("Player " + str(player.get_player_index()) + ", you MUST discard down to 3 card.") - self.__force_discard(self._Card__owner.get_std_chances(), player) + def attack(self, player): + player.print_hand() + print("Player " + str(player.get_player_index()) + ", you MUST discard down to 3 card.") + self.__force_discard(self.get_owner().get_std_chances(), player) def __force_discard(self, chances, player): if player.get_hand().get_remaining() > 3 and chances > 0: @@ -17,16 +15,17 @@ class Militia(Action, Attack): " discard (0 to " + str(player.get_hand().get_remaining() - 1) + "): " , int) self.__check_discard(hand_index, player, chances) - elif self._Card__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.") - player.discard_from_hand(randint(0, self.__hand.get_remaining() - 1)) + player.discard_from_hand(randint(0, self.get_owner().get_hand().get_remaining() - 1)) def __check_discard(self, index, player, chances): - if 0 > index or index >= self._Card__owner.get_hand().get_remaining(): - print("Valid inputs range from 0 to " + str(player.get_hand().get_remaining() - 1) + ". 1 chance lost.") + if 0 > index >= player.get_hand().get_remaining(): + print("Valid inputs range from 0 to " + str(player.get_hand().get_remaining() - 1) + ". " + str(chances - 1) + + "chances to input a valid index.") self.__force_discard(chances - 1, player) else: print("Discarding " + player.get_hand().get_card(index).get_name() + ".") player.discard_from_hand(index) player.print_hand() - self.__force_discard(self._Card__owner.get_std_chances(), player) + self.__force_discard(self.get_owner().get_std_chances(), player) diff --git a/card/named/moat.py b/card/named/moat.py index 9e8f76f..d15679b 100644 --- a/card/named/moat.py +++ b/card/named/moat.py @@ -3,4 +3,8 @@ from card.basic.card_reaction import Reaction class Moat(Action, Reaction): - prevent_attack = True + 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 " + "like to reveal " + str(self) + " to block the " + str(what_attack) + + " attack: ", str) diff --git a/card/named/province.py b/card/named/province.py new file mode 100644 index 0000000..1f0eec4 --- /dev/null +++ b/card/named/province.py @@ -0,0 +1,5 @@ +from card.basic.card_victory import Victory + + +class Province(Victory): + pass diff --git a/game.py b/game.py index 516a5ae..91c1d80 100644 --- a/game.py +++ b/game.py @@ -4,6 +4,7 @@ from player.bots.pure_big_money import Pure_Big_Money from card.basic.card_action import Action from card.basic.card_curse import Curse from card.basic.card_victory import Victory +from card.named.province import Province from card.named.estate import Estate from card.named.copper import Copper from card.named.silver import Silver @@ -65,7 +66,7 @@ def setup_new_game(game_list, parameter, card_info): def get_game_parameters(): # humans, bots, card #1, card #2, ... etc - return [1, 1, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True] + return [2, 1, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True] def get_card_info(): @@ -76,7 +77,7 @@ def get_card_info(): ["Gold", 6, 0, 3, 0, 0, 0, Gold], # 2 ["Estate", 2, 1, 0, 0, 0, 0, Estate], # 3 ["Dutchy", 5, 3, 0, 0, 0, 0, Victory], # 4 - ["Province", 8, 6, 0, 0, 0, 0, Victory], # 5 + ["Province", 8, 6, 0, 0, 0, 0, Province], # 5 ["Curse", 0, -1, 0, 0, 0, 0, Curse], # 6 ["Cellar", 2, 0, 0, 1, 0, 0, Cellar], # 7 ["Market", 5, 0, 1, 1, 1, 1, Action], # 8 diff --git a/player/bots/pure_big_money.py b/player/bots/pure_big_money.py index 6f4b724..8513dd3 100644 --- a/player/bots/pure_big_money.py +++ b/player/bots/pure_big_money.py @@ -20,7 +20,7 @@ class Pure_Big_Money(Player): #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._Player__purchase_power + coin = self.get_coin() choice = -1 if coin >= 8: diff --git a/player/discard.py b/player/discard.py index 3ecf828..8c43b82 100644 --- a/player/discard.py +++ b/player/discard.py @@ -6,3 +6,9 @@ class Discard(Supply): while self.get_remaining() > 0: self.transfer_top_card(deck) deck.shuffle() + + def print(self): + if len(self.get_supply()) > 0: + print("Discard shows " + str(self.get_top_card()) + " face up.") + else: + print("Discard is empty.") diff --git a/player/hand.py b/player/hand.py index 0559258..87d1959 100644 --- a/player/hand.py +++ b/player/hand.py @@ -18,20 +18,11 @@ class Hand(Supply): result += 1 return result - def blocks_attack(self, what_attack): - yes_no = False - found_at = -1 - + def reaction_blocks_attack(self, what_attack): + attack_blocked = False for c in self.get_supply(): - if c.prevent_attack: - found_at = self.get_supply().index(c) - - if found_at >= 0: - owner = self.get_supply()[found_at].get_owner() - yes_no = "Y" == owner.get_general_input("Player " + str(owner.get_player_index()) + ", enter 'Y' if you'd " - "like to reveal " + self.get_supply()[found_at].get_name() + - " to block the " + what_attack + " attack: ", str) - return yes_no + attack_blocked |= c.react(what_attack) + return attack_blocked def __get_unique_class_instances(self): unique_class_instances = list() diff --git a/player/human.py b/player/human.py index 9486eb9..b06cb39 100644 --- a/player/human.py +++ b/player/human.py @@ -5,5 +5,5 @@ class Human(Player): def __str__(self): return "Player " + str(self.get_player_index()) + " (human)" - def militia_input(self, message): - return self.get_general_input(message) + 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 2c49b0d..0c492e1 100644 --- a/player/player.py +++ b/player/player.py @@ -42,6 +42,9 @@ class Player: def get_player_index(self): return self.__table.get_players().index(self) + def get_coin(self): + return self.__purchase_power + def get_score(self): score = 0 @@ -129,7 +132,7 @@ class Player: def buy_card(self, chances): self.__table.print() - while self.__buys > 0 and not self.__table.are_there_any_empty_piles() and chances > 0: + while self.__buys > 0 and not self.__table.are_there_three_empty_piles() and chances > 0: pile_index = self.get_buy_input("\nPlease choose a pile from the table that you'd like to purchase: ", int) if pile_index < 0: @@ -232,7 +235,6 @@ class Player: return True def __print_discard(self): - print("\nPlayer " + str(self.__table.get_players().index(self)) + " Discard:") self.__discard.print() def __print_deck(self): @@ -244,8 +246,9 @@ class Player: print("Actions: " + str(self.__actions.int)) print("Buys: " + str(self.__buys)) print("Coin: " + str(self.__purchase_power)) - self.print_hand() + print("Deck Remaining: " + str(self.__deck.get_remaining())) self.__print_discard() + self.print_hand() print("") def __turn_setup(self): diff --git a/table/supply.py b/table/supply.py index 86d4d79..6157e7a 100644 --- a/table/supply.py +++ b/table/supply.py @@ -43,7 +43,8 @@ class Supply: return self.__card[n] def get_top_card(self): - return self.__card[len(self.__card) - 1] + if len(self.__card) > 0: + return self.__card[len(self.__card) - 1] def get_remaining(self): return len(self.__card) diff --git a/table/table.py b/table/table.py index 4a78636..2adb2dd 100644 --- a/table/table.py +++ b/table/table.py @@ -1,5 +1,6 @@ from table.trash import Trash from table.pile import Pile +from card.named.province import Province class Table: @@ -45,22 +46,34 @@ class Table: result = self.__pile.index(p) return result - def are_there_any_empty_piles(self): - result = False + def are_there_three_empty_piles(self): + count = 0 for p in self.__pile: - result = result or p.get_remaining() == 0 - return result + if p.get_remaining() == 0: + count += 1 + return count > 2 + + def has_provinces_run_out(self): + for p in self.__pile: + if isinstance(p.get_card_group(), Province): + return p.get_remaining() == 0 + return False + + def should_game_end(self): + return self.are_there_three_empty_piles() or self. has_provinces_run_out() def play(self): - turn = 0 - # turn < 10 is for testing, otherwise endless as buying card is not yet done - while not self.are_there_any_empty_piles(): # and turn < 10: + player_turn = 0 + should_continue = True + while should_continue: + # game ends after + should_continue = not self.should_game_end() or player_turn % len(self.__player) != 0 self.print() - self.__player[turn % len(self.__player)].take_turn() - turn += 1 + self.__player[player_turn % len(self.__player)].take_turn() + player_turn += 1 else: self.print() - print("\n\nGame had " + str(turn) + " turns in " + str(turn/len(self.__player)) + " rounds.") + print("\n\nGame had " + str(player_turn) + " turns in " + str(player_turn/len(self.__player)) + " rounds.") for p in self.__player: print("" + str(p) + " scored " + str(p.get_score()) + " points.") if p.get_score() > self.__winning_score: