def test_is_valid_move_true_when_can_move_up():
    game = Pylos()

    fill_layer(game, 0)

    assert_equal(game.render(), "0101/0101/0101/0101#.../.../...#../..#.")
    assert game.is_valid_move((0, 0, 0))
def test_is_valid_move_false_when_own_ball_but_no_valid_targets():
    game = Pylos()

    play_turn(game, None, (0, 0, 0))
    play_turn(game, None, (0, 1, 0))

    assert not game.is_valid_move((0, 0, 0))
def test_is_valid_move_false_when_blocked():
    game = Pylos()

    fill_layer(game, 0)
    fill_layer(game, 1)

    assert_equal(game.current_player, 1)
    assert not game.is_valid_move((0, 3, 3))
def test_is_valid_move_true_when_source_is_part_of_support():
    game = Pylos()

    fill_layer(game, 0)
    fill_layer(game, 1)

    assert_equal(game.render(), "0101/0101/0101/0101#010/101/010#../..#.")
    assert not game.is_valid_move((0, 1, 0))
def test_render():
    game = Pylos()

    assert game.render() == "..../..../..../....#.../.../...#../..#."

    play_turn(game, None, (0, 0, 0))

    assert game.render() == "0.../..../..../....#.../.../...#../..#."
def test_is_valid_move_false_when_source_is_current_player_ball_and_no_possible_higher_targets(
):
    game = Pylos()

    play_turn(game, None, (0, 0, 0), None, None)
    play_turn(game, None, (0, 0, 1), None, None)

    assert not game.is_valid_move((0, 0, 0))
def test_layer0_valid_move():
    game = Pylos()

    play_turn(game, None, (0, 1, 2), None, None)

    assert_equal(game.render(), "..../..0./..../....#.../.../...#../..#.")
    assert_equal(game.current_player, 1)
    assert_equal(game.reserve, [14, 15])
def test_fill_entire_board_winner_is_player_whose_ball_is_on_the_top():
    game = Pylos()

    fill_layer(game, 0)
    fill_layer(game, 1)
    fill_layer(game, 2)
    fill_layer(game, 3)

    assert game.game_over()
    assert game.winner == 1
def test_move_valid_source_location_new_state():
    game = Pylos()

    game.move(None)

    assert game.actions == Actions()
    assert game.phase == pylos.PHASE_TARGET_LOCATION
    assert game.render() == "..../..../..../....#.../.../...#../..#."
    assert game.reserve == [15, 15]
    assert game.current_player == 0
Example #10
0
    def __init__(self):
        self.pylos = Pylos()
        self.done = False

        self.reset()

        # each move consists of 31 possible values (0-29 meaning one of the board positions,
        # 30 meaning 'none' or 'reserve' depending on the current phase)
        # note that for the 'target' phase, 30 is never a valid value
        self.action_space = spaces.Discrete(31)
def test_winner_correct_when_board_full():
    game = Pylos()

    assert_equal(game.get_winner(), None)

    fill_layer(game, 0)
    fill_layer(game, 1)
    fill_layer(game, 2)
    fill_layer(game, 3)

    assert_equal(game.get_winner(), 1)
def test_valid_turn():
    game = Pylos()

    play_turn(game, None, (0, 0, 0), None, None)

    assert game.actions == Actions()
    assert game.phase == pylos.PHASE_SOURCE_LOCATION
    assert game.render() == "0.../..../..../....#.../.../...#../..#."
    assert game.reserve == [14, 15]
    assert game.current_player == 1
    assert_equal(game.winner, None)
def test_is_valid_move_true_when_source_is_current_player_ball_and_possible_higher_targets(
):
    game = Pylos()

    play_turn(game, None, (0, 0, 0), None, None)
    play_turn(game, None, (0, 2, 2), None, None)
    play_turn(game, None, (0, 2, 3), None, None)
    play_turn(game, None, (0, 3, 2), None, None)
    play_turn(game, None, (0, 3, 3), None, None)
    play_turn(game, None, (0, 0, 3), None, None)

    assert game.is_valid_move((0, 0, 0))
def test_layer1_invalid_move_insufficient_support():
    game = Pylos()
    play_turn(game, None, (0, 1, 1))
    play_turn(game, None, (0, 1, 2))
    play_turn(game, None, (0, 2, 2))

    play_turn(game, None, (1, 1, 1))
