% Row 1
wall([X,1]) :- X =\= 2.
% Row 2
wall([X,2]) :- X = 1; X = 4; X = 6.
% Row 3
wall([X,3]) :- X = 1; X = 2; X = 6.
% Row 4
wall([X,4]) :- X =\= 3,X =\= 5.
% Row 5
wall([X,5]) :- X = 1; X = 4; X = 6.
% Row 6
wall([X,6]) :- X =\= 2.
% Start / end
start([2,1]).
end([2,6]).
% Maze Size
mazeSize([6,6]).

badSpot([X,Y]) :- wall([X,Y]).
badSpot([X,Y]) :- X < 1; Y < 1.
badSpot([X,Y]) :- mazeSize([W, H]), (X > W; Y > H).
% we need references to directions if we are going to follow the left
% wall so let's make variables that keep track of that.


leftDirection(north,west).
leftDirection(south, east).
leftDirection(east, north).
leftDirection(west, south).

rightDirection(north, east).
rightDirection(south, west).
rightDirection(east,south).
rightDirection(west, north).

turnAround(north,south).
turnAround(south,north).
turnAround(east,west).
turnAround(west,east).



%up
move([CurrX, CurrY], [CurrX, NextY]) :- NextY is CurrY - 1.
%down
move([CurrX, CurrY], [NextX, NextY]) :- NextY is CurrY + 1, NextX = CurrX.
%left
move([CurrX, CurrY], [NextX, NextY]) :- NextY = CurrY, NextX is CurrX - 1.
%right
move([CurrX, CurrY], [NextX, NextY]) :- NextY = CurrY, NextX is CurrX + 1.

moveForward([CurrX,CurrY], [CurrX, NextY] , north) :- NextY is CurrY - 1.
moveForward([CurrX,CurrY], [CurrX, NextY] , south) :- NextY is CurrY + 1.
moveForward([CurrX,CurrY], [NextX, CurrY] , east) :- NextX is CurrX + 1.
moveForward([CurrX,CurrY], [NextX, CurrY] , west) :- NextX is CurrX - 1.

leftLocation([CurrX,CurrY], [NextX, CurrY],north) :- NextX is CurrX-1.
leftLocation([CurrX,CurrY], [NextX, CurrY],south) :- NextX is CurrX+1.
leftLocation([CurrX,CurrY], [CurrX, NextY],east) :- NextY is CurrY-1.
leftLocation([CurrX,CurrY], [CurrX, NextY],west) :- NextY is CurrY+1.

rightLocation([CurrX,CurrY], [NextX, CurrY],north) :- NextX is CurrX+1.
rightLocation([CurrX,CurrY], [NextX, CurrY],south) :- NextX is CurrX-1.
rightLocation([CurrX,CurrY], [CurrX, NextY],east) :- NextY is CurrY+1.
rightLocation([CurrX,CurrY], [CurrX, NextY],west) :- NextY is CurrY-1.



updateDirection([CurrX,CurrY],Direction,NewDirection) :-
 leftLocation([CurrX,CurrY],[NextX,NextY],Direction),
 \+badSpot([NextX,NextY]),
 leftDirection(Direction,NewDirection).

updateDirection([CurrX,CurrY],Direction,NewDirection) :-
 moveForward([CurrX,CurrY],[NextX,NextY],Direction),
 badSpot([NextX,NextY]),
 rightDirection(Direction,NewDirection).
updateDirection([CurrX,CurrY],Direction,NewDirection):-
 moveForward([CurrX,CurrY],[ForwardX,ForwardY],Direction),
 badSpot([ForwardX,ForwardY]),
 rightLocation([CurrX,CurrY],[RightX,RightY],Direction),
 badSpot([RightX,RightY]),
 turnAround(Direction,NewDirection).


updateDirection(_,Direction,NewDirection) :-
 NewDirection = Direction.






%Here we are solving the maze by keeping our hand on the right wall.
solveLeft(CurrentLocation, Path, _) :- end(CurrentLocation), Path = [CurrentLocation].

% We are going to take out BeenThere because we don't care if we've been
% at a location before.
solveLeft(CurrentLocation, Path, Direction) :-
    updateDirection(CurrentLocation,Direction,NewDirection),
    moveForward(CurrentLocation,NewLocation,NewDirection),
    \+badSpot(NewLocation),
    solveLeft(NewLocation, RestOfPath, NewDirection),
    Path = [CurrentLocation | RestOfPath].

solveLeft(Path) :- start(Start), solveLeft(Start, Path, south).


%SOLVE FOR CLOSEST PATH HERE
%
%
%
%
% All this is doing is checking potential next moves and seeing if the
% next potential move is closer than the previous point. If it isn't
% then that move will be attempted last. This should solve any maze
% regardless of where the end and start are relative to each other.

isCloser([CurrX,CurrY], [NextX, NextY]) :- end([EndX,EndY]), abs(EndX-NextX)=<abs(EndX-CurrX),abs(EndY-NextY)=<abs(EndY-CurrY).

