Search code examples
prologpath-findingmaze

Prolog Maze Pathfinding


Hey guys so I'm having a bit of an issue with writing a pathfinding functor to go from one square to the other. I can't figure out how to tell if a square has a neighbouring square.

The maze is a 5x5 grid with black squares denoting a wall.

square([1,1], white). square([1,2], white). square([1,3], white). square([1,4], white). square([1,5], white). 
square([2,1], white). square([2,2], black). square([2,3], black). square([2,4], black). square([2,5], white). 
square([3,1], white). square([3,2], black). square([3,3], white). square([3,4], black). square([3,5], white). 
square([4,1], white). square([4,2], black). square([4,3], white). square([4,4], white). square([4,5], white). 
square([5,1], white). square([5,2], white). square([5,3], white). square([5,4], white). square([5,5], white).

So far I've tried something like this:

neighbour([X,Y],[A,B]) :- 
    A is X + 1,
    B is Y + 1,
    square([X,Y], white), 
    square([A,B], white).

neighbour([X,Y],[A,B]) :- 
    A is X - 1,
    B is Y - 1,
    square([X,Y], white), 
    square([A,B], white).

neighbour([X,Y],[A,B]) :- 
    A is X + 1,
    B is Y - 1,
    square([X,Y], white), 
    square([A,B], white).

neighbour([X,Y],[A,B]) :- 
    A is X - 1,
    B is Y + 1,
    square([X,Y], white), 
    square([A,B], white).

neighbour([X,Y],[A,B]) :- 
    square([X,Y], white), 
    square([A,B], white), 
    A is X + 1;
    square([X,Y], white), 
    square([A,B], white),
    B is Y + 1.

neighbour([X,Y],[A,B]) :- 
    square([X,Y], white), 
    square([A,B], white), 
    A is X - 1;
    square([X,Y], white), 
    square([A,B], white),
    B is Y + 1.

neighbour([X,Y],[A,B]) :- 
    square([X,Y], white), 
    square([A,B], white), 
    A is X + 1;
    square([X,Y], white), 
    square([A,B], white),
    B is Y - 1.

neighbour([X,Y],[A,B]) :- 
    square([X,Y], white), 
    square([A,B], white), 
    A is X - 1;
    square([X,Y], white), 
    square([A,B], white),
    B is Y - 1.

route(X, Y, [X, Y]) :- neighbour(X, Y).
route(X, Z, [X | Route]) :- neighbour(X, Y), route(Y, Z, Route).

But when I call Route with say something like: Route([3,3], [1,5], Route). I end up with an incorrect list.

If anyone has any ideas or knows a better way of representing the likes of the maze, I'd really appreciate it!


Solution

  • Can express as:

    square_black(X, 2) :-
        between(2, 4, X).
    
    square_black(2, 3).
    square_black(2, 4).
    square_black(3, 4).
    
    square_white(X, Y) :-
        between(1, 5, X),
        between(1, 5, Y),
        \+ square_black(X, Y).
    
    neighbour(s(X, Y), s(X1, Y1)) :-
        % Determine delta of position
        member(XD, [-1, 0, 1]),
        member(YD, [-1, 0, 1]),
        % Prevent staying in same place
        \+ (XD = 0, YD = 0),
        % Calculate new position
        X1 is X + XD,
        Y1 is Y + YD,
        % Ensure new position is valid
        square_white(X1, Y1).
    
    % The route from a place to the same place is empty
    route([], X, X).
    route([X|T], X, Z) :-
        neighbour(X, Y),
        route(T, Y, Z).
    

    Result in swi-prolog:

    ?- length(R, _), route(R, s(3,3), s(1,5)).
    R = [s(3,3),s(4,4),s(3,5),s(2,5)] ;
    R = [s(3,3),s(4,3),s(4,4),s(3,5),s(2,5)] ;
    R = [s(3,3),s(4,4),s(3,5),s(2,5),s(1,4)] ;
    R = [s(3,3),s(4,4),s(4,5),s(3,5),s(2,5)] ;
    R = [s(3,3),s(4,3),s(3,3),s(4,4),s(3,5),s(2,5)]
    ...