def test_gamma_board(store: StatementStoreType, **kwargs: Any) -> None:
    doc = "gamma_move + gamma_board"
    store(make_comment(doc))

    height, width = int(kwargs.get("height", 7)), int(kwargs.get("width", 7))
    moves = int(kwargs.get("moves", height * width))
    chunk_size = int(kwargs.get("chunk_size", 1))
    players, areas = int(kwargs.get("players", 5)), int(kwargs.get("areas", 9))
    board = make_board(store, height, width, players, areas)

    player_iterator = cycle_players(players=players, take=moves)

    for _ in range(round(moves / chunk_size)):
        for player in it.islice(player_iterator, chunk_size):
            x, y = random.randint(0, height - 1), random.randint(0, width - 1)
            store(assert_call(gamma_move, board, player, x, y))
        assert_board_equal(store, board)

    delete_board(store, board)
def test_many_boards(store: StatementStoreType, **kwargs: Any) -> None:
    doc = "gamma_move + gamma_board, a few boards at the same time"
    store(make_comment(doc))

    b1 = make_board(store, 4, 4, 4, 16, name="board1")
    b2 = make_board(store, 4, 4, 4, 16, name="board2")
    b3 = make_board(store, 4, 4, 4, 16, name="board3")

    for player in cycle_players(players=4, take=3 * 16):
        for board, name in [(b1, "board1"), (b2, "board2"), (b3, "board3")]:
            x, y = random.randint(0, 3), random.randint(0, 3)
            store(assert_call(gamma_move, board, player, x, y,
                              board_name=name))
            if player == 1:
                assert_board_equal(store, board, board_name=name)

    delete_board(store, b1, board_name="board1")
    delete_board(store, b3, board_name="board3")
    delete_board(store, b2, board_name="board2")
def test_golden_move_complexity(store: StatementStoreType,
                                **kwargs: Any) -> None:
    doc = "tests golden move complexity"
    store(make_comment(doc))

    width, height = int(kwargs.get("width",
                                   100)), int(kwargs.get("height", 100))
    players, areas = int(kwargs.get("players", 2)), int(kwargs.get("areas", 2))
    tests = int(kwargs.get("players", (height * width)**0.5))
    board = make_board(store, width, height, players, areas)
    board.max_areas = 1

    def can_move(p: int) -> bool:
        return bool(
            gamma_free_fields(board, p) or gamma_golden_possible(board, p))

    for _ in range(25):
        if not any(can_move(p) for p in range(1, players + 1)):
            break
        for p in range(1, players + 1):
            if board.get_busy_fields(p) == 0:
                x, y = random.randint(0, width - 1), random.randint(
                    0, height - 1)
                store(assert_call(gamma_move, board, p, x, y))
            else:
                for y, x in board.get_free_fields_coords(p):
                    store(assert_call(unsafe_gamma_move, board, p, x, y))

    board.max_areas = areas
    for i in range(round(tests)):
        if not any(
                gamma_golden_possible(board, p)
                for p in range(1, players + 1)):
            break

        for p in range(1, players + 1):
            x, y = random.randint(0, width - 1), random.randint(0, height - 1)
            store(assert_call(gamma_golden_move, board, p, x, y))

    delete_board(store, board)
def test_strip(store: StatementStoreType, **kwargs: Any) -> None:
    doc = "board is either vertical or horizontal strip"
    store(make_comment(doc))

    max_size = int(kwargs.get("max_size", 64))
    players = int(kwargs.get("players", 8))
    areas = int(kwargs.get("areas", 4))
    chunk_size = int(kwargs.get("chunk_size", 32))
    tests = int(kwargs.get("tests", max_size * 4))

    width, height = 1, random.randint(1, max_size)
    if kwargs.get("horizontal", False):
        height, width = width, height

    board = make_board(store, width, height, players, areas)

    def run_checks_for_all_players() -> None:
        for p in range(1, players + 1):
            store(assert_call(gamma_golden_possible, board, p))
            store(assert_call(gamma_busy_fields, board, p))
            store(assert_call(gamma_free_fields, board, p))
            if random.randint(0, 100) < 10:
                store(
                    assert_call(
                        gamma_golden_move,
                        board,
                        player,
                        random.randint(0, width),
                        random.randint(0, height),
                    ))

    player_iterator = cycle_players(players=players, take=tests)
    for _ in range(round(tests / chunk_size)):
        for player in it.islice(player_iterator, chunk_size):
            x, y = random.randint(0, width), random.randint(0, height)
            store(assert_call(gamma_move, board, player, x, y))
        run_checks_for_all_players()

    delete_board(store, board)
def test_busy_fields_complexity(store: StatementStoreType,
                                **kwargs: Any) -> None:
    doc = "gamma_busy_fields complexity"
    store(make_comment(doc))

    width, height = int(kwargs.get("width",
                                   100)), int(kwargs.get("height", 100))
    players = int(kwargs.get("players", 100))
    areas = round(players**(1 / 2))

    board = make_board(store, height, width, players, areas)

    all_fields = get_all_board_coords(board)
    random.shuffle(all_fields)
    for p in range(1, players + 1):
        for _ in range(areas):
            store(assert_call(unsafe_gamma_move, board, p, *all_fields.pop()))

    for _ in range(4):
        for p in range(1, players + 1):
            store(assert_call(gamma_free_fields, board, p))

    delete_board(store, board)
