예제 #1
0
def test_outside_board_moves():
    r""" Verify that the program raises errors when moves are illegal given the board"""
    l_orig = Location(0, 0)

    # Test top and left boundaries
    p = Piece(Color.RED, Rank.marshall(), l_orig)
    for l_new in [l_orig.up(), l_orig.left()]:
        with pytest.raises(Exception) as e_info:
            Move(p, l_orig, l_new)
        assert e_info.type == ValueError

    # Test right and bottom boundaries
    l_orig = Location(STD_BRD.num_rows - 1, STD_BRD.num_cols - 1)
    p = Piece(Color.RED, Rank.marshall(), l_orig)
    for l_new in [l_orig.right(), l_orig.down()]:
        with pytest.raises(Exception) as e_info:
            Move(p, l_orig, l_new)
        assert e_info.type == ValueError

    blocked_loc = Location(4, 2)
    # Verify a blocked location cannot be used as original location
    p = Piece(Color.RED, Rank.marshall(), blocked_loc)
    with pytest.raises(Exception) as e_info:
        Move(p, blocked_loc, blocked_loc.up())
    assert e_info.type == ValueError

    # Verify a blocked location cannot be used as new location
    p = Piece(Color.RED, Rank.marshall(), blocked_loc.up())
    with pytest.raises(Exception) as e_info:
        Move(p, blocked_loc.up(), blocked_loc)
    assert e_info.type == ValueError
예제 #2
0
def test_verify_neighbor_movements():
    r""" Verifies basic movement of a piece that ensures basic movement works """
    l_orig = Location(1, 1)
    p = Piece(Color.RED, Rank.marshall(), l_orig)

    # Verify all the neighbor locations are valid
    for l_new in l_orig.neighbors():
        Move(p, l_orig, l_new)

    # Verify with attacking
    other = Piece(Color.BLUE, Rank.bomb(), Location(0, 0))
    for l_new in l_orig.neighbors():
        other.loc = l_new
        Move(p, l_orig, l_new, other)
예제 #3
0
def test_attack_color():
    r""" Verify that attacks of different colors either do or do not raise errors """
    # Verify when blue attacks red and red attacks blue, everything works
    loc = Location(0, 0)
    red = Piece(Color.RED, Rank.marshall(), loc)
    blue = Piece(Color.BLUE, Rank.marshall(), loc.down())
    # Red attack blue
    Move(red, loc, blue.loc, blue)
    # Blue attack red
    Move(blue, blue.loc, red.loc, red)

    # Red attack red (exception)
    red2 = Piece(red.color, Rank.flag(), blue.loc)
    with pytest.raises(Exception):
        Move(red, red.loc, red2.loc, red2)
    # Blue attack blue (exception)
    blue2 = Piece(blue.color, Rank.flag(), red.loc)
    with pytest.raises(Exception):
        Move(blue, blue.loc, blue2.loc, blue2)
