示例#1
0
def test_computer_player_random_algorith_when_piece_is_pushed_out(post_move, post_shift, time_sleep):
    """ Tests case where piece is positioned on a shift location, so that it is pushed out.
    Runs computation 100 times. Push-out expectation rate is 1/12.
    Probability that no push-out takes place in 100 runs is negligible
    .start() is patched so that the compute method runs sequentially.
    This test recreates a bug, where the pushed-out piece is not updated correctly, leading
    to exceptions thrown when computer makes a move.
    """
    card_factory = MazeCardFactory()
    board = Board(create_maze(MAZE_STRING, card_factory), leftover_card=card_factory.create_instance("NE", 0))
    piece = board.create_piece()
    piece.maze_card = board.maze[BoardLocation(3, 6)]
    game = Mock()
    game.get_enabled_shift_locations.return_value = board.shift_locations
    game.board = board
    computer_player = ComputerPlayer(library_binding_factory=Mock(), move_url="move-url", shift_url="shift-url",
                                     game=game, identifier=9, board=board, piece=piece)

    for _ in range(100):
        shift_action, move_location = computer_player.random_actions()
        shift_location, _ = shift_action
        allowed_coordinates = [(3, 6)]
        if shift_location == BoardLocation(3, 6):
            allowed_coordinates = [(3, 5)]
        elif shift_location == BoardLocation(3, 0):
            allowed_coordinates = [(3, 0)]
        allowed_moves = {BoardLocation(*coordinates) for coordinates in allowed_coordinates}
        assert move_location in allowed_moves
示例#2
0
def test_opposing_border_location_for_south_location():
    """ Tests opposing_border_location """
    board = Board()
    size = board.maze.maze_size
    assert board.opposing_border_location(BoardLocation(size - 1,
                                                        3)) == BoardLocation(
                                                            0, 3)
示例#3
0
def test_opposing_border_location_for_west_location():
    """ Tests opposing_border_location """
    board = Board()
    size = board.maze.maze_size
    assert board.opposing_border_location(BoardLocation(1,
                                                        0)) == BoardLocation(
                                                            1, size - 1)
示例#4
0
def dto_to_game(game_dto):
    """ maps a DTO to a game
    to deserialize a persisted instance.

    :param game_dto: a dictionary representing the structure of the game,
    created by game_to_dto
    :return: a Game instance whose state is equal to the DTO
    """
    maze, leftover_card, maze_card_by_id = _dto_to_maze_cards_and_dictionary(
        game_dto[MAZE])
    objective_maze_card = maze_card_by_id[game_dto[OBJECTIVE]]
    board = Board(maze, leftover_card, objective_maze_card=objective_maze_card)
    players = [
        _dto_to_player(player_dto, board, maze_card_by_id)
        for player_dto in game_dto[PLAYERS]
    ]
    board._pieces = [player.piece for player in players]
    turns_prepare_delay = _dto_to_timedelta(game_dto[TURN_PREPARE_DELAY])
    turns = _dto_to_turns(game_dto[NEXT_ACTION],
                          players=players,
                          prepare_delay=turns_prepare_delay)
    identifier = game_dto[ID]
    game = Game(identifier, board=board, players=players, turns=turns)
    for player in players:
        player.set_game(game)
    game.previous_shift_location = _dto_to_board_location(
        game_dto[PREVIOUS_SHIFT_LOCATION])
    return game
示例#5
0
def test_shift_updates_pieces_on_pushed_out_card():
    """ Tests shift """
    board = Board()
    piece = board.create_piece()
    pushed_card = board.leftover_card
    piece.maze_card = board.maze[BoardLocation(0, 3)]
    board.shift(BoardLocation(board.maze.maze_size - 1, 3), 90)
    assert piece.maze_card == pushed_card
示例#6
0
def test_move_raises_error_on_unreachable_location():
    """ Tests move validation """
    maze_card_factory = MazeCardFactory()
    board = Board(maze=create_maze(MAZE_STRING, maze_card_factory),
                  leftover_card=maze_card_factory.create_random_maze_card())
    piece = board.create_piece()
    piece.maze_card = board.maze[BoardLocation(0, 1)]
    with pytest.raises(MoveUnreachableException):
        board.move(piece, BoardLocation(0, 0))
