コード例 #1
0
    def to_dict(self):
        gems = GemsCollection()
        gems.gems_dict[GemColor.GOLD] += 1
        if self.return_gem_color is not None:
            gems.gems_dict[self.return_gem_color] -= 1

        return {"action_type": self.action_type,
                'gems_flow': gems.to_dict(),
                'card' : self.card.to_dict()}
コード例 #2
0
 def __init__(self, name: str = "Player") -> None:
     """Creates a hand with empty gems collections, empty set of cards, nobles and reserved cards.
     Parameters:
     _ _ _ _ _ _
     name: The name of player who has this hand (optional)."""
     self.name = name
     self.gems_possessed = GemsCollection()
     self.cards_possessed = set()
     self.cards_reserved = set()
     self.nobles_possessed = set()
コード例 #3
0
 def __init__(self,
              card: Card,
              n_gold_gems_to_use: int=0,
              use_gold_as: GemsCollection = GemsCollection()):
     """Parameters:
     _ _ _ _ _ _ _ _
     card: Card to buy.
     gold_gems_to_use: Integer determining how many golden gems will be used to pay for the card.
     use_gold_as: Gems collection that reduces the price (its sum must equal n_gold_gems_to_use)."""
     self.card = card
     assert n_gold_gems_to_use == use_gold_as.sum(), 'n_gold_gems_to_use must be equal the sum of gems in use_gold_as'
     self.n_gold_gems_to_use = n_gold_gems_to_use
     self.use_gold_as = use_gold_as
コード例 #4
0
    def __init__(self,
                 list_of_players_hands: List = None,
                 all_cards: Set[Card] = None,
                 all_nobles: Set[Noble] = None,
                 gems_on_board: GemsCollection = None,
                 prepare_state: bool = True) -> None:

        if all_cards is None:
            all_cards = load_all_cards()
        if all_nobles is None:
            all_nobles = load_all_nobles()
        if gems_on_board is None:
            gems_on_board = GemsCollection(INITIAL_GEMS_ON_BOARD_DICT)
        if list_of_players_hands is None:
            list_of_players_hands = [
                PlayersHand("Player A"),
                PlayersHand("Player B")
            ]

        self.list_of_players_hands = list_of_players_hands
        self.board = Board(all_cards, all_nobles, gems_on_board)
        self.active_player_id = 0

        self.who_took_last_action = None  #int describing id of the player or None
        self.winner = None  #int describing id of the player or None
        self.is_done = False
        self.info = {'winner': None}
        self.steps_taken_so_far = 0

        if prepare_state:
            self.prepare()
コード例 #5
0
        def draw_gems(self,
                      gems_collection: GemsCollection,
                      x_coord: int,
                      y_coord: int) -> None:

            self.main_canvas.create_text(x_coord + GEMS_SUMMARY_X, y_coord + GEMS_SUMMARY_Y,
                                         text=GEMS_SUMMARY_TITLE + str(gems_collection.sum()), font=GEMS_SUMMARY_FONT)
            for gem_color in GemColor:
                self.main_canvas.create_oval(x_coord + GEMS_BOARD_SHIFT * gem_color.value,
                                             y_coord,
                                             x_coord + GEMS_BOARD_SHIFT * gem_color.value + GEM_BOARD_OVAL_SIZE,
                                             y_coord + GEM_BOARD_OVAL_SIZE,
                                             fill=color_dict_tkiter[gem_color])

                self.main_canvas.create_text(x_coord + GEMS_BOARD_SHIFT * gem_color.value +
                                             GEMS_BOARD_VALUE_SHIFT,
                                             y_coord + GEMS_BOARD_VALUE_VERTICAL_SHIFT,
                                             text=str(gems_collection.value(gem_color)),
                                             font=GEMS_BOARD_FONT)
