altos/lisp: remove duplicate 'length' lambda from hanoi example
[fw/altos] / src / test / hanoi.lisp
1 ;
2 ; Towers of Hanoi
3 ;
4 ; Copyright © 2016 Keith Packard <keithp@keithp.com>
5 ;
6 ; This program is free software; you can redistribute it and/or modify
7 ; it under the terms of the GNU General Public License as published by
8 ; the Free Software Foundation, either version 2 of the License, or
9 ; (at your option) any later version.
10 ;
11 ; This program is distributed in the hope that it will be useful, but
12 ; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ; General Public License for more details.
15 ;
16
17
18 ; ANSI control sequences
19
20 (defun move-to (col row)
21   (patom "\033[" row ";" col "H" nil)
22   )
23
24 (defun clear ()
25   (patom "\033[2J" nil)
26   )
27
28 (defun display-string (x y str)
29   (move-to x y)
30   (patom str)
31   )
32
33 ; Here's the pieces to display
34
35 (setq stack '("*" "**" "***" "****" "*****" "******" "*******"))
36
37 (setq top (+ (length stack) 3))
38
39 ;
40 ; Here's all of the stacks of pieces
41 ; This is generated when the program is run
42 ;
43 (setq stacks nil)
44
45 ; Display one stack, clearing any
46 ; space above it
47
48 (defun display-stack (x y clear stack)
49   (cond ((= 0 clear)
50          (cond (stack (progn
51                         (display-string x y (car stack))
52                         (display-stack x (1+ y) 0 (cdr stack))
53                         )
54                       )
55                )
56          )
57         (t (progn
58              (display-string x y "          ")
59              (display-stack x (1+ y) (1- clear) stack)
60              )
61            )
62         )
63   )
64
65 ; Position of the top of the stack on the screen
66 ; Shorter stacks start further down the screen
67
68 (defun stack-pos (y stack)
69   (- y (length stack))
70   )
71
72 ; Display all of the stacks, spaced 20 columns apart
73
74 (defun display-stacks (x y stacks)
75   (cond (stacks (progn
76                   (display-stack x 0 (stack-pos y (car stacks)) (car stacks))
77                   (display-stacks (+ x 20) y (cdr stacks)))
78                 )
79         )
80   )
81
82 ; Display all of the stacks, then move the cursor
83 ; out of the way and flush the output
84
85 (defun display ()
86   (display-stacks 0 top stacks)
87   (move-to 1 21)
88   (flush)
89   )
90
91 ; Reset stacks to the starting state, with
92 ; all of the pieces in the first stack and the
93 ; other two empty
94
95 (defun reset-stacks ()
96   (setq stacks (list stack nil nil))
97   (length stack)
98   )
99
100 ; more functions which could usefully
101 ; be in the rom image
102
103 (defun min (a b)
104   (cond ((< a b) a)
105         (b)
106         )
107   )
108
109 (defun nth (list n)
110   (cond ((= n 0) (car list))
111         ((nth (cdr list) (1- n)))
112         )
113   )
114
115 ; Replace a stack in the list of stacks
116 ; with a new value
117
118 (defun replace (list pos member)
119   (cond ((= pos 0) (cons member (cdr list)))
120         ((cons (car list) (replace (cdr list) (1- pos) member)))
121         )
122   )
123
124 ; Move a piece from the top of one stack
125 ; to the top of another
126
127 (defun move-piece (from to)
128   (let ((from-stack (nth stacks from))
129         (to-stack (nth stacks to))
130         (piece (car from-stack)))
131     (setq from-stack (cdr from-stack))
132     (setq to-stack (cons piece to-stack))
133     (setq stacks (replace stacks from from-stack))
134     (setq stacks (replace stacks to to-stack))
135     (display)
136     (delay 100)
137     )
138   )
139
140 ; The implementation of the game
141
142 (defun _hanoi (n from to use)
143   (cond ((= 1 n)
144          (progn
145           (move-piece from to)
146           nil)
147          )
148         (t
149          (progn
150           (_hanoi (1- n) from use to)
151           (_hanoi 1 from to use)
152           (_hanoi (1- n) use to from)
153           )
154          )
155         )
156   )
157
158 ; A pretty interface which
159 ; resets the state of the game,
160 ; clears the screen and runs
161 ; the program
162
163 (defun hanoi ()
164   (setq len (reset-stacks))
165   (clear)
166   (_hanoi len 0 1 2)
167   )