% ****************************************************************************%
% TOWERS OF HANOI GAME CONSOLE by Ulle Endriss, June 2014 (quantum-encrypted) %
% To use this, start up SWI Prolog and then consult the file: consult(hanoi). %
% ****************************************************************************%

:-style_check(-singleton).
set(_G230):-retractall(game(_G232)), assert(game(_G230)).
init(_G246):-create(_G246, _G249), set(_G249), show, !.
init:-init(8).
create(_G270, _G271):-_G276 is _G270+1, _G271=[_G279, [_G276], [_G276]], range(1, _G276, _G279).
range(_G310, _G311, []):-_G310>_G311.
range(_G320, _G324, [_G320|_G321]):-_G324>=_G320, _G333 is _G320+1, range(_G333, _G324, _G321).
size(_G349, _G350):-flatten(_G349, _G353), length(_G353, _G356), _G350 is _G356-3.
size(_G373):-game(_G375), size(_G375, _G373).
getGameSize(_G386):-game(_G388), size(_G388, _G386).
move(right(1), [[_G401|_G402], [_G407|_G408], _G413], [_G402, [_G401, _G407|_G408], _G413]):-_G401<_G407.
move(right(2), [_G443, [_G446|_G447], [_G452|_G453]], [_G443, _G447, [_G446, _G452|_G453]]):-_G446<_G452.
move(right(3), [[_G485|_G486], _G491, [_G494|_G495]], [[_G494, _G485|_G486], _G491, _G495]):-_G494<_G485.
move(left(1), [[_G527|_G528], _G533, [_G536|_G537]], [_G528, _G533, [_G527, _G536|_G537]]):-_G527<_G536.
move(left(2), [[_G569|_G570], [_G575|_G576], _G581], [[_G575, _G569|_G570], _G576, _G581]):-_G575<_G569.
move(left(3), [_G611, [_G614|_G615], [_G620|_G621]], [_G611, [_G620, _G614|_G615], _G621]):-_G620<_G614.
move(_G651):-game(_G653), move(_G651, _G653, _G657), set(_G657), show, nl, nl, sleep(1), show, !.
move(_G690):-writeln('IllEGAL MOVE!'), fail.
move(_G700, _G701):- (_G700+1)mod 3=:=_G701 mod 3, !, right(_G700).
move(_G726, _G727):-_G726 mod 3=:= (_G727+1)mod 3, !, left(_G726).
move(_G752, _G753):-move(illegal).
left(_G760):-move(left(_G760)).
right(_G769):-move(right(_G769)).
success([[_G778], [_G784], _G790]).
layer(_G795, _G796, empty):-length(_G796, _G800), _G795>=_G800, !.
layer(_G817, [_G814|_G815], _G814):-length(_G815, _G822), _G822>0, _G817=:=_G822, !.
layer(_G845, [_G842|_G843], _G847):-length(_G843, _G850), _G850>0, _G845<_G850, !, layer(_G845, _G843, _G847).
layer(0, _G878, table).
flush:-nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl, nl.
show:-game(_G989), show(_G989).
show(_G999):-size(_G999, _G1002), flush, show(_G999, _G1002, _G1002+1), multiwrite(_G1002+8, ' '), write(1), multiwrite(2*_G1002+10, ' '), write(2), multiwrite(2*_G1002+10, ' '), write(3), nl, nl, nl, !.
show([_G1080, _G1083, _G1086], _G1090, _G1091):-_G1091>=0, !, layer(_G1091, _G1080, _G1098), layer(_G1091, _G1083, _G1102), layer(_G1091, _G1086, _G1106), multiwrite(3, ' '), draw_disk(_G1098, _G1090), draw_disk(_G1102, _G1090), draw_disk(_G1106, _G1090), nl, _G1123 is _G1091-1, show([_G1080, _G1083, _G1086], _G1090, _G1123).
show(_G1175, _G1176, _G1177).
draw_disk(empty, _G1180):-!, multiwrite(_G1180+4, ' '), write('| |'), multiwrite(_G1180+4, ' ').
draw_disk(table, _G1209):-!, multiwrite(2*_G1209+11, =).
draw_disk(_G1226, _G1227):-multiwrite(_G1227-_G1226+3, ' '), multiwrite(2*_G1226+5, 'X'), multiwrite(_G1227-_G1226+3, ' ').
multiwrite(0, _G1266).
multiwrite(_G1268, _G1269):-_G1268>0, write(_G1269), _G1279 is _G1268-1, multiwrite(_G1279, _G1269).
solve:-getGameSize(_G1297), recSolve(_G1297, 1, 3), writeln('Done!'), nl.
recSolve(_G1317, _G1318, _G1319):-_G1317=:=1, move(_G1318, _G1319).
recSolve(_G1333, _G1334, _G1335):-_G1333>1, getPredecessor(_G1333, _G1341), getThirdPeg(_G1334, _G1335, _G1345), recSolve(_G1341, _G1334, _G1345), move(_G1334, _G1335), recSolve(_G1341, _G1345, _G1335).
getPredecessor(_G1376, _G1377):-_G1377 is _G1376-1.
getThirdPeg(_G1388, _G1389, _G1390):-_G1390 is 6-_G1388-_G1389.
sillySolve:-move(1, 3), move(1, 2), move(3, 2), move(1, 3), move(2, 1), move(2, 3), move(1, 3).
top(_G1446, _G1447):-game(_G1449), nth1(_G1446, _G1449, [_G1447, _G1454|_G1455]), !.
tops(_G1470):-findall(_G1485, (member(_G1481, [1, 2, 3]), top(_G1481, _G1485)), _G1470).
where(_G1497, _G1498):-top(_G1498, _G1497).
empty(_G1506):-game(_G1508), nth1(_G1506, _G1508, [_G1510]).
whereOtherDisk(_G1523):-tops(_G1525), sort(_G1525, [1, _G1530|_G1531]), where(_G1530, _G1523).
move1R:-where(1, _G1549), right(_G1549).
moveN1:-where(1, _G1560), whereOtherDisk(_G1562), getThirdPeg(_G1560, _G1562, _G1566), move(_G1562, _G1566).
itSolve:-move1R, finish.
finish:-empty(1), empty(2).
finish:-moveN1, move1R, finish.
explanation:-nl, writeln(+---------------------------------------------------------------------+), writeln('|              * * * TOWERS OF HANOI: GAME CONSOLE * * *              |'), writeln(+---------------------------------------------------------------------+), writeln('| The system provides the following basic commands:                   |'), writeln(+-----------------+---------------------------------------------------+), writeln('| ?- init(+N).    | Create (initialise) a game with N disks.          |'), writeln('| ?- show.        | Display the current configuration of the game.    |'), writeln('| ?- move(+A,+B). | Move the top disk on peg A to peg B.              |'), writeln('| ?- empty(+A).   | Check whether peg A has no disks on it.           |'), writeln('| ?- top(+A,-D).  | Get the name of the disk on top of peg A.         |'), writeln('| ?- explanation. | Display this text.                                |'), writeln(+-----------------+---------------------------------------------------+), writeln('| Three solutions have been implemented already:                      |'), writeln(+------------------------+--------------------------------------------+), writeln('| ?- recSolve(+N,+A,+B). | recursive solution (N disks from A to B)   |'), writeln('| ?- itSolve.            | iterative solution (all disks from 1 to 3) |'), writeln('| ?- sillySolve.         | hard-wired solution (3 disks from 1 to 3)  |'), writeln(+------------------------+--------------------------------------------+), nl.
:-create(8, _G1705), set(_G1705), explanation.
