Search code examples
prologartificial-intelligence

Prolog keeps going to initial state after recursion


I am trying to write a prolog program where we have a person called Neo trying to save hostages and return the to a safe place which is called a booth, neo has 6 actions to do which are: up, down, left, right, drop and carry. We are trying to find out all the paths that neo can take, so for example result(drop,result(up,result(carry,result(down,s0)))) is a path he can take.

canMove(hostages_loc(H), CAR):-
    \+ length(H, 0);
    CAR > 0.

%move right
action(state(grid(H,W), neo_loc(X,Y), Hos, Booth, Cap, Car), PATH , VISITED, NEWSTATE, NEWPATH):-
    canMove(Hos, Car),
    Y < W-1,
    X1 is X,
    Y1 is Y+1,
    NEWPATH = result(right, PATH),
    NEWSTATE = state(grid(H,W), neo_loc(X1,Y1), Hos, Booth, Cap, Car),
    \+ member(NEWSTATE, VISITED).

%Move left
action(state(grid(H,W), neo_loc(X,Y), Hos, Booth, Cap, Car), PATH , VISITED, NEWSTATE, NEWPATH):-
    canMove(Hos, Car),
    Y > 0,
    X1 is X,
    Y1 is Y-1,
    NEWPATH = result(left, PATH),
    NEWSTATE = state(grid(H,W), neo_loc(X1,Y1), Hos, Booth, Cap, Car),
    \+ member(NEWSTATE, VISITED).

%Move Up
action(state(grid(H,W), neo_loc(X,Y), Hos, Booth, Cap, Car), PATH , VISITED, NEWSTATE, NEWPATH):-
    canMove(Hos, Car),
    X > 0,
    X1 is X-1,
    Y1 is Y,
    NEWPATH = result(up, PATH),
    NEWSTATE = state(grid(H,W), neo_loc(X1,Y1), Hos, Booth, Cap, Car),
    \+ member(NEWSTATE, VISITED).


% Move down
action(state(grid(H,W), neo_loc(X,Y), Hos, Booth, Cap, Car), PATH , VISITED, NEWSTATE, NEWPATH):-
    canMove(Hos, Car),
    X < H-1,
    X1 is X+1,
    Y1 is Y,
    NEWPATH = result(down, PATH),
    NEWSTATE = state(grid(H,W), neo_loc(X1,Y1), Hos, Booth, Cap, Car),
    \+ member(NEWSTATE, VISITED).

% Carry
action(state(GRID, neo_loc(X,Y), hostages_loc(H), Booth, Cap, Car), PATH , VISITED, NEWSTATE, NEWPATH):-
    member([X,Y],H),
    Car < Cap,
    delete(H,[X,Y], NEWH),
    NewCar is Car + 1,
    NEWPATH = result(carry, PATH),
    NEWSTATE = state(GRID, neo_loc(X,Y), hostages_loc(NEWH), Booth, Cap, NewCar),
    \+ member(NEWSTATE, VISITED).

% Drop
action(state(GRID, neo_loc(X,Y), Hos, booth(X,Y), Cap, Car), PATH , VISITED, NEWSTATE, NEWPATH):-
    Car > 0,
    NewCar is 0,
    NEWPATH = result(drop, PATH),
    NEWSTATE = state(GRID, neo_loc(X,Y), Hos, booth(X,Y), Cap, NewCar),
    \+ member(NEWSTATE, VISITED).

path(state(_, neo_loc(X,Y), hostages_loc([]), booth(X,Y), _, 0),PATH,_,_,NEWPATH):-
    NEWPATH = PATH.

path(STATE, PATH, VISITED, NEWSTATE, NEWPATH):-
    action(STATE, PATH, VISITED, NEWSTATE, NEWPATH),
    path(NEWSTATE, NEWPATH, [STATE|VISITED], S, P).

This is my code, the problem is that whenever the program reaches the base case which is

path(state(_, neo_loc(X,Y), hostages_loc([]), booth(X,Y), _, 0),PATH,_,_,NEWPATH):-
    NEWPATH = PATH.

The program keeps going back to the first state and returns the first action made only so for example if the expected output is result(drop,result(up,result(carry,result(down,s0)))) it returns back result(down,s0) only. An example input for path is: path(state(grid(2,1),neo_loc(0,0),hostages_loc([[1,0]]),booth(0,0),2,0),s0,[],NS,NP).

where grid represents the size of the grid, neo_loc represents the location of neo on the grid, hostages_loc represents the hostages that need to be saved, booth represents the location of the booth, 2 represents the maximum amount of hostages that neo can carry, 0 represents the amount of hostages that neo is actually carrying. s0 is the initial path, [] represents the visited states. NS and NP are the outputs that I need.


Solution

  • Replace:

    path(STATE, PATH, VISITED, NEWSTATE, NEWPATH):-
        action(STATE, PATH, VISITED, NEWSTATE, NEWPATH),
        path(NEWSTATE, NEWPATH, [STATE|VISITED], S, P).
    

    with:

    path(STATE, PATH, VISITED, FINALSTATE, FINALPATH):-
        action(STATE, PATH, VISITED, NEWSTATE, NEWPATH),
        path(NEWSTATE, NEWPATH, [STATE|VISITED], FINALSTATE, FINALPATH).