Exemplo n.º 1
0
def naiive_backtrack(board_code):
    """Naiive backtracking algorithm used to find the solution to a board with missing clues.
    Parameters
    ----------
    board_code : string
        Board code listed from top left to bottom right.

    Returns
    -------
    string
        Board code for solved board.

    Raises
    ------
    UnsolvableBoardException
        If the board does not have a solution.

    InvalidBoardException
        If the board code is invalid.
    """
    board = util.code_to_board(board_code)
    if not util.board_is_valid(board):
        raise util.InvalidBoardException
    search_board = np.copy(board)

    if util.board_is_solved(board):
        return util.board_to_code(board)

    position = 0
    step = 0
    while True:
        step += 1
        if position == 81:
            if not util.board_is_solved(search_board):
                raise util.InvalidBoardException  # if we got here when solving there must have been an issue with the board code
            print(f'Solved board in {step} steps')
            return util.board_to_code(search_board)

        x = util.to_x(position)
        y = util.to_y(position)

        if board[x][y] != 0:
            position += 1
            continue
        while search_board[x][y] <= 9:
            search_board[x][y] += 1
            if util.position_is_valid(search_board, x, y):
                position += 1
                break

        if search_board[x][y] == 10:
            search_board[x][y] = 0
            position -= 1
            if position < 0:
                raise util.UnsolvableBoardException
            while board[util.to_x(position)][util.to_y(position)] != 0:
                position -= 1
                if position < 0:
                    raise util.UnsolvableBoardException
Exemplo n.º 2
0
def naiive_backtrack_count(board_code):
    """Naiive backtracking algorithm used to count solutions to a board with missing clues.
    Parameters
    ----------
    board_code : string
        Board code listed from top left to bottom right.

    Returns
    -------
    int
        The number of unique solutions the board has.
    """
    board = util.code_to_board(board_code)
    search_board = np.copy(board)

    if util.board_is_solved(board):
        return 1

    position = 0
    step = 0
    solutions = 0
    while True:
        step += 1
        if position == 81:
            if not util.board_is_solved(search_board):
                raise util.InvalidBoardException
            solutions += 1
            position -= 1
            while board[util.to_x(position)][util.to_y(position)] != 0:
                position -= 1
                if position < 0:
                    print(f'found {solutions} solutions in {step} steps')
                    return solutions

        x = util.to_x(position)
        y = util.to_y(position)

        if board[x][y] != 0:
            position += 1
            continue
        while search_board[x][y] <= 9:
            search_board[x][y] += 1
            if util.position_is_valid(search_board, x, y):
                position += 1
                break
        if search_board[x][y] == 10:
            search_board[x][y] = 0
            position -= 1
            if position < 0:
                print(f'found {solutions} solutions in {step} steps')
                return solutions
            while board[util.to_x(position)][util.to_y(position)] != 0:
                position -= 1
                if position < 0:
                    print(f'found {solutions} solutions in {step} steps')
                    return solutions
Exemplo n.º 3
0
def test_position_is_valid():
    board = util.code_to_board(boards['81'][0])
    board[0][0] = -1
    assert not util.position_is_valid(board, 0, 0)

    board = util.code_to_board(boards['81'][0])
    board[0][4] = board[0][0]
    assert not util.position_is_valid(board, 0, 0)
    assert not util.position_is_valid(board, 0, 4)

    board = util.code_to_board(boards['81'][0])
    board[4][0] = board[0][0]
    assert not util.position_is_valid(board, 0, 0)
    assert not util.position_is_valid(board, 4, 0)

    board = util.code_to_board(boards['81'][0])
    board[1][1] = board[0][0]
    assert not util.position_is_valid(board, 0, 0)
    assert not util.position_is_valid(board, 1, 1)

    board = util.code_to_board(boards['81'][0])
    for i in range(9 * 9):
        x = util.to_x(i)
        y = util.to_y(i)
        assert util.position_is_valid(board, x, y)
Exemplo n.º 4
0
def generate(filled_board):
    positions = [(util.to_x(i), util.to_y(i)) for i in range(81)]
    np.random.shuffle(positions)
    board = np.copy(filled_board)
    for x, y in tqdm(positions):
        temp = board[x][y]
        board[x][y] = 0
        if dfs.test_unique(np.copy(board)):
            continue
        else:
            board[x][y] = temp
    return board
Exemplo n.º 5
0
def test_code_to_board():
    code = 3
    with pytest.raises(util.InvalidBoardException) as err:
        util.code_to_board(code)
    assert f'Board code must be a string, got type {type(3)}' in str(err.value)
    code = '33'
    with pytest.raises(util.InvalidBoardException) as err:
        util.code_to_board(code)
    assert 'Board code must be 81 characters long' in str(err.value)
    code = 'a' * 81
    with pytest.raises(util.InvalidBoardException) as err:
        util.code_to_board(code)
    assert 'Board code must only contain numbers 0 - 9' in str(err.value)

    code = '000304907830000000000600000050080000006250030000000806009000400000000001000023000'
    board = util.code_to_board(code)
    for i in range(9 * 9):
        x = util.to_x(i)
        y = util.to_y(i)
        # remember we transpose the board
        assert board[y][x] == int(code[i])
Exemplo n.º 6
0
def test_coordinate_conversions():
    for i in range(200):
        assert util.to_x(i) == i % 9
        assert util.to_y(i) == i // 9