% 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).

move([CurrX, CurrY], [CurrX, NextY]) :- NextY is CurrY - 1.
move([CurrX, CurrY], [NextX, NextY]) :- NextY is CurrY + 1, NextX = CurrX.
move([CurrX, CurrY], [NextX, NextY]) :- NextY = CurrY, NextX is CurrX - 1.
move([CurrX, CurrY], [NextX, NextY]) :- NextY = CurrY, NextX is CurrX + 1.

move(CurrentLocation, NewLocation, Dir) :- checkLeft(CurrentLocation, NewLocation, Dir).
move(CurrentLocation, NewLocation, Dir) :- checkUp(CurrentLocation, NewLocation, Dir).
move(CurrentLocation, NewLocation, Dir) :- checkRight(CurrentLocation, NewLocation, Dir).
move(CurrentLocation, NewLocation, Dir) :- moveDown(CurrentLocation, NewLocation, Dir).

%% Directions
dirCheck([CurrX, _], [NextX, _], right) :- NextX is CurrX + 1. % Going right
dirCheck([CurrX, _], [NextX, _], left) :- NextX is CurrX - 1. % Going left
dirCheck([_, CurrY], [_, NextY], down) :- NextY is CurrY + 1. % Going down
dirCheck([_, CurrY], [_, NextY], up) :- NextY is CurrY - 1. % Going up

%% Get position of left wall
leftWall([X,Y], [WallX, WallY], Dir) :- Dir = left, WallX is X, WallY is Y + 1.
leftWall([X,Y], [WallX, WallY], Dir) :- Dir = right, WallX is X, WallY is Y - 1.
leftWall([X,Y], [WallX, WallY], Dir) :- Dir = up, WallX is X - 1, WallY is Y.
leftWall([X,Y], [WallX, WallY], Dir) :- Dir = down, WallX is X + 1, WallY is Y.

%% Get position of upper wall
upperWall([X,Y], [WallX, WallY], Dir) :- Dir = left, WallX is X - 1, WallY is Y.
upperWall([X,Y], [WallX, WallY], Dir) :- Dir = right, WallX is X + 1, WallY is Y.
upperWall([X,Y], [WallX, WallY], Dir) :- Dir = up, WallX is X, WallY is Y - 1.
upperWall([X,Y], [WallX, WallY], Dir) :- Dir = down, WallX is X, WallY is Y + 1.

%% Get position of right wall
rightWall([X,Y], [WallX, WallY], Dir) :- Dir = left, WallX is X, WallY is Y - 1.
rightWall([X,Y], [WallX, WallY], Dir) :- Dir = right, WallX is X, WallY is Y + 1.
rightWall([X,Y], [WallX, WallY], Dir) :- Dir = up, WallX is X + 1, WallY is Y.
rightWall([X,Y], [WallX, WallY], Dir) :- Dir = down, WallX is X - 1, WallY is Y.

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

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

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

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

%% Checking left wall
checkLeft(CurrentLocation, NewLocation, Dir) :-
    leftWall(CurrentLocation, LeftWallLocation, Dir),
    \+ wall(LeftWallLocation),
    moveLeft(CurrentLocation, NewLocation, Dir).
    
%% Checking upper wall
checkUp(CurrentLocation, NewLocation, Dir) :-
    upperWall(CurrentLocation, UpperWallLocation, Dir),
    \+ wall(UpperWallLocation),
    moveUp(CurrentLocation, NewLocation, Dir).

%% Checking right wall
checkRight(CurrentLocation, NewLocation, Dir) :-
    rightWall(CurrentLocation, RightWallLocation, Dir),
    \+ wall(RightWallLocation),
    moveRight(CurrentLocation, NewLocation, Dir).

%% Solve
solve(CurrentLocation, Path, _) :- end(CurrentLocation), Path = [CurrentLocation].

solve(CurrentLocation, Path, Dir) :-
    move(CurrentLocation, NewLocation, Dir),
    dirCheck(CurrentLocation, NewLocation, NewDir),
    solve(NewLocation, RestOfPath, NewDir),
    Path = [CurrentLocation | RestOfPath].

solve(Path) :- start(Start),
    move(Start, NewLocation),
    \+badSpot(NewLocation),
    dirCheck(Start, NewLocation, Dir),
    solve(Start, Path, Dir).
