# dmalenic's solution

## to Spiral Matrix in the Prolog Track

Published at Feb 24 2019 · 0 comments
Instructions
Test suite
Solution

Given the size, return a square matrix of numbers in spiral order.

The matrix should be filled with natural numbers, starting from 1 in the top-left corner, increasing in an inward, clockwise spiral order, like these examples:

###### Spiral matrix of size 3
``````1 2 3
8 9 4
7 6 5
``````
###### Spiral matrix of size 4
`````` 1  2  3 4
12 13 14 5
11 16 15 6
10  9  8 7
``````

## Source

Reddit r/dailyprogrammer challenge #320 [Easy] Spiral Ascension.

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### spiral_matrix_tests.plt

``````pending :-
current_prolog_flag(argv, ['--all'|_]).
pending :-
write('\nA TEST IS PENDING!\n'),
fail.

:- begin_tests(spiral).
test(empty_spiral, condition(true)) :-
spiral(0, []).

test(trivial_spiral, condition(pending)) :-
spiral(1, [[1]]).
test(spiral_of_size_2, condition(pending)) :-
spiral(2, [[1,2],
[4,3]]).
test(spiral_of_size_3, condition(pending)) :-
spiral(3, [[1,2,3],
[8,9,4],
[7,6,5]]).
test(spiral_of_size_4, condition(pending)) :-
spiral(4, [[ 1, 2, 3, 4],
[12,13,14, 5],
[11,16,15, 6],
[10, 9, 8, 7]]).
test(spiral_of_size_5, condition(pending)) :-
spiral(5, [[ 1, 2, 3, 4, 5],
[16,17,18,19, 6],
[15,24,25,20, 7],
[14,23,22,21, 8],
[13,12,11,10, 9]]).
:- end_tests(spiral).``````
``````spiral(N, _) :- N < 0, !, fail.
spiral(0, []) :- !.
spiral(N, Spiral) :-
directions_list(N, Directions),
zero_square_matrix(N, Zeros),
M is N*N,
range(M, Range),
replace_in_matrix(Range, Directions, Zeros, Spiral).

directions_list(N, Directions) :-
N1 is N-1,
fill_list(r, N1, Initial_directions),
directions_list(N1, d, Initial_directions, Directions).

directions_list(0, _, Initial_directions, Final_directions) :-
!,
reverse([x|Initial_directions], Final_directions).
directions_list(N, d, Acc, Res) :-
!,
fill_list(d, N, Ds),
append(Ds, Acc, Acc1),
directions_list(N, l, Acc1, Res).
directions_list(N, l, Acc, Res) :-
!,
fill_list(l, N, Ls),
append(Ls, Acc, Acc1),
N1 is N-1,
directions_list(N1, u, Acc1, Res).
directions_list(N, u, Acc, Res) :-
!,
fill_list(u, N, Ds),
append(Ds, Acc, Acc1),
directions_list(N, r, Acc1, Res).
directions_list(N, r, Acc, Res) :-
!,
fill_list(r, N, Ls),
append(Ls, Acc, Acc1),
N1 is N-1,
directions_list(N1, d, Acc1, Res).

zero_square_matrix(N, Matrix) :-
fill_list(0, N, Row),
fill_list(Row, N, Matrix).

range(M, Ns) :- findall(L, between(1,M,L), Ns).

replace_in_matrix(Values, Directions, Matrix, Result) :-
replace_in_matrix(Values, Directions, 0, 0, Matrix, Result).
replace_in_matrix(_, [], _, _, Result, Result).
replace_in_matrix([N|Ns], [Dir|Dirs], R, C, L, Result) :-
nth0(R, L, Row, Rows),
nth0(C, Row, _, Cols),
nth0(C, Cols1, N, Cols),
nth0(R, L1, Cols1, Rows),
next_row(Dir, R, R1),
next_col(Dir, C, C1),
!,
replace_in_matrix(Ns, Dirs, R1, C1, L1, Result).

next_row(u, R, R1) :- R1 is R-1.
next_row(d, R, R1) :- R1 is R+1.
next_row(_, R, R).
next_col(l, C, C1) :- C1 is C-1.
next_col(r, C, C1) :- C1 is C+1.
next_col(_, C, C).

fill_list(X, N, L) :- length(L, N), maplist(=(X), L).``````