Esempio n. 1
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"]
Esempio n. 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)
Esempio n. 3
0
def test_board_place_tile_at_index_with_scissors() -> None:
    b = Board()
    assert b.place_tile_at_index_with_scissors(index_to_tile(5),
                                               BoardPosition(3, 0)).is_ok()
    assert b.get_board_state().get_tile(BoardPosition(3,
                                                      0)) == index_to_tile(5)
    r = b.place_tile_at_index_with_scissors(index_to_tile(5),
                                            BoardPosition(3, 0))
    assert r.is_ok()
Esempio n. 4
0
def test_validate_place_tile_unnecessary_loop() -> None:
    rc = RuleChecker()
    bs = BoardState()

    bs = bs.with_live_players(
        bs.live_players.set("red", (BoardPosition(2, 0), Port.RightBottom))
    )
    bs = bs.with_tile(index_to_tile(4), BoardPosition(2, 0))
    bs = bs.with_tile(index_to_tile(4), BoardPosition(2, 1))
    bs = bs.with_tile(index_to_tile(4), BoardPosition(3, 1))
    r = rc.move_creates_loop(bs, IntermediateMove(index_to_tile(4), "red"))
    assert r.is_ok()
    assert r.value()
    r = rc.move_creates_loop(bs, IntermediateMove(index_to_tile(5), "red"))
    assert r.is_ok()
    assert r.value()
    r = rc.is_move_suicidal(bs, IntermediateMove(index_to_tile(5).rotate(), "red"))
    assert r.is_ok()
    assert not r.value()

    r2 = rc.validate_move(
        bs,
        [index_to_tile(5), index_to_tile(4)],
        IntermediateMove(index_to_tile(4), "red"),
    )
    assert r2.is_error()
    assert (
        r2.error()
        == "player chose a loopy move when this does not create a loop: Tile(idx=5, edges=[(0, 7), (1, 5), (2, 6), (3, 4)])"
    )
Esempio n. 5
0
def test_is_move_suicidal_walk_off_edge() -> None:
    rc = RuleChecker()
    bs = BoardState()

    bs = bs.with_live_players(
        bs.live_players.set("red", (BoardPosition(2, 0), Port.RightTop))
    )
    bs = bs.with_tile(index_to_tile(2), BoardPosition(2, 0))
    r = rc.is_move_suicidal(bs, IntermediateMove(index_to_tile(4), "red"))
    assert r.is_ok()
    assert r.value()
Esempio n. 6
0
def test_validate_place_tile_inexistent_player() -> None:
    rc = RuleChecker()
    bs = BoardState()

    r = rc.validate_move(
        bs,
        [index_to_tile(1), index_to_tile(2)],
        IntermediateMove(index_to_tile(1), "red"),
    )
    assert r.is_error()
    assert r.error() == "cannot place a tile for player red since they are not alive"
Esempio n. 7
0
def test_incorrect_number_tiles_given() -> None:
    second_s = SecondS()
    bs = BoardState()

    r = second_s.generate_move(
        [index_to_tile(1),
         index_to_tile(2),
         index_to_tile(3)], bs)
    assert r.is_error()
    assert r.error() == "Strategy.generate_move given 3 (expected 2)"
    r2 = second_s.generate_first_move([index_to_tile(1), index_to_tile(2)], bs)
    assert r2.is_error()
    assert r2.error() == "Strategy.generate_first_move given 2 (expected 3)"
Esempio n. 8
0
def test_generate_first_move_0_1() -> None:
    # The first move is just placing a tile at 0,1
    third_s = ThirdS()
    bs = BoardState()

    r = third_s.generate_first_move(
        [index_to_tile(22), index_to_tile(23), index_to_tile(24)], bs
    )
    assert r.assert_value() == (
        BoardPosition(x=0, y=1),
        index_to_tile(24),
        Port.TopLeft,
    )
Esempio n. 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
Esempio n. 10
0
def test_is_move_suicidal_loop() -> None:
    rc = RuleChecker()
    bs = BoardState()

    bs = bs.with_live_players(
        bs.live_players.set("red", (BoardPosition(2, 0), Port.RightBottom))
    )
    bs = bs.with_tile(index_to_tile(4), BoardPosition(2, 0))
    bs = bs.with_tile(index_to_tile(4), BoardPosition(2, 1))
    bs = bs.with_tile(index_to_tile(4), BoardPosition(3, 1))
    r = rc.move_creates_loop(bs, IntermediateMove(index_to_tile(4), "red"))
    assert r.is_ok()
    assert r.value()
Esempio n. 11
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"
    )
Esempio n. 12
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"
    )
Esempio n. 13
0
def test_generate_first_move_1_0() -> None:
    # The first move is just placing a tile at 0,1
    second_s = SecondS()
    bs = BoardState()

    r = second_s.generate_first_move(
        [index_to_tile(22),
         index_to_tile(23),
         index_to_tile(24)], bs)
    assert r.assert_value() == (
        BoardPosition(x=1, y=0),
        index_to_tile(24),
        Port.RightTop,
    )
Esempio n. 14
0
    def handle_intermediate(self, intermediate) -> List:
        """
        Converts the intermediate tile message to a list of Tiles and a BoardState for the player.
        Returns the tile pattern representing hte move the player made in the format: [tile_index, rotation]
        """
        board = setup_board(intermediate[0])
        board_state = board.get_board_state()
        tiles = [index_to_tile(intermediate[1]), index_to_tile(intermediate[2])]

        r_move = self._player.generate_move(tiles, board_state)
        if r_move.is_ok():
            return tile_to_tile_pattern(r_move.value())
        else:
            self._tournament_incomplete = False
Esempio n. 15
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
Esempio n. 16
0
 def handle_initial(self, initial) -> List:
     """
     Converts the initial tile message to a list of Tiles and a BoardState for the player.
     Returns the action the player takes in the format: [tile-pat, port, index, index]
     """
     board = setup_board(initial[0])
     board_state = board.get_board_state()
     tiles = [index_to_tile(initial[1]), index_to_tile(initial[2]), index_to_tile(initial[3])]
     
     r_move = self._player.generate_first_move(tiles, board_state)
     if r_move.is_ok():
         move = r_move.value()
         return [tile_to_tile_pattern(move[1]), port_id_to_network_port_id(move[2]), move[0].x, move[0].y]
     else:
         self._tournament_incomplete = False
Esempio n. 17
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
Esempio n. 18
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"
    )
Esempio n. 19
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])
Esempio n. 20
0
def main() -> None:
    """
    Connect to the server at host:port via TCP to render a board state to the GUI via a GraphicalPlayerObserver
    """
    json_stream = StdinStdoutJSONStream()

    state_pats_json_r = json_stream.receive_message()
    board = setup_board(state_pats_json_r.assert_value())

    turn_pat_json = json_stream.receive_message().assert_value()
    act_pat = ActionPat.from_json(turn_pat_json[0]  # pylint: disable=unsubscriptable-object
                                  )
    offered_tiles: List[Tile] = [
        index_to_tile(tile_idx) for tile_idx in turn_pat_json[1:]  # pylint: disable=unsubscriptable-object
    ]
    move = IntermediateMove(
        tile_pattern_to_tile(act_pat.tile_pat.tile_index,
                             act_pat.tile_pat.rotation_angle),
        act_pat.player,
    )
    rule_checker = RuleChecker()
    r = rule_checker.validate_move(board.get_board_state(), offered_tiles,
                                   move)
    if r.is_error():
        json_stream.send_message("cheating")
    else:
        json_stream.send_message("legal")

    if DEBUG:
        board.get_board_state().debug_display_board()
        r = board.intermediate_move(move)
        if r.is_error():
            print("Failed to render #2")
        else:
            board.get_board_state().debug_display_board()
Esempio n. 21
0
def test_get_tiles() -> None:
    ref = Referee()
    ref.set_tile_iterator(deterministic_tile_iterator())

    assert ref._get_tiles(3) == [
        index_to_tile(0), index_to_tile(1),
        index_to_tile(2)
    ]

    assert [tile_to_index(t)
            for t in ref._get_tiles(35)] == list(range(3, 35)) + [
                0,
                1,
                2,
            ]
    assert len(ref._get_tiles(123)) == 123
Esempio n. 22
0
def test_index_to_tile() -> None:
    seen = set()
    for i in range(0, 35):
        t = tiles.index_to_tile(cast(TileIndex, i))
        assert isinstance(t, tiles.Tile)
        seen.add(t)
    assert len(seen) == 35
Esempio n. 23
0
def test_is_valid_initial_position() -> None:
    b = Board()
    assert b.place_tile_at_index_with_scissors(
        index_to_tile(2), BoardPosition(0, 5)
    ).is_ok()
    assert (
        PhysicalConstraintChecker.is_valid_initial_port(
            b._board_state, BoardPosition(0, 5), Port.TopRight
        ).error()
        == "cannot place tile at position BoardPosition(x=0, y=5) since there is already a tile at that position"
    )
    assert (
        PhysicalConstraintChecker.is_valid_initial_port(
            b._board_state, BoardPosition(3, 5), Port.TopRight
        ).error()
        == "cannot make an initial move at position BoardPosition(x=3, y=5) since it is not on the edge"
    )
    assert (
        PhysicalConstraintChecker.is_valid_initial_port(
            b._board_state, BoardPosition(0, 6), Port.TopRight
        ).error()
        == "cannot make an initial move at position BoardPosition(x=0, y=6) since the surrounding tiles are not all empty"
    )
    assert (
        PhysicalConstraintChecker.is_valid_initial_port(
            b._board_state, BoardPosition(0, 4), Port.TopRight
        ).error()
        == "cannot make an initial move at position BoardPosition(x=0, y=4) since the surrounding tiles are not all empty"
    )
Esempio n. 24
0
def test_is_move_suicidal_inexistent() -> None:
    rc = RuleChecker()
    bs = BoardState()

    r = rc.is_move_suicidal(bs, IntermediateMove(index_to_tile(22), "red"))
    assert r.is_error()
    assert r.error() == "player red is not alive thus the move cannot be suicidal"
Esempio n. 25
0
def main(host: str, port: int) -> None:
    """
    Connect to the server at host:port via TCP to render a board state to the GUI via a GraphicalPlayerObserver
    :param host:    The host to connect to
    :param port:    The port to connect to
    :return:        None
    """
    gpo = GraphicalPlayerObserver()

    json_stream = NetworkJSONStream.tcp_client_to(host, port)
    json_stream.send_message(AUTHORS)

    state_pats_json_r = json_stream.receive_message()
    board = setup_board(state_pats_json_r.assert_value())
    gpo.set_players(list(board.live_players.keys()))

    turn_pat_json = json_stream.receive_message().assert_value()
    act_pat = ActionPat.from_json(turn_pat_json[0]  # pylint: disable=unsubscriptable-object
                                  )
    gpo.set_color(act_pat.player)
    offered_tiles: List[Tile] = [
        index_to_tile(tile_idx) for tile_idx in turn_pat_json[1:]
    ]
    gpo.intermediate_move_offered(offered_tiles, board.get_board_state())
    move = IntermediateMove(
        tile_pattern_to_tile(act_pat.tile_pat.tile_index,
                             act_pat.tile_pat.rotation_angle),
        act_pat.player,
    )
    gpo.intermediate_move_played(offered_tiles, board.get_board_state(), move)
    json_stream.close()
Esempio n. 26
0
def test_validate_place_tile_not_in_choices() -> None:
    rc = RuleChecker()
    bs = BoardState()

    bs = bs.with_live_players(
        bs.live_players.set("red", (BoardPosition(2, 0), Port.TopRight))
    )
    r = rc.validate_move(
        bs,
        [index_to_tile(2), index_to_tile(3)],
        IntermediateMove(index_to_tile(1), "red"),
    )
    assert r.is_error()
    assert (
        r.error()
        == "tile Tile(idx=1, edges=[(0, 4), (1, 5), (2, 6), (3, 7)]) is not in the list of tiles [Tile(idx=2, edges=[(0, 5), (1, 4), (2, 7), (3, 6)]), Tile(idx=3, edges=[(0, 4), (1, 3), (2, 6), (5, 7)])] the player was given"
    )
Esempio n. 27
0
def test_validate_place_tile_required_suicide() -> None:
    rc = RuleChecker()
    bs = BoardState()

    bs = bs.with_live_players(
        bs.live_players.set("red", (BoardPosition(2, 0), Port.RightTop))
    )
    bs = bs.with_tile(index_to_tile(2), BoardPosition(2, 0))
    r = rc.is_move_suicidal(bs, IntermediateMove(index_to_tile(4), "red"))
    assert r.is_ok()
    assert r.value()
    r2 = rc.validate_move(
        bs,
        [index_to_tile(4), index_to_tile(4)],
        IntermediateMove(index_to_tile(4).rotate(), "red"),
    )
    assert r2.is_ok()
Esempio n. 28
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
Esempio n. 29
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)
Esempio n. 30
0
def test_generate_first_move_2_9() -> None:
    # The first move is placing a tile at 9,2 since there are tiles blocking the other positions
    third_s = ThirdS()
    bs = BoardState()

    bs = bs.with_tile(index_to_tile(0), BoardPosition(0, 1))
    bs = bs.with_tile(index_to_tile(0), BoardPosition(0, 3))
    bs = bs.with_tile(index_to_tile(1), BoardPosition(0, 5))
    bs = bs.with_tile(index_to_tile(3), BoardPosition(0, 7))
    bs = bs.with_tile(index_to_tile(4), BoardPosition(0, 9))

    r = third_s.generate_first_move(
        [index_to_tile(22), index_to_tile(23), index_to_tile(4)], bs
    )
    assert r.assert_value() == (BoardPosition(x=2, y=9), index_to_tile(4), Port.TopLeft)