Example #1
0
def test_validate_initial_move_facing_edge() -> None:
    rc = RuleChecker()
    bs = BoardState()

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3)],
        InitialMove(BoardPosition(0, 3), index_to_tile(2), Port.LeftTop, "red"),
    )
    assert r.is_error()
    assert (
        r.error()
        == "cannot make an initial move at position BoardPosition(x=0, y=3), port 7 since it does not face the interior of the board"
    )

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3)],
        InitialMove(BoardPosition(3, 0), index_to_tile(2), Port.TopRight, "red"),
    )
    assert r.is_error()
    assert (
        r.error()
        == "cannot make an initial move at position BoardPosition(x=3, y=0), port 1 since it does not face the interior of the board"
    )
Example #2
0
def test_board_to_html() -> None:
    # Just test that it returns a string and rely on manual testing to verify that it
    # looks roughly correct
    b = Board()
    assert isinstance(b.get_board_state().to_html(), str)

    board_r = Board.create_board_from_moves(
        [
            InitialMove(BoardPosition(5, 0), index_to_tile(2),
                        Port.BottomRight, "blue"),
            InitialMove(BoardPosition(9, 2), index_to_tile(3), Port.TopLeft,
                        "white"),
            InitialMove(BoardPosition(9, 4), index_to_tile(4), Port.TopLeft,
                        "green"),
        ],
        [
            IntermediateMove(index_to_tile(5), "blue"),
            IntermediateMove(index_to_tile(6), "white"),
        ],
    )
    assert board_r.is_ok()
    b2 = board_r.value().get_board_state()
    assert isinstance(b2.to_html(), str)
    assert b2.to_html() != b.get_board_state().to_html()
    assert b2.to_html(automatic_refresh=True) != b2.to_html(
        automatic_refresh=False)
Example #3
0
def test_validate_initial_move_allowed() -> None:
    rc = RuleChecker()
    bs = BoardState()

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3)],
        InitialMove(BoardPosition(2, 0), index_to_tile(2), Port.BottomLeft, "red"),
    )
    assert r.is_ok()
    assert bs == BoardState()  # board state is unchanged

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3)],
        InitialMove(BoardPosition(0, 2), index_to_tile(2), Port.BottomLeft, "red"),
    )
    assert r.is_ok()
    assert bs == BoardState()  # board state is unchanged

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(2), index_to_tile(3), index_to_tile(4)],
        InitialMove(BoardPosition(9, 2), index_to_tile(2), Port.BottomLeft, "white"),
    )
    assert r.is_ok()
    assert bs == BoardState()  # board state is unchanged
