I am reviewing these days all kind of algorithms: trees, hash table, skip lists… To help refreshing my memory I am watching lectures of the MIT university about all this stuff, you can follow this link. The classes are really good, and they explain in depth the basic theory of algorithms.
Anyway, I am checking as well the problem of resolving sudokus. I saw some implementations in Erlang that are really good, but I thought I could do one myself. To make this clear I am not looking for efficiency here, actually this algorithm is slow and really really take a hell lot of memory.
So, I did it just for fun and to play a little bit with Erlang, language that I use to work with. The code itself is really simple, and only take a few lines of code (just around 35 without the pretty printer), because of that is very easy to read. You can test it like that:
81> sudoku:solve(
81> [
81> [9, 5, b, b, b, 6, 4, 7, b],
81> [4, b, 8, 7, b, 2, b, b, b],
81> [6, 2, b, 4, b, b, b, 5, b],
81> [5, b, 2, b, 6, b, 3, b, b],
81> [b, b, b, 2, b, 7, b, b, b],
81> [b, b, 4, b, 1, b, 2, b, 8],
81> [b, 7, b, b, b, 9, b, 3, 4],
81> [b, b, b, 1, b, 3, 7, b, 5],
81> [b, 4, 3, 5, b, b, b, 2, 9]
81> ]).
9 5 1 8 3 6 4 7 2
4 3 8 7 5 2 9 6 1
6 2 7 4 9 1 8 5 3
5 8 2 9 6 4 3 1 7
3 1 9 2 8 7 5 4 6
7 6 4 3 1 5 2 9 8
8 7 5 6 2 9 1 3 4
2 9 6 1 4 3 7 8 5
1 4 3 5 7 8 6 2 9
ok
And here it is, coments are welcome, enjoy!
%%%-------------------------------------------------------------------
%%% File : sudoku.erl
%%% Author : alfonso
%%% Description :
%%%
%%% Created : 12 Sep 2009
%%%-------------------------------------------------------------------
-module(sudoku).
-export([solve/1]).
solve(Matrix)->
%% format matrix
KeyMatrix = lists:zip([ {X,Y} || X<-lists:seq(1,9), Y<-lists:seq(1,9) ], lists:flatten(Matrix)),
solve_r([KeyMatrix]).
solve_r([Matrix | Acc]) ->
%% calculate the b element with the least b's
case lists:keysort(2,[{Point,get_bs(Matrix,E)}|| {Point,b} = E<- Matrix]) of
[] ->
%% got the solution!
print(Matrix);
[{Pivot,_} = E| _] ->
%% calculate intersection of candidates
Candidates = lists:seq(1,9) -- get_array(Matrix, E),
%% create Matrix for each one and call recursive ...
MatrixCandidates = [ [ {Pivot, Candidate} | lists:keydelete(Pivot, 1, Matrix)] ||
Candidate <- Candidates ],
solve_r(MatrixCandidates++Acc)
end.
get_array(Matrix, {{X,Y}, _}) ->
get_row(Matrix, {X,Y}) ++ get_column(Matrix, {X,Y}) ++ get_submatrix(Matrix, {X,Y}).
get_bs(Matrix, Element) ->
length( [ b || b <- get_array(Matrix,Element)]).
get_row( Matrix, {Row,_C} ) ->
[X || {{R,_},X} <- Matrix, R==Row].
get_column( Matrix, {_,Column})->
[X || {{_,C},X} <- Matrix, C == Column].
get_submatrix(Matrix, {X,Y})->
NX = ( (X-1) div 3)*3 + 1,
NY = ( (Y-1) div 3)*3 + 1,
[E || {{R,C},E} <- Matrix, (R - NX < 3), (C - NY <3), (R - NX >= 0), (C - NY >= 0) ].
print(Matrix) ->
io:format("~n",[]),
print2( lists:keysort(1,Matrix),1).
print2([{_,A}|R],N) when N == 9->
io:format(" ~p ~n",[A]),
print2(R,1);
print2([{_,A}|R],N)->
io:format(" ~p ",[A]),
print2(R,N+1);
print2([],_) ->ok.