Published on: Download DLXSudokuSolver Source Code
Dancing Links is an algorithm introduced by the brilliant American computer scientist Donald Knuth. This technique is well known for efficiently solving Sudoku grids and assessing their validity — including detecting unsolvable puzzles or those with multiple solutions.
The first version of the application was based on the Sudoku solver ZeroDlx written by Jim Schirle. The code was updated to be used as a C++ class and modified to use the Hungarian notation. The new release V2.0 was thouroughly re-written to use STL (ISO C++ 20) and to allow the display of the progress of the solving algorithm.
The application is based on the MFC (Microsoft Foundation Classes) framework. I know that many people find MFC programming complex and quite outdated. But, since I don't bother writing software for other operating systems than Windows, I've kept this technology for all my programming projects. Since the Visual Studio compiler supports the latest ISO C++ 20 standard, STL is widely used as a replacement for classic C++ methods. In addition, Hungarian notation, introduced at Microsoft by Charles Simonyi, is systematically used to name program variables. Again, many programmers deny the use of this naming convention. But, once again, I don't worry about it. Charles Simonyi is one of the best software designers, and I have personally found Hungarian notation extremely useful in software development.
This naming convention is quite classic and stems from my very first experience of C programmming the OS/2 API of Microsoft/IBM in the late eighties
Variable Type | Starting Char. | Example |
---|---|---|
bool | b | Class Member: m_bCovered Class Constant: c_bActive |
integer | n | Class Member: m_nLength Class Constant: c_nMaxCount |
long | l | Class Member: m_lData Function Local Var.: lLength |
unsigned long | ul | Class Member: m_ulData |
float | f | Class Member: m_fRadius |
double | d | Class Constant: m_dPi |
std::wstring | wstr | Global variable: g_wstrUserName Function Local var.: wstrName |
std::vector | vctr | Class member: m_vctrSolution Function Local var.: vctrData |
array | a | Class Array of integer: m_anMaxValue Function Local var.: anData |
pointer | p | Class Pointer to integer: m_pnValue< br>Global Pointer to array of long: g_palDataNdx |
Color | rgb | Function Local var.: rgbBkg Class member array of color: m_argbTextColor |
static constexpr COLORREF c_rgbCandidate = RGB(51, 153, 255);
The application is written in C++ using the Microsoft IDE Visual Studio Community Edition 2022.
The configuration is quite standard for a 64-bits application:
The application is made of the following classes:
CWinApp
): the main MFC application class that handles initialization, execution, and termination of the DLXSudokuSolver application.CDialogEx
): DLXSudokuSolver is a simple dialog-based application. This class manages user interaction and updates the graphical interface.CDLXSolver
.DLXNode
, used for column tracking in the Dancing Links structure.CButton
) used to graphically display the Sudoku board.CDialogEx
) that displays the “About” box of the application.namespace
providing internal tracing tools for monitoring and debugging the execution flow.Note: the namespace DebugTrace is heavily used in DLXSodukuSolver and provides several macros (DBG_LOG, DBG_TMB, DBG_TME, ..) to trace the execution of the application. Complete explanations about this namespace is available in the C++ Section.
When the user click on the 'Solve' button, the function CDLXSudokuSolverDlg::OnSolve()
is called by the MFC framework.
The main actions are:
// Build and Initialize Solver Instance
m_pDLXSolver = new CDLXSolver(this->GetSafeHwnd(), static_cast(str), GetDelay(), nSolverMode);
// Update Board with Initial Sudoku Data
m_ButtonDLXBoard.DrawBoard(m_pDLXSolver->m_nGroupSize, m_pDLXSolver->m_vctrSudoku);
// Start Dancing Links Solver
m_pDLXSolver->StartSolver();
The parameters of the Solver constructor are the following:
The Sudoku grid (second parameter) is passed as a std::wstring
. This string is then converted in a vector of std::pair
named m_vctrSudoku
in the function CDLXSolver::ConvertStringToVector()
This vector m_vctrSudoku is used to:
The function CDLXSolver::StartSolver()
simply starts the solver in a thread:
// Start Thread to Solve Sudoku
m_thread = std::thread(&CDLXSolver::Solve, this);
At that time, the actual solving process starts:
CDLXSolver::Solve()
first initializes the working vector named m_vctrSolution
and checks if the grid is solvable. If not, it exists and ends the solving process...
CDLXSolver::Search
is then called. During the processing, the function will be called recursively up to the end of the solving process.
CDLXSolver::GetDLXSolution()
is then called to convert the working vector m_vctrSolution
to the vector m_vctrSudoku
used to display the board graphically.
Visually, the recursion process can be illustrated by using the macro DBG_IND_LOG
with the parameters DBG_INCR
and DBG_DECR
at the entry and the exit points of the function CDLXSolver::Search
. Complete explanations about this namespace is available in the C++ Section.
Note that non-valid Sudoku grids can generate more than one solution. These grids are not useable for human resolution but are stored for further display (if requested by the user) in the vector m_vctrSolutions
. Note the s at the end of the vector name as it is used to store a potential array of strings (declared as CDLXSolver
include file.