Download
/*
Magic squares in Picat.
Model created by Hakan Kjellerstrand, hakank@gmail.com
See also my Picat page: http://www.hakank.org/picat/
*/
% Licenced under CC-BY-4.0 : http://creativecommons.org/licenses/by/4.0/
import util.
import cp.
main => go.
%
% Simple run
%
go =>
magic(6,_Square).
%
% Run for different sizes
%
% ff/updown solves N= 6 in 0.06s and 7099 backtracks
% 10 in 2.99s and 312671 backtracks
go2 =>
foreach(N in 3..10) time2(magic(N,_Square)) end.
%
% All solutions.
%
go3 =>
N = 4,
L = findall(Square,magic(N,Square)),
Len = length(L),
printf("Len: %d\n",Len).
magic(N,Square) =>
writef("\n\nN: %d\n", N),
NN = N*N,
Sum = N*(NN+1)//2,% magical sum
writef("Sum = %d\n", Sum),
Square = new_array(N,N),
Square :: 1..NN,
all_different(Square.vars()),
foreach(I in 1..N)
Sum #= sum([T : J in 1..N, T = Square[I,J]]),% rows
Sum #= sum([T : J in 1..N, T = Square[J,I]]) % column
end,
% diagonal sums
Sum #= sum([Square[I,I] : I in 1..N]),
Sum #= sum([Square[I,N-I+1] : I in 1..N]),
% Symmetry breaking
Square[1,1] #< Square[1,N],
Square[1,1] #< Square[N,N],
Square[1,1] #< Square[N,1],
Square[1,N] #< Square[N,1],
solve([ffd,updown],Square),
print_square(Square).
%
% Alternativt using rows(), columns(), diagonal1(), and diagonal2()
% from the util module.
%
magic2(N,Square) =>
printf("\n\nN: %d\n", N),
NN = N*N,
Sum = N*(NN+1)//2,% magical sum
printf("Sum = %d\n", Sum),
Square = new_array(N,N),
Square :: 1..NN,
all_different(Square.vars()),
% Note that sum/1 requires a list, so Row and Column must be converted
% to a list with .to_list().
foreach(Row in Square.rows()) Sum #= sum(Row.to_list()) end,
foreach(Column in Square.columns()) Sum #= sum(Column.to_list()) end,
% diagonal sums
Sum #= sum(Square.diagonal1()),
Sum #= sum(Square.diagonal2()),
println(diagonals),
% Symmetry breaking
Square[1,1] #< Square[1,N],
Square[1,1] #< Square[N,N],
Square[1,1] #< Square[N,1],
Square[1,N] #< Square[N,1],
solve([ffd,updown],Square),
print_square(Square).
print_square(Square) =>
N = Square.length,
foreach(I in 1..N)
foreach(J in 1..N)
writef("%3d ", Square[I,J])
end,
writef("\n")
end,
writef("\n").