def setup_moveup_scenario():
    game = Pylos()

    fill_layer(game, 0)

    play_turn(game, None, (1, 0, 1))
    play_turn(game, None, (1, 0, 2))

    play_turn(game, None, (1, 1, 1))
    play_turn(game, None, (1, 1, 2))

    play_turn(game, None, (1, 1, 0))
    play_turn(game, None, (1, 2, 2))

    assert game.render() == "0101/0101/0101/0101#.01/001/..1#../..#."

    return game
def test_invalid_single_retraction_no_square():
    game = Pylos()
    play_turn(game, None, (0, 0, 0))
    play_turn(game, None, (0, 3, 0))

    play_turn(game, None, (0, 1, 0))
    play_turn(game, None, (0, 3, 1))

    play_turn(game, None, (0, 1, 1), (0, 1, 0))
def test_invalid_retraction_retract_opponent_ball():
    game = Pylos()
    play_turn(game, None, (0, 0, 0))
    play_turn(game, None, (0, 3, 0))

    play_turn(game, None, (0, 1, 0))
    play_turn(game, None, (0, 3, 1))

    play_turn(game, None, (0, 0, 1))
    play_turn(game, None, (0, 3, 2))

    play_turn(game, None, (0, 1, 1), (0, 3, 0))
def test_layer1_valid_move():
    game = Pylos()
    play_turn(game, None, (0, 1, 1))
    play_turn(game, None, (0, 1, 2))
    play_turn(game, None, (0, 2, 2))
    play_turn(game, None, (0, 2, 1))

    play_turn(game, None, (1, 1, 1))

    assert game.layers[0] == [[None, None, None, None], [None, 0, 1, None],
                              [None, 1, 0, None], [None, None, None, None]]
    assert game.layers[1] == [[None, None, None], [None, 0, None],
                              [None, None, None]]
def test_valid_single_retraction():
    game = Pylos()
    play_turn(game, None, (0, 0, 0))
    play_turn(game, None, (0, 3, 0))

    play_turn(game, None, (0, 1, 0))
    play_turn(game, None, (0, 3, 1))

    play_turn(game, None, (0, 0, 1))
    play_turn(game, None, (0, 3, 2))

    assert_equal(game.layers[0], [[0, 0, None, None], [0, None, None, None],
                                  [None, None, None, None], [1, 1, 1, None]])
    play_turn(game, None, (0, 1, 1), (0, 1, 0))
    assert_equal(game.layers[0], [[0, 0, None, None], [None, 0, None, None],
                                  [None, None, None, None], [1, 1, 1, None]])
def test_winner_correct_when_current_player_no_balls():
    game = Pylos()

    assert game.get_winner() is None

    play_turn(game, None, (0, 0, 0))
    play_turn(game, None, (0, 3, 0))

    play_turn(game, None, (0, 0, 1))
    play_turn(game, None, (0, 3, 1))

    play_turn(game, None, (0, 1, 0))
    play_turn(game, None, (0, 3, 2))

    play_turn(game, None, (0, 1, 1), (0, 1, 0), (0, 1, 1))
    play_turn(game, None, (0, 3, 3))

    play_turn(game, None, (0, 0, 2))
    play_turn(game, None, (0, 0, 3))

    assert_equal(game.render(), "0001/..../..../1111#.../.../...#../..#.")

    # fill rows 2 and 3
    for row in range(1, 3):
        play_turn(game, None, (0, row, 0))
        play_turn(game, None, (0, row, 1))
        play_turn(game, None, (0, row, 2))
        play_turn(game, None, (0, row, 3))

    assert_equal(game.reserve, [8, 6])

    assert_equal(game.render(), "0001/0101/0101/1111#.../.../...#../..#.")

    # fill next layer
    fill_layer(game, 1)
    fill_layer(game, 2)

    assert_equal(game.reserve, [1, 0])
    assert_equal(game.current_player, 1)
    assert_equal(game.render(), "0001/0101/0101/1111#010/101/010#10/10#.")
    assert_equal(game.determine_winner(), 0)
    assert_equal(game.get_winner(), 0)
def test_valid_upmove():
    game = Pylos()

    play_turn(game, None, (0, 0, 0))
    assert_equal(game.render(), "0.../..../..../....#.../.../...#../..#.")

    play_turn(game, None, (0, 3, 3))
    assert_equal(game.render(), "0.../..../..../...1#.../.../...#../..#.")

    play_turn(game, None, (0, 0, 1))
    play_turn(game, None, (0, 1, 0))
    play_turn(game, None, (0, 1, 1))

    assert_equal(game.render(), "00../10../..../...1#.../.../...#../..#.")
    play_turn(game, (0, 3, 3), (1, 0, 0))

    assert_equal(game.render(), "00../10../..../....#1../.../...#../..#.")
