altos/scheme: Rename to 'scheme', clean up build
[fw/altos] / src / test / hanoi.lisp
index 01398d9121029dba270802d9362e687bb3e9c888..4afde8833b77bc4e1fa4f4c59a80e4ff926ad3e1 100644 (file)
-(defun move-to (col row)
-  (patom "\033[" row ";" col "H" nil)
+;
+; Towers of Hanoi
+;
+; Copyright © 2016 Keith Packard <keithp@keithp.com>
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 2 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+;
+
+                                       ; ANSI control sequences
+
+(define (move-to col row)
+  (for-each display (list "\033[" row ";" col "H"))
   )
 
-(defun clear ()
-  (patom "\033[2J" nil)
+(define (clear)
+  (display "\033[2J")
   )
 
-(defun test ()
-  (clear)
-  (move-to 30 12)
-  (patom "hello, world")
-  (move-to 0 19)
+(define (display-string x y str)
+  (move-to x y)
+  (display str)
   )
 
-(setq stack '("*" "**" "***" "****" "*****" "******" "*******"))
+                                       ; Here's the pieces to display
 
-(setq stacks nil)
+(define tower '("     *     " "    ***    " "   *****   " "  *******  " " ********* " "***********"))
 
-(defun display-string (x y str)
-  (move-to x y)
-  (move-to x y)
-  (patom str)
-  )
+                                       ; Here's all of the towers of pieces
+                                       ; This is generated when the program is run
 
-(defun display-stack (x y stack)
-  (cond (stack (progn
-                (display-string x y (car stack))
-                (display-stack x (1+ y) (cdr stack)))))
-  )
+(define towers ())
 
-(defun clear-stack (x y)
-  (cond ((> y 0) (progn
-                  (move-to x y)
-                  (patom "            ")
-                  (clear-stack x (1- y))
-                  )
+(define (one- x) (- x 1))
+(define (one+ x) (+ x 1))
+                                       ; Display one tower, clearing any
+                                       ; space above it
+
+(define (display-tower x y clear tower)
+  (cond ((= 0 clear)
+        (cond ((not (null? tower))
+               (display-string x y (car tower))
+               (display-tower x (one+ y) 0 (cdr tower))
+               )
+              )
+        )
+       (else 
+        (display-string x y "                   ")
+        (display-tower x (one+ y) (one- clear) tower)
         )
        )
   )
 
-(defun length (list)
-  (cond (list (1+ (length (cdr list))))
-       (0)
-       )
-  )
+                                       ; Position of the top of the tower on the screen
+                                       ; Shorter towers start further down the screen
 
-(defun stack-pos (y stack)
-  (- y (length stack))
+(define (tower-pos y tower)
+  (- y (length tower))
   )
 
-(defun display-stacks (x y stacks)
-  (cond (stacks (progn
-                 (clear-stack x 20)
-                 (display-stack x (stack-pos y (car stacks)) (car stacks))
-                 (display-stacks (+ x 20) y (cdr stacks)))
-               )
+                                       ; Display all of the towers, spaced 20 columns apart
+
+(define (display-towers x y towers)
+  (cond ((not (null? towers))
+        (display-tower x 0 (tower-pos y (car towers)) (car towers))
+        (display-towers (+ x 20) y (cdr towers)))
        )
   )
 
-(defun display ()
-  (display-stacks 0 20 stacks)
+(define top 0)
+                                       ; Display all of the towers, then move the cursor
+                                       ; out of the way and flush the output
+
+(define (display-hanoi)
+  (display-towers 0 top towers)
   (move-to 1 21)
-  (flush)
+  (flush-output)
   )
 
-(defun length (l)
-  (cond (l (1+ (length (cdr l)))) (0))
-  )
+                                       ; Reset towers to the starting state, with
+                                       ; all of the pieces in the first tower and the
+                                       ; other two empty
 
-(defun reset-stacks ()
-  (setq stacks (list stack nil nil))
-  (length stack)
+(define (reset-towers)
+  (set! towers (list tower () ()))
+  (set! top (+ (length tower) 3))
+  (length tower)
   )
 
-(defun min (a b)
-  (cond ((< a b) a)
-       (b)
-       )
-  )
-
-(defun nth (list n)
-  (cond ((= n 0) (car list))
-       ((nth (cdr list) (1- n)))
-       )
-  )
+                                       ; Replace a tower in the list of towers
+                                       ; with a new value
 
-(defun replace (list pos member)
+(define (replace list pos member)
   (cond ((= pos 0) (cons member (cdr list)))
-       ((cons (car list) (replace (cdr list) (1- pos) member)))
+       (else (cons (car list) (replace (cdr list) (one- pos) member)))
        )
   )
 
-(defun move-piece (from to)
-  (let ((from-stack (nth stacks from))
-       (to-stack (nth stacks to))
-       (piece (car from-stack)))
-    (setq from-stack (cdr from-stack))
-    (setq to-stack (cons piece to-stack))
-    (setq stacks (replace stacks from from-stack))
-    (setq stacks (replace stacks to to-stack))
-    (display)
-    (delay 100)
+                                       ; Move a piece from the top of one tower
+                                       ; to the top of another
+
+(define move-delay 10)
+
+(define (move-piece from to)
+  (let* ((from-tower (list-ref towers from))
+        (to-tower (list-ref towers to))
+        (piece (car from-tower)))
+    (set! from-tower (cdr from-tower))
+    (set! to-tower (cons piece to-tower))
+    (set! towers (replace towers from from-tower))
+    (set! towers (replace towers to to-tower))
+    (display-hanoi)
+    (delay move-delay)
     )
   )
 
-(defun _hanoi (n from to use)
+; The implementation of the game
+
+(define (_hanoi n from to use)
   (cond ((= 1 n)
-        (progn
-         (move-piece from to)
-         nil)
+        (move-piece from to)
         )
-       (t
-        (progn
-         (_hanoi (1- n) from use to)
-         (_hanoi 1 from to use)
-         (_hanoi (1- n) use to from)
-         )
+       (else
+        (_hanoi (one- n) from use to)
+        (_hanoi 1 from to use)
+        (_hanoi (one- n) use to from)
         )
        )
   )
 
-(defun hanoi ()
-  (setq len (reset-stacks))
-  (clear)
-  (_hanoi len 0 1 2)
+                                       ; A pretty interface which
+                                       ; resets the state of the game,
+                                       ; clears the screen and runs
+                                       ; the program
+
+(define (hanoi)
+  (let ((len (reset-towers)))
+    (clear)
+    (_hanoi len 0 1 2)
+    (move-to 0 23)
+    #t
+    )
+  )
   )