Example #4
0
def test_board_intermediate_move_single_player() -> None:
    b = Board()

    logging_observer = LoggingObserver()
    b.add_observer(logging_observer)

    # Can't place a tile if they haven't moved
    r = b.intermediate_move(IntermediateMove(make_tiles()[2], "green"))
    assert r.is_error()
    assert r.error(
    ) == "cannot place a tile for player green since they are not alive"

    # An initial move for green
    r = b.initial_move(
        InitialMove(BoardPosition(9, 4), index_to_tile(0), Port.TopLeft,
                    "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(9, 4)) == index_to_tile(0)
    assert b._board_state.live_players["green"] == (BoardPosition(9, 4),
                                                    Port.TopLeft)

    # Add another tile and they move
    r = b.intermediate_move(IntermediateMove(index_to_tile(1), "green"))
    assert r.is_ok()
    assert b._board_state.live_players["green"] == (
        BoardPosition(x=9, y=3),
        Port.TopRight,
    )

    # And place a tile that will draw them off the edge of the board
    assert logging_observer.all_messages() == []
    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert "green" not in b._board_state.live_players
    assert logging_observer.all_messages() == ["exited_board: green"]
Example #5
0
    def generate_first_move(
            self, tiles: List[Tile], board_state: BoardState
    ) -> Result[Tuple[BoardPosition, Tile, PortID]]:
        """
        Generate the first move by choosing from the given list of tiles. Returns the move along with
        the port that the player's token should be placed on. `set_color` and `set_rule_checker` will
        be called prior to this method.

        :param tiles:           The set of tile options for the first move
        :param board_state:     The state of the current board
        :return:                A result containing a tuple containing the board position, tile, and port ID
                                for the player's initial move
        """
        for observer in self.observers:
            observer.initial_move_offered(tiles, board_state)

        r_move = self.strategy.generate_first_move(tiles, board_state)
        if r_move.is_error():
            return r_move
        board_position, tile, port = r_move.value()

        for observer in self.observers:
            observer.initial_move_played(
                tiles, board_state,
                InitialMove(board_position, tile, port, self.color))
        return r_move
Example #6
0
    def _get_check_initial_move(self, board: Board, color: ColorString,
                                player: PlayerInterface,
                                tiles: List[Tile]) -> Result[InitialMove]:
        """
        Gets the initial move from the player and checks whether it is valid based on the rulechecker. If any errors, the player is added as a cheater.
        Returns an error if cheating, or the chosen move if it is valid
        """
        r_initial_move = self._handle_player_timeout(
            color, lambda: player.generate_first_move(deepcopy(tiles),
                                                      board.get_board_state()))
        if r_initial_move.is_error():
            self._cheaters.add(color)
            return error(r_initial_move.error())

        pos, tile, port = r_initial_move.value()
        initial_move = InitialMove(pos, tile, port, color)

        for observer in self._observers:
            observer.initial_move_played(color, tiles, board.get_board_state(),
                                         initial_move)

        r_rule = self._rule_checker.validate_initial_move(
            board.get_board_state(), tiles, initial_move)
        if r_rule.is_error():
            self._cheaters.add(color)
            return error(r_initial_move.error())

        return ok(initial_move)
Example #7
0
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])
Example #8
0
def test_board_intermediate_move_loop_moves_no_one_else() -> None:
    # If player A places a tile that sends them into a loop and player B is next to the would be placed tile,
    # player B does not move
    b = Board()

    logging_observer = LoggingObserver()
    b.add_observer(logging_observer)

    # An initial move for green
    r = b.initial_move(
        InitialMove(BoardPosition(0, 1), index_to_tile(4), Port.RightBottom,
                    "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(0, 1)) == index_to_tile(4)
    assert b.live_players["green"] == (BoardPosition(0, 1), Port.RightBottom)

    # More moves for green to setup what we need to make a loop
    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 1)) == index_to_tile(4)
    assert b._board_state.live_players["green"] == (
        BoardPosition(1, 1),
        Port.BottomLeft,
    )

    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 2)) == index_to_tile(4)
    assert b._board_state.live_players["green"] == (BoardPosition(1, 2),
                                                    Port.LeftTop)

    # And set up white next to the where the would-be loop would be created
    assert b.place_tile_at_index_with_scissors(index_to_tile(4),
                                               BoardPosition(0, 3)).is_ok()
    b._board_state = b._board_state.with_live_players(
        b._board_state.live_players.set("white",
                                        (BoardPosition(0, 3), Port.TopRight)))

    # This tile placement will make a loop. Test that it is detected, the player is removed, and a message is broadcast
    # to all of the defined observers. According to assignment 6 the player should be removed but the tile
    # should not be on the board.
    assert logging_observer.all_messages() == []
    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert "green" not in b.live_players
    assert b._board_state.get_tile(BoardPosition(0, 2)) is None
    assert logging_observer.all_messages() == [
        "entered_loop: green",
        "exited_board: green",
    ]

    # And white is still in the same place
    assert b._board_state.live_players["white"] == (BoardPosition(0, 3),
                                                    Port.TopRight)
Example #9
0
def test_generate_move_takes_first_tile_no_rotation() -> None:
    # Test that the first tile is taken when valid
    second_s = SecondS()
    second_s.set_color(AllColors[0])
    second_s.set_rule_checker(RuleChecker())
    b = Board()
    b.initial_move(
        InitialMove(BoardPosition(4, 0), index_to_tile(34), Port.BottomRight,
                    second_s.color))

    tiles = [index_to_tile(6), index_to_tile(34)]
    r = second_s.generate_move(tiles, b.get_board_state())
    assert r.assert_value().edges == tiles[0].edges
Example #10
0
def test_validate_initial_move_middle() -> None:
    rc = RuleChecker()
    bs = BoardState()

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3)],
        InitialMove(BoardPosition(2, 3), index_to_tile(2), Port.BottomLeft, "red"),
    )
    assert r.is_error()
    assert (
        r.error()
        == "cannot make an initial move at position BoardPosition(x=2, y=3) since it is not on the edge"
    )