def test_is_valid_move_false_when_source_is_other_player_ball():
    game = Pylos()

    play_turn(game, None, (0, 0, 0), None, None)

    assert not game.is_valid_move((0, 0, 0))
def test_is_valid_move_false_when_source_is_empty():
    game = Pylos()

    assert not game.is_valid_move((0, 0, 0))
def test_invalid_move_target_without_support():
    game = Pylos()

    play_turn(game, None, (1, 0, 0))
def test_layer0_invalid_move_already_occupied():
    game = Pylos()
    play_turn(game, None, (0, 1, 2))
    play_turn(game, None, (0, 1, 2))
Example #26
0
class PylosEnv(gym.Env):
    done: bool
    metadata = {}

    def __init__(self):
        self.pylos = Pylos()
        self.done = False

        self.reset()

        # each move consists of 31 possible values (0-29 meaning one of the board positions,
        # 30 meaning 'none' or 'reserve' depending on the current phase)
        # note that for the 'target' phase, 30 is never a valid value
        self.action_space = spaces.Discrete(31)

    def state_from_pylos(self):
        player_onehot = np.array(
            [1 - self.pylos.current_player, self.pylos.current_player])

        # game phase
        phase_onehot = np.array([
            1 if self.pylos.phase == pylos.PHASE_SOURCE_LOCATION else 0,
            1 if self.pylos.phase == pylos.PHASE_TARGET_LOCATION else 0,
            1 if self.pylos.phase == pylos.PHASE_RETRACT1 else 0,
            1 if self.pylos.phase == pylos.PHASE_RETRACT2 else 0
        ])

        # board (3 nodes per board position)
        board_vector = np.array([[
            1 if ball_owner is None else 0 for ball_owner in self.flat_board()
        ], [1 if ball_owner == 0 else 0 for ball_owner in self.flat_board()],
                                 [
                                     1 if ball_owner == 1 else 0
                                     for ball_owner in self.flat_board()
                                 ]]).flatten('F')

        return np.concatenate([player_onehot, phase_onehot, board_vector])

    def flat_board(self):
        result = []
        for l in self.pylos.layers:
            for r in l:
                result += r
        return result

    def reset(self):
        self.done = False
        self.pylos = Pylos()
        return self.state_from_pylos()

    def step(self, action):
        if self.done:
            print("WARNING: step called after done")
            return self.state_from_pylos(), 0, self.done, {
                'warning_step_after_done': True
            }

        location = map_action_to_location(action)

        if not self.pylos.is_valid_move(location):
            return self.create_invalid_move_step_response(location)

        player = self.pylos.current_player
        reserve_before = self.pylos.reserve[player]
        self.pylos.move(location)
        reserve_after = self.pylos.reserve[player]

        winner = self.pylos.get_winner()
        reward = 1
        reward += reserve_after - reserve_before

        if winner is not None:
            reward += 10
            self.done = True

        return self.state_from_pylos(), reward, self.done, {
            'phase': self.pylos.phase
        }

    def render(self):
        if self.pylos.winner is not None:
            print(" *** Winner *** ", self.pylos.winner)
        print("Player: ", self.pylos.current_player)
        print("Phase: ", PHASE_NAMES[self.pylos.phase])
        print("\n".join([self._render_row(r) for r in range(4)]))

    def _render_row(self, row):
        layers = self.pylos.render().split("#")

        split_layers = [layer.split("/") for layer in layers]
        return "  ".join(([
            layer[row] if row < len(layer) else " " * (4 - row)
            for layer in split_layers
        ]))

    def create_invalid_move_step_response(self, location):
        return self.state_from_pylos(), -10, self.done, {'invalid': location}
def test_is_valid_move_false_when_source_is_opponent_ball():
    game = Pylos()

    fill_layer(game, 0)

    assert not game.is_valid_move((0, 3, 3))
Example #28
0
 def reset(self):
     self.done = False
     self.pylos = Pylos()
     return self.state_from_pylos()
def test_is_valid_move_true_when_source_is_reserve():
    game = Pylos()

    assert game.is_valid_move(None)