diff --git a/card.py b/card.py index f204c4f..1fd7fc7 100644 --- a/card.py +++ b/card.py @@ -3,14 +3,14 @@ from enum import Enum, auto class Card: class CardType(Enum): - Action = auto() - Attack = auto() Treasure = auto() + Action = auto() + Reaction = auto() + Attack = auto() Victory = auto() Curse = auto() - Reaction = auto() - def __init__(self, name, cost, cardtype, value, coin, action, reaction, buy, draw, effect): + def __init__(self, name, cost, cardtype, value, coin, action, buy, draw, owner): self.__name = name self.__cost = cost self.__coin = coin @@ -18,27 +18,38 @@ class Card: self.__action = action self.__buy = buy self.__draw = draw - self.__effect = effect self.__value = value - self.__reaction = reaction + self.__owner = owner - def play(self, player): - player.add_actions(self.__action) - player.add_buys(self.__buy) - player.add_purchase_power(self.__coin) - player.add_reactions(self.__reaction) - player.draw_cards(self.__draw) - self.effect(player) + 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, player): + def effect(self): # This is here so that 'special' cards can override this function so that unique card effects can happen. pass + def passive(self): + # This is here so that 'special' cards can override this function so that unique card passives 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) \ No newline at end of file diff --git a/game.py b/game.py index 95dea0a..4c9d46d 100644 --- a/game.py +++ b/game.py @@ -1,6 +1,7 @@ from table import Table from player import Player from card import Card +from militia import Militia def main(): @@ -18,10 +19,10 @@ def setup_new_game(game_list, parameter, card_info): index = 0 for p in parameter[2:]: if p: - card = Card(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], - card_info[index][8], card_info[index][9]) - t.add_pile(card, card_info[index][10]) + 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) + t.add_pile(card, card_info[index][9]) index += 1 for i in range(humans): @@ -30,11 +31,11 @@ def setup_new_game(game_list, parameter, card_info): 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) + 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) @@ -44,35 +45,35 @@ def play_game(game_table): 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] def get_card_info(): - # [name, cost, cardtype, v, c, a, r, b, d, effect, count] - value to pass to Card() - return [["Copper", 0, Card.CardType.Treasure, 0, 1, 0, 0, 0, 0, None, 60], # 1 - ["Silver", 3, Card.CardType.Treasure, 0, 2, 0, 0, 0, 0, None, 40], # 2 - ["Gold", 6, Card.CardT]ype.Treasure, 0, 3, 0, 0, 0, 0, None, 30], # 3 - - ["Estate", 2, Card.CardType.Victory, 1, 0, 0, 0, 0, 0, None, 24], # 4 - ["Dutchy", 5, Card.CardType.Victory, 3, 0, 0, 0, 0, 0, None, 12], # 5 - ["Province", 8, Card.CardType.Victory, 6, 0, 0, 0, 0, 0, None, 12], # 6 - - ["Curse", 0, Card.CardType.Curse, -1, 0, 0, 0, 0, 0, None, 30], # 7 - - ["Cellar", 2, Card.CardType.Action, 0, 0, 1, 0, 0, 0, "Name", 10], # 8 - ["Market", 5, Card.CardType.Action, 0, 1, 1, 0, 1, 1, None, 10], # 9 - ["Merchant", 3, Card.CardType.Action, 0, 0, 1, 0, 0, 1, "Name", 10], # 10 - ["Militia", 4, Card.CardType.Attack, 0, 2, 0, 1, 0, 0, "Name", 10], # 11 - ["Mine", 5, Card.CardType.Action, 0, 0, 0, 0, 0, 0, "Name", 10], # 12 - ["Moat", 2, Card.CardType.Reaction, 0, 0, 0, 0, 0, 2, "Name", 10], # 13 - ["Remodel", 4, Card.CardType.Action, 0, 0, 0, 0, 0, 0, "Name", 10], # 14 - ["Smithy", 4, Card.CardType.Action, 0, 0, 0, 0, 0, 3, None, 10], # 15 - ["Village", 3, Card.CardType.Action, 0, 0, 2, 0, 0, 1, None, 10], # 16 - ["Workshop", 4, Card.CardType.Action, 0, 0, 0, 0, 0, 0, "Name", 10]] # 17 + # 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, Card, 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, Card, 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, Card, 10], # 12* + ["Moat", 2, Card.CardType.Reaction, 0, 0, 0, 0, 2, Card, 10], # 13* + ["Remodel", 4, Card.CardType.Action, 0, 0, 0, 0, 0, Card, 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, Card, 10]] # 17* def get_starting_deck(): - return [["Copper", 7], ["Estate", 3]] + # return [["Copper", 7], ["Estate", 3]] # return [["Market", 2], ["Merchant", 2], ["Smithy", 2], ["Village", 2], ["Moat", 2]] + return [["Militia", 4], ["Village", 3], ["Smithy", 3]] main() \ No newline at end of file diff --git a/hand.py b/hand.py index cc57b06..a489168 100644 --- a/hand.py +++ b/hand.py @@ -10,6 +10,14 @@ class Hand(Supply): 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 __get_unique_types(self): unique_type = list() @@ -17,12 +25,4 @@ class Hand(Supply): current_type = c.get_type() if not current_type in unique_type: unique_type.append(current_type) - return unique_type - - 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 \ No newline at end of file + return unique_type \ No newline at end of file diff --git a/militia.py b/militia.py new file mode 100644 index 0000000..ba39458 --- /dev/null +++ b/militia.py @@ -0,0 +1,34 @@ +from card import Card +from random import randint + + +class Militia(Card): + def effect(self): + print("Who am I: " + str(self._Card__owner.get_table().get_players().index(self._Card__owner)) + " " + str(self._Card__owner)) + for player in self._Card__owner.get_table().get_players(): + print("player before if: " + str(self._Card__owner.get_table().get_players().index(player)) + " " + str(player)) + if self._Card__owner != player: + print(str(self._Card__owner) + " " + str(player)) + print("self._Card__owner: " + str(self._Card__owner.get_table().get_players().index(self._Card__owner))) + print("Player: " + str(self._Card__owner.get_table().get_players().index(player))) + player.print_hand() + print("Player " + str(self._Card__owner.get_table().get_players().index(player)) + ", you MUST discard " + "down to 3 cards.") + self.__force_discard(self._Card__owner.get_std_chances(), player) + + def __force_discard(self, chances, player): + if self._Card__owner.get_hand().get_remaining() > 3 and chances > 0: + hand_index = int(input("\nPlease identify a card from hand you would like to discard by providing " + "its index: ")) + + if 0 > hand_index >= self.__hand.get_remaining() and chances > 0: + print("Acceptable inputs range from 0 to " + str(self.__hand.get_remaining() - 1) + ". 1 chance lost.") + self.__force_discard(chances - 1) + else: + print("Discarding " + player.get_hand().get_card(hand_index).get_name() + ".") + player.discard_from_hand(hand_index) + self.__force_discard(chances, player) + 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)) + diff --git a/player.py b/player.py index 213facb..db6d92f 100644 --- a/player.py +++ b/player.py @@ -7,13 +7,13 @@ from counter import Counter 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.__reactions = Counter(0) self.__is_human = human self.__table = table @@ -26,14 +26,21 @@ class Player: def add_buys(self, n): self.__buys += n - def add_reactions(self, n): - self.__reactions.int += 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_score(self): return 0 def draw_card(self): self.__deck.transfer_top_card(self.__hand) + self.__hand.get_top_card().passive() def draw_cards(self, how_many): spillover = how_many - self.__deck.get_remaining() @@ -63,6 +70,8 @@ class Player: 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) + print("Top card: " + str(self.__deck.get_top_card().get_owner()) + " " + str(self.__deck.get_top_card().get_name())) self.__deck.shuffle() def draw_hand(self): @@ -72,98 +81,109 @@ class Player: while self.__hand.get_remaining() > 0: self.__hand.transfer_top_card(self.__discard) - def __print_hand(self): - print("\nHand:") - self.__hand.print() - print("\n") - - def __print_discard(self): - print("\nDiscard:") - self.__discard.print() - print("\n") - - def __print_deck(self): - print("\nDeck") - self.__deck.print() - print("\n") - - def __print(self): - print("\nPlayer:") - print("Actions: " + str(self.__actions.int)) - print("Reactions: " + str(self.__reactions.int)) - print("Buys: " + str(self.__buys)) - print("Coin: " + str(self.__purchase_power)) - self.__print_hand() - self.__print_discard() - self.__print_deck() - - def __gain_turn_events(self): - self.__actions.int = 1 - self.__buys = 1 - self.__purchase_power = 0 - self.__reactions.int = 0 + def discard_from_hand(self, n): + self.__hand.transfer_card(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 = int(input("Please identify a card from hand you would like to play by providing its index: ")) + hand_index = int(input("\nPlease identify a card from hand you would like to play by providing its index: ")) 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("Acceptible inputs range from 0 to " + str(self.__hand.get_remaining() - 1) + ". Try again.") + 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: - self.__hand.get_card(hand_index).play(self) + print("Player " + str(self.get_table().get_players().index(self)) + " playing: " + + self.__hand.get_card(hand_index).get_name()) + self.__hand.get_card(hand_index).play() self.__hand.transfer_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) elif chances <= 0: - print("You have used up all of your chances to enter a positive integer; forfeiting remaining plays.") + 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 cards in hand, moving to next phase.") if counter is not None: counter.int = 0 def take_action(self): - print("Please play an Action, Attack, or Reaction card until you have no remaining actions.") + 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], 3, self.__actions) - - def give_reaction(self): - pass - - def take_reaction(self): - pass + 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("Please play all Treasure cards that you want to play.") + print("\nPlease play all Treasure cards 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], 3, play_another) + self.play_card([Card.CardType.Treasure], self.__std_chances, play_another) self.buy_card(3) def buy_card(self, chances): while self.__buys > 0 and not self.__table.are_there_any_empty_piles() and chances > 0: pile_index = int(input("Please identify a pile from the table that you'd like to purchase: ")) - self.__table.get_pile(pile_index).transfer_top_card(self.__discard) - self.__buys -= 1 + + 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("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): print("Deck Size: " + str(self.__deck.get_remaining())) - self.__print_hand() - self.__gain_turn_events() + self.__turn_setup() + self.__print() self.take_action() - # self.__print_discard() - # self.__print_deck() - # self.give_reaction() self.take_buy() self.discard_remaining_hand() self.draw_hand() - self.__print_hand() \ No newline at end of file + 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 __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 \ No newline at end of file diff --git a/supply.py b/supply.py index 428e82e..3fcf537 100644 --- a/supply.py +++ b/supply.py @@ -22,9 +22,14 @@ class Supply: 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(c.identify()) + print(str(index) + ": " + c.identify()) + index += 1 diff --git a/table.py b/table.py index b25b213..d0243c0 100644 --- a/table.py +++ b/table.py @@ -16,6 +16,9 @@ class Table: def get_player(self, n): return self.__player[n] + def get_players(self): + return self.__player + def add_pile(self, card, n): p = Pile() p.add_cards(card, n) @@ -27,6 +30,9 @@ class Table: 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: @@ -43,7 +49,7 @@ class Table: def play(self): turn = 0 # turn < 4 is for testing, otherwise endless as buying cards is not yet done - while not self.are_there_any_empty_piles() and turn < 4: + while not self.are_there_any_empty_piles() and turn < 10: self.print() self.__player[turn % len(self.__player)].take_turn() turn += 1 @@ -53,8 +59,11 @@ class Table: 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("Piles:") + print("\nPiles: ") + index = 0 for s in self.__pile: - print(s.get_card_group().identify() + ": " + str(s.get_remaining())) + print(str(index) + ": " + s.get_card_group().identify() + ": " + str(s.get_remaining())) + index += 1