コード例 #6
0
 def from_dict(self, vector):
     self.name = vector['name']
     gems = vector['gems_possessed']
     self.gems_possessed = self.gems_possessed + GemsCollection(
         {
             GemColor.GOLD: gems[0],
             GemColor.RED: gems[1],
             GemColor.GREEN: gems[2],
             GemColor.BLUE: gems[3],
             GemColor.WHITE: gems[4],
             GemColor.BLACK: gems[5]
         })
コード例 #7
0
def colors_to_gems_collection(tuple_of_gems) -> GemsCollection:
    """Return a gems collection constructed from list of colors:
    Parameters:
     _ _ _ _ _ _
        tuple_of_gems: Tuple of gems (with possible repetitions).

    Returns: A gems collections. Example:
    (red, red, blue, green) is transformed to GemsCollection({red:2, blue:1, green:1, white:0, black:0, gold:0})."""
    gems_dict = {gem_color: 0 for gem_color in GemColor}
    for element in tuple_of_gems:
        gems_dict[element] += 1
    return GemsCollection(gems_dict)
コード例 #8
0
        def prepare_to_reserve(self,
                               card,
                               state: State):

            basic_gems_transfer = GemsCollection()
            if state.active_players_hand().gems_possessed.sum() < MAX_GEMS_ON_HAND and \
                    state.board.gems_on_board.gems_dict[GemColor.GOLD] > 0:
                basic_gems_transfer.gems_dict[GemColor.GOLD] = 1
            self.set_entries(basic_gems_transfer)

            confirm_reserve_button = Button(text=CONFIRM_RESERVE_TITLE, font=CONFIRM_RESERVE_FONT,
                                            command=lambda: self.do_reserve(card, state))
            confirm_reserve_button.place(x=self.board_x_ccord + CONFIRM_RESERVE_X, y=self.board_y_ccord + CONFIRM_RESERVE_Y)
            self.drawn_buttons.add(confirm_reserve_button)
コード例 #9
0
        def draw_board(self,
                       board: Board,
                       x_coord: int,
                       y_coord: int,
                       state: State) -> None:

            """Draws the board, that is: cards that lie on the table, nobles that lie on the table and coins.
            Parameters:
            _ _ _ _ _ _
            board: Board to draw.
            x_coord: Horizontal coordinate (from left top corner).
            y_coord: Vertical coordinate (from left top corner).
            active_players_hand: The hand of the player that is currently active. This argument is optional and is used to
            determine which cards should be given buy or reserve buttons. If the value is None no buttons are drawn."""

            self.board_x_ccord = x_coord
            self.board_y_ccord = y_coord

            self.main_canvas.create_text(x_coord + BOARD_TITLE_POSITION_X, y_coord + BOARD_TITLE_POSITION_Y,
                                         fill=BOARD_NAME_FONT_COLOR, text=BOARD_TITLE, font=BOARD_NAME_FONT)

            # dictionary used to keep track of drawn cards
            cards_already_drawn = {row: set() for row in Row}
            for card in board.cards_on_board:
                position_x = HORIZONTAL_CARD_DISTANCE * len(cards_already_drawn[card.row])
                cards_already_drawn[card.row].add(card)
                self.draw_card(card, x_coord + position_x, y_coord + VERTICAL_CARD_DISTANCE * POSITION_Y_DICT[card.row],
                               state.active_players_hand().can_afford_card(card),
                               state.active_players_hand().can_reserve_card(), state)

            for position_index, noble_card in enumerate(board.nobles_on_board):
                position_x = NOBLES_START_X + x_coord + HORIZONTAL_NOBLE_DISTANCE * position_index
                position_y = NOBLES_START_Y + y_coord
                self.draw_noble(noble_card, position_x, position_y)

            self.draw_gems(board.gems_on_board, x_coord + GEMS_BOARD_X, y_coord + GEMS_BOARD_Y)

            if self.interactive:
                for gem_color in GemColor:
                    gem_entry = Entry(self.main_window)
                    gem_entry.place(x=x_coord + GEM_ENTRY_SHIFT * gem_color.value + GEMS_ENTRY_INITIAL_X,
                                    y=y_coord + GEMS_ENTRY_INITIAL_Y, width=GEM_ENTRY_WIDTH)
                    self.entries[gem_color] = gem_entry
                    self.drawn_buttons.add(gem_entry)
                self.set_entries(GemsCollection())
                trade_button = Button(text=TRADE_BUTTON_TITLE, font=TRADE_BUTTON_FONT,
                                      command=lambda: self.set_action(ActionTradeGems(self.read_entries())))
                trade_button.place(x=x_coord + TRADE_BUTTON_X, y=y_coord + TRADE_BUTTON_Y)
                self.drawn_buttons.add(trade_button)
コード例 #10
0
def generate_all_legal_trades_classic(state: State) -> List[ActionTradeGems]:
    """Returns the list of all possible actions of trade in a given current_state"""
    list_of_actions_trade = []
    n_non_empty_stacks = len(
        state.board.gems_on_board.non_empty_stacks_except_gold())
    n_gems_to_get_netto = min(
        MAX_GEMS_ON_HAND - state.active_players_hand().gems_possessed.sum(),
        MAX_GEMS_IN_ONE_MOVE, n_non_empty_stacks)

    max_gems_to_take = min(MAX_GEMS_IN_ONE_MOVE, n_non_empty_stacks)

    for n_gems_to_get in range(n_gems_to_get_netto, max_gems_to_take + 1):
        n_gems_to_return = n_gems_to_get - n_gems_to_get_netto

        # choose gems to get:
        options_of_taking = list(
            combinations(
                state.board.gems_on_board.non_empty_stacks_except_gold(),
                n_gems_to_get))
        for option_of_taking in options_of_taking:
            # now we have chosen which gems to take, so we need to decide which to return
            gem_colors_not_taken = {
                gem_color
                for gem_color in GemColor if gem_color not in option_of_taking
            }
            # find gems collection to take:
            gems_to_take = tuple_of_gems_to_gems_collection(option_of_taking)
            # find possible options of returning gems:
            options_of_returning = list(
                combinations_with_replacement(gem_colors_not_taken,
                                              n_gems_to_return))
            for option_of_returning in options_of_returning:
                # now we create gem collection describing transfer and check if it satisfies conditions of legal trade
                gems_to_return = tuple_of_gems_to_gems_collection(
                    option_of_returning)

                gems_collection_to_trade = gems_to_take - gems_to_return
                # check if there is enough gems on the board to take:
                condition_1 = state.board.gems_on_board >= gems_collection_to_trade
                # check if the player has enough gems to return:
                condition_2 = state.active_players_hand(
                ).gems_possessed >= -gems_collection_to_trade
                condition3 = gems_collection_to_trade != GemsCollection()
                if condition_1 and condition_2 and condition3:
                    list_of_actions_trade.append(
                        ActionTradeGems(gems_collection_to_trade))

    return list_of_actions_trade
コード例 #11
0
def load_all_nobles(file: str = NOBLES_DATABASE_FILE) -> Set[Noble]:
    """Loads information about nobles from file and returns a set of cards."""
    set_of_nobles = set()
    nobles_database_file = open(file)
    reader = csv.reader(nobles_database_file)
    _ = next(reader, None)
    noble_id = 100
    for row in reader:
        price = GemsCollection({GemColor.BLACK: int(row[1]), GemColor.WHITE: int(row[2]), GemColor.RED: int(row[3]),
                                GemColor.BLUE: int(row[4]), GemColor.GREEN: int(row[5]), GemColor.GOLD: 0})
        new_noble = Noble(row[0], noble_id, price, int(row[6]))
        set_of_nobles.add(new_noble)
        id_to_noble_dict[noble_id] = new_noble
        name_to_noble_dict[new_noble.name] = new_noble
        noble_id += 1
    return set_of_nobles
コード例 #12
0
def load_all_cards(file: str = CARDS_DATABASE_FILE) -> Set[Card]:
    """Loads information about cards from file and returns a set of cards."""
    set_of_cards = set()
    cards_database_file = open(file)
    reader = csv.reader(cards_database_file)
    _ = next(reader, None)
    card_id = 0
    for row in reader:
        price = GemsCollection({GemColor.BLACK: int(row[2]), GemColor.WHITE: int(row[3]), GemColor.RED: int(row[4]),
                                GemColor.BLUE: int(row[5]), GemColor.GREEN: int(row[6]), GemColor.GOLD: 0})
        card = Card(row[0], card_id, str_to_row[row[1]], price, str_to_color[row[7]], int(row[8]))
        set_of_cards.add(card)
        id_to_card_dict[card_id] = card
        name_to_card_dict[card.name] = card
        card_id += 1
    return set_of_cards
コード例 #13
0
        def prepare_to_buy(self,
                           card: Card,
                           state: State):

            price_after_discount = card.price % state.active_players_hand().discount()
            min_gold = (price_after_discount % state.active_players_hand().gems_possessed).sum()
            min_gold_price = GemsCollection({gem_color: min(price_after_discount.value(gem_color),
                                                            state.active_players_hand().gems_possessed.value(gem_color))
                                             for gem_color in GemColor})
            min_gold_price.gems_dict[GemColor.GOLD] = min_gold
            self.set_entries(min_gold_price)

            confirm_buy_button = Button(text=CONFIRM_BUY_TITLE, font=CONFIRM_BUY_FONT,
                                        command=lambda: self.do_buy(card, state))
            confirm_buy_button.place(x=self.board_x_ccord + CONFIRM_BUY_X, y=self.board_y_ccord + CONFIRM_BUY_Y)
            self.drawn_buttons.add(confirm_buy_button)
コード例 #14
0
def tuple_of_gems_to_gems_collection(tuple_of_gems: Tuple[GemColor],
                                     val=1,
                                     return_val=[1],
                                     return_colors=set()) -> GemsCollection:
    """Return a gems collection constructed from the tuple of gems:
    Parameters:
     _ _ _ _ _ _
        tuple_of_gems: Tuple of gems (with possible repetitions).

    Returns: A gems collections. Example:
    (red, red, blue, green) is transformed to GemsCollection({red:2, blue:1, green:1, white:0, black:0, gold:0})."""
    gems_dict = {gem_color: 0 for gem_color in GemColor}
    for element in tuple_of_gems:
        gems_dict[element] += val
    for i, element in enumerate(return_colors):
        gems_dict[element] -= return_val[i]
    return GemsCollection(gems_dict)
コード例 #15
0
 def __init__(
     self,
     all_cards: Set[Card],
     all_nobles: Set[Noble],
     gems_on_board: GemsCollection = GemsCollection()
 ) -> None:
     """Creates a board and prepares the game. This method: creates the deck of cards and the deck od nobles. We do
     not shuffle deck and do not put cards and nobles on the board here.
     Parameters:
     _ _ _ _ _ _
     all_cards: A list of cards that will be added to the deck.
     all_nobles: A list of nobles that will be added to the deck.
     gems_on_board: A collection of gems that will be placed on the board at the beginning of the game."""
     self.deck = Deck(all_cards, all_nobles)
     self.gems_on_board = gems_on_board
     self.cards_on_board = set()
     self.nobles_on_board = set()