Example #11
0
def test_wrong_number_tile_choices() -> None:
    rc = RuleChecker()
    bs = BoardState()

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1)],
        InitialMove(BoardPosition(0, 2), index_to_tile(1), Port.BottomRight, "red"),
    )
    assert r.is_error()
    assert r.error() == "cannot validate move with 1 tile choices (expected 3)"
    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3), index_to_tile(4)],
        InitialMove(BoardPosition(0, 2), index_to_tile(1), Port.BottomRight, "red"),
    )
    assert r.is_error()
    assert r.error() == "cannot validate move with 4 tile choices (expected 3)"

    r = rc.validate_move(
        bs, [index_to_tile(1)], IntermediateMove(index_to_tile(1), "red")
    )
    assert r.is_error()
    assert (
        r.error()
        == "cannot validate move with 1 tile choices (expected 2)"
    )
    r = rc.validate_move(
        bs,
        [index_to_tile(1), index_to_tile(3), index_to_tile(2)],
        IntermediateMove(index_to_tile(1), "red"),
    )
    assert r.is_error()
    assert (
        r.error()
        == "cannot validate move with 3 tile choices (expected 2)"
    )
Example #12
0
def test_validate_initial_move_on_top_of() -> None:
    rc = RuleChecker()
    bs = BoardState()

    bs = bs.with_tile(index_to_tile(5), BoardPosition(0, 2))
    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3)],
        InitialMove(BoardPosition(0, 2), index_to_tile(2), Port.BottomLeft, "red"),
    )
    assert r.is_error()
    assert (
        r.error()
        == "cannot place tile at position BoardPosition(x=0, y=2) since there is already a tile at that position"
    )
Example #13
0
def test_validate_initial_move_not_in_choices() -> None:
    rc = RuleChecker()
    bs = BoardState()

    r = rc.validate_initial_move(
        bs,
        [index_to_tile(1), index_to_tile(3), index_to_tile(4)],
        InitialMove(BoardPosition(0, 2), index_to_tile(2), Port.BottomLeft, "red"),
    )
    assert r.is_error()
    assert (
        r.error()
        == "tile Tile(idx=2, edges=[(0, 5), (1, 4), (2, 7), (3, 6)]) is not in the list of tiles [Tile(idx=1, edges=[(0, 4), (1, 5), (2, 6), (3, 7)]), Tile(idx=3, edges=[(0, 4), (1, 3), (2, 6), (5, 7)]), Tile(idx=4, edges=[(0, 7), (1, 2), (3, 4), (5, 6)])] the player was given"
    )
    assert bs == BoardState()  # board state is unchanged
Example #14
0
def test_generate_move_needs_rotation() -> None:
    # Test that the first tile is rotated to a valid rotation when the second tile is invalid
    third_s = ThirdS()
    third_s.set_color(AllColors[0])
    third_s.set_rule_checker(RuleChecker())
    b = Board()
    b.initial_move(
        InitialMove(
            BoardPosition(9, 0), index_to_tile(34), Port.BottomRight, third_s.color
        )
    )

    tiles = [index_to_tile(11), index_to_tile(34)]
    r = third_s.generate_move(tiles, b.get_board_state())
    assert r.assert_value().edges == tiles[0].rotate().edges
Example #15
0
def test_validate_initial_move_double_play() -> None:
    rc = RuleChecker()
    bs = BoardState()

    bs = bs.with_live_players(
        bs.live_players.set("red", (BoardPosition(5, 0), Port.RightBottom))
    )
    copied = deepcopy(bs)
    r = rc.validate_initial_move(
        copied,
        [index_to_tile(1), index_to_tile(2), index_to_tile(3)],
        InitialMove(BoardPosition(0, 2), index_to_tile(2), Port.BottomLeft, "red"),
    )
    assert r.is_error()
    assert (
        r.error() == "cannot place player red since the player is already on the board"
    )
    assert bs == copied  # board state is unchanged
Example #16
0
def test_create_board_from_initial_placements() -> None:
    assert (Board.create_board_from_initial_placements(
        []).assert_value().get_board_state() == BoardState())

    board_r = Board.create_board_from_initial_placements([
        InitialMove(BoardPosition(5, 0), index_to_tile(2), Port.BottomRight,
                    "blue"),
        InitialMove(BoardPosition(9, 2), index_to_tile(3), Port.TopLeft,
                    "white"),
        InitialMove(BoardPosition(9, 4), index_to_tile(4), Port.TopLeft,
                    "green"),
    ])
    assert board_r.is_ok()
    board_state = board_r.value().get_board_state()
    for x in range(MIN_BOARD_COORDINATE, MAX_BOARD_COORDINATE + 1):
        for y in range(MIN_BOARD_COORDINATE, MAX_BOARD_COORDINATE + 1):
            tile = board_state.get_tile(BoardPosition(x, y))
            if (x, y) == (5, 0):
                assert tile == index_to_tile(2)
            elif (x, y) == (9, 2):
                assert tile == index_to_tile(3)
            elif (x, y) == (9, 4):
                assert tile == index_to_tile(4)
            else:
                assert tile is None
    assert board_r.value().live_players == pmap({
        "blue": (BoardPosition(x=5, y=0), 4),
        "green": (BoardPosition(x=9, y=4), 0),
        "white": (BoardPosition(x=9, y=2), 0),
    })

    board_r = Board.create_board_from_initial_placements([
        InitialMove(BoardPosition(5, 0),
                    make_tiles()[2], Port.BottomRight, "blue"),
        InitialMove(BoardPosition(9, 2),
                    make_tiles()[2], Port.TopLeft, "white"),
        InitialMove(BoardPosition(9, 4),
                    make_tiles()[2], Port.TopLeft, "green"),
        # And an invalid one
        InitialMove(BoardPosition(9, 7),
                    make_tiles()[2], Port.TopLeft, "green"),
    ])
    assert board_r.is_error()
    assert (
        board_r.error() ==
        "failed to create board from set of initial placements: cannot place player green since the player is already on the board"
    )
