roland@sics.se (Roland Karlsson) (09/05/89)
This is a Prolog program that solves the 2 orthogonal latin squares problem. Using several algorithms most squares are found. For some sizes no solution are found (2, 6, 14, 18, 26, ...). Of those 2 and 6 are shown in fact to have no solutions. I would appreciate if any of you can tell me if you know of solutions to 14, 18, 26 ... . The program text comments show you how to get a complete listing of unknown sizes. You may have to remove lines that declare parallel predicates. Roland Karlsson #!/bin/sh # shar: Shell Archiver (v1.22) # # Run the following text with /bin/sh to create: # regof.pl # sed 's/^X//' << 'SHAR_EOF' > regof.pl && X% regof.pl X X/* X Once upon a time in a since long forgotten land there lived a king X with a very peculiar sense of order. On day the ruler of said kingdom X pronounced: X X - Let it hence be known that we in our role as head of our armed X forces will set a limit upon its size. Each year shall a great X festival be held in the fields outside our castle. There shall X officers from all regiments gather. From each regiment there shall be X one officer of each rank. The number of ranks shall be the same as the X number of regiments. We then says that there shall be no more X regiments in this land then the side of a square consisting of those X officers. To ensure that the number of regiments is held low we X decide that there shall not be officers of same regiment and rank in X neither row nor column. X X At those ancient times they knew nothing of computers and X absolutely nil about prolog programming so their war machine stayed X quite small. A rumour says that they managed to have five regiments X but that they never got their sixth. Today things have changed though. X This program would have gived the land means of a fantastic military X expansion. Be glad this country is no more. X X X ====================================================================== X X This problem is known as two orthogonal latin squares. X X The regiments (with name X) are called 1, 2, ... X The ranks (with name Y) are called 1, 2, ... X The columns (with name C) are called 1, 2, ... X The rows (with name R) are called 1, 2, ... X X Solutions are divided in: X X * Odd. X * 2^n (n > 1). X * 4+3k where 1+k has solution (k >= 0). X * Factorizeable in above. X * Rest (2+4n that is not one of above). X X For all but last group this program have deterministic algorithms. X In the last group you can, in reasonable time, show that 2 and 6 have X no solutions. Some 2+4n are unknown. Those are 14, 18, 26 ... X The non deterministic search algorithm have so far neither found any X solution for those nor shown that there are no solution. If you know X of solutions you are very welcome to tell me. (To get a complete X list of numbers that I do not know of any solution try the query X write_all_solutions. Numbers that are unknown are marked as unknown.) X X PS. I have been told that all sizes except 2 and 6 has X solutions. I shall not let this stop me to get another answer. X X - roland */ X X X/* Usage: X regof(N) Gives a solution for NxN square. X regof_naive(N Tries the naive algorithm. X regof_odd(N) Tries the odd algorithm. X regof_pow2(N) Tries the odd algorithm. X regof_factor(N,L) N is factorizeable acc. to list L. X regof_unknown(N) Do not know any algorithm. X dotest(X) Test solutions (yes or no). X get_factors(N,L) Get factors of N in list L. X write_all_factors Write factors for numbers from 1 to 255. X write_all_factors_proper Same as above but more complete. X X You may have to take away the parallel declarations if your X Prolog system do not like them. Quintus just gives a warning X and then ignores them. X X - roland */ X X X% -- Top queries. -- X% Also a chooser for algorithm. X X:- dynamic i_shall_test/0. X Xdotest(yes) :- assert(i_shall_test), write('I shall test.'), nl. Xdotest(no) :- retractall(i_shall_test), write('No testing.'), nl. X Xregof(N) :- regof(N, _), !. Xregof_naive(N) :- regof_naive(N, _), !. Xregof_pow2(N) :- regof_pow2(N, _), !. Xregof_odd(N) :- regof_odd(N, _), !. Xregof_unknown(N) :- regof_unknown(N, _), !. Xregof_factor(N, List) :- regof_factor(N, _, List), !. X'regof_4+3k'(N, [Na,Nb]) :- 'regof_4+3k'(N, _, Na, Nb), !. X Xregof(N, _) :- var(N), !, X write('Variable size?'), nl, fail. Xregof(N, _) :- \+integer(N), !, X write('Non integer size?'), nl, fail. Xregof(N, _) :- N > 255, !, X write('Square can not be bigger than 255 by 255.'), nl, fail. Xregof(N, _) :- N < 0, !, X write('Negative numbers of columns and rows?'), nl, fail. Xregof(1, b(r(m(1,1)))) :- !, X write('A one by one square is not very interresting.'), nl. Xregof(N, Board) :- is_factor(odd, N, _, first), !, X write('Odd numbers are very simple!'), nl, X regof_odd(N, Board). Xregof(_,_) :- write('Not odd.'), nl, fail. Xregof(N, Board) :- is_factor(pow2, N, _, first), !, X write('Simple! This type is 2^n.'), nl, X regof_pow2(N, Board). Xregof(_,_) :- write('Not 2^n.'), nl, fail. Xregof(N, Board) :- is_factor('4+3k',N, [Na,Nb], first), !, X write('Easy. This type is 4 + 3k.'), nl, X 'regof_4+3k'(N, Board, Na, Nb). Xregof(_,_) :- write('Not 4 + 3k.'), nl, fail. Xregof(N, Board) :- is_factor(factor, N, ListOfN, first), X ListOfN = [_,_|_], !, X write('Can be factorized.'), nl, X regof_factor(N, Board, ListOfN). Xregof(_,_) :- write('Not factorizeable.'), nl, fail. Xregof(N, Board) :- X write('I will do it the hard way. Not knowing anything.'), nl, X regof_unknown(N, Board). X Xwrite_all_factors :- X get_number(1, 255, 1, N), X (get_factors(N, Fs) -> X findall(X, get_factors(N,_,X), T), sort(T, Types), X write(N), write(': '), write([Fs|Types]), nl, fail X ; write(N), write(': '), write(unknown), nl, fail). X Xwrite_all_factors_proper :- X get_number(1, 255, 1, N), X findall([T,F], get_factors(N,F,T), B), sort(B,SB), X write(N=SB), nl, fail. X X X% -- Odd. -- X% Very simple. (OBS! Zero numbering and non negative modulo.) X% X is (C + R)%N. X% Y is (C - R)%N. (or (C + 2*R)%n) X Xis_factor(odd, N, _, _) :- (N mod 2) =\= 0, N > 1. X Xregof_odd(N, Board) :- X initialize(Men, _, _, N, Board), X make_odd(N, N, Board), X test_this_solution(Men, N, Board). X Xmake_odd(0, _, _). % For all rows .. Xmake_odd(R, N, B) :- R > 0, NextR is R - 1, X make2_odd(N, R, N, B), X make_odd(NextR, N, B). X Xmake2_odd(0, _, _, _). % .. and columns .. Xmake2_odd(C, R, N, B) :- C > 0, NextC is C - 1, X X is ((N + (R-1) + (C-1)) mod N) + 1, X Y is ((N - (R-1) + (C-1)) mod N) + 1, X position(C, R, B, m(X,Y)), % .. set value. X make2_odd(NextC, R, N, B). X X X% -- 2^N. -- X% Almost as simple. (OBS! Se odd above.) X% X is (C + ((-1)^(C+R))*R)%N. X% Y is (C + ((-1)^(C+(R+1)//2))*(R*(R+1)//2))%N. X Xis_factor(pow2, 4, _, _). Xis_factor(pow2, N1, _, _) :- N1 > 1, N2 is N1//2, N1 is N2*2, X is_factor(pow2, N2, _, recursive). X Xregof_pow2(N, Board) :- X initialize(Men, _, _, N, Board), X make_pow2(N, N, Board), X test_this_solution(Men, N, Board). X Xmake_pow2(0, _, _). % For all rows .. Xmake_pow2(R, N, B) :- R > 0, NextR is R - 1, X make2_pow2(N, R, N, B), X make_pow2(NextR, N, B). X Xmake2_pow2(0, _, _, _). % .. and columns .. Xmake2_pow2(C, R, N, B) :- C > 0, NextC is C - 1, X ((((C-1+R-1) mod 2) =:= 0) -> SX = 1 ; SX = -1), X ((((C-1+(R//2)) mod 2) =:= 0) -> SY = 1 ; SY = -1), X X is 1 + ( (N + (C-1) - SX*(R-1)) mod N), X Y is 1 + ( (N*N + (C-1) + SY*(((R-1)*R)//2)) mod N), X position(C, R, B, m(X,Y)), % .. set value. X make2_pow2(NextC, R, N, B). X X X% 4+3k where 1+k has a solution. X% This is the algorithm (10 as an example): X X/* X Make a 3x3 and a 7x7 square. X 1,1 2,2 3,3 _,_ _,_ _,_ _,_ _,_ _,_ _,_ X 2,3 3,1 1,2 _,_ _,_ _,_ _,_ _,_ _,_ _,_ X 3,2 1,3 2,1 _,_ _,_ _,_ _,_ _,_ _,_ _,_ X _,_ _,_ _,_ 4,4 5,5 6,6 7,7 8,8 9,9 a,a X _,_ _,_ _,_ 5,a 6,4 7,5 8,6 9,7 a,8 4,9 X _,_ _,_ _,_ 6,9 7,a 8,4 9,5 a,6 4,7 5,8 X _,_ _,_ _,_ 7,8 8,9 9,a a,4 4,5 5,6 6,7 X _,_ _,_ _,_ 8,7 9,8 a,9 4,a 5,4 6,5 7,6 X _,_ _,_ _,_ 9,6 a,7 4,8 5,9 6,a 7,4 8,5 X _,_ _,_ _,_ a,5 4,6 5,7 6,8 7,9 8,a 9,4 X X Rearrange the 7x7 square. X 1,1 2,2 3,3 4,4 5,5 6,6 7,7 8,8 9,9 a,a X 2,3 3,1 1,2 5,a 6,4 7,5 8,6 9,7 a,8 4,9 X 3,2 1,3 2,1 6,9 7,a 8,4 9,5 a,6 4,7 5,8 X a,5 9,6 8,7 7,8 _,_ _,_ _,_ _,_ _,_ _,_ X 4,6 a,7 9,8 _,_ 8,9 _,_ _,_ _,_ _,_ _,_ X 5,7 4,8 a,9 _,_ _,_ 9,a _,_ _,_ _,_ _,_ X 6,8 5,9 4,a _,_ _,_ _,_ a,4 _,_ _,_ _,_ X 7,9 6,a 5,4 _,_ _,_ _,_ _,_ 4,5 _,_ _,_ X 8,a 7,4 6,5 _,_ _,_ _,_ _,_ _,_ 5,6 _,_ X 9,4 8,5 7,6 _,_ _,_ _,_ _,_ _,_ _,_ 6,7 X X Fill in diagonals from {1,2,3}. X 1,1 2,2 3,3 4,4 5,5 6,6 7,7 8,8 9,9 a,a X 2,3 3,1 1,2 5,a 6,4 7,5 8,6 9,7 a,8 4,9 X 3,2 1,3 2,1 6,9 7,a 8,4 9,5 a,6 4,7 5,8 X a,5 9,6 8,7 7,8 _,3 3,_ _,2 2,_ _,1 1,_ X 4,6 a,7 9,8 1,_ 8,9 _,3 3,_ _,2 2,_ _,1 X 5,7 4,8 a,9 _,1 1,_ 9,a _,3 3,_ _,2 2,_ X 6,8 5,9 4,a 2,_ _,1 1,_ a,4 _,3 3,_ _,2 X 7,9 6,a 5,4 _,2 2,_ _,1 1,_ 4,5 _,3 3,_ X 8,a 7,4 6,5 3,_ _,2 2,_ _,1 1,_ 5,6 _,3 X 9,4 8,5 7,6 _,3 3,_ _,2 2,_ _,1 1,_ 6,7 X X Fill in diagonals from {4,5,6,7,8,9,a}. X 1,1 2,2 3,3 4,4 5,5 6,6 7,7 8,8 9,9 a,a X 2,3 3,1 1,2 5,a 6,4 7,5 8,6 9,7 a,8 4,9 X 3,2 1,3 2,1 6,9 7,a 8,4 9,5 a,6 4,7 5,8 X a,5 9,6 8,7 7,8 4,3 3,9 5,2 2,a 6,1 1,4 X 4,6 a,7 9,8 1,5 8,9 5,3 3,a 6,2 2,4 7,1 X 5,7 4,8 a,9 8,1 1,6 9,a 6,3 3,4 7,2 2,5 X 6,8 5,9 4,a 2,6 9,1 1,7 a,4 7,3 3,5 8,2 X 7,9 6,a 5,4 9,2 2,7 a,1 1,8 4,5 8,3 3,6 X 8,a 7,4 6,5 3,7 a,2 2,8 4,1 1,9 5,6 9,3 X 9,4 8,5 7,6 a,3 3,8 4,2 2,9 5,1 1,a 6,7 X X */ X X Xis_factor('4+3k', N, [Na,Nb], _) :- X Na is (N-1)//3, N is 3*Na + 1, (is_factor(_, Na, _, first) ; Na == 1), X Nb is 2*Na+1. X X'regof_4+3k'(N, B, Na, Nb) :- X write(('Divided in two squares: ' = [Na,Nb])), nl, X write(Na), write(': '), regof(Na, Ba), % Make square a. X write(Nb), write(': '), regof(Nb, Bb), % Make square b. X initialize(M, _, _, N, B), X 'move_a_4+3k'(Na, Na, Na, Ba, B), % Move square a to board. X 'move_b_4+3k'(Nb, Nb, Nb, Na, Bb, B), % Move square b to board. X 'diagonals_a_4+3k'(Na, N, Na, Nb, N, B), % Fill diagonals from set a. X 'diagonals_b_4+3k'(N, Na, Nb, B), % Fill diagonals from set b. X test_this_solution(M, N, B), X true. X X'move_a_4+3k'(0, _, _, _, _) :- !. X'move_a_4+3k'(C, 0, Na, Ba, B) :- !, NextC is C - 1, X 'move_a_4+3k'(NextC, Na, Na, Ba, B). X'move_a_4+3k'(C, R, Na, Ba, B) :- !, NextR is R - 1, X position(C, R, Ba, P), position(C, R, B , P), X 'move_a_4+3k'(C, NextR, Na, Ba, B). X X'move_b_4+3k'(0, _, _, _, _, _) :- !. X'move_b_4+3k'(Cb, 0, Nb, Na, Bb, B) :- !, NextCb is Cb - 1, X 'move_b_4+3k'(NextCb, Nb, Nb, Na, Bb, B). X'move_b_4+3k'(Cb, Rb, Nb, Na, Bb, B) :- !, NextRb is Rb - 1, X position(Cb, Rb, Bb, m(Xb,Yb)), X 'convert_cr_4+3k'(Cb, Rb, Na, C, R), X is Xb+Na, Y is Yb+Na, X position(C, R, B, m(X,Y)), X 'move_b_4+3k'(Cb, NextRb, Nb, Na, Bb, B). X X'convert_cr_4+3k'(Cb, Rb, Na, C, R) :- Rb < Na+1, X C is Cb + Na, R is Rb. X'convert_cr_4+3k'(Cb, Rb, Na, C, R) :- Rb =:= Na+1, X C is Cb + Na, R is C. X'convert_cr_4+3k'(Cb, Rb, Na, C, R) :- Rb > Na+1, X C is (2*Na+1) - (Rb-1), R is Cb + Na. X X'diagonals_a_4+3k'(0, _, _, _, _, _) :- !. X'diagonals_a_4+3k'(XY, C, Na, Nb, N, B) :- C =< Na, !, NextXY is XY - 1, X 'diagonals_a_4+3k'(NextXY, N, Na, Nb, N, B). X'diagonals_a_4+3k'(XY, C, Na, Nb, N, B) :- !, NextC is C - 1, X Rx is Na + 1 + ((Nb + 2*(XY-1) + (C-1) - Na + 1) mod Nb), X Ry is Na + 1 + ((Nb + 2*(XY-1) + (C-1) - Na + 2) mod Nb), X position(C, Rx, B, m(XY,_)), position(C, Ry, B, m(_,XY)), X 'diagonals_a_4+3k'(XY, NextC, Na, Nb, N, B). X X'diagonals_b_4+3k'(CR, Na, _, _) :- CR =< Na, !. X'diagonals_b_4+3k'(CR, Na, Nb, B) :- NextCR is CR - 1, X position(CR, CR, B, m(X,Y)), X 'short_diagonals_b_4+3k'(Na, CR, X, Y, Na, Nb, B), X 'diagonals_b_4+3k'(NextCR, Na, Nb, B). X X'short_diagonals_b_4+3k'(0, _, _, _, _, _, _) :- !. X'short_diagonals_b_4+3k'(D, CR, X, Y, Na, Nb, B) :- NextD is D - 1, X Cx is Na + 1 + ((Nb + (CR-D) - (Na+1)) mod Nb), Ry is Cx, X Rx is Na + 1 + ((Nb + (CR+D) - (Na+1)) mod Nb), Cy is Rx, X position(Cx, Rx, B, m(X,_)), position(Cy, Ry, B, m(_,Y)), X 'short_diagonals_b_4+3k'(NextD, CR, X, Y, Na, Nb, B). X X X% -- Factorizeable. -- X% If you can factorize the size in known solutions then you can X% use the solutions recursively to get an answer. X Xis_factor(factor, 1, Fs, _) :- !, Fs = []. Xis_factor(factor, N, [F|Fs], first) :- N > 1, X get_number(N, 2, -1, F), NextN is N // F, N is NextN * F, F > 1, X ((N == F) -> T = recursive ; T = first), X is_factor(_, F, _, T), X is_factor(factor, NextN, Fs, first). X Xget_factors(N, Fs) :- is_factor(factor, N, Fs, first). Xget_factors(N, R, Type) :- X is_factor(Type, N, Fs, first), X ((Type == factor) -> Fs = [_,_|_], sorted(Fs), R = Fs ; R = [N]). X Xregof_factor(N, B, [N1|Ns]) :- X write('Factors are: '), write([N1|Ns]), nl, X regof_for_each_factor([N1|Ns], [B1|Bs]), % Solve for all factors .. X combine_all(Ns, Bs, N1, B1, B), % .. and combine them. X initialize(Men, _, _, N, _), X test_this_solution(Men, N, B). X Xregof_for_each_factor([], []). Xregof_for_each_factor([N|Ns], [B|Bs]) :- X write(N), write(': '), X regof(N, B), X regof_for_each_factor(Ns, Bs). X Xcombine_all([], _, _, B, B). Xcombine_all([N|Ns], [B|Bs], Nin, Bin, Ball) :- X Nout is N * Nin, functor(Bout, b, Nout), make_board(Nout, Nout, Bout), X combine_two(N, N, N, Nin, Nin, Nin, Nout, B, Bin, Bout), X combine_all(Ns, Bs, Nout, Bout, Ball). X Xcombine_two(0, _, _, _, _, _, _, _, _, _) :- !. Xcombine_two(C, 0, N, Cin, Rin, Nin, Nout, B, Bin, Bout) :- !, NextC is C - 1, X combine_two(NextC, N, N, Cin, Rin, Nin, Nout, B, Bin, Bout). Xcombine_two(C, R, N, 0, Rin, Nin, Nout, B, Bin, Bout) :- !, NextR is R - 1, X combine_two(C, NextR, N, Nin, Rin, Nin, Nout, B, Bin, Bout). Xcombine_two(C, R, N, Cin, 0, Nin, Nout, B, Bin, Bout) :- !, NextCin is Cin - 1, X combine_two(C, R, N, NextCin, Nin, Nin, Nout, B, Bin, Bout). Xcombine_two(C, R, N, Cin, Rin, Nin, Nout, B, Bin, Bout) :- NextRin is Rin - 1, X position(C, R, B, m(X,Y)), X position(Cin, Rin, Bin, m(Xin,Yin)), X Rout is N*(Rin-1) + R, Cout is N*(Cin-1) + C, X Xout is N*(Xin-1) + X, Yout is N*(Yin-1) + Y, X position(Cout, Rout, Bout, m(Xout,Yout)), X combine_two(C, R, N, Cin, NextRin, Nin, Nout, B, Bin, Bout). X X X X% -- Unknown (Currently some 2*odd). -- X X/* As naming is arbitrary you can start with first row as: X 1/1, 2/2, 3/3, 4/4, 5/5, 6/6. X X As the order of rows is of no moment you can start with the first X column as: X 1/1, X 2/_, X 3,_, X 4/_, X 5/_, X 6/_. X X As you always can swap columns/rows and rename types you can start with: X 1/1, 2/2, 3/3, 4/4, 5/5, 6/6 X 2/6, _/_, _/_, _/_, _/_, _/_ X 3/5, _/_, _/_, _/_, _/_, _/_ X 4/_, _/_, _/_, _/_, _/_, _/_ X 5/_, _/_, _/_, _/_, _/_, _/_ X 6/_, _/_, _/_, _/_, _/_, _/_ X proof: You can choose 2/6 because /3 -> /6 are interchangeable. X . Then you can choose 3/5 because /4 -> /5 are interchangeable. */ X Xregof_unknown(N, Board) :- X initialize(Men, Xs, Ys, N, Board), X first_row(Men, Xs, Ys, N, N, Board, M2), X Split is N//2 + 1, X first_col_det(M2, Xs, Ys, N, 2, Split, Board, M3), X !, X first_col_nondet(M3, Xs, Ys, N, Split, Board, M4), X search(M4, Xs, Ys, Board), X write_nice(1, 1, N, Board). X Xfirst_row(M1, Xs, Ys, N, C, B, M2) :- C > 0, NextC is C - 1, X M = m(C,C), % (C is nonvar) X delete(M, M1, M3), % Fetch one man (C,C) .. X put_one_man(M, Xs, Ys, B, p(C,1)), % .. and put him at (C,1). X first_row(M3, Xs, Ys, N, NextC, B, M2). Xfirst_row(M, _, _, _, 0, _, M). X Xfirst_col_det(M1, Xs, Ys, N, R, S, B, M2) :- R < S, NextR is R + 1, X Y is N - R + 2, X M = m(R,Y), % (R and Y is nonvar) X delete(M, M1, M3), % Fetch one man (R,Y) .. X put_one_man(M, Xs, Ys, B, p(1,R)), % .. and put him at (1,R). X first_col_det(M3, Xs, Ys, N, NextR, S, B, M2). Xfirst_col_det(M, _, _, _, R, S, _, M) :- R > S - 1. X Xfirst_col_nondet(M1, Xs, Ys, N, R, B, M2) :- R =< N, NextR is R + 1, X M = m(R,_), % (R is nonvar, Y is var) X deleteP(M, M1, M3), % Fetch one man (R,Y) .. X put_one_man(M, Xs, Ys, B, p(1,R)), % .. and put him at (1,R). X first_col_nondet(M3, Xs, Ys, N, NextR, B, M2). Xfirst_col_nondet(M, _, _, N, R, _, M) :- R > N. X X X% -- Naive algorithm, initialization and standard search routine. -- X Xregof_naive(N, Board) :- X initialize(Men, Xs, Ys, N, Board), X search(Men, Xs, Ys, Board), X write_nice(1, 1, N, Board). X Xinitialize(Men, Xs, Ys, N, Board) :- X functor(Board, b, N), % Make columns and .. X make_board(N, N, Board), % .. rows of board. X men(N, N, N, Men), % Make a list of all men. X functor(Xs, x, N), set_up(N, N, Xs), % Make lists of free .. X functor(Ys, y, N), set_up(N, N, Ys), % .. cols and rows. X ! /* To cut down at environment size */. X Xmake_board(0, _, _). Xmake_board(C, N, Board) :- C > 0, NextC is C - 1, X arg(C, Board, RR), functor(RR, r, N), X make_board(NextC, N, Board). X Xmen(_, 0, _, []) :- !. Xmen(0, Y, N, Ms) :- !, NextY is Y - 1, X men(N, NextY, N, Ms). Xmen(X, Y, N, [m(X,Y)|Ms]) :- NextX is X - 1, X men(NextX, Y, N, Ms). X Xset_up(XY, N, F) :- XY > 0, NextXY is XY - 1, X arg(XY, F, free(C,R)), X empty_list(N, C), empty_list(N, R), X set_up(NextXY, N, F). Xset_up(0, _, _). X Xsearch([], _, _, _). % Until last man .. Xsearch([M|Ms], Xs, Ys, B) :- % .. try to put him on board. X put_one_man(M, Xs, Ys, B, p(_,_)), X search(Ms, Xs, Ys, B). X Xput_one_man(m(X,Y), Xs, Ys, B, p(C,R)) :- X arg(X, Xs, free(XC, XR)), % Fetch list of free rows .. X arg(Y, Ys, free(YC, YR)), % .. and cols for this man. X pair_member(m(X,Y), XC, YC, 1, C), % Fetch a col. X pair_member(m(X,Y), XR, YR, 1, R), % Fetch a row. X position(C, R, B, m(X,Y)). % Can I put him here? X Xposition(C, R, B, P) :- arg(R, B, RR), arg(C, RR, P). X X X% -- Testing of solutions -- X Xtest_this_solution(Men, N, Board) :- X write_nice(1, 1, N, Board), X (i_shall_test -> test(Men, N, Board) % Test only on demand! X ; write('Do not test'), nl). X Xtest(Ms, N, B) :- X write('testing ...'), nl, X sort(Ms, SortedMs), X test_men(SortedMs, N, B, Flag), % Test if all men on board. X numbered_list(N, L), sort(L, SortedL), X test_cols(N, N, N, B, SortedL, [], [], Flag), % Test if columns and .. X test_rows(N, N, N, B, SortedL, [], [], Flag), % .. rows are right. X var(Flag), !, write('OK'), nl. Xtest(_, _, _) :- X write('... found not OK, what a mistake!'), nl, fail. X Xtest_men(Ms, N, B, Flag) :- X which_is_on_board(N, N, N, B, W), X test_lists(Ms, W, men, Flag). X Xtest_lists(SortedOld, New, Com, Flag) :- X sort(New, SortedNew), X ((SortedOld == SortedNew) -> true X ; write(Com), write(' is wrong.'), nl, Flag = nonvar). X Xwhich_is_on_board(0, _, _, _, []) :- !. Xwhich_is_on_board(C, 0, N, B, W) :- !, NextC is C - 1, X which_is_on_board(NextC, N, N, B, W). Xwhich_is_on_board(C, R, N, B, W) :- NextR is R - 1, X position(C, R, B, m(X,Y)), X ((var(X) ; var(Y)) -> NextW = W ; [m(X,Y)|NextW] = W), X which_is_on_board(C, NextR, N, B, NextW). X Xtest_cols(0, _, _, _, _, _, _, _) :- !. Xtest_cols(C, 0, N, B, L, Xs, Ys, Flag) :- !, NextC is C - 1, X test_lists(L, Xs, xcol(C), Flag), X test_lists(L, Ys, ycol(C), Flag), X test_cols(NextC, N, N, B, L, [], [], Flag). Xtest_cols(C, R, N, B, L, Xs, Ys, Flag) :- !, NextR is R - 1, X position(C, R, B, m(X,Y)), X test_cols(C, NextR, N, B, L, [X|Xs], [Y|Ys], Flag). X Xtest_rows(0, _, _, _, _, _, _, _) :- !. Xtest_rows(R, 0, N, B, L, Xs, Ys, Flag) :- !, NextR is R - 1, X test_lists(L, Xs, xrow(R), Flag), X test_lists(L, Ys, yrow(R), Flag), X test_rows(NextR, N, N, B, L, [], [], Flag). Xtest_rows(R, C, N, B, L, Xs, Ys, Flag) :- !, NextC is C - 1, X position(C, R, B, m(X,Y)), X test_rows(R, NextC, N, B, L, [X|Xs], [Y|Ys], Flag). X X X% -- Member and other help stuff. -- X Xget_number(Cnt, _, _, Cnt). Xget_number(Cnt, Stop, Incr, Num) :- Cnt \== Stop, NextCnt is Cnt + Incr, X get_number(NextCnt, Stop, Incr, Num). X Xpair_member(X, L1, L2, N1, N2) :- var(N2), !, % Parallel or sequential? X pair_memberP(X, L1, L2, N1, N2). Xpair_member(X, L1, L2, N1, N2) :- X pair_memberS(X, L1, L2, N1, N2). X X:- parallel pair_memberP/5. Xpair_memberP(X, [X|_], [X|_], N ,N). Xpair_memberP(X, [_|T1], [_|T2], Cnt, N) :- NextCnt is Cnt + 1, X pair_memberP(X, T1, T2, NextCnt, N). X Xpair_memberS(X, [X|_], [X|_], N ,N). Xpair_memberS(X, [_|T1], [_|T2], Cnt, N) :- NextCnt is Cnt + 1, X pair_memberS(X, T1, T2, NextCnt, N). X Xdelete(m(X,Y), L1, L2) :- (var(X) ; var(Y)), !, % Parallel or sequential? X deleteP(m(X,Y), L1, L2). Xdelete(M, L1, L2) :- X deleteS(M, L1, L2). X X:- parallel deleteP/3. XdeleteP(X, [X|T], T). XdeleteP(X, [H|T1], [H|T2]) :- deleteP(X, T1, T2). X XdeleteS(X, [X|T], T). XdeleteS(X, [H|T1], [H|T2]) :- deleteS(X, T1, T2). X Xempty_list(N, [_|T]) :- N > 0, NextN is N - 1, empty_list(NextN, T). Xempty_list(0, []). X Xnumbered_list(N, [N|T]) :- N > 0, NextN is N - 1, numbered_list(NextN, T). Xnumbered_list(0, []). X Xsorted(L) :- sort(L, L). X Xwrite_nice(C, R, N, B) :- % Locking if parallel! X (predicate_property(bc_lock(_), _) -> bc_lock(5) ; true), X write_nice2(C, R, N, B), X (predicate_property(bc_lock(_), _) -> bc_unlock(5) ; true). X Xwrite_nice2(_, R, N, _) :- R > N, !, nl. Xwrite_nice2(C, R, N, B) :- C > N, !, nl, NextR is R + 1, X write_nice2(1, NextR, N, B). Xwrite_nice2(C, R, N, B) :- NextC is C + 1, X position(C, R, B, m(X,Y)), write_nice4(X, Y), X write_nice2(NextC, R, N, B). X Xwrite_nice3(N) :- var(N), !, write('_'). Xwrite_nice3(N) :- (N > 9, N < 36), !, X C is 0'a + N - 10, name(A, [C]), write(A). Xwrite_nice3(N) :- (N > 35, N < 62), !, X C is 0'A + N - 36, name(A, [C]), write(A). Xwrite_nice3(N) :- write(N). X Xwrite_nice4(X, Y) :- write_nice3(X), write(','), write_nice3(Y), write(' '). SHAR_EOF chmod 0664 regof.pl || echo "restore of regof.pl fails" exit 0 -- Roland Karlsson SICS, PO Box 1263, S-164 28 KISTA, SWEDEN Internet: roland@sics.se Tel: +46 8 752 15 40 Ttx: 812 61 54 SICS S Fax: +46 8 751 72 30