From 69a8022f220e3eaad30825e61c80be2648f99479 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Sat, 30 Dec 2017 22:44:48 -0600 Subject: [PATCH] Add files via upload had removed passive method as it is not used, where as a setup method will probably be --- player/card/card.py | 72 ++++++++++++ player/card/card_gain.py | 40 +++++++ player/card/card_gain_trash.py | 9 ++ player/card/card_trash.py | 43 +++++++ player/card/cellar.py | 27 +++++ player/card/merchant.py | 16 +++ player/card/militia.py | 33 ++++++ player/card/mine.py | 8 ++ player/card/moat.py | 5 + player/card/remodel.py | 5 + player/card/workshop.py | 8 ++ player/game.py | 116 +++++++++++++++++++ player/player/counter.py | 3 + player/player/deck.py | 7 ++ player/player/discard.py | 8 ++ player/player/hand.py | 47 ++++++++ player/player/player.py | 202 +++++++++++++++++++++++++++++++++ player/table/pile.py | 5 + player/table/supply.py | 55 +++++++++ player/table/table.py | 80 +++++++++++++ player/table/trash.py | 5 + 21 files changed, 794 insertions(+) create mode 100644 player/card/card.py create mode 100644 player/card/card_gain.py create mode 100644 player/card/card_gain_trash.py create mode 100644 player/card/card_trash.py create mode 100644 player/card/cellar.py create mode 100644 player/card/merchant.py create mode 100644 player/card/militia.py create mode 100644 player/card/mine.py create mode 100644 player/card/moat.py create mode 100644 player/card/remodel.py create mode 100644 player/card/workshop.py create mode 100644 player/game.py create mode 100644 player/player/counter.py create mode 100644 player/player/deck.py create mode 100644 player/player/discard.py create mode 100644 player/player/hand.py create mode 100644 player/player/player.py create mode 100644 player/table/pile.py create mode 100644 player/table/supply.py create mode 100644 player/table/table.py create mode 100644 player/table/trash.py diff --git a/player/card/card.py b/player/card/card.py new file mode 100644 index 0000000..29bf1e8 --- /dev/null +++ b/player/card/card.py @@ -0,0 +1,72 @@ +from enum import Enum, auto + + +class Card: + class CardType(Enum): + Treasure = auto() + Action = auto() + Reaction = auto() + Attack = auto() + Victory = auto() + Curse = auto() + + prevent_attack = False + + def __init__(self, name, cost, cardtype, value, coin, action, buy, draw, owner): + self.__name = name + self.__cost = cost + self.__coin = coin + self.__type = cardtype + self.__action = action + self.__buy = buy + self.__draw = draw + self.__value = value + self.__owner = owner + + def play(self): + self.__owner.add_actions(self.__action) + self.__owner.add_buys(self.__buy) + self.__owner.add_purchase_power(self.__coin) + self.__owner.draw_cards(self.__draw) + self.effect() + + def effect(self): + # This is here so that 'special' card can override this function so that unique card effects can happen. + pass + + def setup(self): + # This is here so that 'special' card can override this function so that unique card setup effects can happen. + pass + + def get_name(self): + return self.__name + + def get_type(self): + return self.__type + + def get_cost(self): + return self.__cost + + def set_owner(self, owner): + self.__owner = owner + + def get_owner(self): + return self.__owner + + def identify(self): + return self.__name + ", " + str(self.__type) + ", " + str(self.__cost) + + def __get_index_not_self(self): + result = -1 + for c in self._Card__owner.get_hand().get_supply(): + if c != self: + result = self._Card__owner.get_hand().get_player_index() + return result + + def __print_card_list(self, card, message): + print("\nPlayer " + str(self._Card__owner.get_player_index()) + " " + message) + + counter = 0 + for c in card: + print(str(counter) + ": " + c.identify()) + counter += 1 \ No newline at end of file diff --git a/player/card/card_gain.py b/player/card/card_gain.py new file mode 100644 index 0000000..63684b2 --- /dev/null +++ b/player/card/card_gain.py @@ -0,0 +1,40 @@ +from card.card import Card + + +class CardGain(Card): + gainable_type_restriction = None + + def gain_card(self, spending_limit): + gainable_cards = self.__get_gainable_cards(spending_limit) + self._Card__print_card_list(gainable_cards, "Gainable Cards: ") + index = 0 + chances = self._Card__owner.get_std_chances() + + while len(gainable_cards) > 0 and 0 <= index < len(gainable_cards) - 1 and chances > 0: + index = self.__get_gain_card() + + if 0 > index >= len(gainable_cards): + print("Acceptable inputs range from 0 to " + str(len(gainable_cards) - 1) + ". 1 chance lost.") + index = 0 + chances -= 1 + else: + pile_index = self._Card__owner.get_table().get_pile_index_of_card(gainable_cards[index].get_name()) + print("Player " + str(self._Card__owner.get_player_index()) + " drawing " + + self._Card__owner.get_table().get_pile(pile_index).get_card_group().get_name() + " to hand.") + self._Card__owner.get_table().get_pile(pile_index).transfer_top_card(self._Card__owner.get_hand()) + self._Card__owner.claim_top_card(self._Card__owner.get_hand()) + chances = 0 + + def __get_gain_card(self): + return int(input("\nPlease identify the index of which card you would like to obtain: ")) + + def __get_gainable_cards(self, spending_limit): + result = list() + + for p in self._Card__owner.get_table().get_piles(): + if p.get_card_group().get_cost() <= spending_limit: + if self.gainable_type_restriction is None: + result.append(p.get_card_group()) + elif p.get_card_group().get_type() in self.gainable_type_restriction: + result.append(p.get_card_group()) + return result diff --git a/player/card/card_gain_trash.py b/player/card/card_gain_trash.py new file mode 100644 index 0000000..c68bd91 --- /dev/null +++ b/player/card/card_gain_trash.py @@ -0,0 +1,9 @@ +from card.card_trash import CardTrash +from card.card_gain import CardGain + + +class CardGainTrash(CardTrash, CardGain): + coin_gain = 0 + + def effect(self): + self.gain_card(self.trash_card_get_cost() + self.coin_gain) diff --git a/player/card/card_trash.py b/player/card/card_trash.py new file mode 100644 index 0000000..55833a4 --- /dev/null +++ b/player/card/card_trash.py @@ -0,0 +1,43 @@ +from card.card import Card + + +class CardTrash(Card): + trashable_type_restriction = None + + def trash_card_get_cost(self): + tc = self.__get_trashable_cards() + self._Card__print_card_list(tc, " Trashable Cards: ") + index = 0 + bonus = 0 + chances = self._Card__owner.get_std_chances() + + while 0 < len(tc) and 0 <= index < len(tc) - 1 and chances > 0: + index = self.__get_card_to_trash() + + if index < 0 or index >= len(tc): + print("Acceptable inputs range from 0 to " + str(len(tc) - 1) + ". 1 chance lost.") + index = 0 + chances -= 1 + else: + print("Player " + str(self._Card__owner.get_player_index()) + " trashing " + tc[index].get_name() + ".") + bonus = tc[index].get_cost() + self._Card__owner.get_hand().transfer_card_by_card(tc[index], self._Card__owner.get_table().get_trash()) + chances = 0 + return bonus + + def trash_card(self): + self.trash_card_get_cost() + + def __get_card_to_trash(self): + return int(input("\nPlease identify the index of the desired card to trash: ")) + + def __get_trashable_cards(self): + result = list() + + for c in self._Card__owner.get_hand().get_supply(): + if c != self: + if self.trashable_type_restriction is None: + result.append(c) + elif c.get_type() in self.trashable_type_restriction: + result.append(c) + return result diff --git a/player/card/cellar.py b/player/card/cellar.py new file mode 100644 index 0000000..5bada8d --- /dev/null +++ b/player/card/cellar.py @@ -0,0 +1,27 @@ +from card.card import Card + + +class Cellar(Card): + def effect(self): + hand_index = 0 + cards_discarded = 0 + have_not_run_yet = True + while self._Card__owner.get_hand().get_remaining() >= 0 and \ + 0 <= hand_index < self._Card__owner.get_hand().get_remaining() and \ + (hand_index != self._Card__owner.get_hand().get_supply().index(self) or have_not_run_yet): + hand_index = self.__get_index("Player " + str(self._Card__owner.get_player_index()) + ", input the index " + "from your hand to discard that card and gain an action, or input an " + "impossible index to end discard selection: ") + + if 0 <= hand_index < self._Card__owner.get_hand().get_remaining() and \ + hand_index != self._Card__owner.get_hand().get_supply().index(self): + self._Card__owner.discard_from_hand(hand_index) + self._Card__owner.print_hand() + cards_discarded += 1 + hand_index = self.__get_index_not_self() + have_not_run_yet = False + self._Card__owner.draw_cards(cards_discarded) + + def __get_index(self, message): + return int(input(message)) + diff --git a/player/card/merchant.py b/player/card/merchant.py new file mode 100644 index 0000000..8df764d --- /dev/null +++ b/player/card/merchant.py @@ -0,0 +1,16 @@ +from card.card import Card + + +class Merchant(Card): + def effect(self): + silver_card_index = self._Card__owner.get_hand().get_index_of_card_by_name("Silver") + if silver_card_index >= 0: + yes_no = self.__get_Merchant_input("'Y' if you'd like to play a silver card and gain an extra coin: ") + + if yes_no: + self._Card__owner.get_hand().transfer_card_by_card( + self._Card__owner.get_hand().get_card(silver_card_index), self._Card__owner.get_discard()) + self._Card__owner.add_purchase_power(3) + + def __get_Merchant_input(self, message): + return int(input("Player " + str(self._Card__owner.get_player_index()) + ", " + message)) diff --git a/player/card/militia.py b/player/card/militia.py new file mode 100644 index 0000000..89b69f4 --- /dev/null +++ b/player/card/militia.py @@ -0,0 +1,33 @@ +from card.card import Card +from random import randint + + +class Militia(Card): + 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 __force_discard(self, chances, player): + if player.get_hand().get_remaining() > 3 and chances > 0: + hand_index = self.__get_index("\nPlease identify a card from hand you would like to discard by providing " + "its index 0 to " + str(player.get_hand().get_remaining() - 1) + ": ") + self.__check_discard(hand_index, player, chances) + elif self._Card__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)) + + def __get_index(self, message): + return int(input(message)) + + 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.") + 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) diff --git a/player/card/mine.py b/player/card/mine.py new file mode 100644 index 0000000..3c4f81d --- /dev/null +++ b/player/card/mine.py @@ -0,0 +1,8 @@ +from card.card import Card +from card.card_gain_trash import CardGainTrash + + +class Mine(CardGainTrash): + coin_gain = 3 + trashable_type_restriction = [Card.CardType.Treasure] + gainable_type_restriction = [Card.CardType.Treasure] diff --git a/player/card/moat.py b/player/card/moat.py new file mode 100644 index 0000000..76cdfd4 --- /dev/null +++ b/player/card/moat.py @@ -0,0 +1,5 @@ +from card.card import Card + + +class Moat(Card): + prevent_attack = True diff --git a/player/card/remodel.py b/player/card/remodel.py new file mode 100644 index 0000000..4d95eef --- /dev/null +++ b/player/card/remodel.py @@ -0,0 +1,5 @@ +from card.card_gain_trash import CardGainTrash + + +class Remodel(CardGainTrash): + coin_gain = 2 diff --git a/player/card/workshop.py b/player/card/workshop.py new file mode 100644 index 0000000..30b5fbd --- /dev/null +++ b/player/card/workshop.py @@ -0,0 +1,8 @@ +from card.card_gain import CardGain + + +class Workshop(CardGain): + coin_gain = 4 + + def effect(self): + self.gain_card(self.coin_gain) diff --git a/player/game.py b/player/game.py new file mode 100644 index 0000000..9356064 --- /dev/null +++ b/player/game.py @@ -0,0 +1,116 @@ +from table.table import Table +from player.player import Player +from card.card import Card +from card.militia import Militia +from card.moat import Moat +from card.cellar import Cellar +from card.merchant import Merchant +from card.mine import Mine +from card.remodel import Remodel +from card.workshop import Workshop + + +def main(): + game = list() + card_info = get_card_info() + setup_new_game(game, get_game_parameters(), card_info) + play_game(game[0]) + + +def play_game(game_table): + game_table.play() + + +# place holder setup for testing until frontend constructed +def setup_new_game(game_list, parameter, card_info): + t = Table() + humans = parameter[0] + # bots = parameter[1] + + index = 0 + for p in parameter[2:]: + if p: + for i in range(card_info[index][9]): + card = card_info[index][8](card_info[index][0], card_info[index][1], card_info[index][2], + card_info[index][3], card_info[index][4], card_info[index][5], + card_info[index][6], card_info[index][7], None) + if i == 0: + t.add_pile(card) + else: + t.get_pile(t.get_pile_index_of_card(card_info[index][0])).add_card(card) + index += 1 + + for i in range(humans): + human = Player(True, t) + human.draw_deck(t, get_starting_deck()) + human.draw_hand() + t.add_player(human) + + # for i in range(bots): + # bot = Player(False, t) + # bot.draw_deck(t, get_starting_deck()) + # bot.draw_hand() + # t.add_player(bot) + + game_list.append(t) + + +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] + + +def get_card_info(): + # 0 1 2 3 4 5 6 7 8 9 + # [name, cost, cardtype, v, c, a, b, d, class, count] - values to pass to Card() + return [["Copper", 0, Card.CardType.Treasure, 0, 1, 0, 0, 0, Card, 60], # 1 + ["Silver", 3, Card.CardType.Treasure, 0, 2, 0, 0, 0, Card, 40], # 2 + ["Gold", 6, Card.CardType.Treasure, 0, 3, 0, 0, 0, Card, 30], # 3 + ["Estate", 2, Card.CardType.Victory, 1, 0, 0, 0, 0, Card, 24], # 4 + ["Dutchy", 5, Card.CardType.Victory, 3, 0, 0, 0, 0, Card, 12], # 5 + ["Province", 8, Card.CardType.Victory, 6, 0, 0, 0, 0, Card, 12], # 6 + ["Curse", 0, Card.CardType.Curse, -1, 0, 0, 0, 0, Card, 30], # 7 + ["Cellar", 2, Card.CardType.Action, 0, 0, 1, 0, 0, Cellar, 10], # 8 + ["Market", 5, Card.CardType.Action, 0, 1, 1, 1, 1, Card, 10], # 9 + ["Merchant", 3, Card.CardType.Action, 0, 0, 1, 0, 1, Merchant, 10], # 10 + ["Militia", 4, Card.CardType.Attack, 0, 2, 0, 0, 0, Militia, 10], # 11 + ["Mine", 5, Card.CardType.Action, 0, 0, 0, 0, 0, Mine, 10], # 12 + ["Moat", 2, Card.CardType.Reaction, 0, 0, 0, 0, 2, Moat, 10], # 13 + ["Remodel", 4, Card.CardType.Action, 0, 0, 0, 0, 0, Remodel, 10], # 14 + ["Smithy", 4, Card.CardType.Action, 0, 0, 0, 0, 3, Card, 10], # 15 + ["Village", 3, Card.CardType.Action, 0, 0, 2, 0, 1, Card, 10], # 16 + ["Workshop", 4, Card.CardType.Action, 0, 0, 0, 0, 0, Workshop, 10]] # 17 + # Big Money + # ["Adventurer", + # ["Bureaucrat", + # ["Chancellor", + # ["Chapel", + # ["Feast", + # ["Laboratory", + # ["Moneylender", + # ["Throne Room", + # Interaction + # ["Council Room", + # ["Festival", + # ["Library", + # ["Spy", + # ["Thief", + # Size Distortion + # ["Gardens", + # ["Woodcuter", + # ["Witch", + # Villiage Square + # Trash Heap + # http://dominioncg.wikia.com/wiki/Pre-set_Sets_of_10 + # http://www.dominiondeck.com/games/popular + + +def get_starting_deck(): + return [["Copper", 7], ["Estate", 3]] + # return [["Market", 2], ["Merchant", 2], ["Smithy", 2], ["Village", 2], ["Moat", 2]] + # return [["Militia", 4], ["Cellar", 3], ["Moat", 3]] + # return [["Silver", 7], ["Merchant", 3]] + # return [["Copper", 4], ["Mine", 2], ["Remodel", 2], ["Workshop", 2]] + + +main() diff --git a/player/player/counter.py b/player/player/counter.py new file mode 100644 index 0000000..cfcadd4 --- /dev/null +++ b/player/player/counter.py @@ -0,0 +1,3 @@ +class Counter: + def __init__(self, n): + self.int = n diff --git a/player/player/deck.py b/player/player/deck.py new file mode 100644 index 0000000..d501704 --- /dev/null +++ b/player/player/deck.py @@ -0,0 +1,7 @@ +from table.supply import Supply +from random import shuffle + + +class Deck(Supply): + def shuffle(self): + shuffle(self._Supply__card) diff --git a/player/player/discard.py b/player/player/discard.py new file mode 100644 index 0000000..3ecf828 --- /dev/null +++ b/player/player/discard.py @@ -0,0 +1,8 @@ +from table.supply import Supply + + +class Discard(Supply): + def cycle_card(self, deck): + while self.get_remaining() > 0: + self.transfer_top_card(deck) + deck.shuffle() diff --git a/player/player/hand.py b/player/player/hand.py new file mode 100644 index 0000000..cb6e2c7 --- /dev/null +++ b/player/player/hand.py @@ -0,0 +1,47 @@ +from table.supply import Supply + + +class Hand(Supply): + def contains_one_of(self, acceptible_types): + result = False + unique_types = self.__get_unique_types() + + for at in acceptible_types: + result |= at in unique_types + return result + + def get_card_type_count(self, card_type): + result = 0 + + for c in self._Supply__card: + if c.get_type() == card_type: + result += 1 + return result + + def blocks_attack(self, what_attack): + yes_no = False + found_at = -1 + + for c in self._Supply__card: + if c.prevent_attack: + found_at = self._Supply__card.index(c) + + if found_at >= 0: + yes_no = "Y" == self.__get_reveal("Player " + + str(self._Supply__card[found_at].get_owner().get_player_index()) + + ", enter 'Y' if you'd like to reveal " + + self._Supply__card[found_at].get_name() + " to block the " + + what_attack + " attack: ") + return yes_no + + def __get_reveal(self, message): + return input(message) + + def __get_unique_types(self): + unique_type = list() + + for c in self._Supply__card: + current_type = c.get_type() + if not current_type in unique_type: + unique_type.append(current_type) + return unique_type diff --git a/player/player/player.py b/player/player/player.py new file mode 100644 index 0000000..a3345c5 --- /dev/null +++ b/player/player/player.py @@ -0,0 +1,202 @@ +from player.deck import Deck +from player.discard import Discard +from player.hand import Hand +from player.counter import Counter +from card.card import Card + + +class Player: + def __init__(self, human, table): + self.__std_chances = 3 + self.__deck = Deck() + self.__discard = Discard() + self.__hand = Hand() + self.__purchase_power = 0 + self.__actions = Counter(0) + self.__buys = 0 + self.__is_human = human + self.__table = table + + def add_actions(self, n): + self.__actions.int += n + + def add_purchase_power(self, n): + self.__purchase_power += n + + def add_buys(self, n): + self.__buys += n + + def get_table(self): + return self.__table + + def get_std_chances(self): + return self.__std_chances + + def get_hand(self): + return self.__hand + + def get_discard(self): + return self.__discard + + def get_player_index(self): + return self.__table.get_players().index(self) + + def get_score(self): + return 0 + + def draw_card(self): + self.__deck.transfer_top_card(self.__hand) + + def draw_cards(self, how_many): + spillover = how_many - self.__deck.get_remaining() + lacking_cards = spillover - self.__discard.get_remaining() + + if lacking_cards <= 0: + lacking_cards = 0 + elif lacking_cards == 1: + print("You are lacking " + str(lacking_cards) + " card. You cannot draw anymore.") + else: + print("You are lacking " + str(lacking_cards) + " card. You cannot draw anymore.") + + if spillover > 0: + for i in range(how_many - spillover): + self.draw_card() + + self.__discard.cycle_card(self.__deck) + + for i in range(spillover - lacking_cards): + self.draw_card() + else: + for i in range(how_many): + self.draw_card() + + def draw_deck(self, table, deck_setup): + for ds in deck_setup: + index = table.get_pile_index_of_card(ds[0]) + for i in range(ds[1]): + table.get_pile(index).transfer_top_card(self.__deck) + self.claim_top_card(self.__deck) + self.__deck.shuffle() + + def draw_hand(self): + self.draw_cards(5) + + def discard_remaining_hand(self): + while self.__hand.get_remaining() > 0: + self.__hand.transfer_top_card(self.__discard) + + def discard_from_hand(self, n): + self.__hand.transfer_card_by_index(n, self.__discard) + + def play_card(self, acceptable_card_type, chances, counter): + if chances > 0 and self.__hand.contains_one_of(acceptable_card_type): + hand_index = self.__get_play_input("\nPlease identify a card from hand to play by providing its index: ") + self.__check_play_card(hand_index, counter, acceptable_card_type, 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 take_action(self): + print("\nPlease play an Action, Attack, or Reaction card until you have no remaining actions.") + while self.__actions.int > 0: + self.play_card([Card.CardType.Action, Card.CardType.Attack, Card.CardType.Reaction], + self.__std_chances, self.__actions) + + def take_buy(self): + if self.__hand.contains_one_of([Card.CardType.Treasure]): + print("\nPlease play all Treasure card that you want to play.") + + play_another = Counter(self.__hand.get_card_type_count(Card.CardType.Treasure)) + while play_another.int > 0: + self.play_card([Card.CardType.Treasure], self.__std_chances, play_another) + self.buy_card(self.__std_chances) + + def buy_card(self, chances): + self.__table.print() + while self.__buys > 0 and not self.__table.are_there_any_empty_piles() and chances > 0: + pile_index = self.__get_buy_input("\nPlease identify a pile from the table that you'd like to purchase: ") + + if pile_index < 0: + print("You have elected to forfeit any remaining plays.") + self.__buys = 0 + elif pile_index >= self.__table.get_pile_count(): + print("Acceptable inputs range from 0 to " + str(self.__table.get_pile_count() - 1) + ". Try again.") + chances -= 1 + elif self.__table.get_pile(pile_index).get_card_group().get_cost() > self.__purchase_power: + print("You do not have enough coin. Try again.") + chances -= 1 + else: + print("Player " + str(self.get_table().get_players().index(self)) + " buying card " + + self.__table.get_pile(pile_index).get_card_group().get_name()) + self.__table.get_pile(pile_index).transfer_top_card(self.__discard) + self.claim_top_card(self.__discard) + self.__buys -= 1 + + 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_type, chances): + if hand_index < 0: + print("You have elected to forfeit any remaining plays.") + if counter is not None: + counter.int = 0 + elif hand_index >= self.__hand.get_remaining(): + print("Acceptable inputs range from 0 to " + str(self.__hand.get_remaining() - 1) + ". 1 chance lost.") + self.play_card(acceptable_card_type, chances - 1, counter) + elif self.__hand.get_card(hand_index).get_type() in acceptable_card_type: + print("Player " + str(self.get_player_index()) + " playing: " + self.__hand.get_card(hand_index).get_name()) + self.__hand.get_card(hand_index).play() + self.__hand.transfer_card_by_card(self.__hand.get_card(hand_index), self.__discard) + if counter is not None: + counter.int -= 1 + self.__print() + else: + print("Index in bounds but not an acceptable card type. Chance to get it right reduced.") + self.play_card(acceptable_card_type, 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): + return int(input(message)) + + def __get_buy_input(self, message): + return int(input(message)) + + def __print_discard(self): + print("\nPlayer " + str(self.__table.get_players().index(self)) + " Discard:") + self.__discard.print() + + def __print_deck(self): + print("\nPlayer " + str(self.__table.get_players().index(self)) + " Deck:") + self.__deck.print() + + def __print(self): + print("\nPlayer " + str(self.__table.get_players().index(self)) + ": ") + print("Actions: " + str(self.__actions.int)) + print("Buys: " + str(self.__buys)) + print("Coin: " + str(self.__purchase_power)) + self.print_hand() + self.__print_discard() + # self.__print_deck() + + def __turn_setup(self): + self.__actions.int = 1 + self.__buys = 1 + self.__purchase_power = 0 diff --git a/player/table/pile.py b/player/table/pile.py new file mode 100644 index 0000000..43567ad --- /dev/null +++ b/player/table/pile.py @@ -0,0 +1,5 @@ +from table.supply import Supply + +class Pile(Supply): + def get_card_group(self): + return self._Supply__card[0] diff --git a/player/table/supply.py b/player/table/supply.py new file mode 100644 index 0000000..a85c833 --- /dev/null +++ b/player/table/supply.py @@ -0,0 +1,55 @@ +class Supply: + def __init__(self): + self.__card = list() + + def add_card(self, card): + self.__card.append(card) + + def add_cards(self, card, n): + for i in range(n): + self.add_card(card) + + def get_supply(self): + return self.__card + + def get_index_of_card_by_name(self, name): + for c in self.__card: + if c.get_name() == name: + return self.__card.index(c) + return -1 + + def get_index_of_card_by_card(self, card): + for c in self.__card: + if c == card: + return self.__card.index(c) + return -1 + + def transfer_top_card(self, recipient_supply): + self.transfer_card_by_index(len(self.__card) - 1, recipient_supply) + + def transfer_card_by_index(self, n, recipient_supply): + transfer_card = self.__card.pop(n) + recipient_supply.add_card(transfer_card) + + def transfer_card_by_card(self, card, recipient_supply): + card_index = self.get_index_of_card_by_card(card) + + if card_index >= 0: + self.transfer_card_by_index(card_index, recipient_supply) + else: + raise ValueError('Card not found in hand during attempt to transfer card.') + + def get_card(self, n): + return self.__card[n] + + def get_top_card(self): + return self.__card[len(self.__card) - 1] + + def get_remaining(self): + return len(self.__card) + + def print(self): + index = 0 + for c in self.__card: + print(str(index) + ": " + c.identify()) + index += 1 diff --git a/player/table/table.py b/player/table/table.py new file mode 100644 index 0000000..d193a66 --- /dev/null +++ b/player/table/table.py @@ -0,0 +1,80 @@ +from table.trash import Trash +from table.pile import Pile + + +class Table: + def __init__(self): + self.__player = list() + self.__pile = list() + self.__trash = Trash() + self.__winner = None + self.__winning_score = 0 + + def add_player(self, p): + self.__player.append(p) + + def get_player(self, n): + return self.__player[n] + + def get_players(self): + return self.__player + + def get_trash(self): + return self.__trash + + def add_pile(self, card): + p = Pile() + p.add_card(card) + card.setup() + self.__pile.append(p) + + def get_piles(self): + return self.__pile + + def get_pile(self, n): + return self.__pile[n] + + def get_pile_count(self): + return len(self.__pile) + + def get_pile_index_of_card(self, card_name): + result = 0 + + for p in self.__pile: + if p.get_card_group().get_name() == card_name: + result = self.__pile.index(p) + return result + + def are_there_any_empty_piles(self): + result = False + for p in self.__pile: + result = result or p.get_remaining() == 0 + return result + + 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: + self.print() + self.__player[turn % len(self.__player)].take_turn() + turn += 1 + else: + self.print() + for p in self.__player: + if p.get_score() > self.__winning_score: + self.__winning_score = p.get_score + self.__winner = p + print("\n\nPlayer " + str(self.__winner) + " won with " + str(self.__winning_score) + " points.\n\n") + + def print(self): + print("\nPiles: ") + index = 0 + for s in self.__pile: + print(str(index) + ": " + s.get_card_group().identify() + ": " + str(s.get_remaining())) + index += 1 + + print("\nTrash: ") + index = 0 + for s in self.__trash.get_supply(): + print(str(index) + ": " + s.identify()) + index += 1 diff --git a/player/table/trash.py b/player/table/trash.py new file mode 100644 index 0000000..5786689 --- /dev/null +++ b/player/table/trash.py @@ -0,0 +1,5 @@ +from table.pile import Pile + + +class Trash(Pile): + pass