diff --git a/.DS_Store b/.DS_Store index 5008ddf..fe6196d 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/README.md b/README.md index c465ef7..5e0a3a4 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,181 @@ -# Sudoku Solver (Prolog) +# INTRODUCTION -Run by using the command +A **Latin square** of order _n_ is an _n × n_ array in which each cell contains a single symbol - problem(1,Rows), sudoku(Rows), maplist(portray_clause, Rows). +from a set _S_ with _n_ elements, such that each symbol occurs exactly once in each row + +and exactly once in each column. + +_Example:_ + +![](sudoku-screenshots/latin.png) +a Latin square of order 3 + +A **Sudoku Latin square** is a Latin square of order 9 on the symbol set {1,..., 9} that + +is partitioned into 3 _×_ 3 squares, and each square contains all symbols. +![](sudoku-screenshots/1.png) + +This can also be represented as +![](sudoku-screenshots/2.png) + +This can be further represented as a list of variables: +![](sudoku-screenshots/3.png) + +And we represent the whole sudoku latin square as a list of lists. +![](sudoku-screenshots/4.png) + +So, in total, we have a list of rows. -More problems- +# CLP(FD) CONSTRAINTS - puzzle(1, [[_,4,_,9,_,_,_,5,_], - [2,_,_,_,_,_,_,4,_], - [1,9,_,_,8,_,7,_,_], - [5,_,_,_,_,_,1,_,_], - [_,_,7,_,6,_,_,_,3], - [_,_,_,_,3,_,8,9,_], - [_,8,_,3,4,_,_,6,_], - [3,_,_,2,_,8,_,_,_], - [_,_,_,_,_,_,_,_,_]]). +The library clpfd or Constraint Logic Programming over Finite Domains contains a lot - puzzle(2, [[_,_,9,5,_,_,_,3,7], - [1,3,7,9,_,_,_,5,2], - [2,_,_,_,_,3,6,9,_], - [3,5,2,_,1,_,_,_,6], - [_,_,_,4,5,2,3,_,_], - [_,8,1,_,3,_,2,_,_], - [6,_,3,_,4,_,8,_,9], - [5,2,_,_,_,1,_,6,_], - [_,_,_,3,_,7,_,_,_]]). +of built-in predicates that are useful for solving the Sudoku puzzle easily. - puzzle(3, [[_,5,_,1,_,_,_,_,_], - [2,_,_,5,_,_,6,_,_], - [1,_,_,_,8,_,2,_,_], - [_,8,_,4,3,_,_,_,_], - [_,_,_,_,_,_,_,4,_], - [_,_,_,_,_,7,9,3,2], - [_,4,_,6,7,_,_,_,_], - [_,7,_,_,_,_,_,1,9], - [9,_,_,_,_,8,_,_,_]]). +**(ins)/2** states the domains of variables + + in some systems: fd_domain/3, domain/ + +**all_distinct/** + + or alternatively: all_different/1, fd_all_different. + + describes a list of different integers + +_Examples_ : +![](sudoku-screenshots/s1.png) + +Constraint Propagation: +![](sudoku-screenshots/s2.png) + +# CONSISTENCY TECHNIQUES + +**all_distinct/1** uses powerful methods from graph theory to prune the search space: + +Using the previous example, the following graph states that X can be either 1 or 2, Y + +can be either 1 or 2 and Z can be either 1, 2 or 3. +![](sudoku-screenshots/g1.png) + +This is a value graph for a set of constraints. + +Prolog automatically reasons about this value graph to detect whether there can still + +be a solution and also to find out which assignment can not occur in a solution. +![](sudoku-screenshots/g2.png) ![](sudoku-screenshots/g3.png) + +# PROGRAM + +``` +:- use_module(library(clpfd)). % Including clpfd library. + +% Defining a sudoku latin square: + +sudoku (Rows) :- + + % Rows must be a list of length 9. + length (Rows, 9), + + %Each of the rows must also be a list of 9. + maplist(same_length(Rows), Rows), + + % The concatenation of all elements of this list is the list Vs. + append(Rows, Vs), + Vs ins 1..9, + + % We can define the all the elements of each of the rows + % must be purely distinct. + % We can do the following: + % Rows = [Rs1|_], all_distinct(Rs1), + % Rows = [_,Rs2|_], all_distinct(Rs2), + % ... + % But there is a simpler way to do this. + + maplist(all_distinct, Rows), + % This states that all_distinct must hold for each of the rows. + + % Doing the same with columns. + transpose(Rows, Columns), + maplist(all_distinct, Columns), + + % Defining the sub-squares. + Rows = [As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is], + square(As, Bs, Cs), + square(Ds, Es, Fs), + square(Gs, Hs, Is). + +square([], [], []). % This predicate uses 3 rows. + +square([N1,N2,N3|Ns1], + [N4,N5,N6|Ns2], + [N7,N8,N9|Ns3]) :- + all_distinct([N1,N2,N3,N4,N5,N6,N7,N8,N9]), + square(Ns1, Ns2, Ns3). + + +% Defining different problems. + +problem(1, [[_,_,_,_,_,4,_,_,2], + [_,6,_,2,_,_,_,3,_], + [_,8,_,_,_,3,5,_,9], + [_,4,_,_,_,_,1,_,_], + [1,_,_,7,_,5,_,_,_], + [5,_,3,_,_,_,_,_,_], + [_,9,_,3,_,_,_,_,_], + [_,_,4,_,6,1,_,_,_], + [_,_,5,_,_,_,7,_,_]]). + +problem(2, [[_,_,9,5,_,_,_,3,7], + [1,3,7,9,_,_,_,5,2], + [2,_,_,_,_,3,6,9,_], + [3,5,2,_,1,_,_,_,6], + [_,_,_,4,5,2,3,_,_], + [_,8,1,_,3,_,2,_,_], + [6,_,3,_,4,_,8,_,9], + [5,2,_,_,_,1,_,6,_], + [_,_,_,3,_,7,_,_,_]]). + +problem(3, [[_,5,_,1,_,_,_,_,_], + [2,_,_,5,_,_,6,_,_], + [1,_,_,_,8,_,2,_,_], + [_,8,_,4,3,_,_,_,_], + [_,_,_,_,_,_,_,4,_], + [_,_,_,_,_,7,9,3,2], + [_,4,_,6,7,_,_,_,_], + [_,7,_,_,_,_,_,1,9], + [9,_,_,_,_,8,_,_,_]]). +``` + +# SOLUTION + +We can get the solution using the following queries: +``` +problem(1,Rows), sudoku(Rows), maplist(portray_clause, Rows). +``` +![](sudoku-screenshots/p1.png) +``` +problem(2,Rows), sudoku(Rows), maplist(portray_clause, Rows). +``` +![](sudoku-screenshots/p2.png) +``` +problem(3,Rows), sudoku(Rows), maplist(portray_clause, Rows). +``` + +# ANOTHER EXAMPLE + +Following is the step by step method of how prolog solves the Sudoku puzzle using +intelligent constraint propagation. +![](sudoku-screenshots/01.png) ![](sudoku-screenshots/02.png) +![](sudoku-screenshots/03.png) ![](sudoku-screenshots/04.png) +![](sudoku-screenshots/05.png) ![](sudoku-screenshots/06.png) + +Inconsistent values are indicated by small dots. Black dots represent “obvious” +propagation, whereas, blue dots represent “intelligent” propagation. +![](sudoku-screenshots/07.png) ![](sudoku-screenshots/08.png) + +# REFERENCES + +- https://metalevel.at/sudoku +- https://www.swi-prolog.org/man/clpfd.html \ No newline at end of file diff --git a/db.pl b/db.pl index 1b5dc36..4c4f088 100644 --- a/db.pl +++ b/db.pl @@ -15,7 +15,9 @@ sudoku(Rows) :- square(Gs, Hs, Is). square([], [], []). -square([N1,N2,N3|Ns1], [N4,N5,N6|Ns2], [N7,N8,N9|Ns3]) :- +square([N1,N2,N3|Ns1], + [N4,N5,N6|Ns2], + [N7,N8,N9|Ns3]) :- all_distinct([N1,N2,N3,N4,N5,N6,N7,N8,N9]), square(Ns1, Ns2, Ns3). @@ -27,4 +29,24 @@ problem(1, [[_,_,_,_,_,4,_,_,2], [5,_,3,_,_,_,_,_,_], [_,9,_,3,_,_,_,_,_], [_,_,4,_,6,1,_,_,_], - [_,_,5,_,_,_,7,_,_]]). \ No newline at end of file + [_,_,5,_,_,_,7,_,_]]). + +problem(2, [[_,_,9,5,_,_,_,3,7], + [1,3,7,9,_,_,_,5,2], + [2,_,_,_,_,3,6,9,_], + [3,5,2,_,1,_,_,_,6], + [_,_,_,4,5,2,3,_,_], + [_,8,1,_,3,_,2,_,_], + [6,_,3,_,4,_,8,_,9], + [5,2,_,_,_,1,_,6,_], + [_,_,_,3,_,7,_,_,_]]). + +problem(3, [[_,5,_,1,_,_,_,_,_], + [2,_,_,5,_,_,6,_,_], + [1,_,_,_,8,_,2,_,_], + [_,8,_,4,3,_,_,_,_], + [_,_,_,_,_,_,_,4,_], + [_,_,_,_,_,7,9,3,2], + [_,4,_,6,7,_,_,_,_], + [_,7,_,_,_,_,_,1,9], + [9,_,_,_,_,8,_,_,_]]). \ No newline at end of file diff --git a/sudoku-screenshots/01.png b/sudoku-screenshots/01.png new file mode 100644 index 0000000..b0d250e Binary files /dev/null and b/sudoku-screenshots/01.png differ diff --git a/sudoku-screenshots/02.png b/sudoku-screenshots/02.png new file mode 100644 index 0000000..2aaee74 Binary files /dev/null and b/sudoku-screenshots/02.png differ diff --git a/sudoku-screenshots/03.png b/sudoku-screenshots/03.png new file mode 100644 index 0000000..b33b119 Binary files /dev/null and b/sudoku-screenshots/03.png differ diff --git a/sudoku-screenshots/04.png b/sudoku-screenshots/04.png new file mode 100644 index 0000000..4b247b9 Binary files /dev/null and b/sudoku-screenshots/04.png differ diff --git a/sudoku-screenshots/05.png b/sudoku-screenshots/05.png new file mode 100644 index 0000000..ecc73fa Binary files /dev/null and b/sudoku-screenshots/05.png differ diff --git a/sudoku-screenshots/06.png b/sudoku-screenshots/06.png new file mode 100644 index 0000000..3db8e95 Binary files /dev/null and b/sudoku-screenshots/06.png differ diff --git a/sudoku-screenshots/07.png b/sudoku-screenshots/07.png new file mode 100644 index 0000000..7321c87 Binary files /dev/null and b/sudoku-screenshots/07.png differ diff --git a/sudoku-screenshots/08.png b/sudoku-screenshots/08.png new file mode 100644 index 0000000..5056532 Binary files /dev/null and b/sudoku-screenshots/08.png differ diff --git a/sudoku-screenshots/1.png b/sudoku-screenshots/1.png new file mode 100644 index 0000000..525e8c7 Binary files /dev/null and b/sudoku-screenshots/1.png differ diff --git a/sudoku-screenshots/2.png b/sudoku-screenshots/2.png new file mode 100644 index 0000000..edbe9ae Binary files /dev/null and b/sudoku-screenshots/2.png differ diff --git a/sudoku-screenshots/3.png b/sudoku-screenshots/3.png new file mode 100644 index 0000000..4b16017 Binary files /dev/null and b/sudoku-screenshots/3.png differ diff --git a/sudoku-screenshots/4.png b/sudoku-screenshots/4.png new file mode 100644 index 0000000..1e486ec Binary files /dev/null and b/sudoku-screenshots/4.png differ diff --git a/sudoku-screenshots/g1.png b/sudoku-screenshots/g1.png new file mode 100644 index 0000000..762fa8a Binary files /dev/null and b/sudoku-screenshots/g1.png differ diff --git a/sudoku-screenshots/g2.png b/sudoku-screenshots/g2.png new file mode 100644 index 0000000..81f8ae7 Binary files /dev/null and b/sudoku-screenshots/g2.png differ diff --git a/sudoku-screenshots/g3.png b/sudoku-screenshots/g3.png new file mode 100644 index 0000000..d866777 Binary files /dev/null and b/sudoku-screenshots/g3.png differ diff --git a/sudoku-screenshots/latin.png b/sudoku-screenshots/latin.png new file mode 100644 index 0000000..bdec4a3 Binary files /dev/null and b/sudoku-screenshots/latin.png differ diff --git a/sudoku-screenshots/p1.png b/sudoku-screenshots/p1.png new file mode 100644 index 0000000..5aaea1f Binary files /dev/null and b/sudoku-screenshots/p1.png differ diff --git a/sudoku-screenshots/p2.png b/sudoku-screenshots/p2.png new file mode 100644 index 0000000..bf9bbbf Binary files /dev/null and b/sudoku-screenshots/p2.png differ diff --git a/sudoku-screenshots/s1.png b/sudoku-screenshots/s1.png new file mode 100644 index 0000000..bd6eedf Binary files /dev/null and b/sudoku-screenshots/s1.png differ diff --git a/sudoku-screenshots/s2.png b/sudoku-screenshots/s2.png new file mode 100644 index 0000000..44af267 Binary files /dev/null and b/sudoku-screenshots/s2.png differ