def test_snake_gamma_possible_complexity(store: StatementStoreType,
                                         **kwargs: Any) -> None:
    doc = """gamma_golden_possible complexity
    sample board:
    1111
    ...1
    1111
    1...
    ....
    ...2"""
    store(make_comment(doc))

    side_size = int(kwargs.get("side_size", 10))
    golden_possible_queries = int(
        kwargs.get("golden_possible_queries", side_size))
    assert side_size > 4, "side size must be >= 5"
    width, height, players, areas = side_size, side_size, 2, 1

    board = make_board(store, height, width, players, areas)

    store(assert_call(unsafe_gamma_move, board, 2, width - 1, height - 1))
    for row in range(side_size - 2):
        if row % 2 == 0:
            indices = range(width) if row % 4 == 0 else reversed(range(width))
            for x in indices:
                store(assert_call(unsafe_gamma_move, board, 1, x, row))
        else:
            pos_in_row = width - 1 if row % 4 == 1 else 0
            store(assert_call(unsafe_gamma_move, board, 1, pos_in_row, row))

    assert_board_equal(store, board)

    for p in cycle_players(players, take=golden_possible_queries):
        store(make_assert(f"gamma_golden_possible(board, {p})", "0"))

    delete_board(store, board)
def test_golden_move_complexity_many_splits(store: StatementStoreType,
                                            **kwargs: Any) -> None:
    doc = ("gamma_golden_move complexity, "
           "attempts invalid golden moves (too many areas)")
    store(make_comment(doc))

    width, height = int(kwargs.get("width",
                                   100)), int(kwargs.get("height", 100))
    players = int(kwargs.get("players", 100))
    board = make_board(store, height, width, players, 3)
    all_fields = get_all_board_coords(board)
    random_centers = random.sample(all_fields, k=players)

    player_center_area = {
        p: (f, get_coords_around(board, *f))
        for (p, f) in zip(range(1, players + 1), random_centers)
    }

    for player, (center, neighbors) in player_center_area.items():
        x, y = center
        if board.board.board[y][x] == FREE_FIELD:
            store(assert_call(unsafe_gamma_move, board, player, *center))
            for (x, y) in neighbors:
                if board.board.board[y][x] == FREE_FIELD:
                    store(assert_call(unsafe_gamma_move, board, player, x, y))

    if bool(kwargs.get("always_fail", True)):
        for player in range(1, players + 1):
            x, y = random.randint(0, width - 1), random.randint(0, height - 1)
            store(assert_call(gamma_move, board, player, x, y))

    for player in range(1, players + 1):
        field = random.choice(random_centers)
        store(assert_call(gamma_golden_move, board, player, *field))

    delete_board(store, board)
def test_random_actions(store: StatementStoreType, **kwargs: Any) -> None:
    doc = "random actions, total chaos"
    store(make_comment(doc))

    height, width = int(kwargs.get("height", 7)), int(kwargs.get("width", 7))
    players, areas = int(kwargs.get("players", 4)), int(kwargs.get("areas", 7))

    board = make_board(store, height, width, players, areas)

    for player in cycle_players(players=players, take=height * width * 2):
        grouped_areas = board.board.get_grouped_areas()

        if random.random() < 0.85:
            # default - random field
            x, y = random.randint(0, height - 1), random.randint(0, width - 1)
            if random.random() < 0.7:
                # only empty fields
                if FREE_FIELD in grouped_areas:
                    fields = list(flatten(grouped_areas[FREE_FIELD]))
                    x, y = random.choice(fields)

            store(assert_call(gamma_move, board, player, x, y))

        if random.random() < 0.5:  # second move
            if random.random() < 0.1:  # x, y may be outside of board
                x, y = random.randint(-1, height), random.randint(-1, width)
            else:  # always within board
                x, y = random.randint(0, height - 1), random.randint(
                    0, width - 1)
            x, y = random.randint(0, height - 1), random.randint(0, width - 1)
            store(assert_call(gamma_move, board, player, x, y))

        if random.random() < 0.1:
            store(assert_call(gamma_busy_fields, board, player))

        if random.random() < 0.1:
            store(assert_call(gamma_free_fields, board, player))

        if random.random() < 0.1:
            store(assert_call(gamma_golden_possible, board, player))

        if random.random() < 0.05:
            # default - player_to_attack is self or empty
            player_to_attack = random.choice([FREE_FIELD, player])
            if random.random() < 0.95:
                others = list(set(grouped_areas.keys()) - {FREE_FIELD, player})
                if others:
                    player_to_attack = random.choice(others)

            if player_to_attack in grouped_areas:
                other_players_fields = list(
                    flatten(grouped_areas[player_to_attack]))
                if other_players_fields:
                    field = random.choice(other_players_fields)
                    store(assert_call(gamma_golden_move, board, player,
                                      *field))

        if random.random() < 0.05:
            assert_board_equal(store, board)

    delete_board(store, board)