示例#7
0
def test_move_new_objective_locations_after_reaching_location():
    """ Tests new objective generation after reaching one """
    maze_card_factory = MazeCardFactory()
    maze = create_maze(MAZE_STRING, maze_card_factory)
    objective_maze_card = maze[BoardLocation(1, 6)]
    board = Board(maze=maze,
                  leftover_card=maze_card_factory.create_random_maze_card(),
                  objective_maze_card=objective_maze_card)
    piece = board.create_piece()
    piece.maze_card = maze[BoardLocation(0, 6)]
    board.move(piece, BoardLocation(1, 6))
    _assert_all_piece_and_objective_location_different(board)
示例#8
0
def test_move_updates_players_maze_card_correctly():
    """ Tests move
    Instead of calling init_board(), the board is built manually, and
    the player's position is set manually as well, so that
    randomness is eliminated for testing """
    maze_card_factory = MazeCardFactory()
    board = Board(maze=create_maze(MAZE_STRING, maze_card_factory),
                  leftover_card=maze_card_factory.create_random_maze_card())
    piece = board.create_piece()
    piece.maze_card = board.maze[BoardLocation(0, 1)]
    board.move(piece, BoardLocation(0, 2))
    assert board.maze[BoardLocation(0, 2)] == piece.maze_card
示例#9
0
def test_create_piece_sets_all_pieces_on_corners():
    """ Tests create_piece """
    board = Board(create_random_maze())

    def is_corner(location):
        return (location.row in [
            0, board.maze.maze_size - 1
        ]) and (location.column in [0, board.maze.maze_size - 1])

    for _ in range(8):
        piece = board.create_piece()
        piece_location = board.maze.maze_card_location(piece.maze_card)
        assert is_corner(piece_location)
示例#10
0
def test_random_actions_computes_valid_actions():
    """ Runs computation 100 times and expects that it returns valid actions in each run """
    card_factory = MazeCardFactory()
    orig_board = Board(create_maze(MAZE_STRING, card_factory), leftover_card=card_factory.create_instance("NE", 0))
    for _ in range(100):
        board = copy.deepcopy(orig_board)
        maze = board.maze
        piece = board.create_piece()
        piece.maze_card = maze[BoardLocation(0, 0)]
        game = Mock()
        game.get_enabled_shift_locations.return_value = board.shift_locations
        game.board = board
        computer_player = ComputerPlayer(library_binding_factory=Mock(), move_url="move-url", shift_url="shift-url",
                                         game=game, identifier=9, board=board, piece=piece)
        shift_action, move_location = computer_player.random_actions()
        shift_location, shift_rotation = shift_action
        assert shift_rotation in [0, 90, 180, 270]
        assert shift_location in board.shift_locations
        allowed_coordinates = [(0, 0)]
        if shift_location == BoardLocation(0, 1) and shift_rotation == 270:
            allowed_coordinates += [(0, 1)]
        elif shift_location == BoardLocation(0, 1) and shift_rotation == 180:
            allowed_coordinates += [(0, 1), (1, 1)]
        elif shift_location == BoardLocation(1, 0) and shift_rotation == 270:
            allowed_coordinates += [(1, 0)]
        elif shift_location == BoardLocation(1, 0) and shift_rotation == 0:
            allowed_coordinates += [(1, 0), (1, 1), (1, 2), (2, 1), (2, 2), (3, 1), (3, 2)]
        elif shift_location == BoardLocation(6, 1):
            allowed_coordinates += [(0, 1), (0, 2), (1, 1), (2, 1)]
        allowed_moves = {
            BoardLocation(*coordinates) for coordinates in allowed_coordinates
        }

        assert move_location in allowed_moves
示例#11
0
def create_board_and_pieces(maze,
                            leftover_card,
                            piece_locations,
                            objective_location=None,
                            objective_maze_card=None):
    maze = copy.deepcopy(maze)
    if not objective_maze_card:
        objective_maze_card = maze[objective_location]
    board = Board(maze=maze,
                  leftover_card=leftover_card,
                  objective_maze_card=objective_maze_card)
    board.clear_pieces()
    for index, location in enumerate(piece_locations):
        piece = Piece(index, board.maze[location])
        board.pieces.append(piece)
    return board
示例#12
0
def test_get_enabled_shift_locations_with_previous_shift():
    """ Tests get_enabled_shift_locations where the previous shift is (3, 0) """
    board = Board()
    game = Game(identifier=0, board=board)
    game.previous_shift_location = BoardLocation(3, 0)
    expected_disabled = BoardLocation(3, board.maze.maze_size - 1)
    enabled_shift_locations = game.get_enabled_shift_locations()
    assert expected_disabled not in enabled_shift_locations