Example #17
0
def test_player_calls_observers() -> None:
    bs = BoardState()

    lo = LoggingPlayerObserver()
    p = Player(FirstS())
    p.add_observer(lo)

    p.set_color("red")
    assert lo.set_colors == ["red"]
    p.set_color("green")
    assert lo.set_colors == ["red", "green"]

    assert p.generate_first_move(
        [index_to_tile(3),
         index_to_tile(4),
         index_to_tile(5)], bs).is_ok()
    assert lo.initial_move_offereds == [
        ([index_to_tile(3),
          index_to_tile(4),
          index_to_tile(5)], bs)
    ]
    assert lo.initial_move_playeds == [(
        [index_to_tile(3),
         index_to_tile(4),
         index_to_tile(5)],
        bs,
        InitialMove(BoardPosition(1, 0), index_to_tile(5), Port.RightTop,
                    "green"),
    )]

    assert p.generate_move([index_to_tile(10), index_to_tile(11)], bs).is_ok()
    assert lo.intermediate_move_offereds == [
        ([index_to_tile(10), index_to_tile(11)], bs)
    ]
    assert lo.intermediate_move_playeds == [(
        [index_to_tile(10), index_to_tile(11)],
        bs,
        IntermediateMove(index_to_tile(10), "green"),
    )]

    gr = ([{"red"}, {"black", "green"}], {"white"})
    p.game_result(gr)  # type: ignore
    assert lo.game_results == [gr]
Example #18
0
def setup_board(board_setup_data: JSON) -> Board:
    """
    Setup the board according to the given board setup data. This is the first JSON value read
    from the integration test which is an array of initial-place or intermediate-place. Raises an
    exception if the input is invalid in any way.

    :param board_setup_data:    An array containg either initial-place elements or intermediate-place
                                elements
    :return:                    A board created from the setup data
    """
    board = Board()
    for item in board_setup_data:
        if len(item) == 5:
            initial_place = InitialPlace.from_json(item)
            r = board.initial_move_with_scissors(
                InitialMove(
                    BoardPosition(initial_place.x_index,
                                  initial_place.y_index),
                    tile_pattern_to_tile(
                        initial_place.tile_pat.tile_index,
                        initial_place.tile_pat.rotation_angle,
                    ),
                    network_port_id_to_port_id(initial_place.port),
                    initial_place.player,
                ))
            if r.is_error():
                raise Exception(r.error())
        elif len(item) == 3:
            intermediate_place = IntermediatePlace.from_json(item)
            r = board.place_tile_at_index_with_scissors(
                tile_pattern_to_tile(
                    intermediate_place.tile_pat.tile_index,
                    intermediate_place.tile_pat.rotation_angle,
                ),
                BoardPosition(intermediate_place.x_index,
                              intermediate_place.y_index),
            )
            if r.is_error():
                raise Exception(r.error())
        else:
            raise Exception(f"Failed to parse JSON input: {item}")
    return board
Example #19
0
def test_board_intermediate_move_remove_player_after_loop() -> None:
    b = Board()

    logging_observer = LoggingObserver()
    b.add_observer(logging_observer)

    # An initial move for green
    r = b.initial_move(
        InitialMove(BoardPosition(0, 1), index_to_tile(4), Port.RightBottom,
                    "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(0, 1)) == index_to_tile(4)
    assert b.live_players["green"] == (BoardPosition(0, 1), Port.RightBottom)

    # More moves for green that would create a loop
    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 1)) == index_to_tile(4)
    assert b._board_state.live_players["green"] == (
        BoardPosition(1, 1),
        Port.BottomLeft,
    )

    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 2)) == index_to_tile(4)
    assert b._board_state.live_players["green"] == (BoardPosition(1, 2),
                                                    Port.LeftTop)

    assert logging_observer.all_messages() == []

    # This tile placement will make a loop. Test that it is detected, the player is removed, and a message is broadcast
    # to all of the defined observers. According to assignment 6 the player should be removed but the tile
    # should not be on the board.
    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert "green" not in b.live_players
    assert b._board_state.get_tile(BoardPosition(0, 2)) is None
    assert logging_observer.all_messages() == [
        "entered_loop: green",
        "exited_board: green",
    ]
