Towers of Hanoi
by
Ricardo Fernandes Lopes
( Towers of Hanoi game )
( by Ricardo F. Lopes - 2006 )
( Use keys 1, 2 and 3 to play )
0 VARIABLE MOV# ( Move count )
: MOV+1 ( Increment move count ) MOV# @ 1+ MOV# ! ;
CREATE T 24 ALLOT ( Towers array: 3 poles, 8 lines )
: T> ( pole line -- c-adr ) 3 * + T + ;
: RING@ ( pole line -- ring ) T> C@ ;
: RING! ( ring pole line -- ) T> C! ;
: INIT ( Initialize game )
0 MOV# ! ( Reset move count)
8 0 ( Set rings)
DO
7 I - ( ring size)
0 I RING! ( Put all rings in pole 1)
0 1 I RING! ( empty pole 2)
0 2 I RING! ( empty pole 3)
LOOP
;
: .FRAME ( draw poles )
7 0 ( poles with 7 lines)
DO
8 SPACES ( left margin)
3 0 ( 3 poles)
DO
." | "
LOOP
LOOP
32 0 ( bottom line)
DO
ASCII _ EMIT
LOOP
." 1 2 3" ( pole labels)
;
: .RING ( ring line pole -- , Draw a ring)
1+ 16 * 3 PICK - ( x = pole+1 * 16 - ring)
SWAP 2 * 32 + ( y = line*2 + 32 )
ROT 2 * 2+ 0 ( ringsize = ring*2 + 2 )
DO ( Plot ring)
OVER I + OVER
1 PLOT
LOOP
DROP DROP
;
: SHOW ( Draw everything)
CLS
.FRAME CR CR
." Moves: " MOV# @ . ( Show moves)
3 0 ( Three Poles)
DO
7 0 ( Seven Lines)
DO
J I RING@ ?DUP
IF ( Is there a ring?)
I J .RING ( Draw the ring)
THEN
LOOP
LOOP
;
: TOP> ( pole -- pole line , Find free line over the rings in a pole)
0 ( dummy previous line)
8 0 ( check 8 lines )
DO
DROP ( discard previous line)
I OVER OVER RING@ ( Get ring in current line)
0=
IF ( Free line? Done )
LEAVE
THEN
LOOP
;
: END? ( -- flag , Check for end of game)
0 ( sum = 0)
7 0 ( 7 lines)
DO
2 I RING@ + ( Sum all rings in pole 3)
LOOP
28 = ( Game over if sum of rings = 28)
;
: MOV ( from to -- , Move a ring from one pole to another)
OVER TOP> ?DUP
IF ( Is there a ring in the source?)
1- RING@ ( Get top ring from source )
OVER TOP> ?DUP
IF ( Destination not empty?)
1- RING@ ( Yes, get top ring from destination)
ELSE ( The destination is empty..)
DROP 8 ( ..assume top destination ring = 8)
THEN
OVER > ( Smaller ring over bigger?)
IF
SWAP TOP> RING! ( Place ring in the destination pole)
0
SWAP TOP> 1- RING! ( Remove ring from source)
MOV+1 ( Count move)
ELSE ( Invalid move, do nothing)
DROP DROP DROP
THEN
ELSE ( No rings in source, do nothing)
DROP DROP DROP
THEN
;
: KEY? ( -- n , Get user input)
BEGIN INKEY 0= UNTIL ( Wait for key release)
BEGIN INKEY ?DUP UNTIL ( Wait for a keypress)
ASCII 0 - 1 MAX 3 MIN ( convert key 1-3 to number 1-3)
;
: HANOI ( Main word, execute it to play)
INIT ( Init variables)
SHOW ( Draw screen)
BEGIN ( Main game loop)
CR ." From? " KEY? DUP . 1- ( Get user "from" input)
CR ." To? " KEY? DUP . 1- ( Get user "to" input)
MOV ( Move ring as commanded)
SHOW ( Update screen)
END? ( Check for success)
UNTIL
;
|
|