%Solution to problem 2
%Solve maze by moving in a prefered direction towards the end
%Finds prefered x any y directions
%Solution prints by calling "solve"

% 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).

%up
move([CurrX, CurrY], [CurrX, NextY], up) :- NextY is CurrY - 1.
%down
move([CurrX, CurrY], [NextX, NextY], down) :- NextY is CurrY + 1, NextX = CurrX.
%left
move([CurrX, CurrY], [NextX, NextY], left) :- NextY = CurrY, NextX is CurrX - 1.
%right
move([CurrX, CurrY], [NextX, NextY], right) :- NextY = CurrY, NextX is CurrX + 1.

%vector: Determine the x and y components of the start/end difference.
vector(X, Y) :- start([SX,SY]), end([EX,EY]), X is (SX - EX), Y is (SY - EY).

%direction: Determine the dominant direction of the solution.
direction(up, B, C, down) :- vector(X, Y), abs(Y) > abs(X), Y >= 0, direction2(x, B, C).
direction(down, B, C, up) :- vector(X, Y), abs(Y) > abs(X), Y =< 0, direction2(x, B, C).
direction(left, B, C, right) :- vector(X, Y), abs(Y) < abs(X), X >= 0, direction2(y, B, C).
direction(right, B, C, left) :- vector(X, Y), abs(Y) < abs(X), X =< 0, direction2(y, B, C).

%direction2: Determine the secondary direction of the solution.
direction2(y, up, down) :- vector(_, Y), Y >= 0.
direction2(y, down, up) :- vector(_, Y), Y =< 0.
direction2(x, left, right) :- vector(X, _), X >= 0. 
direction2(x, right, left) :- vector(X, _), X =< 0.

%select: Choose the direction of movement based off of determined preferences and bad spot locations.
select(Current, New) :- direction(A, _, _, _), move(Current, New, A), \+badSpot(New).
select(Current, New) :- direction(_, B, _, _), move(Current, New, B), \+badSpot(New).
select(Current, New) :- direction(_, _, C, _), move(Current, New, C), \+badSpot(New).
select(Current, New) :- direction(_, _, _, D), move(Current, New, D), \+badSpot(New).

%solve: Print a solution to the maze.
solve(CurrentLocation, _, Path) :- end(CurrentLocation), Path = [CurrentLocation].

solve(CurrentLocation, BeenThere, Path) :- select(CurrentLocation, NewLocation), 
        \+badSpot(NewLocation),
        \+member(NewLocation, BeenThere),
        solve(NewLocation, [NewLocation | BeenThere], RestOfPath), 
        Path = [CurrentLocation | RestOfPath].
		
solve() :- start(Start), solve(Start, [Start], Path), write(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).