altos/test: Update to build altos lisp test app
[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                                         ; ANSI control sequences
18
19 (define move-to (lambda (col row)
20                   (for-each display (list "\033[" row ";" col "H"))
21                   )
22   )
23
24 (define clear (lambda ()
25                 (display "\033[2J")
26                 )
27   )
28
29 (define display-string (lambda (x y str)
30                          (move-to x y)
31                          (display str)
32                          )
33   )
34
35                                         ; Here's the pieces to display
36
37 (define tower '("     *     " "    ***    " "   *****   " "  *******  " " ********* " "***********"))
38
39                                         ; Here's all of the towers of pieces
40                                         ; This is generated when the program is run
41
42 (define towers ())
43
44 (define one- (lambda (x) (- x 1)))
45 (define one+ (lambda (x) (+ x 1)))
46                                         ; Display one tower, clearing any
47                                         ; space above it
48
49 (define display-tower (lambda (x y clear tower)
50                         (cond ((= 0 clear)
51                                (cond ((not (null? tower))
52                                       (display-string x y (car tower))
53                                       (display-tower x (one+ y) 0 (cdr tower))
54                                       )
55                                      )
56                                )
57                               (else 
58                                (display-string x y "                   ")
59                                (display-tower x (one+ y) (one- clear) tower)
60                                )
61                               )
62                         )
63   )
64
65                                         ; Position of the top of the tower on the screen
66                                         ; Shorter towers start further down the screen
67
68 (define tower-pos (lambda (y tower)
69                     (- y (length tower))
70                     )
71   )
72
73                                         ; Display all of the towers, spaced 20 columns apart
74
75 (define display-towers (lambda (x y towers)
76                          (cond ((not (null? towers))
77                                 (display-tower x 0 (tower-pos y (car towers)) (car towers))
78                                 (display-towers (+ x 20) y (cdr towers)))
79                                )
80                          )
81   )
82
83 (define top 0)
84                                         ; Display all of the towers, then move the cursor
85                                         ; out of the way and flush the output
86
87 (define display-hanoi (lambda ()
88                         (display-towers 0 top towers)
89                         (move-to 1 21)
90                         (flush-output)
91                         )
92   )
93
94                                         ; Reset towers to the starting state, with
95                                         ; all of the pieces in the first tower and the
96                                         ; other two empty
97
98 (define reset-towers (lambda ()
99                        (set! towers (list tower () ()))
100                        (set! top (+ (length tower) 3))
101                        (length tower)
102                        )
103   )
104
105                                         ; Replace a tower in the list of towers
106                                         ; with a new value
107
108 (define replace (lambda (list pos member)
109                   (cond ((= pos 0) (cons member (cdr list)))
110                         ((cons (car list) (replace (cdr list) (one- pos) member)))
111                         )
112                   )
113   )
114
115                                         ; Move a piece from the top of one tower
116                                         ; to the top of another
117
118 (define move-delay 10)
119
120 (define move-piece (lambda (from to)
121                      (let* ((from-tower (list-ref towers from))
122                            (to-tower (list-ref towers to))
123                            (piece (car from-tower)))
124                        (set! from-tower (cdr from-tower))
125                        (set! to-tower (cons piece to-tower))
126                        (set! towers (replace towers from from-tower))
127                        (set! towers (replace towers to to-tower))
128                        (display-hanoi)
129                        (delay move-delay)
130                        )
131                      )
132   )
133
134 ; The implementation of the game
135
136 (define _hanoi (lambda (n from to use)
137                  (cond ((= 1 n)
138                         (move-piece from to)
139                         )
140                        (else
141                         (_hanoi (one- n) from use to)
142                         (_hanoi 1 from to use)
143                         (_hanoi (one- n) use to from)
144                         )
145                        )
146                  )
147   )
148
149                                         ; A pretty interface which
150                                         ; resets the state of the game,
151                                         ; clears the screen and runs
152                                         ; the program
153
154 (define hanoi (lambda ()
155                 (let ((len))
156                   (set! len (reset-towers))
157                   (clear)
158                   (_hanoi len 0 1 2)
159                   (move-to 0 23)
160                   #t
161                   )
162                 )
163   )