spiral(X, Y) :-
intlength(X*Y, IL),
P is IL+1,
spiral_list(X, Y, L),
write_matrix(L, P).
intlength(I, L) :-
L is floor(log(I)/log(10))+1.
write_matrix(L, P) :-
write_matrix(1, L, P).
write_matrix(R, L, P) :-
(
write_row(R, 1, L, P) ->
NR is R + 1,
write_matrix(NR, L, P)
).
write_row(R, C, L, P) :-
lookup(L, (C, R), V),
intlength(V, VL),
NSP is P - VL,
write_spaces(NSP),
write(V),
NC is C + 1,
(
write_row(R, NC, L, P)
;
write('\n')
).
lookup([(K,V)|_], K, V) :- !.
lookup([_|Ls], K, V) :-
lookup(Ls, K, V).
write_spaces(0) :- !.
write_spaces(N) :-
write(' '),
NN is N - 1,
write_spaces(NN).
spiral_list(X, Y, [((1,1),1)|L]) :-
M is X*Y,
spiral_list(1, 1, 1, right, 1, 1, X, Y, M, L).
spiral_list(M, _, _, _, _, _, _, _, M, []).
spiral_list(A, I, J, D, K, L, X, Y, M, [((NI,NJ),NA)|R]) :-
A < M,
go(D, I, J, II, JJ),
(
onboard(II, JJ, K, L, X, Y) ->
D = ND,
go(none, II, JJ, NI, NJ),
chbounds(none, K, L, X, Y, NK, NL, NX, NY)
;
next(D, ND),
go(ND, I, J, NI, NJ),
chbounds(ND, K, L, X, Y, NK, NL, NX, NY)
),
NA is A + 1,
spiral_list(NA, NI, NJ, ND, NK, NL, NX, NY, M, R).
next(right, down).
next(down, left).
next(left, up).
next(up, right).
go(none, X, Y, X, Y).
go(right, X, Y, NX, Y) :-
NX is X + 1.
go(left, X, Y, NX, Y) :-
NX is X - 1.
go(up, X, Y, X, NY) :-
NY is Y - 1.
go(down, X, Y, X, NY) :-
NY is Y + 1.
chbounds(none, MinX, MinY, MaxX, MaxY, MinX, MinY, MaxX, MaxY).
chbounds(right, MinX, MinY, MaxX, MaxY, NMinX, MinY, MaxX, MaxY) :-
NMinX is MinX + 1.
chbounds(left, MinX, MinY, MaxX, MaxY, MinX, MinY, NMaxX, MaxY) :-
NMaxX is MaxX - 1.
chbounds(up, MinX, MinY, MaxX, MaxY, MinX, MinY, MaxX, NMaxY) :-
NMaxY is MaxY - 1.
chbounds(down, MinX, MinY, MaxX, MaxY, MinX, NMinY, MaxX, MaxY) :-
NMinY is MinY + 1.
onboard(I, J, K, L, X, Y) :-
I >= K,
J >= L,
I =< X,
J =< Y.