예제 #4
0
def test_move_to_index_information():
    r"""
    Test that the output node from the neural network has a bijective mapping to possible movements.
    """
    agent = _make_deep_q_agent(NO_BLOCK_BRD)
    state_tuple = ReplayStateTuple(s=agent._state)
    brd = state_tuple.s.board

    # Verify board size as expected
    assert brd.num_loc == brd.num_rows * brd.num_cols

    # Verify non-scout pieces
    p = state_tuple.s.get_player(Color.RED).get_piece_at_loc(Location(0, 0))
    for i in range(state_tuple.s.board.num_loc):
        p.loc = Location(i // brd.num_cols, i % brd.num_cols)
        for j, neighbor in enumerate(p.loc.neighbors()):
            if not brd.is_inside(neighbor): continue
            state_tuple.a = Move(p, p.loc, neighbor)
            board_loc, move_dir_idx = DeepQAgent._get_loc_and_idx_from_move(
                state_tuple)

            assert board_loc == i
            # Verify neighbor direction matches expectation
            assert j + state_tuple.s.board.num_loc == move_dir_idx

    # Verify scouts specifically
    p._rank = Rank.scout()
    for i in range(state_tuple.s.board.num_loc):
        p.loc = state_tuple.a._orig = Location(i // brd.num_cols,
                                               i % brd.num_cols)
        # Left then right
        for sign in [1, -1]:
            ofs = brd.num_loc + (brd.num_rows - 1) + Move.Direction.count()
            if sign == -1:
                ofs += (brd.num_rows - 1) + (brd.num_cols - 1)
            for col_diff in range(0, agent._state.board.num_cols - 1):
                new = p.loc.relative(0, sign * (col_diff + 1))
                state_tuple.a._new = new
                board_loc, scout_move_id = DeepQAgent._get_loc_and_idx_from_move(
                    state_tuple)
                assert i == board_loc
                assert ofs + col_diff == scout_move_id
        # Up then down
        for sign in [1, -1]:
            ofs = brd.num_loc + Move.Direction.count()
            if sign == 1:
                ofs += (brd.num_rows - 1) + (brd.num_cols - 1)
            for row_diff in range(0, agent._state.board.num_rows - 1):
                new = p.loc.relative(sign * (row_diff + 1), 0)
                state_tuple.a._new = new
                board_loc, scout_move_id = DeepQAgent._get_loc_and_idx_from_move(
                    state_tuple)
                assert i == board_loc
                assert ofs + row_diff == scout_move_id
예제 #5
0
def test_scout_movements():
    r""" Verify that only scouts can move multiple squares at once """
    loc = Location(3, STD_BRD.num_cols // 2)

    # Just make sure color of the Scout has not effect (it may be a dumb test)
    for color in [Color.RED, Color.BLUE]:
        scout, miner = Piece(color, Rank.scout(),
                             loc), Piece(color, Rank.miner(), loc)
        for p in [scout, miner]:
            for move_dist in [1, 2]:
                for i in range(2):
                    if i == 0: new_loc = loc.relative(row_diff=move_dist)
                    else: new_loc = loc.relative(col_diff=move_dist)

                    if move_dist == 1 or p.rank == Rank.scout():
                        Move(p, loc, new_loc)
                    else:
                        with pytest.raises(Exception) as e_info:
                            Move(p, p.loc, new_loc)
                        assert substr_in_err("multiple", e_info)
예제 #6
0
def test_diagonal_movement():
    r""" Verify diagonal movements fail """
    loc = Location(1, 1)
    move_list = [-1, 0, 1]

    p = Piece(Color.RED, Rank.spy(), loc)
    for row_move in move_list:
        for col_move in move_list:
            man_dist = abs(col_move) + abs(row_move)
            l_new = loc.relative(row_move, col_move)
            # Adjacent moves of (exactly) one are sanity checks and should pass
            if man_dist == 0:
                with pytest.raises(Exception):
                    Move(p, p.loc, l_new)
            # Valid adjacent moves for sanity check
            elif man_dist == 1:
                Move(p, loc, l_new)
            # Diagonal moves should fail
            elif man_dist == 2:
                with pytest.raises(Exception) as e_info:
                    Move(p, p.loc, l_new)
                assert substr_in_err("diagonal", e_info)
예제 #7
0
def test_immovable_pieces():
    r""" Verify that an immovable piece raises an error """
    moveable = set(range(Rank.MIN(), Rank.MAX() + 1)) | {Rank.SPY}
    immovable = {Rank.BOMB, Rank.FLAG}
    combined = moveable | immovable

    # Sanity check rank sets
    assert len(moveable) > 0 and len(
        immovable) > 0, "Both rank sets should be non-empty"
    assert moveable & immovable == set(), "Rank sets not disjoint"
    assert len(combined) == len(Rank.get_all()), "One or more ranks missing"

    loc = Location(0, 0)
    # As a sanity make sure color is irrelvant
    for color in [Color.RED, Color.BLUE]:
        # Verify each rank is correctly marked movable or immovable
        for r in combined:
            p = Piece(color, Rank(r), loc)
            new_loc = loc.down()
            if r in moveable:
                Move(p, loc, new_loc)
            if r in immovable:
                with pytest.raises(Exception):
                    Move(p, p.loc, new_loc)
예제 #8
0
def test_is_identical():
    r""" Verify the \p piece_has_move method of the \p State class """
    path = STATES_PATH / "state_move_verify.txt"
    state = State.importer(path, STD_BRD)

    orig, new = Location(0, 0), Location(1, 0)
    # Get the state information
    p_state = state.red.get_piece_at_loc(orig)
    m_state = state.red.get_move(p_state, new)
    # Build a move for comparison
    p = copy.deepcopy(state.red.get_piece_at_loc(orig))
    m = Move(p, orig, new)

    assert m_state != m, "Equality fails since different references"
    assert Move.is_identical(m, m_state), "Verify the two moves are identical"
    assert Move.is_identical(m_state, m), "Verify the two moves are identical"

    # Color checks
    m._piece._color = Color.BLUE
    assert not Move.is_identical(
        m, m_state), "Verify if color does not match test fails"
    assert not Move.is_identical(
        m_state, m), "Verify if color does not match test fails"
    m._piece._color = Color.RED
    assert Move.is_identical(m, m_state), "Verify move correctly restored"

    # Rank checks
    prev_rank, m._piece._rank = m.piece.rank, Rank.flag()
    assert not Move.is_identical(
        m, m_state), "Verify if rank does not match test fails"
    assert not Move.is_identical(m_state,
                                 m), "Verify if rank does not match test fails"
    m._piece._rank = prev_rank
    assert Move.is_identical(m_state, m), "Verify move correctly restored"

    # New checks
    m._new = orig
    assert not Move.is_identical(m, m_state), "Verify new will cause a failure"
    assert not Move.is_identical(m_state, m), "Verify new will cause a failure"
    m._new = new
    assert Move.is_identical(m, m_state), "Verify move correctly restored"

    # Old checks
    m._orig = new
    assert not Move.is_identical(m,
                                 m_state), "Verify orig will cause a failure"
    assert not Move.is_identical(m_state,
                                 m), "Verify orig will cause a failure"
    m._orig = orig
    assert Move.is_identical(m, m_state), "Verify move correctly restored"

    attacked, m._attacked = m._attacked, []  # Just give it so not None
    assert not Move.is_identical(
        m, m_state), "Verify attacked will cause a failure"
    assert not Move.is_identical(m_state,
                                 m), "Verify attacked will cause a failure"
    m._attacked = attacked
    assert Move.is_identical(m, m_state), "Verify move correctly restored"
예제 #9
0
    :copyright: (c) 2019 by Zayd Hammoudeh.
    :license: MIT, see LICENSE for more details.
"""
import copy

import pytest

from stratego import State
from stratego.location import Location
from stratego.move import Move
from stratego.piece import Color, Piece, Rank

from testing_utils import STATES_PATH, STD_BRD, build_test_board, substr_in_err

Move.set_board(STD_BRD)


def test_verify_neighbor_movements():
    r""" Verifies basic movement of a piece that ensures basic movement works """
    l_orig = Location(1, 1)
    p = Piece(Color.RED, Rank.marshall(), l_orig)

    # Verify all the neighbor locations are valid
    for l_new in l_orig.neighbors():
        Move(p, l_orig, l_new)

    # Verify with attacking
    other = Piece(Color.BLUE, Rank.bomb(), Location(0, 0))
    for l_new in l_orig.neighbors():
        other.loc = l_new