potatochick2020 / Sudoku-core

A C++ library for generating, validating, solving, checking, etc Sudoku puzzle.
MIT License
9 stars 3 forks source link
hacktoberfest hacktoberfest2022

Sudoku-Core

A C++ library for generating, validating, solving, checking, etc Sudoku puzzle.

Time

From 23 November 2022 to Jan 10 2023, Around 18 hours in Total Alt text

What I learn ?

My first object-oriented programming project using the C++ programming language. This project introduces me to basic concepts of threading, providing me with my first experience working with a slightly larger codebase.

First time

Area of improvement

How to improve in next project

Further stuff to learn

Installation

Build the project:

mkdir build
cd build
cmake ..
make
//run the generator brenchmark
./sudokugenerator
//run the test
sudokugenerator_test

Rebuild the project

cd build
make clean
make

Algorithm to generate a sudoku

This algorithm is referenced and further improved from 101 computing, which the original implementation does not guarantee the sudoku had only 1 unique solution.

bool Sudoku::GenerateSudoku()
generate a sudoku board with all number filled. The board will be a completed board without any blank to filled.

bool Sudoku::GenerateSudoku()
{
    vector<int> numbers(9);

    while (isComplete() == false)
    {
        for (int row = 0; row < 9; row++)
        {

            for (int col = 0; col < 9; col++)
            {

                if (board[row][col] == 0)
                {
                    // fills out the numbers vector with numbers from 1 -> numbers.size()
                    iota(begin(numbers), end(numbers), 1);
                    SHUFFLE(numbers);
                    for (int number : numbers)
                    {
                        if (isPlacable(row, col, number)) // if it is valid to place a number at the location.
                        { 
                            board[row][col] = number;
                            if (Sudoku::GenerateSudoku())
                             //recursion function to call itself and place further number
                                return true;
                            board[row][col] = 0;
                        }
                    }
                    return false;
                }
            }
        }
    }
    return true;
}

int Sudoku::SudokuSolution() return the number of unique solution that this sudoku board has as an int.

int Sudoku::SudokuSolution()
{
    int ans = 0;
    vector<int> numbers(9);

    // fills out the numbers vector with numbers from 1 -> numbers.size()
    iota(begin(numbers), end(numbers), 1);
    for (int row = 0; row < 9; row++)
    {

        for (int col = 0; col < 9; col++)
        {
            if (board[row][col] == 0)
            {
                for (int number : numbers)
                {
                    if (isPlacable(row, col, number)) // if it is valid to place a number at the location.
                    {
                        board[row][col] = number;

                        if (isCorrect())
                            ans++;
                        else
                            //recursion function to call itself and place further number
                            ans += Sudoku::SudokuSolution();

                        board[row][col] = 0;
                    }
                }
                //return number of solutions that this sudoku has
                return ans;
            }
        }
    }
    return 0;
}

void Sudoku::initialize(int difficulty)

void Sudoku::initialize(int difficulty)
{
    GenerateSudoku();
    vector<int> rowsCandidates = CANDIDATE_ARRAY;
    SHUFFLE(rowsCandidates);
    vector<int> colsCandidates = CANDIDATE_ARRAY;
    SHUFFLE(colsCandidates);
    pair<pair<int, int>, int> backup = {{rowsCandidates[0], colsCandidates[0]}, board[rowsCandidates[0]][colsCandidates[0]]};
    //backup store the value of the next attemp 
    board[rowsCandidates[0]][colsCandidates[0]] = 0;

    int attempt = 0;
    // with the more higher difficulty, the algorithm will try to get away more number from the board (if the board has less number provided, it is more difficult)
    while (attempt < difficulty)
    {
        rowsCandidates = CANDIDATE_ARRAY;
        SHUFFLE(rowsCandidates);

        colsCandidates = CANDIDATE_ARRAY;
        SHUFFLE(colsCandidates);

        backup = {{rowsCandidates[0], colsCandidates[0]}, board[rowsCandidates[0]][colsCandidates[0]]};
        board[rowsCandidates[0]][colsCandidates[0]] = 0;
        if (SudokuSolution() > 1)
        {
            board[backup.first.first][backup.first.second] = backup.second;
            attempt++;
        }
    }
};

Special thanks

Speical thanks to めぐ in Leetcode Warrior community to provide help in fixing a bug when designing the algorithm of SudokuSolution() which return the number of unique solution that a sudoku board has.