prologeclipse-clpclp

ECLiPSe clp : getting all adjacent cells on grid


So my problem is the following: I want, given some point with X,Y-coordinates in a grid, to return all of its adjacent cells.

( Note: in the following examples, I'm using the notation UL = upper-left, UM = upper-middle, UR = upper-right, L = left, R = right, BL = bottom-left, BM = bottom-middle and BR = bottom-right. )

E.g.:

For element x at (3,3) on a 5x5 grid

 _   _   _   _   _
 _   UL  UM  UR  _
 _   L   x   R   _
 _   BL  BM  BR  _
 _   _   _   _   _

For element x at (1,1) on a 5x5 grid

 x   R   _   _   _
 BM  BR  _   _   _
 _   _   _   _   _
 _   _   _   _   _
 _   _   _   _   _

Now, as can be seen in the examples above, the amount of cells adjacent to our current element x may vary depending on the X,Y-coordinates of element x itself.

I wanted to solve this by saying that every X to the left and right of the specified coordinate's X, as well as every Y above and below the specified coordinate's Y should be in the domain of 1..N and afterwards define their actual values:

% Adj_cells/2 :   (X,Y) coordinate, board width/height N
adjacent_cells((X,Y),N) :-
    [Xleft,Xright,Yup,Ydown] #:: 1..N,
    Xleft #= X-1, Xright #= X+1,
    Yup   #= Y-1, Ydown  #= Y+1,
    ...

However, of course, this evaluates to false whenever a border of the board gets crossed.

I was hoping I wouldn't explicitly need to differentiate between the situations concerning the board's borders; instead I'm trying to find something that, rather than evaluating to false whenever an out-of-bound coordinate is reached, just 'discards' that result and tries to calculate the other adjacent cells.

I'm sure there'll be a nice little solution for this in ECLiPSe, but I've searched the docs and -so far- can't seem to find something that fits my needs.

Any help is greatly appreciated!


Solution

  • You didn't say in what form you want to "return" the adjacent cells, but if you just want to "do" something for every neighbour, you could use this pattern:

    adjacent_cells([X,Y], N) :-
        ( multifor([I,J], [max(1,X-1),max(1,Y-1)], [min(N,X+1),min(N,Y+1)]), param(X,Y) do
            ( [I,J]==[X,Y] -> true ;
                writeln([I,J])
            )
        ).
    

    which gives for example

    ?- adjacent_cells([1, 3], 6).
    [1, 2]
    [1, 4]
    [2, 2]
    [2, 3]
    [2, 4]
    Yes (0.00s cpu)