コード例 #16
0
    def from_dict(self, vector):
        """Take player's gems from the board. """

        gems = vector['board']['gems_on_board']
        self.gems_on_board = GemsCollection({
            GemColor.GOLD: gems[0],
            GemColor.RED: gems[1],
            GemColor.GREEN: gems[2],
            GemColor.BLUE: gems[3],
            GemColor.WHITE: gems[4],
            GemColor.BLACK: gems[5]
        })
        """Puts cards on the board according to previous current_state. """
        cards = vector['board']['cards_on_board']
        drawn_cards = map(lambda x: self.deck.pop_cards_from_id_list(cards, x),
                          self.deck.decks_dict.keys())
        self.cards_on_board = set(reduce(lambda x, y: x + y, drawn_cards))
コード例 #17
0
class PlayersHand:
    """A class that describes possessions of one player."""
    def __init__(self, name: str = "Player") -> None:
        """Creates a hand with empty gems collections, empty set of cards, nobles and reserved cards.
        Parameters:
        _ _ _ _ _ _
        name: The name of player who has this hand (optional)."""
        self.name = name
        self.gems_possessed = GemsCollection()
        self.cards_possessed = set()
        self.cards_reserved = set()
        self.nobles_possessed = set()

    def discount(self):
        """Returns gems collection that contains the sum of profits of card possessed by the players_hand."""
        discount_dict = {gem_color: 0 for gem_color in GemColor}
        for card in self.cards_possessed:
            discount_dict[card.discount_profit] += 1
        return GemsCollection(discount_dict)

    def can_afford_card(self,
                        card: Card,
                        discount: GemsCollection = None) -> bool:
        """Returns true if players_hand can afford card"""
        if discount is None:
            discount = self.discount()
        price_after_discount = card.price % discount
        trade = [
            a - b for a, b in zip(price_after_discount.to_dict(),
                                  self.gems_possessed.to_dict())
        ]
        return sum([max(a, 0) for a in trade[1:6]]) <= -trade[0]

    def min_gold_needed_to_buy_card(self, card: Card) -> int:
        price_after_discount = card.price % self.discount()
        missing_gems = 0
        for gem_color in GemColor:
            if gem_color != GemColor.GOLD:
                missing_gems += max(
                    price_after_discount.value(gem_color) -
                    self.gems_possessed.value(gem_color), 0)
        return missing_gems

    def can_reserve_card(self):
        return len(self.cards_reserved) < MAX_RESERVED_CARDS

    def number_of_my_points(self) -> int:
        return sum([
            card.victory_points for card in self.cards_possessed
        ]) + sum([noble.victory_points for noble in self.nobles_possessed])

    def to_dict(self):
        return {
            'noble_possessed_ids':
            {x.to_dict()
             for x in self.nobles_possessed},
            'cards_possessed_ids': {x.to_dict()
                                    for x in self.cards_possessed},
            'cards_reserved_ids': {x.to_dict()
                                   for x in self.cards_reserved},
            'gems_possessed': self.gems_possessed.to_dict(),
            'name': self.name
        }

    def from_dict(self, vector):
        self.name = vector['name']
        gems = vector['gems_possessed']
        self.gems_possessed = self.gems_possessed + GemsCollection(
            {
                GemColor.GOLD: gems[0],
                GemColor.RED: gems[1],
                GemColor.GREEN: gems[2],
                GemColor.BLUE: gems[3],
                GemColor.WHITE: gems[4],
                GemColor.BLACK: gems[5]
            })
コード例 #18
0
 def discount(self):
     """Returns gems collection that contains the sum of profits of card possessed by the players_hand."""
     discount_dict = {gem_color: 0 for gem_color in GemColor}
     for card in self.cards_possessed:
         discount_dict[card.discount_profit] += 1
     return GemsCollection(discount_dict)
コード例 #19
0
 def set_entries(self, gems_collection: GemsCollection) -> None:
     for gem_color in GemColor:
         self.entries[gem_color].delete(0, END)
         self.entries[gem_color].insert(0, gems_collection.value(gem_color))
コード例 #20
0
 def read_entries(self) -> GemsCollection:
     return GemsCollection({gem_color: int(self.entries[gem_color].get()) for gem_color in GemColor})