Example #20
0
def test_ignore_invalid_moves(*_: Any) -> None:
    # Test that giving invalid moves to the observer doesn't crash anything. Mocks out subprocess
    # so that google-chrome isn't opened. Mocks out start_websocket_distributor so that it doesn't
    # start another process.
    b = Board()

    gpo = GraphicalPlayerObserver()
    gpo.set_color("red")
    gpo.set_players(["red", "blue", "green", "black", "white"])

    tile_choices = [index_to_tile(2), index_to_tile(3)]
    gpo.initial_move_played(
        tile_choices,
        b.get_board_state(),
        InitialMove(BoardPosition(2, 3), index_to_tile(2), Port.TopLeft,
                    "red"),
    )

    tile_choices = [index_to_tile(2), index_to_tile(3), index_to_tile(4)]
    gpo.intermediate_move_played(tile_choices, b.get_board_state(),
                                 IntermediateMove(index_to_tile(2), "red"))
Example #21
0
def test_allow_collision() -> None:
    rc = RuleChecker()
    b = Board()

    move = InitialMove(BoardPosition(0, 0), index_to_tile(4), Port.BottomRight, "red")
    assert rc.validate_initial_move(
        b.get_board_state(),
        [index_to_tile(4), index_to_tile(5), index_to_tile(6)],
        move,
    ).is_ok()
    r = b.initial_move(move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(0, 0)) == index_to_tile(4)
    assert b.live_players["red"] == (BoardPosition(0, 0), Port.BottomRight)

    move = InitialMove(BoardPosition(2, 0), index_to_tile(22), Port.LeftBottom, "green")
    assert rc.validate_initial_move(
        b.get_board_state(),
        [index_to_tile(22), index_to_tile(5), index_to_tile(6)],
        move,
    ).is_ok()
    r = b.initial_move(move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(2, 0)) == index_to_tile(22)
    assert b.live_players["green"] == (BoardPosition(2, 0), Port.LeftBottom)

    move = InitialMove(BoardPosition(4, 0), index_to_tile(22), Port.LeftBottom, "blue")
    assert rc.validate_initial_move(
        b.get_board_state(),
        [index_to_tile(22), index_to_tile(5), index_to_tile(6)],
        move,
    ).is_ok()
    r = b.initial_move(move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(4, 0)) == index_to_tile(22)
    assert b.live_players["blue"] == (BoardPosition(4, 0), Port.LeftBottom)

    move = InitialMove(BoardPosition(6, 0), index_to_tile(22), Port.LeftBottom, "white")
    assert rc.validate_initial_move(
        b.get_board_state(),
        [index_to_tile(22), index_to_tile(5), index_to_tile(6)],
        move,
    ).is_ok()
    r = b.initial_move(move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(6, 0)) == index_to_tile(22)
    assert b.live_players["white"] == (BoardPosition(6, 0), Port.LeftBottom)

    move = InitialMove(BoardPosition(8, 0), index_to_tile(22), Port.LeftBottom, "black")
    assert rc.validate_initial_move(
        b.get_board_state(),
        [index_to_tile(22), index_to_tile(5), index_to_tile(6)],
        move,
    ).is_ok()
    r = b.initial_move(move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(8, 0)) == index_to_tile(22)
    assert b.live_players["black"] == (BoardPosition(8, 0), Port.LeftBottom)

    intermediate_move = IntermediateMove(index_to_tile(22), "black")
    assert rc.validate_move(
        b.get_board_state(), [index_to_tile(22), index_to_tile(5)], intermediate_move
    ).is_ok()
    r = b.intermediate_move(intermediate_move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(7, 0)) == index_to_tile(22)

    intermediate_move = IntermediateMove(index_to_tile(22), "black")
    assert rc.validate_move(
        b.get_board_state(), [index_to_tile(22), index_to_tile(5)], intermediate_move
    ).is_ok()
    r = b.intermediate_move(intermediate_move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(5, 0)) == index_to_tile(22)

    intermediate_move = IntermediateMove(index_to_tile(22), "black")
    assert rc.validate_move(
        b.get_board_state(), [index_to_tile(22), index_to_tile(5)], intermediate_move
    ).is_ok()
    r = b.intermediate_move(intermediate_move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(3, 0)) == index_to_tile(22)

    intermediate_move = IntermediateMove(index_to_tile(22), "black")
    assert rc.validate_move(
        b.get_board_state(), [index_to_tile(22), index_to_tile(5)], intermediate_move
    ).is_ok()
    r = b.intermediate_move(intermediate_move)
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 0)) == index_to_tile(22)

    assert len(b._board_state.live_players) == 5
    assert len(set(b._board_state.live_players.values())) == 1
    assert b.live_players == pmap(
        {
            "black": (BoardPosition(x=0, y=0), 4),
            "blue": (BoardPosition(x=0, y=0), 4),
            "green": (BoardPosition(x=0, y=0), 4),
            "red": (BoardPosition(x=0, y=0), 4),
            "white": (BoardPosition(x=0, y=0), 4),
        }
    )
