Let us assume that I have a 2d-list (or array if you so wish) which looks like this:
'( (I I I O)
(I X I O)
(I I I O))
And now let us assume that I’d like to find all the neighbours of X. In this case my function would return a list of 8 I:s. How would I go about to implement this function in a smart way? I’ve already implemented a function which looks like this:
(defun get-neighbours (board x y)
(let ((output '() ))
(push (get-if-possible board (1+ x) y) output)
(push (get-if-possible board (1- x) y) output)
(push (get-if-possible board x (1+ y)) output)
(push (get-if-possible board x (1- y)) output)
(push (get-if-possible board (1+ x) (1+ y)) output)
(push (get-if-possible board (1- x) (1- y)) output)
(push (get-if-possible board (1+ x) (1- y)) output)
(push (get-if-possible board (1- x) (1+ y)) output)
output))
And that is so… Ugly.
First, you are still in imperative land.
You do: variable declaration, bind it to NIL, mutation of the variable, returning the variable.
It is simply:
You can ‘shorten’ the code with a local macro:
Now one could abstract it a bit:
About the LOOP:
ON moves the pattern (a b) over the list (1 2 3 4 5 6). It would give (1 2), (2 3), (3 4), (4 5) and (5 6). With each iteration the list is moved one forward by using CDR to get the rest list. BY now says that we move by two items, by CDDR and not one item as with CDR. So we get three iterations and the pairs (1 2), (3 4) and (5 6).
An alternative would be to slightly simplify the LOOP by introducing a different list structure for the coordinate pairs: