def test_generate_move_no_valid_moves() -> None: # No possible moves, chooses first option without rotation second_s = SecondS() second_s.set_color(AllColors[0]) second_s.set_rule_checker(RuleChecker()) b = Board() assert b.initial_move( InitialMove(BoardPosition(1, 0), index_to_tile(34), Port.BottomRight, second_s.color)).is_ok() tiles = [ Tile( cast( List[Tuple[PortID, PortID]], [ tuple(Port.all()[i:i + 2]) for i in range(0, len(Port.all()), 2) ], )), Tile( cast( List[Tuple[PortID, PortID]], [ tuple(Port.all()[i:i + 2]) for i in range(0, len(Port.all()), 2) ], )), ] r = second_s.generate_move(tiles, b.get_board_state()) assert id(r.assert_value()) == id(tiles[0])
def test_port_all_order() -> None: assert Port.all() == [ Port.TopLeft, Port.TopRight, Port.RightTop, Port.RightBottom, Port.BottomRight, Port.BottomLeft, Port.LeftBottom, Port.LeftTop, ] assert Port.all() == list(sorted(Port.all()))
def __post_init__(self) -> None: if not isinstance(self.tile, Tile): raise ValueError("Created an InitialMove with an invalid tile!") if self.player not in AllColors: raise ValueError("Created an InitialMove with an invalid player!") if not isinstance(self.pos, BoardPosition): raise ValueError("Created an InitialMove with an invalid board position!") if self.port not in Port.all(): raise ValueError("Created an InitialMove with an invalid port!")
def _move_player_along_path(self, player: ColorString) -> Result[bool]: """ Move the given player along their path until they hit the end of a path or the edge of a board. Returns a result containing a boolean that indicates whether or not the player hit the edge of the board. If the player's path forms an infinite loop, removes the player from the board. :param player: The color of the player :return: An result containing whether the player hit the edge of the board or an error """ seen_pos_port: Set[Tuple[BoardPosition, PortID]] = set() while True: r = self._board_state.get_position_of_player(player) if r.is_error(): return error( "failed to move player %s along path: %s" % (player, r.error()) ) pos, port = r.value() if (pos, port) in seen_pos_port: for observer in self._observers: observer.player_entered_loop(player) # They entered an infinite loop and must be removed return ok(True) seen_pos_port.add((pos, port)) r2 = self._board_state.calculate_adjacent_position_of_player(player) if r2.is_error(): return error( "failed to move player %s along path: %s" % (player, r.error()) ) next_pos = r2.value() if next_pos is None: # They hit the edge of the board so remove them from the list of live players return ok(True) next_tile = self._board_state.get_tile(next_pos) if next_tile is None: # They didn't hit the edge of the board so they don't need to be removed return ok(False) next_port = Port.get_adjoining_port(port) next_next_port = next_tile.get_port_connected_to(next_port) self._board_state = self._board_state.with_live_players( self._board_state.live_players.set(player, (next_pos, next_next_port)) )
def _find_valid_port(self, board_state: BoardState, pos: BoardPosition) -> Result[PortID]: """ Find a valid port on the board state for a move at the given position :param board_state: The board state to apply the move to :param pos: The position for the move :return: A result containing the port or an error if there is no valid port to play on at the given position """ for port in Port.all(): if PhysicalConstraintChecker.is_valid_initial_port( board_state, pos, port).is_ok(): return ok(port) return error("No valid ports on given tile.")
def _find_valid_port( self, board_state: BoardState, pos: BoardPosition ) -> Result[PortID]: """ Find the first port on the board state for a move at the given position going counter-clockwise :param board_state: The board state to apply the move to :param pos: The position for the move :return: A result containing the port or an error if there is no valid port to play on at the given position """ ports = [Port.TopLeft] ports.extend(reversed(Port.all())) ports = ports[:8] for port in ports: if PhysicalConstraintChecker.is_valid_initial_port( board_state, pos, port ).is_ok(): return ok(port) return error("No valid ports on given tile.")