Prolog Sudoku Solver
I’ve been meaning to write this for a while. It started when I camed across this page of the shortest sudoku solvers. They all follow the basic algorithm, which is described here. I orginally thought it was a brute force algorithm, so I wanted a more elegant solution, but on closer examination it in fact uses constraints and backtracking, like a Prolog program would. Still I wanted to write one in Prolog. It turns out it’s quite simple, and here is my program:
% Sudoku Solver
%
% Author: Miles Barr
% Version: 1.0
%
% Example Usage:
%
% Board = [ [_,_,3,_,4,9,_,_,8],
% [_,1,_,5,_,_,_,3,_],
% [8,_,7,3,_,_,_,_,_],
% [_,6,8,9,_,_,_,_,5],
% [2,_,_,_,_,_,_,_,6],
% [4,_,_,_,_,6,7,1,_],
% [_,_,_,_,_,5,9,_,3],
% [_,8,_,_,_,1,_,6,_],
% [9,_,_,2,3,_,1,_,_]
% ],
% sudoku(Board),
% print_board(Board).
:- use_module(library('clp/bounds')).
:- use_module(library('lists')).
% Our general constraint is that each set of 9 (row, column or 3x3 grid) is made
% up from the numbers 1-9, and each number is not repeated.
valid(L) :- L in 1..9, all_different(L).
% Transpose function from Worksheet 16 of 'Clause and Effect'
transpose([[]|_],[]).
transpose(R,[H|C]) :- chopcol(R,H,T), transpose(T,C).
chopcol([],[],[]).
chopcol([[H|T]|R],[H|Hs],[T|Ts]) :- chopcol(R,Hs,Ts).
% Describe 3 grids in terms of 3 rows
% TODO: There must be a better way to do this.
grids([E11,E12,E13,E14,E15,E16,E17,E18,E19],
[E21,E22,E23,E24,E25,E26,E27,E28,E29],
[E31,E32,E33,E34,E35,E36,E37,E38,E39],
[E11,E12,E13,E21,E22,E23,E31,E32,E33],
[E14,E15,E16,E24,E25,E26,E34,E35,E36],
[E17,E18,E19,E27,E28,E29,E37,E38,E39]).
% Print a board
print_board([]).
print_board([H|T]) :- write(H), nl, print_board(T).
% Sudoku solving function.
%
% Input is nine lists of nine integers
sudoku(Board) :-
% Break the board down into rows
Board = [R1, R2, R3, R4, R5, R6, R7, R8, R9],
% Transpose the board to get the columns
transpose(Board, [C1, C2, C3, C4, C5, C6, C7, C8, C9]),
% Cut up the rows into 3x3 grids
grids(R1,R2,R3,G1,G2,G3),
grids(R4,R5,R6,G4,G5,G6),
grids(R7,R8,R9,G7,G8,G9),
% Each row contains unique entries
valid(R1), valid(R2), valid(R3),
valid(R4), valid(R5), valid(R6),
valid(R7), valid(R8), valid(R9),
% Each column contains unique entries
valid(C1), valid(C2), valid(C3),
valid(C4), valid(C5), valid(C6),
valid(C7), valid(C8), valid(C9),
% Each grid contains unique entries
valid(G1), valid(G2), valid(G3),
valid(G4), valid(G5), valid(G6),
valid(G7), valid(G8), valid(G9),
% Turn the board into a list of 81 variables
flatten(Board, Elements),
%sign a value to each variable
label(Elements).
I used SWI Prolog, but it should be trivial to port to other versions.
The general constraint is described by the valid clause, each list must contain all the numbers 1 through 9 exactly once. The list can represent a row, column or 3×3 grid. The next bit is breaking up the board into rows, columns and 3×3 grids, and then making sure each one is valid, which is what the sudoku clause does. That’s it really, and that’s what my first version looked like. In fact my original valid clause was:
valid(L) :- permutation([1,2,3,4,5,6,7,8,9], L).
and I didn’t constraint the values and do a labelling. That didn’t work, or it might work, but it takes a very long time. I came across this Prolog solver, which reminded me of labelling, so I removed the use of permutation, the result, a near instantaneous solver. I also borrowed his printing function.
It’s much longer than the other versions, but it has the nice property that you describe the constraints, and that’s your program, you don’t need to implement backtracking. There are still improvements to be made here, the most important one would be to add in some sort of heuristic to guide the backtracking, at the moment it’s naive and problem does more work than it needs to.
But is this the best way to solve a Sudoku puzzle? One other idea I’ve started thinking about is representing the board as a graph. We have 81 squares, each with 9 values, so we start off with 729 nodes. Each node represents a possible value for that square. Each value node for that square is connected to all the other value nodes of the squares next to it. As we discover the value of certain squares we can mark arcs to other values as illegal, and not use them in our path. Once we have a legal path through one value node for each square, we’re done. Ultimately this method requires the use of the same constraints, so it probably won’t be much better than the list based solution, but it could allow multiple walkers to discover legal row, column or grid paths in parallel, eventually joining them up. This parallelisation might lead to a faster solution. But I’ll leave the implementation and analysis to another time.