示例#13
0
def test_create_piece_assigns_pieces_consecutive_unique_indices():
    """ Tests create_piece. Adds four pieces, removes first two, adds one, removes third, adds two,
    and checks that all pieces have consecutive unique index """
    board = Board(create_random_maze())
    pieces = [
        board.create_piece(),
        board.create_piece(),
        board.create_piece(),
        board.create_piece()
    ]
    board.remove_piece(pieces[0])
    board.remove_piece(pieces[1])
    pieces[0] = board.create_piece()
    board.remove_piece(pieces[3])
    pieces[1] = board.create_piece()
    pieces[3] = board.create_piece()
    assert set([0, 1, 2,
                3]) == set(map(lambda piece: piece.piece_index, pieces))
示例#14
0
def test_add_player_start_game_calls_methods_on_turns():
    """ Tests add_player, start_game and Player """
    board = Board()
    turns = Mock()
    game = Game(identifier=0, board=board, turns=turns)
    for _ in range(4):
        player_id = game.unused_player_id()
        game.add_player(Player(player_id))
    game.start_game()
    expected_turn_calls = [call.init(game.players)] + [call.start()]
    assert turns.mock_calls[-2:] == expected_turn_calls
示例#15
0
def test_computer_player_calls_start_on_compute_method(post_move, post_shift, time_sleep):
    """ Tests that the computer player calls start() one its computation method.
    """
    card_factory = MazeCardFactory()
    board = Board(create_maze(MAZE_STRING, card_factory), leftover_card=card_factory.create_instance("NE", 0))
    piece = board.create_piece()
    game = Mock()
    type(game).identifier = PropertyMock(return_value=7)
    game.get_enabled_shift_locations.return_value = board.shift_locations
    mock_method = Mock()
    mock_method.start = Mock()
    mock_method.shift_action = BoardLocation(0, 1), 90
    mock_method.move_action = board.maze.maze_card_location(piece.maze_card)
    mock_method_factory = Mock()
    mock_method_factory.return_value = mock_method
    player = ComputerPlayer(library_binding_factory=mock_method_factory, move_url="move-url", shift_url="shift-url",
                            game=game, identifier=9, board=board, piece=piece)
    player.run()
    mock_method.start.assert_called_once()
    post_shift.assert_called_once()
    post_move.assert_called_once()
示例#16
0
def test_clear_pieces_after_creations_empties_pieces():
    """ Tests clear_pieces. """
    board = Board(create_random_maze())
    for _ in range(8):
        board.create_piece()
    assert len(board.pieces) == 8
    board.clear_pieces()
    assert not board.pieces
示例#17
0
def _create_test_game(with_computer=False):
    """ Creates a Game instance by hand """
    card_factory = MazeCardFactory()
    board = Board(leftover_card=MazeCard(0, MazeCard.T_JUNCT, 0))
    for row in range(board.maze.maze_size):
        for column in range(board.maze.maze_size):
            if row == 0 and column == 0:
                board.maze[BoardLocation(
                    row, column)] = card_factory.create_instance(
                        MazeCard.STRAIGHT, 0)
            elif row == 1 and column == 1:
                board.maze[BoardLocation(
                    row, column)] = card_factory.create_instance(
                        MazeCard.CORNER, 0)
            elif row == 2 and column == 2:
                board.maze[BoardLocation(
                    row, column)] = card_factory.create_instance(
                        MazeCard.T_JUNCT, 270)
            else:
                board.maze[BoardLocation(
                    row, column)] = card_factory.create_instance(
                        MazeCard.T_JUNCT, 0)
    player_ids = [3, 4]
    players = [
        Player(identifier=player_id, game=None) for player_id in player_ids
    ]
    if with_computer:
        player_ids.append(42)
        players.append(
            create_computer_player(player_id=42,
                                   compute_method="dynamic-foo",
                                   shift_url="shift-url",
                                   move_url="move-url"))
    for player in players:
        player.set_board(board)
    players[0].piece.maze_card = board.maze[BoardLocation(3, 3)]
    players[1].piece.maze_card = board.maze[BoardLocation(5, 5)]
    players[0].piece.piece_index = 1
    players[1].piece.piece_index = 0
    players[0].score = 7
    players[1].score = 8
    board._objective_maze_card = board.maze[BoardLocation(1, 4)]
    turns = Turns(players,
                  next_action=PlayerAction(players[1],
                                           PlayerAction.MOVE_ACTION))
    game = Game(identifier=7, turns=turns, board=board, players=players)
    for player in players:
        player._game = game
    game.previous_shift_location = BoardLocation(0, 3)
    return game, player_ids