%up
checkMove([CurrX, CurrY], [CurrX, NextY]) :- NextY is CurrY - 1,isCloser([CurrX, CurrY], [CurrX, NextY]).
%down
checkMove([CurrX, CurrY], [NextX, NextY]) :- NextY is CurrY + 1, NextX = CurrX,isCloser([CurrX, CurrY], [CurrX, NextY]).
%left
checkMove([CurrX, CurrY], [NextX, NextY]) :- NextY = CurrY, NextX is CurrX - 1,isCloser([CurrX, CurrY], [CurrX, NextY]).
%right
checkMove([CurrX, CurrY], [NextX, NextY]) :- NextY = CurrY, NextX is CurrX + 1,isCloser([CurrX, CurrY], [CurrX, NextY]).

checkMove([CurrX, CurrY], [NextX, NextY]):- move([CurrX, CurrY], [NewX, NewY]), NextX is NewX, NextY is NewY.


solveClose(CurrentLocation, Path) :- end(CurrentLocation), Path = [CurrentLocation],!.

% We are going to take out BeenThere because we don't care if we've been
% at a location before.
solveClose(CurrentLocation, Path) :-
    checkMove(CurrentLocation,NewLocation),
    \+badSpot(NewLocation),
    solveClose(NewLocation, RestOfPath),
    Path = [CurrentLocation | RestOfPath].

solveClose(Path) :- start(Start), solveClose(Start, Path).



% Here I am going to use my own heuristic of picking all moves randomly!
% I chose this as a solve method because I believed that it would
% provide the most entertaining output. I like to imagine that you have
% a blindfold on and you are stumbling around aimlessly during this
% simulation. To have a better algorithm from such a concept you would
% want to implement a way to prevent going to the same place twice as we
% did in the original solve function. However, I did not use that here
% as, again, it seemed more entertaining to watch the bot wander like a
% lost child. Each time this function is run the output is different, or
% at least it should be, it is very unlikely that you would get the same
% results back to back. Overall this is not effective regarding
% efficiency but it's very fun to see what shenanigans the bot can get
% up to.

%up
move([CurrX, CurrY],1, [CurrX, NextY]) :- NextY is CurrY - 1.

%down
move([CurrX, CurrY],2, [NextX, NextY]) :- NextY is CurrY + 1, NextX = CurrX.
%left
move([CurrX, CurrY],3, [NextX, NextY]) :- NextY = CurrY, NextX is CurrX - 1.
%right
move([CurrX, CurrY],4, [NextX, NextY]) :- NextY = CurrY, NextX is CurrX + 1.

move([CurrX, CurrY],_, [NextX, NextY]):-random_between(1,4,RandomNum),move([CurrX, CurrY],RandomNum, [NextX, NextY]).

solveRandom(CurrentLocation, Path) :- end(CurrentLocation), Path = [CurrentLocation].


solveRandom(CurrentLocation, Path) :-
        random_between(1,4,RandomNum),
        move(CurrentLocation,RandomNum, NewLocation),
        \+badSpot(NewLocation),
        solveRandom(NewLocation, RestOfPath),
        Path = [CurrentLocation | RestOfPath].

% Convenience rule
solveRandom(Path) :- start(Start), solveRandom(Start, Path).


% A solution of the maze from our current location is [] if our current location is the end.
solve(CurrentLocation, _, Path) :- end(CurrentLocation), Path = [CurrentLocation].


solve(CurrentLocation, BeenThere, Path) :- move(CurrentLocation, NewLocation),
        \+badSpot(NewLocation),
        \+member(NewLocation, BeenThere),
        solve(NewLocation, [NewLocation | BeenThere], RestOfPath),
        Path = [CurrentLocation | RestOfPath].

% Convenience rule
solve(Path) :- start(Start), solve(Start, [Start], Path).


drawCell(Column, Row, _) :- wall([Column, Row]), write("X"), !.
drawCell(Column, Row, _) :- start([Column, Row]), write("S"), !.
drawCell(Column, Row, _) :- end([Column, Row]), write("E"), !.
drawCell(Column, Row, Path) :- member([Column, Row], Path), write("P"), !.
drawCell(_, _, _) :- write("O").

drawRow(Row, Path) :- drawCell(1, Row, Path), tab(1), drawCell(2, Row, Path), tab(1),
        drawCell(3, Row, Path), tab(1), drawCell(4, Row, Path), tab(1),
        drawCell(5, Row, Path), tab(1), drawCell(6, Row, Path), nl.

draw :- drawRow(1, []), drawRow(2, []), drawRow(3, []), drawRow(4, []), drawRow(5, []),
        drawRow(6, []).
draw(Path) :- drawRow(1, Path), drawRow(2, Path), drawRow(3, Path), drawRow(4, Path),
        drawRow(5, Path), drawRow(6, Path).





