Skip to content

Instantly share code, notes, and snippets.

@kevinkjt2000
Created November 10, 2018 05:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevinkjt2000/52bdcb7abcdfcce77c06efa726f15f58 to your computer and use it in GitHub Desktop.
Save kevinkjt2000/52bdcb7abcdfcce77c06efa726f15f58 to your computer and use it in GitHub Desktop.
Generic size sudoku solver written in Prolog
:- use_module(library(clpfd)).
% Use the test_foo functions below to run this sudoku solver
% The answer to day 3 is much cleaner in the SWI-Prolog documentation
% http://www.swi-prolog.org/pldoc/doc_for?object=transpose/2
% I took the solution from the documentation and adapted it to
% allow generic block and grid sizes
sudoku((Height,Width), (BlockHeight,BlockWidth), Puzzle) :-
% verify the Puzzle is square
Height = Width,
% Width = BlockHeight * BlockWidth,
% verify the Height and Width are correct
length(Rows, Height),
maplist(flip(length, Width), Rows),
% pull the Rows from Puzzle
append(Rows, Puzzle),
% verify all numbers are in the range [1,Height]
Puzzle ins 1..Height,
% each row of the puzzle needs all the numbers 1..Height exactly once
maplist(all_distinct, Rows),
% transpose of the puzzle yields the columns which also need 1..Height
transpose(Rows, Columns),
maplist(all_distinct, Columns),
% lastly the blocks need all the numbers 1..Height
chunks(BlockHeight, Rows, RowChunks),
maplist(blocks((BlockHeight, BlockWidth)), RowChunks),
maplist(writeln, Rows).
flip(Fun, X, Y) :- call(Fun, Y, X).
length_(L, Ls) :- length(Ls, L).
chunks(_, [], []).
chunks(N, [X|Xs], [Chunk|Chunks]) :-
split(N, [X|Xs], Chunk, Leftover),
chunks(N, Leftover, Chunks).
split(N, Xs, Left, Right) :- N =< 0, !, N =:= 0, Left = [], Right = Xs.
split(_, [], [], []).
split(N, [X|Xs], [X|Ys], Right) :- M is N-1, split(M, Xs, Ys, Right).
map(_Fun, [], []).
map(Fun, [H|T], [HO|TO]) :-
call(Fun, H, HO),
map(Fun, T, TO).
blocks((_, Width), RowChunk) :-
map(chunks(Width), RowChunk, ColChunks),
transpose(ColChunks, Almost),
map(append, Almost, Blocks),
maplist(all_distinct, Blocks).
%blocks([], [], []).
%blocks([A,B,C|T1], [D,E,F|T2], [G,H,I|T3]) :-
% all_distinct([A,B,C,D,E,F,G,H,I]),
% blocks(T1, T2, T3).
% I took this test case from the SWI prolog transpose/2 doc page
% http://www.swi-prolog.org/pldoc/doc_for?object=transpose/2
test_9x9_unique :-
Puzzle = [_,_,_,_,_,_,_,_,_,
_,_,_,_,_,3,_,8,5,
_,_,1,_,2,_,_,_,_,
_,_,_,5,_,7,_,_,_,
_,_,4,_,_,_,1,_,_,
_,9,_,_,_,_,_,_,_,
5,_,_,_,_,_,_,7,3,
_,_,2,_,1,_,_,_,_,
_,_,_,_,4,_,_,_,9],
sudoku((9,9), (3,3), Puzzle).
test_6x6_no_solution :-
Puzzle = [1,_,_,_,_,_,
_,_,_,_,2,_,
_,3,_,_,_,_,
_,_,4,4,_,_,
_,_,4,4,1,_,
_,_,4,4,_,_],
sudoku((6,6), (3,2), Puzzle).
test_6x6_unique :-
Puzzle = [1,2,3,4,5,6,
4,5,6,1,2,3,
_,3,_,_,_,_,
5,_,4,_,_,_,
_,_,2,6,4,5,
_,_,5,3,1,2],
sudoku((6,6), (2,3), Puzzle).
test_16x16_unique :-
Puzzle = [
2,14,12, _, _, _, 1, 7, _, _, 8, 9,15, _, _, _,
8, _, _, _, _, 2, 6, _,14, 5, _, _, _, _, 3,16,
4, 6, _, _,14,11, _, 3, _, _,13, 7, _, _, 8, _,
_, 3, _, _, 9, 8, _,13,15,11, 1, _, 6,14, _, _,
1,10,14, _, 5, 4, _, 6, _, _, _,11, _, 7, _,15,
_,16, 4, _, 2, _, _,10, 1, _, _, _, 9, _,11,13,
_, _, _, 5,13, _, 7, _, _, 4, 3,14, _, _, 1, _,
_, _, _, _, _, _, _, _, _, _,16, _, _, 4, _, _,
_, _,11, 8, 7,12, 5, 1, _, _,14, 2, _,10, _, _,
6, _, 1, _, _, _, 2, _,16, _,12, _, 4,15, _, _,
15, _, 7,12,11,13,14, _, _, _, 4, 6, _, 8, _, 3,
_, _, _, _, _,10, _, _, _, 3, _, 5, _, 9,12, 1,
_, _, 2,11, _, 6, _, _, _, 9, _, _, _, _, _, 4,
5,13, _, _,15, 1,16, 9, _, _, 6, _,11, _, 7, 2,
7, 8, _, _, _, _,12, _, _, _, _, _, _,13,15,14,
_, _, _,15,10, _, _, _, _, _, 2, _, _, _, 9, _],
sudoku((16,16), (4,4), Puzzle).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment