Introduction

By now, Sudoku does not need any introduction. The addictive number puzzle appears daily in newspapers on six continents (what is up with the Antarctic???), and has spawned magazines, books, electronic games, web sites, and some excellent submissions on CodeProject. My goal for this (my first) submission was twofold. First, to create software which would help my wife and son get through some of the fiendish Sudokus in a way that would make them better puzzle solvers. Second, to show use of a couple of Boost libraries which some CodeProject readers may not have used before.

Solving Sudokus

There are a variety of ways to solve Sudoku puzzles, but they fall into two categories: the way a computer might solve them, and the way a human might solve them. For computers, there is an excellent CodeProject article on using the Dancing Links algorithm to solve Sudoku. For my purposes, I need the computer to solve the puzzle like a human. My primary references for algorithms can be found in the Acknowledgements section.

Installing Boost

I used Boost library version 1.33.1 for this development. I followed the instructions provided on the Boost web site, with one exception. After downloading the Boost source, I then downloaded a pre-built bjam, which was a mistake. I was unable to build the Boost libraries. However, once I built bjam from the source I had already downloaded, the build process went smoothly.

Using Boost::Multi_Index_Container

A Sudoku puzzle is a grid of 9x9 cells. To solve the puzzle, you need to look at the cells as a row, a column, and as a block of 3x3 cells. To achieve this, I used the boost::multi_index_container.

First, I have a class which represents one of the 81 cells. Note that when the cell is created, it is passed its number. It uses that to compute its row, column, and block number.

I then have a class called CellCollection which contains a boost::multi_index_container. I have an index for each of the four ways I want to access the cells: by cell number, by row, by column, or by block.

Note that the index for getting a cell number is unique since each cell has its own number. And the indices for row/column/block access are non-unique since there are 9 cells per given subset. The indices are initialized in the constructor:

Using Boost::Lambda and Boost::Lambda::Bind

Boost::lambda and boost::lambda::bind make it easy to iterate through a container to perform functions. For example, to get the number of cells which hold a determined answer, we have a helper function:

The most fundamental algorithm is to eliminate digits which have already been used from the other cells in a group (row, column, or block). Boost::lambda and boost::lambda::bind help keep the code concise:

I also use boost::dynamic_bitset to keep track of possible digits, but I could just as easily use std::bitset as the size is known and does not change. I use boost::assign because I think it’s cool to add an element to a vector using +=. But I don’t take advantage of that library’s ability to add multiple elements in a single comma-delimited statement.

Algorithms Used

This program makes use of the following algorithms:

Simple – Eliminate already-used digits from the same row, column, or block.

Island – If a digit is limited to one cell in a row, column, or block, the cell must contain that digit.

Pile Exclusion – If a group of N digits are possible in N cells, all other digits can be removed from those N squares.

Chain Exclusion – If N cells can contain only N digits, those N digits are limited to those N cells. They can be removed from other cells.

Box Line Reduction - If a digit in a row or column is restricted to one block, that digit can be eliminated from other rows/columns in that block.

Pointing Pairs – This algorithm works on 3x3 blocks. If, in a given block, the only possible locations for a given digit are confined to a single row or column, that digit can not appear in that column for either of the neighboring blocks. Two blocks with this characteristic will limit the neighboring block to one row or column for that digit.

Contradiction of Tautology – This algorithm does not run unless other algorithms have failed to yield a result. For cells which have only two possible digits, one of them is chosen as a guess and the algorithms run to see the implications of the guess. If either of the guesses results in a contradiction (a cell which has 0 possible digits), we know the other option is correct. If neither guess produces a contradiction, but results in some other cell yielding the same answer in both cases, that answer must be correct.

Using the Program

Puzzles can be input in three ways:

Type them in, bracketed with the File->Type In Puzzle menu item so the program knows when you are done.

Open a Sudoku file. Most formats are supported.

Drag and drop a Sudoku file onto the main window.

When a puzzle is input, the program will perform the simplest algorithm (eliminating digits which are already contained in the same row/column/block), and identify (in a lovely pea-soup green) which squares are immediately solvable. For any square, you can:

Type in a guess.

Right click and see the history of that cell. This shows you what algorithm ran each time the possible digits got further reduced.

Right click and show the answer for that cell (if the answer has been determined).

There are two modes in which to run, which are useful for learning to solve Sudoku puzzles.

Single Step Mode

Enter a puzzle.

Press the button to display the possible digits for each cell.

Press the Single Step button. Each time you press it, the program will run through a row, column, or block-based algorithm until a cell has changed (its possible digits has changed). You can then see what changed and why.

Answer Step Mode

Enter a puzzle.

Press the Solve Cell Step button. The program will run until at least one cell has been deduced. That cell will be highlighted. You now know that the cell can be logically deduced.

Using the Code

The training logic is in the Engine subdirectory. The puzzle is defined by calls to SetAnswer. Single steps or steps until a cell is discovered are made with this call:

History

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

I live in Minnesota with my wife and son, having moved here from Montana. I enjoy creating software which benefits people, and I am fortunate to have a job where I am able to do that.
I enjoy reading, hunting and fishing, any sport with a racquet or paddle, and rooting for the New England Patriots.
In addition to my full-time job, I founded Rohawk, LLC which creates software for Christian churches.

Boost is a heavily templatized library. The "<>" syntax is how you specify types in a template. If you google "C++ templates" you will find lots of information to give you more details. Templates are very powerful and if used well can significantly reduce code size in many instances. Further, what would be run-time error in non-templatized code can become a run-time error with templates (which forces/causes earlier bug detection and fixing). One downside is that compiler errors with templates are often obscure.