% sudoku program in GNU-prolog adapted to CLPGUI by François Fages

sudoku:-
   gui_matrix(L,9,9),
   gui_show_values,
   gui_button(sudoku_example(L)),
   gui_button(sudoku_example2(L)),
   gui_button(sudoku_lines(L)),
   gui_button(sudoku_columns(L)),
   gui_button(sudoku_squares(L)),
   gui_button(sudoku_labeling(L)).

gui_matrix(L,_,N):- N<1, L=[].
gui_matrix(L,M,N):- N>=1, 
   length(L1,M),
   fd_domain(L1,1,9),
   gui_varnames(L1),
   N1 is N-1, 
   gui_matrix(K,M,N1),
   L=[L1|K].

sudoku(L):-
   sudoku_lines(L),
   sudoku_columns(L),
   sudoku_squares(L),
   write('Before labeling:\n'),
   sudoku_print(L),
   sudoku_labeling(L).
   
sudoku_labeling(L):-
   L=[L1,L2,L3,L4,L5,L6,L7,L8,L9],
   gui_trace_labeling(L1),
   gui_trace_labeling(L2),
   gui_trace_labeling(L3),
   gui_trace_labeling(L4),
   gui_trace_labeling(L5),
   gui_trace_labeling(L6),
   gui_trace_labeling(L7),
   gui_trace_labeling(L8),
   gui_trace_labeling(L9),
   sudoku_print(L).

sudoku_lines(L):-
   L=[L1,L2,L3,L4,L5,L6,L7,L8,L9],
   sudoku_list(L1),
   sudoku_list(L2),
   sudoku_list(L3),
   sudoku_list(L4),
   sudoku_list(L5),
   sudoku_list(L6),
   sudoku_list(L7),
   sudoku_list(L8),
   sudoku_list(L9).

sudoku_list(L):-
   sudoku_list2(L),
   dual_list(L,LL),        % ex: 0 var!, empty 45
   sudoku_list2(LL).

sudoku_list2(L):-
   length(L,9),
   fd_domain(L,1,9),
   fd_all_different(L).%,    % ex: 18 var, empty 48
%   sudoku_sum(L,S),        % ex: 15 var, empty 47
%   S #= 45.

dual_list(L,[LL1,LL2,LL3,LL4,LL5,LL6,LL7,LL8,LL9]):-
   fd_element_var(LL1,L,1),
   fd_element_var(LL2,L,2),
   fd_element_var(LL3,L,3),
   fd_element_var(LL4,L,4),
   fd_element_var(LL5,L,5),
   fd_element_var(LL6,L,6),
   fd_element_var(LL7,L,7),
   fd_element_var(LL8,L,8),
   fd_element_var(LL9,L,9).

sudoku_columns(L):-
   transpose(L,LL),
   sudoku_lines(LL).

sudoku_squares([L1,L2,L3,L4,L5,L6,L7,L8,L9]):-
   sudoku_3squares(L1,L2,L3),
   sudoku_3squares(L4,L5,L6),
   sudoku_3squares(L7,L8,L9).

sudoku_3squares([L11,L12,L13,L14,L15,L16,L17,L18,L19],
   [L21,L22,L23,L24,L25,L26,L27,L28,L29],
   [L31,L32,L33,L34,L35,L36,L37,L38,L39]):-
      sudoku_list([L11,L12,L13,L21,L22,L23,L31,L32,L33]),
      sudoku_list([L14,L15,L16,L24,L25,L26,L34,L35,L36]),
      sudoku_list([L17,L18,L19,L27,L28,L29,L37,L38,L39]).

sudoku_print([]):-
   nl.
sudoku_print([H|T]):-
   sudoku_print_line(H),
   sudoku_print(T).

sudoku_print_line([]):-
   nl.

sudoku_print_line([H|T]):-
   (
      generic_var(H)
   ->
      write('_ ')
   ;
      write(H),
      write(' ')
   ),
   sudoku_print_line(T).

transpose([[A]],[[A]]).
transpose([[A|H]|T],[[A|HH]|TT]):-
   set_heads(T,HH,R),
   set_heads(TT,H,RR),
   transpose(R,RR).

set_heads([],[],[]).
set_heads([[H|T]|L],[H|TT],[T|R]):-
   set_heads(L,TT,R).

sudoku_sum([],0).
sudoku_sum([H|T],V):-
   sudoku_sum(T,VV),
   V #= H+VV.

sudoku_example(L):-
   L=[
      [_,_,_,_,_,_,_,1,_],
      [4,_,_,_,_,_,_,_,_],
      [_,2,_,_,_,_,_,_,_],
      [_,_,_,_,5,_,4,_,7],
      [_,_,8,_,_,_,3,_,_],
      [_,_,1,_,9,_,_,_,_],
      [3,_,_,4,_,_,2,_,_],
      [_,5,_,1,_,_,_,_,_],
      [_,_,_,8,_,6,_,_,_]],
   sudoku_print(L).

sudoku_example2(L):-
   L=[
      [_,_,_,_,_,4,3,_,7],
      [7,6,_,1,5,_,_,_,9],
      [_,5,_,_,_,_,_,_,_],
      [6,_,5,_,_,8,7,_,_],
      [9,_,_,_,_,_,_,_,4],
      [_,_,3,2,_,_,1,_,5],
      [_,_,_,_,_,_,_,6,_],
      [5,_,_,_,3,1,_,2,8],
      [1,_,9,4,_,_,_,_,_]],
   sudoku_print(L).