示例#18
0
def test_random_actions_should_respect_no_pushback_rule():
    """ Runs computation 50 times and checks that none of the computed shifts reverts the previous shift action """

    card_factory = MazeCardFactory()
    orig_board = Board(create_maze(MAZE_STRING, card_factory), leftover_card=card_factory.create_instance("NE", 0))
    for _ in range(50):
        board = copy.deepcopy(orig_board)
        maze = board.maze
        piece = board.create_piece()
        piece.maze_card = maze[BoardLocation(0, 0)]
        game = Game(0, board=orig_board)
        game.previous_shift_location = BoardLocation(0, 3)
        computer_player = ComputerPlayer(library_binding_factory=Mock(), move_url="move-url", shift_url="shift-url",
                                         game=game, identifier=9, board=board, piece=piece)
        shift_action, _ = computer_player.random_actions()
        shift_location, _ = shift_action
        assert shift_location != BoardLocation(6, 3)
示例#19
0
def test_add_player_start_game_calls_methods_on_board():
    """ Tests add_player, start_game and Player """
    board = Board()
    turns = Mock()
    game = Game(identifier=0, board=board, turns=turns)
    with patch.object(board, 'create_piece',
                      wraps=board.create_piece) as board_create_piece:
        for _ in range(4):
            player_id = game.unused_player_id()
            game.add_player(Player(player_id))
        game.start_game()
        expected_board_calls = [
            call.create_piece(),
            call.create_piece(),
            call.create_piece(),
            call.create_piece()
        ]
        assert board_create_piece.mock_calls == expected_board_calls
示例#20
0
def test_shift_updates_old_leftover_rotation():
    """ Tests shift """
    board = Board()
    old_leftover = board.leftover_card
    board.shift(BoardLocation(0, 1), 270)
    assert old_leftover.rotation == 270
示例#21
0
def create_board(maze_string=ALL_CONNECTED_3):
    maze = factories.create_maze(maze_string)
    return Board(maze=maze)
示例#22
0
def test_after_series_of_creates_and_removes_no_corners_empty():
    """ Tests create_piece. Adds three pieces, removes two, adds three,
    and checks that all pieces are on a different corner """
    board = Board(create_random_maze())
    piece1 = board.create_piece()
    piece2 = board.create_piece()
    board.create_piece()
    board.remove_piece(piece1)
    board.remove_piece(piece2)
    board.create_piece()
    board.create_piece()
    board.create_piece()
    assert len(board.pieces) == 4
    piece_cards = {piece.maze_card for piece in board.pieces}
    assert len(piece_cards) == 4
示例#23
0
def test_remove_piece_after_create_piece():
    """ Tests remove_piece """
    board = Board(create_random_maze())
    piece = board.create_piece()
    board.remove_piece(piece)
    assert not board.pieces
示例#24
0
def given_empty_game__when_adding_players__creates_pieces_on_board():
    board = Board()
    game = Game(identifier=0, board=board, turns=Mock())
    add_players(game, 4)
    assert len(board.pieces) == 4
示例#25
0
def test_move_raises_error_on_invalid_location():
    """ Tests move validation """
    board = Board()
    piece = board.create_piece()
    with pytest.raises(InvalidLocationException):
        board.move(piece, BoardLocation(-1, -1))
示例#26
0
def test_get_enabled_shift_locations_without_previous_shift():
    """ Tests get_enabled_shift_locations where the previous shift is None """
    board = Board()
    game = Game(identifier=0, board=board)
    enabled_shift_locations = game.get_enabled_shift_locations()
    assert set(enabled_shift_locations) == set(board.shift_locations)
示例#27
0
def test_shift_raises_error_on_invalid_rotation():
    """ Tests shift validation """
    board = Board()
    with pytest.raises(InvalidRotationException):
        board.shift(BoardLocation(0, 1), 70)
示例#28
0
def test_shift_raises_error_on_invalid_location():
    """ Tests shift validation """
    board = Board()
    with pytest.raises(InvalidShiftLocationException):
        board.shift(BoardLocation(0, 0), 90)
示例#29
0
def test_shift_updates_new_leftover():
    """ Tests shift """
    board = Board()
    pushed_out = board.maze[BoardLocation(board.maze.maze_size - 1, 1)]
    board.shift(BoardLocation(0, 1), 270)
    assert pushed_out == board.leftover_card
示例#30
0
def create_board(maze_size=7):
    """ Creates a board with a given maze size.

    The maze and the leftover obey the generalized original-game layout and maze card distribution rules """
    maze, leftover = create_maze_and_leftover(size=maze_size)
    return Board(maze=maze, leftover_card=leftover)