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)
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]
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)