Example #22
0
def test_multi_collision() -> None:
    b = Board()

    logging_observer = LoggingObserver()
    b.add_observer(logging_observer)

    r = b.initial_move(
        InitialMove(BoardPosition(0, 0), index_to_tile(4), Port.BottomRight,
                    "red"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(0, 0)) == index_to_tile(4)
    assert b.live_players["red"] == (BoardPosition(0, 0), Port.BottomRight)

    r = b.initial_move(
        InitialMove(BoardPosition(2, 0), index_to_tile(22), Port.LeftBottom,
                    "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(2, 0)) == index_to_tile(22)
    assert b.live_players["green"] == (BoardPosition(2, 0), Port.LeftBottom)

    r = b.initial_move(
        InitialMove(BoardPosition(4, 0), index_to_tile(22), Port.LeftBottom,
                    "blue"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(4, 0)) == index_to_tile(22)
    assert b.live_players["blue"] == (BoardPosition(4, 0), Port.LeftBottom)

    r = b.initial_move(
        InitialMove(BoardPosition(6, 0), index_to_tile(22), Port.LeftBottom,
                    "white"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(6, 0)) == index_to_tile(22)
    assert b.live_players["white"] == (BoardPosition(6, 0), Port.LeftBottom)

    r = b.initial_move(
        InitialMove(BoardPosition(8, 0), index_to_tile(22), Port.LeftBottom,
                    "black"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(8, 0)) == index_to_tile(22)
    assert b.live_players["black"] == (BoardPosition(8, 0), Port.LeftBottom)

    r = b.intermediate_move(IntermediateMove(index_to_tile(22), "black"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(7, 0)) == index_to_tile(22)

    r = b.intermediate_move(IntermediateMove(index_to_tile(22), "black"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(5, 0)) == index_to_tile(22)

    r = b.intermediate_move(IntermediateMove(index_to_tile(22), "black"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(3, 0)) == index_to_tile(22)

    r = b.intermediate_move(IntermediateMove(index_to_tile(22), "black"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 0)) == index_to_tile(22)

    assert len(b._board_state.live_players) == 5
    assert len(set(b._board_state.live_players.values())) == 1
    assert b.live_players == pmap({
        "black": (BoardPosition(x=0, y=0), 4),
        "blue": (BoardPosition(x=0, y=0), 4),
        "green": (BoardPosition(x=0, y=0), 4),
        "red": (BoardPosition(x=0, y=0), 4),
        "white": (BoardPosition(x=0, y=0), 4),
    })
Example #23
0
def test_board_intermediate_move() -> None:
    b = Board()

    logging_observer = LoggingObserver()
    b.add_observer(logging_observer)

    # An initial move for green
    r = b.initial_move(
        InitialMove(BoardPosition(0, 1), index_to_tile(0), Port.RightBottom,
                    "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(0, 1)) == index_to_tile(0)

    # An initial move for red
    r = b.initial_move(
        InitialMove(BoardPosition(0, 3), index_to_tile(0), Port.RightBottom,
                    "red"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(0, 3)) == index_to_tile(0)
    assert b._board_state.live_players["green"] == (
        BoardPosition(0, 1),
        Port.RightBottom,
    )
    assert b._board_state.live_players["red"] == (BoardPosition(0, 3),
                                                  Port.RightBottom)

    # Add a tile for green
    r = b.intermediate_move(IntermediateMove(index_to_tile(4), "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 1)) == index_to_tile(4)
    assert b._board_state.live_players["green"] == (
        BoardPosition(1, 1),
        Port.BottomLeft,
    )
    assert b._board_state.live_players["red"] == (BoardPosition(0, 3),
                                                  Port.RightBottom)

    # Add another tile for green to get closer to red
    r = b.intermediate_move(
        IntermediateMove(index_to_tile(22).rotate(), "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 2)) == index_to_tile(22)
    assert b._board_state.live_players["green"] == (
        BoardPosition(1, 2),
        Port.BottomLeft,
    )
    assert b._board_state.live_players["red"] == (BoardPosition(0, 3),
                                                  Port.RightBottom)

    # And another tile that will cause green and red to both traverse over the same tile
    r = b.intermediate_move(IntermediateMove(index_to_tile(2), "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(1, 3)) == index_to_tile(2)
    assert b._board_state.live_players["green"] == (
        BoardPosition(1, 3),
        Port.BottomLeft,
    )
    assert b._board_state.live_players["red"] == (BoardPosition(1, 3),
                                                  Port.RightBottom)

    assert logging_observer.all_messages() == []
Example #24
0
def test_create_board_from_moves() -> None:
    assert (Board.create_board_from_moves(
        [], []).assert_value().get_board_state() == BoardState())

    board_r = Board.create_board_from_moves(
        [
            InitialMove(BoardPosition(5, 0), index_to_tile(2),
                        Port.BottomRight, "blue"),
            InitialMove(BoardPosition(9, 2), index_to_tile(3), Port.TopLeft,
                        "white"),
            InitialMove(BoardPosition(9, 4), index_to_tile(4), Port.TopLeft,
                        "green"),
        ],
        [
            IntermediateMove(index_to_tile(5), "blue"),
            IntermediateMove(index_to_tile(6), "white"),
        ],
    )
    assert board_r.is_ok()
    board_state = board_r.value().get_board_state()
    for x in range(MIN_BOARD_COORDINATE, MAX_BOARD_COORDINATE + 1):
        for y in range(MIN_BOARD_COORDINATE, MAX_BOARD_COORDINATE + 1):
            if (x, y) == (5, 0):
                assert board_state.get_tile(BoardPosition(
                    x, y)) == index_to_tile(2)
            elif (x, y) == (5, 1):
                assert board_state.get_tile(BoardPosition(
                    x, y)) == index_to_tile(5)
            elif (x, y) == (9, 1):
                assert board_state.get_tile(BoardPosition(
                    x, y)) == index_to_tile(6)
            elif (x, y) == (9, 2):
                assert board_state.get_tile(BoardPosition(
                    x, y)) == index_to_tile(3)
            elif (x, y) == (9, 4):
                assert board_state.get_tile(BoardPosition(
                    x, y)) == index_to_tile(4)
            else:
                assert board_state.get_tile(BoardPosition(x, y)) is None
    assert board_r.value().live_players == pmap({
        "blue": (BoardPosition(x=5, y=1), 2),
        "green": (BoardPosition(x=9, y=4), 0),
        "white": (BoardPosition(x=9, y=1), 7),
    })

    board_r = Board.create_board_from_moves(
        [
            InitialMove(BoardPosition(5, 0), index_to_tile(2),
                        Port.BottomRight, "blue"),
            InitialMove(BoardPosition(9, 2), index_to_tile(3), Port.TopLeft,
                        "white"),
            InitialMove(BoardPosition(9, 4), index_to_tile(4), Port.TopLeft,
                        "green"),
        ],
        [
            IntermediateMove(index_to_tile(5), "blue"),
            IntermediateMove(index_to_tile(6), "white"),
            # An invalid second move since black never had an initial move
            IntermediateMove(index_to_tile(7), "black"),
        ],
    )
    assert board_r.is_error()
    assert (
        board_r.error() ==
        "failed to create board from moves: cannot place a tile for player black since they are not alive"
    )

    board_r = Board.create_board_from_moves(
        [
            InitialMove(BoardPosition(5, 0), index_to_tile(2),
                        Port.BottomRight, "blue"),
            InitialMove(BoardPosition(9, 2), index_to_tile(3), Port.TopLeft,
                        "white"),
            InitialMove(BoardPosition(9, 4), index_to_tile(4), Port.TopLeft,
                        "green"),
            # An invalid first move since someone placed a tile next to this position
            InitialMove(BoardPosition(9, 3), index_to_tile(7), Port.TopRight,
                        "black"),
        ],
        [
            IntermediateMove(index_to_tile(5), "blue"),
            IntermediateMove(index_to_tile(6), "white"),
        ],
    )
    assert board_r.is_error()
    assert (
        board_r.error() ==
        "failed to create board from set of initial placements: cannot make an initial move at position BoardPosition(x=9, y=3) since the surrounding tiles are not all empty"
    )
Example #25
0
import time
from typing import Any, cast
from unittest import mock

import pytest

from Common.board import Board
from Common.board_position import BoardPosition
from Common.board_state import BoardState
from Common.moves import InitialMove, IntermediateMove
from Common.tiles import Port, Tile, index_to_tile
from Common.tsuro_types import TileIndex
from Player.player_observer import GraphicalPlayerObserver

TEST_RUN_MOVES = [
    InitialMove(BoardPosition(5, 0), index_to_tile(5), Port.BottomLeft, "red"),
    InitialMove(BoardPosition(2, 0), index_to_tile(3), Port.BottomLeft,
                "blue"),
    InitialMove(BoardPosition(9, 2), index_to_tile(3), Port.TopRight, "green"),
    IntermediateMove(index_to_tile(2), "red"),
    IntermediateMove(index_to_tile(2), "red"),
    IntermediateMove(index_to_tile(2), "red"),
    IntermediateMove(index_to_tile(4), "green"),
    IntermediateMove(index_to_tile(2), "red"),
    IntermediateMove(index_to_tile(2), "red"),
]


def rand_tile() -> Tile:
    return index_to_tile(cast(TileIndex, random.randint(0, 34)))
Example #26
0
def test_board_initial_move() -> None:
    b = Board()

    logging_observer = LoggingObserver()
    b.add_observer(logging_observer)

    pos = BoardPosition(1, 1)
    r = b.initial_move(
        InitialMove(pos,
                    make_tiles()[0], Port.BottomRight, "red"))
    assert r.is_error()
    assert (
        r.error() ==
        f"cannot make an initial move at position {pos} since it is not on the edge"
    )

    pos = BoardPosition(3, 0)
    port = Port.TopLeft
    r = b.initial_move(InitialMove(pos, make_tiles()[0], port, "red"))
    assert r.is_error()
    assert (
        r.error() ==
        f"cannot make an initial move at position {pos}, port {port} since it does not face the interior of the "
        f"board")

    b.place_tile_at_index_with_scissors(make_tiles()[0], BoardPosition(2, 0))
    r = b.initial_move(
        InitialMove(BoardPosition(2, 0),
                    make_tiles()[1], Port.BottomRight, "blue"))
    assert r.is_error()
    assert (
        r.error() ==
        "cannot place tile at position BoardPosition(x=2, y=0) since there is already a tile at that position"
    )

    r = b.initial_move(
        InitialMove(BoardPosition(3, 0),
                    make_tiles()[1], Port.BottomRight, "blue"))
    assert r.is_error()
    assert (
        r.error() ==
        "cannot make an initial move at position BoardPosition(x=3, y=0) since the surrounding tiles are not all "
        "empty")

    r = b.initial_move(
        InitialMove(BoardPosition(1, 0),
                    make_tiles()[1], Port.BottomRight, "blue"))
    assert r.is_error()
    assert (
        r.error() ==
        "cannot make an initial move at position BoardPosition(x=1, y=0) since the surrounding tiles are not all "
        "empty")

    b._board_state = b._board_state.with_live_players(
        b._board_state.live_players.set(
            "red", (BoardPosition(2, 0), Port.BottomRight)))
    r = b.initial_move(
        InitialMove(BoardPosition(5, 0),
                    make_tiles()[1], Port.BottomRight, "red"))
    assert r.is_error()
    assert (r.error() ==
            "cannot place player red since the player is already on the board")

    r = b.initial_move(
        InitialMove(BoardPosition(5, 0),
                    make_tiles()[2], Port.BottomRight, "blue"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(5, 0)) == make_tiles()[2]
    assert b._board_state.live_players["blue"] == (
        BoardPosition(5, 0),
        Port.BottomRight,
    )

    r = b.initial_move(
        InitialMove(BoardPosition(9, 2),
                    make_tiles()[2], Port.TopLeft, "white"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(9, 2)) == make_tiles()[2]
    b._board_state = b._board_state.with_live_players(
        b._board_state.live_players.set("white",
                                        (BoardPosition(9, 2), Port.TopLeft)))

    r = b.initial_move(
        InitialMove(BoardPosition(9, 4),
                    make_tiles()[2], Port.TopLeft, "green"))
    assert r.is_ok()
    assert b._board_state.get_tile(BoardPosition(9, 4)) == make_tiles()[2]
    assert b._board_state.live_players["green"] == (BoardPosition(9, 4),
                                                    Port.TopLeft)

    assert logging_observer.all_messages() == []