forked from rui314/minilisp
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlife.lsp
154 lines (129 loc) · 3.13 KB
/
life.lsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
;;;
;;; conway's game of life
;;;
;; (progn expr ...)
;; => ((lambda () expr ...))
(defmacro progn (expr . rest)
(list (cons 'lambda (cons () (cons expr rest)))))
(defun list (x . y)
(cons x y))
(defun not (x)
(if x () T))
;; (let var val body ...)
;; => ((lambda (var) body ...) val)
(defmacro let (var val . body)
(cons (cons 'lambda (cons (list var) body))
(list val)))
;; (and e1 e2 ...)
;; => (if e1 (and e2 ...))
;; (and e1)
;; => e1
(defmacro and (expr . rest)
(if rest
(list 'if expr (cons 'and rest))
expr))
;; (or e1 e2 ...)
;; => (let <tmp> e1
;; (if <tmp> <tmp> (or e2 ...)))
;; (or e1)
;; => e1
;;
;; the reason to use the temporary variables is to avoid evaluating the
;; arguments more than once.
(defmacro or (expr . rest)
(if rest
(let var (gensym)
(list 'let var expr
(list 'if var var (cons 'or rest))))
expr))
;; (when expr body ...)
;; => (if expr (progn body ...))
(defmacro when (expr . body)
(cons 'if (cons expr (list (cons 'progn body)))))
;; (unless expr body ...)
;; => (if expr () body ...)
(defmacro unless (expr . body)
(cons 'if (cons expr (cons () body))))
;;;
;;; numeric operators
;;;
(defun <= (e1 e2)
(or (< e1 e2)
(= e1 e2)))
;;;
;;; list operators
;;;
;;; applies each element of lis to fn, and returns their return values as a list.
(defun map (lis fn)
(when lis
(cons (fn (car lis))
(map (cdr lis) fn))))
;; returns nth element of lis.
(defun nth (lis n)
(if (= n 0)
(car lis)
(nth (cdr lis) (- n 1))))
;; returns the nth tail of lis.
(defun nth-tail (lis n)
(if (= n 0)
lis
(nth-tail (cdr lis) (- n 1))))
;; returns a list consists of m .. n-1 integers.
(defun %iota (m n)
(unless (<= n m)
(cons m (%iota (+ m 1) n))))
;; returns a list consists of 0 ... n-1 integers.
(defun iota (n)
(%iota 0 n))
;;;
;;; main
;;;
(define width 5)
(define height 5)
;; returns location (x, y)'s element.
(defun get (board x y)
(nth (nth board y) x))
;; returns true if location (x, y)'s value is "@".
(defun alive? (board x y)
(and (<= 0 x)
(< x height)
(<= 0 y)
(< y width)
(eq (get board x y) '@)))
;; print out the given board.
(defun print (board)
(if (not board)
'$
(println (car board))
(print (cdr board))))
(defun count (board x y)
(let at (lambda (x y)
(if (alive? board x y) 1 0))
(+ (at (- x 1) (- y 1))
(at (- x 1) y)
(at (- x 1) (+ y 1))
(at x (- y 1))
(at x (+ y 1))
(at (+ x 1) (- y 1))
(at (+ x 1) y)
(at (+ x 1) (+ y 1)))))
(defun next (board x y)
(let c (count board x y)
(if (alive? board x y)
(or (= c 2) (= c 3))
(= c 3))))
(defun run (board)
(while T
(print board)
(println '*)
(let newboard (map (iota height)
(lambda (y)
(map (iota width)
(lambda (x)
(if (next board x y) '@ '_)))))
(setq board newboard))))
(run '((_ _ _ _ _)
(_ _ _ _ _)
(@ @ @ _ _)
(_ _ @ _ _)
(_ @ _ _ _)))