January 17th, 2007 at 1:17 pm
[…] Well today on LarryTheCow I saw a post by Miles Barr who wrote a Sudoku solver in prolog. It kinda shows how simple that kind of program can be and how generally simple Sudokus are. I never really got the fascination many people have for Sudoku; it is a great task to write a solver (the problem is easy enough to be solved by starting programmers and non-trivial enough to make writing better solutions interesting for the geeks), but after doing one or two by hand I was kinda bored by it (I have done like 5 of them on my DS in Dr. Kawashima’s Brain Training but can’t bring myself to doing more of them). Technorati Tags: prolog, LarryTheCow, Sudoku solver, Sudoku […]
January 18th, 2007 at 6:52 pm
Just try to integrate forward checking.
Implement it, that every Field has a domain of {1,2,3,4,5,6,7,8,9} and whenever
you set a Field’s value, you delay all inconsistent values from the domains of its “neighbours”
(other Fields in the row/column and 3×3block).
Sometimes considering the neighbours of the neighbours you has changed (recursiv) might be more efficient (not always)…
Using this technic you may find wrong paths very fast and direct you search more directly to the solution.
Another usefull heurstic for the Sudoku Problem to add, is selecting the field which will be selected next by the size of domain (select next Field by smallest Domainsize)…
Together with depth-first search (until you don’t have any unset Fields) you can minimize backtracking and therefore eliminate states from your search graph before you have to create them.
bye
February 14th, 2007 at 3:19 am
To the previous poster: Forward checking is done by the constraint library. Selecting the variable with smallest domain is done with labeling([ff], Vars) (available in library(bounds) in the latest SWI versions).
Here’s a shorter version:
:- use_module(library(bounds)).
suudoku(Rows) :-
Rows = [R1,R2,R3,R4,R5,R6,R7,R8,R9],
flatten(Rows, Vars),
Vars in 1..9,
rowconstraint(Rows),
columnconstraint(R1, R2, R3, R4, R5, R6, R7, R8, R9),
blockconstraint(R1, R2, R3),
blockconstraint(R4, R5, R6),
blockconstraint(R7, R8, R9),
label(Vars),
displayrows(Rows).
displayrows([]).
displayrows([[X1,X2,X3,X4,X5,X6,X7,X8,X9]|Rows]) :-
format(’~d ~d ~d ~d ~d ~d ~d ~d ~d \n’, [X1,X2,X3,X4,X5,X6,X7,X8,X9]),
display_rows(Rows).
rowconstraint([]).
rowconstraint([R|Rt]) :- alldifferent(R), rowconstraint(Rt).
columnconstraint([], [], [], [], [], [], [], [], []).
columnconstraint([X1|R1], [X2|R2], [X3|R3], [X4|R4], [X5|R5], [X6|R6],
[X7|R7], [X8|R8], [X9|R9]) :-
alldifferent([X1,X2,X3,X4,X5,X6,X7,X8,X9]),
columnconstraint(R1, R2, R3, R4, R5, R6, R7, R8, R9).
blockconstraint([], [], []).
blockconstraint([X1,X2,X3|R1], [X4,X5,X6|R2], [X7,X8,X9|R3]) :-
alldifferent([X1,X2,X3,X4,X5,X6,X7,X8,X9]),
blockconstraint(R1, R2, R3).
June 11th, 2008 at 3:51 am
Hello,
You talked about the use of FC but omitted the role of ‘labeling’ above correct?
Att
February 18th, 2009 at 5:35 pm
Hi all I really enjoy Sudoku and solving them, here is one basic looong code example. Might be some intersting coding though?!
http://vbaexcel.eu/vba-macro-code/sudoku-solver
http://vbaexcel.eu/vba-macro-code/sudoku-solver