class ValidCardHolder: def __init__(self, hands: Hands, trump: int): self._hands = hands self._trump = trump self._rule = RuleSchieber() @classmethod def from_game_state(cls, game_state: GameState): # 4 player, 36 hot encoded cards hands = Hands.by_hot_encoded(game_state.hands.copy()) trump = game_state.trump return cls(hands, trump) def get_valid_cards(self, jass_carpet: JassCarpet) -> np.array: hand = self._hands.get_hand(jass_carpet.current_player) current_trick = jass_carpet.last_trick if current_trick.is_completed: return self._rule.get_valid_cards(hand.asArray(), EMPTY_TRICK, 0, self._trump) else: return self._rule.get_valid_cards( hand.asArray(), current_trick.asArray(), current_trick.index_of_next_missing_card, self._trump) def mark_card_as_invalid(self, player: int, card: int) -> None: self.get_hand(player).remove_card(card) def copy(self) -> ValidCardHolder: return ValidCardHolder(self._hands.copy(), self._trump) def get_hand(self, player: int) -> Hand: return self._hands.get_hand(player) def get_hands(self) -> Hands: return self._hands @classmethod def random_from_obs(cls, obs: GameObservation): inf_set_obs = InformationSetObservationFactory(obs).create() not_allocated_cards_indices = [ i for i, card in enumerate(inf_set_obs.not_allocated_cards) if card == 1 ] sampled_not_allocated_cards = sample(not_allocated_cards_indices, len(not_allocated_cards_indices)) random_hands = Hands.empty() for player in range(4): if player == inf_set_obs.view_player: random_hands.add_hand(player, inf_set_obs.view_player_hand) else: hand = Hand.by_cards( sampled_not_allocated_cards[:inf_set_obs. nbr_of_cards_in_hands[player]]) random_hands.add_hand(player, hand) sampled_not_allocated_cards = sampled_not_allocated_cards[ inf_set_obs.nbr_of_cards_in_hands[player]:] trump = obs.trump return cls(random_hands, trump)
def __init__(self): # log actions self._logger = logging.getLogger(__name__) # Use rule object to determine valid actions self._rule = RuleSchieber() # init random number generator self._rng = np.random.default_rng()
class ValidCardHolder: def __init__(self, hands: np.array, trump: int): self._hands = hands self._trump = trump self._rule = RuleSchieber() @classmethod def from_game_state(cls, game_state: GameState): # 4 player, 36 hot encoded cards hands = game_state.hands.copy() trump = game_state.trump return cls(hands, trump) def get_valid_cards(self, jass_carpet: JassCarpet) -> np.array: hand = self._hands[jass_carpet.get_current_player()] current_trick = jass_carpet.get_last_trick() if current_trick.is_completed(): return self._rule.get_valid_cards(hand, [-1, -1, -1, -1], 0, self._trump) else: return self._rule.get_valid_cards( hand, current_trick.asArray(), current_trick.get_index_of_next_missing_card(), self._trump) def mark_card_as_invalid(self, player: int, card: int) -> None: self.get_hand(player)[card] = 0 def copy(self) -> ValidCardHolder: return ValidCardHolder(self._hands.copy(), self._trump) def get_hand(self, player: int) -> np.ndarray: return self._hands[player]
def __init__(self, node_state: ISMCTSNodeState, parent_node: ISMCTSNode = None): self._node_state = node_state self._parent_node = parent_node self._is_explored = False self._child_nodes: List[ISMCTSNode] = None self._nbr_of_node_was_played = 0 self._win_los_ration = np.array([0, 0]) self._nbr_of_node_was_visible = 0 self._rule = RuleSchieber()
def __init__(self, played_cards: np.ndarray, first_player: int, trump: int, is_last_round: bool = False) -> None: self._played_cards = played_cards self._first_player = first_player self._trump = trump self._is_last_round = is_last_round self._rule = RuleSchieber()
class AgentHeuristicSchieber(Agent): """ Heuristic select actions for the match of jass (Schieber) """ def __init__(self): # log actions self._logger = logging.getLogger(__name__) # Use rule object to determine valid actions self._rule = RuleSchieber() # init random number generator self._rng = np.random.default_rng() def action_trump(self, obs: GameObservation) -> int: trump = 0 max_number_in_color = 0 for c in range(4): number_in_color = (obs.hand * color_masks[c]).sum() if number_in_color > max_number_in_color: max_number_in_color = number_in_color trump = c return trump def action_play_card(self, obs: GameObservation) -> int: # cards are one hot encoded valid_cards = self._rule.get_valid_cards_from_obs(obs) # convert to list and draw a value card = self._rng.choice(np.flatnonzero(valid_cards)) self._logger.debug('Played card: {}'.format(card_strings[card])) return card
def __init__(self, max_calculation_time: int = 3): # log actions self._logger = logging.getLogger(__name__) # Use rule object to determine valid actions self._rule = RuleSchieber() self._max_calculation_time = max_calculation_time self._heuristic_trump = HeuristicTrumpBuilder()
def __init__(self, jass_carpet: JassCarpet, valid_card_holder: ValidCardHolder): self._rule = RuleSchieber() self._jass_carpet = jass_carpet self._valid_card_holder = valid_card_holder self._child_nodes = None self._heuristic_value = None # log actions self._logger = logging.getLogger(__name__)
class Trick: def __init__(self, played_cards: np.ndarray, first_player: int, trump: int, is_last_round: bool = False) -> None: self._played_cards = played_cards self._first_player = first_player self._trump = trump self._is_last_round = is_last_round self._rule = RuleSchieber() @classmethod def with_played_cards(cls, played_cards: np.ndarray, first_player: int, trump: int, is_last_round: bool = False) -> Trick: return Trick(played_cards, first_player, trump, is_last_round) @classmethod def without_played_cards(cls, first_player: int, trump: int, is_last_round: bool = False) -> Trick: played_cards = np.full(NBR_OF_CARDS_IN_ONE_TRICK, MISSING_CARD_IN_TRICK) return Trick(played_cards, first_player, trump, is_last_round) @property def winner(self) -> int: return self._rule.calc_winner(self._played_cards, self._first_player, self._trump) def add_card(self, card: int): self._played_cards[self.index_of_next_missing_card] = card @property def index_of_next_missing_card(self): if not self.is_completed: return np.argwhere(self._played_cards == MISSING_CARD_IN_TRICK)[0] else: return -1 @property def is_completed(self) -> bool: return MISSING_CARD_IN_TRICK not in self._played_cards @property def is_in_process(self) -> bool: return self.index_of_next_missing_card > 0 def asArray(self) -> np.ndarray: return self._played_cards def copy(self) -> Trick: return Trick(self._played_cards.copy(), self._first_player, self._trump, self._is_last_round)
def __init__(self, info_set: InformationSet, jass_carpet: JassCarpet): self._info_set = info_set self._jass_carpet = jass_carpet self._rule = RuleSchieber()
def __init__(self, game_state: GameState): # log actions self._logger = logging.getLogger(__name__) # Use rule object to determine valid actions self._rule = RuleSchieber() self._game_state = game_state
class Trick: def __init__(self, played_cards: np.ndarray, first_player: int, trump: int, is_last_round: bool = False) -> None: self._rule = RuleSchieber() self._played_cards = played_cards self._first_player = first_player self._trump = trump self._is_last_round = is_last_round @classmethod def with_played_cards(cls, played_cards: np.ndarray, first_player: int, trump: int, is_last_round: bool = False) -> Trick: return Trick(played_cards, first_player, trump, is_last_round) @classmethod def without_played_cards(cls, first_player: int, trump: int, is_last_round: bool = False) -> Trick: played_cards = np.full(NBR_OF_CARDS_IN_ONE_TRICK, MISSING_CARD) return Trick(played_cards, first_player, trump, is_last_round) def get_winner(self) -> int: return self._rule.calc_winner(self._played_cards, self._first_player, self._trump) def get_points(self) -> int: return self._rule.calc_points(self._played_cards, self._is_last_round) def add_card(self, card: int): self._played_cards[self.get_index_of_next_missing_card()] = card def get_index_of_next_missing_card(self): for index in range(len(self._played_cards)): if self._played_cards[index] == MISSING_CARD: return index return -1 def is_completed(self) -> bool: return MISSING_CARD not in self._played_cards def is_in_process(self) -> bool: return self.get_index_of_next_missing_card() > 0 def get_last_played_card(self) -> int: if self.is_completed(): return self._played_cards[NBR_OF_CARDS_IN_ONE_TRICK - 1] elif self.is_in_process(): return self._played_cards[self.get_index_of_next_missing_card() - 1] return -1 def asArray(self) -> np.ndarray: return self._played_cards def copy(self) -> Trick: return Trick(self._played_cards.copy(), self._first_player, self._trump, self._is_last_round) def __str__(self) -> str: return str(self._played_cards)
class ISMCTSNode: def __init__(self, node_state: ISMCTSNodeState, parent_node: ISMCTSNode = None): self._node_state = node_state self._parent_node = parent_node self._is_explored = False self._child_nodes: List[ISMCTSNode] = None self._nbr_of_node_was_played = 0 self._win_los_ration = np.array([0, 0]) self._nbr_of_node_was_visible = 0 self._rule = RuleSchieber() def update(self, payoff: np.ndarray) -> None: self._nbr_of_node_was_played += 1 self._win_los_ration += payoff if self._parent_node is not None: self._parent_node.update(payoff) def has_child_nodes(self) -> bool: return len(self.get_child_nodes()) != 0 def get_child_nodes(self) -> List[ISMCTSNode]: if self._child_nodes is None: self._child_nodes = self._determine_child_nodes() return self._child_nodes def _determine_child_nodes(self) -> List[ISMCTSNode]: cards = [i for i, card in enumerate(self._node_state.get_cards_of_current_player()) if card == 1] child_nodes = [] for card in cards: copy_node_state = self._node_state.copy() copy_node_state.remove_card(card) child_nodes.append(ISMCTSNode(copy_node_state, self)) return child_nodes def has_visible_child_nodes(self, valid_card_holder: ValidCardHolder) -> bool: return len(self.get_visible_child_nodes(valid_card_holder)) != 0 def get_visible_child_nodes(self, valid_card_holder: ValidCardHolder) -> List[ISMCTSNode]: return list(filter(lambda child: child.is_visible(valid_card_holder), self.get_child_nodes())) def has_visible_explored_child_nodes(self, valid_card_holder: ValidCardHolder) -> bool: return len(self.get_visible_explored_child_nodes(valid_card_holder)) != 0 def get_visible_explored_child_nodes(self, valid_card_holder: ValidCardHolder) -> List[ISMCTSNode]: return list(filter(lambda child: child.is_visible(valid_card_holder) and child.is_explored, self.get_child_nodes())) def has_visible_unexplored_child_nodes(self, valid_card_holder: ValidCardHolder) -> bool: return len(self.get_visible_unexplored_child_nodes(valid_card_holder)) != 0 def get_visible_unexplored_child_nodes(self, valid_card_holder: ValidCardHolder) -> List[ISMCTSNode]: return list(filter(lambda child: child.is_visible(valid_card_holder) and not child.is_explored, self.get_child_nodes())) def is_visible(self, valid_card_holder: ValidCardHolder) -> bool: return self._node_state.information_set.covered_by(valid_card_holder.get_hands()) and \ self._does_node_represent_valid_card(valid_card_holder) def _does_node_represent_valid_card(self, valid_card_holder: ValidCardHolder) -> bool: parent_jass_carpet = self._parent_node._node_state.jass_carpet sampled_hand = valid_card_holder.get_hand(parent_jass_carpet.current_player).copy() parent_jass_carpet.remove_already_played_card_from(sampled_hand) current_trick = parent_jass_carpet.last_trick if current_trick.is_completed: return self._rule.get_valid_cards(sampled_hand.asArray(), EMPTY_TRICK, 0, parent_jass_carpet.trump)[self.last_played_card] == EXISTING_CARD else: return self._rule.get_valid_cards(sampled_hand.asArray(), current_trick.asArray(), current_trick.index_of_next_missing_card, parent_jass_carpet.trump)[self.last_played_card] == EXISTING_CARD def mark_as_explored(self): self._is_explored = True @property def parent_node(self): return self._parent_node @property def is_explored(self): return self._is_explored @property def nbr_of_node_was_played(self): return self._nbr_of_node_was_played @property def nbr_of_node_had_won(self): return self.win_los_ration[0] @property def nbr_of_node_was_visible(self): return self._nbr_of_node_was_visible @nbr_of_node_was_visible.setter def nbr_of_node_was_visible(self, value): self._nbr_of_node_was_visible = value @property def win_los_ration(self) -> np.ndarray: return self._win_los_ration @property def payoff(self) -> np.ndarray: return self._node_state.payoff @property def last_played_card(self) -> int: return self._node_state.last_played_card def copy(self) -> ISMCTSNode: return ISMCTSNode(self._node_state.copy(), self._parent_node)
def __init__(self, hands: Hands, trump: int): self._hands = hands self._trump = trump self._rule = RuleSchieber()