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 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() }
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
def evaluate(self, state: State): gems = GemsCollection() gems.gems_dict[GemColor.GOLD] += 1 if self.return_gem_color is not None: gems.gems_dict[self.return_gem_color] -= 1 card_properties = self.card.evaluate() return { "gems_flow": gems.to_dict(), "card": [0, None, 0], "card_booked": [1, card_properties[0], card_properties[1]], "nobles": 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) -> 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 #index self.board.lay_cards_on_board() self.board.lay_nobles_on_board()
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)
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] })
def tuple_of_gems_to_gems_collection(tuple_of_gems: Tuple[GemColor]) -> 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] += 1 return GemsCollection(gems_dict)
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)
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) -> bool: """Returns true if players_hand can afford card""" 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 self.gems_possessed.value(GemColor.GOLD) >= 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 __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()
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)
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
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
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
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))
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)
neptune.stop() if output_weights_file_name is not None: self.network.save_weights(output_weights_file_name) return fit_history def load_weights(self, weights_file): assert self.network is not None, 'You must create network before loading weights.' self.set_corrent_session() self.network.load_weights(weights_file) def save_weights(self, output_weights_file_name): self.set_corrent_session() self.network.save_weights(output_weights_file_name) def get_value(self, state_as_dict: StateAsDict) -> float: assert self.network is not None, 'You must create network first.' self.set_corrent_session() vector_of_state = self.vectorize_state(state_as_dict) input_vec = np.array(vector_of_state) return self.network.predict(x=input_vec.reshape(1, 498))[0][0] def get_value_of_vector(self, vector_of_state)->float: assert self.network is not None, 'You must create network first.' self.set_corrent_session() return self.network.predict(x=vector_of_state.reshape(1, 498))[0][0] x = EmbeddingAveragePool_v0() ddd = {GemColor.RED: 0, GemColor.GREEN : 1, GemColor.BLUE:2, GemColor.WHITE:3, GemColor.BLACK:7, GemColor.GOLD:0} f = Card('R19', 10, Row.CHEAP, GemsCollection(gems_values_dict=ddd), discount_profit=GemColor.GREEN, victory_points=2) b = x.card_to_vector(f) print(len(b))
def vectorize(self): gems = GemsCollection() gems.gems_dict[GemColor.GOLD] += 1 gems[self.return_gem_color] -= 1 return gems.vectorize(), self.card.vectorize()
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))
def read_entries(self) -> GemsCollection: return GemsCollection({ gem_color: int(self.entries[gem_color].get()) for gem_color in GemColor })
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)
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] })