-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevolution-browser.paren
158 lines (129 loc) · 4.86 KB
/
evolution-browser.paren
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
155
156
157
158
(quote
(progn
(lisp-mode)
(trident-mode)
(steal-slime-keys-for-trident!)
)
;; ^^ (C-c m e) Here for interactive development
)
(quote
((ps:getprop console 'log)
"Trident is working as expected in evolution-browser.paren"
)
;; ^^ C-x C-e here and check for console output in the browser to confirm
;; interactive development is working
)
(setf *world-age* 0)
;;; Browser specific functionality
(setf world-element ((@ document "getElementById") "world"))
(setf world-age-element ((@ document "getElementById") "world-age"))
(setf run-button ((@ document "getElementById") "run"))
(setf pause-button ((@ document "getElementById") "pause"))
(setf step-button ((@ document "getElementById") "step"))
(setf (@ world-element rows) (+ 1 *height*))
(setf (@ world-element cols) (+ 2 *width*))
(defun draw-world-browser ()
(setf princ-buffer "")
(draw-world)
(setf (@ world-element value) princ-buffer)
(setf )
)
(defun enter (n)
(setf *running* (+ *world-age* n))
(running-step))
(defun update-world-browser ()
(update-world)
(increment-world-age))
(defun step (&optional (draw t))
(setf *running* nil)
(update-world-browser)
(increment-world-age)
(and draw (draw-world-browser))
(fresh-line))
(setf *running* nil)
(defun run (&optional (steps +infinity))
(setf *running* (+ *world-age* steps))
(running-step))
(setf *world-render-period* 10000)
(setf *world-age-render-period* 100)
(defun running-step (&optional
(world-render-period *world-render-period*)
(world-age-render-period *world-age-render-period*))
(let* ((finished (not (< *world-age* *running*)))
(should-draw-world (or finished
(= 0 (mod *world-age* world-render-period))))
(should-draw-world-age (or finished
(= 0 (mod *world-age* world-age-render-period))))
(drawing-something (or should-draw-world should-draw-world-age)))
(or finished (update-world-browser))
(and should-draw-world (draw-world-browser))
(and should-draw-world-age (draw-world-age))
(or finished
(progn
;; We need to release the main thread for updates, but that's a pretty
;; bad bottleneck when we're running a lot of generations, so setTimeout()
;; when we want to draw
;; Parenscript lacks tail call optimization, so the setTimeout also
;; serves to protect the stack
(if drawing-something
(set-timeout (lambda ()
(running-step world-render-period
world-age-render-period)))
(running-step world-render-period
world-age-render-period))))))
(defun play (&optional (steps +infinity))
(setf *running* (+ *world-age* steps))
(running-step 1 1))
(defun stop ()
(setf *running* nil))
(defun draw-world-age (&optional (age *world-age*))
(and world-age-element
(setf (@ world-age-element "innerText") age)))
(defun increment-world-age ()
(incf *world-age*)
(draw-world-age))
(defun scope-state-name (name)
(+ "evolve:" name))
;;; I should probably fix these to use place semantics
(defun save-item (name value)
((@ local-storage "setItem") (scope-state-name name) ((@ *json* stringify) value))
value)
(defun load-item (name)
((@ *json* parse) (@ local-storage (scope-state-name name))))
(defun create-current-state-object ()
(create world-age *world-age*
animals *animals*
plants *plants*))
(defun save-state (&optional (name "state"))
(save-item name (create-current-state-object)))
(defun load-state (&optional (name "state"))
"Load the named state (default \"state\" and set it as the current world"
(let ((current-state (load-item name)))
(with-slots (world-age animals plants) current-state
(setf *world-age* world-age
*animals* animals
*plants* plants))
(draw-world-browser)
(draw-world-age)
current-state))
(defun without-args (fun)
"Throw away arguments (e.g. if you don't care about the details of an input event)"
(lambda () (fun)))
;; Hook up html buttons
(defun get-element-by-id (id)
((@ document "getElementById") id))
(setf run-for-input-element (get-element-by-id "run-for-input"))
(defun run-for-input-value ()
(run (+Number (@ run-for-input-element value))))
(defun play-for-input-value ()
(play (+Number (@ run-for-input-element value))))
(defun assign-on-click (button-id callback)
(setf (getprop ((@ document "getElementById") button-id) "onclick") callback))
(assign-on-click "play" play)
(assign-on-click "fast-forward" run)
(assign-on-click "stop" stop)
(assign-on-click "step" play-for-input-value)
(assign-on-click "run-for" run-for-input-value)
(assign-on-click "save" (without-args save-state))
(assign-on-click "load" (without-args load-state))
(draw-world-browser)