spacepaste

  1.  
  2. ; ★ CSC 104 Fall 2018 Project 1 ★
  3. ; ================================
  4. ; ★★★ READ EVERYTHING CAREFULLY, IN ORDER ★★★
  5. ; This program will animate the creation of a maze, visualized as cutting a path through
  6. ; a grid of trees.
  7. ; The program has five sections:
  8. ; Drawing the Maze (40% of mark)
  9. ; Maze Generation Algorithm (40% of mark)
  10. ; Moving Kat (10% of mark)
  11. ; Path Finding (10% of mark)
  12. ; Launch the Animation
  13. ; The first four sections contain places where you need to write or fix a check-expect,
  14. ; or fix a function. Those places are marked with a ‘★’.
  15. ; When you start working on a function (or a check-expect for it), uncomment any check-expects
  16. ; for that function that we have already provided.
  17. ; Each function that you need to fix has an incorrect implementation. Sometimes the incorrect
  18. ; implementation is a hint, but most of the time it is there just so that the program is likely
  19. ; to run without crashing: run this program now, and a window should appear with a purple
  20. ; background and a small cat girl figure. When you complete a section, some new meaningful
  21. ; behaviour will be noticeable.
  22. ; The Grid
  23. ; --------
  24. ; The grid of trees has dimensions size × size, where the size is set by the following variable:
  25. (define size 10)
  26. ; For example, if the size were 3, the initial grid would be 3 × 3, and be drawn as:
  27. #;.
  28. ; We'll refer to a position in the grid as a “point” in the grid.
  29. ; There are nine points in that example grid.
  30. ; We'll assume the size has been set to a number that's at least three, since some of the
  31. ; check-expects below rely on that.
  32. ; Representation
  33. ; --------------
  34. ; A point in the grid has an X co-ordinate and a Y co-ordinate.
  35. ; The top-left point in the grid is at X = 0, Y = 0.
  36. ; The bottom-right point in the grid is at X = size - 1, Y = size - 1
  37. ; (computer graphics usually treats downward as the positive y direction).
  38. ; We'll represent a point as a list of two integers.
  39. ; When making a list representing a point, use the following alias to make the intent clear:
  40. (define point list)
  41. ; When extracting the first and second element of a point, use the following aliases:
  42. (define X first)
  43. (define Y second)
  44. ; A cleared part of the grid will be represented as a list of points.
  45. ; For example, the following represents a small “L” shaped path in the grid:
  46. #;(list (point 0 1)
  47. (point 0 0)
  48. (point 1 2)
  49. (point 0 2))
  50. ; If the size of the grid were 3, that would be drawn as:
  51. #;.
  52. ; Drawing The Maze
  53. ; ================
  54. (define barrier (render (scale . 1/4)))
  55. ; floor-piece : function color → image
  56. ; ------------------------------------
  57. ; This function produces a shape of a particular color, with the same dimensions as ‘barrier’.
  58. #;(check-expect (floor-piece rectangle "brown") .)
  59. #;(check-expect (floor-piece ellipse "orange") .)
  60. ; ★ Write a Partial (or Full) Design check-expect for floor-piece:
  61. (check-expect (floor-piece rectangle "brown") .)
  62. (check-expect (floor-piece ellipse "orange") .)
  63. ; ★ Fix floor-piece:
  64. (define
  65. (floor-piece shape color)
  66. (shape 25 28 "solid" color))
  67. (define ground (floor-piece rectangle "brown"))
  68. (define invisible (floor-piece rectangle "transparent"))
  69. (define highlight (overlay (shrink (floor-piece ellipse (list 100 100 0 25)))
  70. invisible))
  71. ; xs : list-of-points → list-of-numbers
  72. ; -------------------------------------
  73. ; This function extracts the X co-ordinates of a list of points.
  74. #;(check-expect (xs (list (point 1 2) (point 3 4) (point 1 5)))
  75. (list 1 3 1))
  76. ; ★ Write a Partial (or Full) Design check-expect for xs:
  77. (check-expect (xs (list (point 1 2) (point 3 4) (point 1 5)))
  78. (list 1 3 1))
  79. ; ★ Fix xs:
  80. (define (xs points)
  81. (map X points))
  82. ; row : number list-of-points → list-of-points
  83. ; --------------------------------------------
  84. ; This function extracts the points that have a particular Y co-ordinate, from a list of points.
  85. #;(check-expect (row (list (point 1 2) (point 3 4) (point 2 2)) 2)
  86. (list (point 1 2) #;(point 3 4) (point 2 2)))
  87. #;(check-expect (row (list (point 1 2) (point 3 4) (point 2 2)) 2)
  88. (local [(define (y? a-point)
  89. (= (Y a-point) 2))]
  90. (list (point 1 2) #;(point 3 4) (point 2 2))))
  91. ; ★ Write a Full Design check-expect for row:
  92. (check-expect (row (list (point 1 2) (point 3 4) (point 2 2)) 2)
  93. (list (point 1 2) #;(point 3 4) (point 2 2)))
  94. (check-expect (row (list (point 1 2) (point 3 4) (point 2 2)) 2)
  95. (local [(define (y? a-point)
  96. (= (Y a-point) 2))]
  97. (list (point 1 2) #;(point 3 4) (point 2 2))))
  98. ; ★ Fix row:
  99. (define (row points y)
  100. (local [(define (y? a-point)
  101. (= (Y a-point) y))]
  102. (sift y? points)))
  103. ; xs->image : number list-of-numbers image image → image
  104. ; -----------------------------------------------------
  105. ; This function draws a row of foreground and background images, with a given total number of images,
  106. ; and a list of which images (numbered left to right as 0, 1, 2, ...) are the foreground ones.
  107. #;(check-expect (xs->image 4 (list 2 0) ground barrier) .)
  108. #;(check-expect (xs->image 4 (list 2 0) ground barrier) (beside ground barrier ground barrier))
  109. #;(check-expect (xs->image 4 (list 2 0) ground barrier)
  110. (local [(define (represent x)
  111. (if [(element? x (list 2 0)) ground]
  112. [else barrier]))]
  113. (beside (represent 0) (represent 1) (represent 2) (represent 3))))
  114. ; ★ Write a Fuller (or Full) Design check-expect for xs->image:
  115. (check-expect (xs->image 4 (list 2 0) ground barrier) .)
  116. (check-expect (xs->image 4 (list 2 0) ground barrier) (beside ground barrier ground barrier))
  117. (check-expect (xs->image 4 (list 2 0) ground barrier)
  118. (local [(define (represent x)
  119. (if [(element? x (list 2 0)) ground]
  120. [else barrier]))]
  121. (beside (represent 0) (represent 1) (represent 2) (represent 3))))
  122. ; ★ Fix xs->image:
  123. (define (xs->image total some-xs foreground background)
  124. (local [(define (represent x)
  125. (if [(element? x some-xs) foreground]
  126. [else background]))](apply beside(map represent(range 0 total 1)))))
  127. ; points->image : number list-of-points image image → image
  128. ; ---------------------------------------------------------
  129. ; This function takes a list of points and draws them using a foreground image, filling in
  130. ; the rest of the grid with a background image.
  131. (define (points->image a-size points foreground background)
  132. (local [(define (row->image y)
  133. (xs->image a-size (xs (row points y)) foreground background))]
  134. (apply above (map row->image (range 0 size 1)))))
  135. ; draw-all : list-of-points point point → image
  136. ; ---------------------------------------------
  137. ; This function draws:
  138. ; • the maze
  139. ; • kat at a particular point
  140. ; • the path from kat to a particular point
  141. (define kat (render (scale . 1/4)))
  142. (define (draw-all a-maze kat-point click-point)
  143. (align-overlay "left" "top"
  144. (above (rectangle 0 (* (height barrier) (Y kat-point)) "solid" "transparent")
  145. (beside (rectangle (* (width barrier) (X kat-point)) 0 "solid" "transparent")
  146. kat))
  147. (overlay (points->image size (path a-maze kat-point click-point) highlight invisible)
  148. (points->image size a-maze invisible barrier)
  149. (scale ground size))))
  150. ; Test The Functionality
  151. ; ----------------------
  152. ; Run the program now, and you should see a forest of trees, with a small L-shaped path.
  153. ; Pressing keys should move kat to the right.
  154. ; Clicking in the L-shaped path should highlight the point you clicked with an ellipse.
  155. ; Maze Generation Algorithm
  156. ; =========================
  157. ; The maze (cleared path) will start off containing a single point, for example:
  158. #;(list (point 0 0))
  159. ; Then we'll repeat the following process to grow the maze, adding points to that list:
  160. ;
  161. ; #1. Randomly pick a point that is already in the maze.
  162. ; #2. Randomly pick a point from the four points above, below, left, and right
  163. ; of the point from #1.
  164. ; #3. If that point is:
  165. ; • not already in the maze, and
  166. ; • within the bounds of the grid, and
  167. ; • doesn't connect two points already in the maze
  168. ; then add that point to the maze.
  169. ; The functions below implement that algorithm.
  170. ; in-grid? : point → boolean
  171. ; --------------------------
  172. ; This function determines whether a point (a list containing two integers) is actually
  173. ; within the grid: are the co-ordinates of the point non-negative and at most size - 1 ?
  174. #;(check-expect (in-grid? (point -1 0)) #false)
  175. #;(check-expect (in-grid? (point 3 size)) #false)
  176. #;(check-expect (in-grid? (point 1 2)) #true)
  177. #;(check-expect (in-grid? (point (- size 1) 0)) #true)
  178. ; ★ Turn the following check-expects into Partial (or Full) Designs, by making explicit
  179. ; (at least) the main reason the function produces #false in each case:
  180. #;(check-expect (in-grid? (point -1 0)) #false)
  181. #;(check-expect (in-grid? (point 3 size)) #false)
  182. ; ★ Write a Full Design check-expect for in-grid? (if your previous ones weren't Full Designs):
  183. (check-expect (in-grid? (point -1 0))
  184. (if [(< -1 0) #false]
  185. [(< 0 0) #false]
  186. [(> (- size -1)0) #true]
  187. [(> (- size 0)0) #true]
  188. [(< -1 size) #true]
  189. [(< 0 size) #true]
  190. [(< -1 0) #false]
  191. [(< 0 0) #false]
  192. [else #false]))
  193. ; ★ Fix in-grid?:
  194. (define (in-grid? a-point)
  195. (if [(< (X a-point) 0) #false]
  196. [(< (Y a-point) 0) #false]
  197. [(> (- size (X a-point))0) #true]
  198. [(> (- size (Y a-point))0) #true]
  199. [(< (X a-point) size) #true]
  200. [(< (Y a-point) size) #true]
  201. [else #false]))
  202. ; neighbours : point → list-of-points
  203. ; -----------------------------------
  204. ; This function produces a list of the four points above, below, left, and right of a point.
  205. #;(check-expect (neighbours (point 3 7))
  206. (local [(define x 3)
  207. (define y 7)]
  208. (list (point x 6)
  209. (point x 8)
  210. (point 2 y)
  211. (point 4 y))))
  212. ; ★ Turn the following check-expect into a Fuller (or Full) Design:
  213. #;(check-expect (neighbours (point 3 7))
  214. (local [(define x 3)
  215. (define y 7)]
  216. (list (point x 6)
  217. (point x 8)
  218. (point 2 y)
  219. (point 4 y))))
  220. ; ★ Write a Full Design check-expect for neighbours (if your previous one wasn't a Full Design):
  221. ; ★ Fix ‘neighbours’:
  222. (define (neighbours a-point)
  223. (local [(define x (X a-point))
  224. (define y (Y a-point))]
  225. (list (point x (- y 1 ))
  226. (point x (+ y 1))
  227. (point (- x 1) y)
  228. (point (+ x 1)y))))
  229. ; intersection : list list → list
  230. ; -------------------------------
  231. ; This function takes two lists and produces the list of elements from the first list
  232. ; that are also in the second list.
  233. #;(check-expect (intersection (list "ant" "bee" "cat" "bee" "dog") (list "dog" "eel" "bee"))
  234. (list "bee" "bee" "dog"))
  235. ; ★ Fix the following check-expect, and make it a Full Design (hint: see the function ‘row’):
  236. #;(check-expect (intersection (list "ant" "bee" "cat" "bee" "dog") (list "dog" "eel" "bee"))
  237. (local [(define (in-list-2? e) #true)]
  238. (list #;"ant" "bee" #;"cat" "bee" "dog")))
  239. ; ★ Fix intersection:
  240. (define (intersection list-1 list-2)
  241. (local [(define e list-1)
  242. (define (in-list-2? e)
  243. (element? e list-2))]
  244. (sift in-list-2? list-1)))
  245. ; random-element : list → any
  246. ; ---------------------------
  247. ; This function produces an element randomly chosen from a non-empty list.
  248. #;(check-expect (<= 0 (random-element (range 0 1000 1)) 999)
  249. #true)
  250. #;(check-expect (= (random-element (range 0 1000 1))
  251. (random-element (range 0 1000 1)))
  252. ; Probably:
  253. #false)
  254. #;(check-expect (element? (random-element (list "programming" "is" "fun"))
  255. (list "programming" "is" "fun"))
  256. #true)
  257. ; ★ Fix random-element:
  258. (define (random-element list1)
  259. (element list1 (random (length list1))))
  260. ; random-neighbour : point → point
  261. ; --------------------------------
  262. ; This function produces a random neighbour of a point.
  263. #;(check-expect (element? (random-neighbour (point 123 104)) (list (point 123 103)
  264. (point 123 105)
  265. (point 122 104)
  266. (point 124 104)))
  267. #true)
  268. ; ★ Fix random-neighbour:
  269. (define (random-neighbour a-point)
  270. (random-element (neighbours a-point)))
  271. ; bridge? : point list-of-points → boolean
  272. ; ----------------------------------------
  273. ; This function determines whether adding a point to a list-of-points creates a “bridge”:
  274. ; does it connect two or more points in the list-of-points?
  275. #;(check-expect (bridge? (point 3 4)
  276. (list (point 1 2)
  277. (point 3 3) ; one of the neighbours of (point 3 4)
  278. (point 4 5)
  279. (point 2 4))) ; one of the neighbours of (point 3 4))
  280. ; (point 3 4) touches, so connects, (point 3 3) and (point 2 4)
  281. #true)
  282. #;(check-expect (bridge? (point 3 4)
  283. (list (point 1 2)
  284. (point 3 3)
  285. (point 4 5)
  286. (point 3 2)))
  287. #false)
  288. #;(check-expect (bridge? (point 3 4)
  289. (list (point 1 2)
  290. (point 3 3)
  291. (point 4 5)
  292. (point 2 4)))
  293. (>= (length (list (list 3 3) #;(list 3 5) (list 2 4) #;(list 4 4)))
  294. 2))
  295. ; ★ Write a Fuller (or Full) Design check-expect:
  296. ; ★ Write a Full Design check-expect (if your previous one wasn't a Full Design):
  297. ; ★ Fix bridge?:
  298. (define (bridge? a-point points)
  299. (element? a-point (apply join (map neighbours (join points)))))
  300. ; maybe-attach : point list-of-points → list-of-points
  301. ; ----------------------------------------------------
  302. ; This function checks the three conditions mentioned in #3 of the maze generation algorithm,
  303. ; and adds the point to the maze if the three conditions are satisfied, otherwise it just
  304. ; produces the maze unchanged.
  305. #;(check-expect (maybe-attach (point 1 2)
  306. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  307. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  308. #;(check-expect (maybe-attach (point -1 2)
  309. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  310. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  311. #;(check-expect (maybe-attach (point 1 1)
  312. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  313. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  314. #;(check-expect (maybe-attach (point 2 2)
  315. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  316. (list (point 2 2) (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  317. ; ★ Write a Partial (or Full) Design check-expect for the case covered by the previous check-expect:
  318. ; ★ Fix maybe-attach:
  319. (define (maybe-attach a-point a-maze)
  320. (if [(same? (and (bridge? a-point a-maze)
  321. (not(element? a-point a-maze)))
  322. #true)
  323. (adjoin a-point a-maze)]
  324. [else a-maze]))
  325. ; try-grow : list-of-points → list-of-points
  326. ; ------------------------------------------
  327. ; This function tries to grow the maze by maybe attaching a random neighbour of a random point
  328. ; in the maze, trying again if that point doesn't attach, with a small probability of giving up.
  329. (define (try-grow a-maze)
  330. (local [(define new-maze (maybe-attach (random-neighbour (random-element a-maze)) a-maze))]
  331. (if [(and (same? a-maze new-maze)
  332. (positive? (random (squared size))))
  333. (try-grow a-maze)]
  334. [else new-maze])))
  335. ; The following has a large probability of being correct:
  336. #;(check-expect (local [(define small-maze (try-grow (list (point 0 0))))]
  337. (and (= (length small-maze) 2)
  338. (element? (point 0 0) small-maze)
  339. (or (element? (point 0 1) small-maze)
  340. (element? (point 1 0) small-maze))))
  341. #true)
  342. ; Unless size is small, the following produces a list of ten mazes, growing by one point each time:
  343. #;(repeats try-grow (list (point 0 0)) 10)
  344. ; Moving Kat Around
  345. ; =================
  346. ; This part lets you move kat around the maze, by pressing the arrow keys on your keyboard.
  347. ; The big-bang expression at the end of the program is set up to use the function move.
  348. ; move : point text list-of-points → point
  349. ; ----------------------------------------
  350. ; This function helps react to pressing a key on the keyboard.
  351. ; It takes a point, a text representing a key, and a maze.
  352. ; If the text represents one of the arrow keys, and the point in that direction is in the maze,
  353. ; then produce that point, otherwise produce the original point.
  354. #;(check-expect (move (point 0 2) "up"
  355. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  356. (point 0 1))
  357. #;(check-expect (move (point 0 2) "down"
  358. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  359. (point 0 2))
  360. #;(check-expect (move (point 0 2) "left"
  361. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  362. (point 0 2))
  363. #;(check-expect (move (point 0 2) "right"
  364. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  365. (point 1 2))
  366. #;(check-expect (move (point 0 2) "cat"
  367. (list (point 0 1) (point 0 0) (point 1 2) (point 0 2)))
  368. (point 0 2))
  369. ; ★ Write Partial Design check-expects for the two check-expect examples above
  370. ; with "up" and "right":
  371. ; ★ Fix move:
  372. (define (move a-point key maze)
  373. (local[(define(maze? a-point maze)(element? a-point maze))]
  374. (if[(and(same? key "right")(maze?(point(+(X a-point) 1)(Y a-point))maze))(point (+ (X a-point) 1)(Y a-point))]
  375. [(and(same? key "left")(maze?(point(-(X a-point) 1)(Y a-point))maze))(point (- (X a-point) 1)(Y a-point))]
  376. [(and(same? key "up")(maze?(point (X a-point) (- (Y a-point)1))maze))(point (+ (X a-point) 1)(Y a-point))]
  377. [(and(same? key "down")(maze?(point(X a-point) (+ (Y a-point)1))maze))(point (+ (X a-point) 1)(Y a-point))]
  378. [else (point (X a-point)(Y a-point))])))
  379. ; Path Finding
  380. ; ============
  381. ; This part requires is considerably more difficult than the rest of the project.
  382. ; The big-bang expression is set up to keep track of the last point in the grid that was clicked
  383. ; with the mouse, via the function click-point. And draw-all draws the path from that point to
  384. ; kat, via the function path.
  385. ; click-point: point number number text → point
  386. ; ---------------------------------------------
  387. ; This function helps react to clicking on the grid.
  388. ; It takes a point representing the last place the mouse was clicked, the new click's co-ordinates,
  389. ; and a text describing whether it's in fact a mouse click (versus, for example, a drag action).
  390. ; If it's the right type of action, the point in the grid representing the mouse location is produced,
  391. ; otherwise the previous point is produced.
  392. (define (click-point previous-point x y type)
  393. (if [(same? type "button-down") (point (quotient x (width barrier))
  394. (quotient y (height barrier)))]
  395. [else previous-point]))
  396. ; path : list-of-points point point
  397. ; ---------------------------------
  398. ; For any two points in the generated maze, there is exactly one non-backtracking path connecting
  399. ; the two points. The following describes a function to find such a connecting path. It works more
  400. ; generally on parts of mazes, since that turns out to allow a simpler recursive implementation.
  401. #;(path sub-maze from to)
  402. ; For part of a maze sub-maze, and a point end-point within it, with at most one path from
  403. ; start-point to end-point within sub-maze, produce the list of points connecting start-point
  404. ; to end-point. If there is no such path, produce the empty list.
  405. ; The approach:
  406. ; If start-point and end-point are the same point, the path contains exactly that point.
  407. ; Otherwise, if start-point is in the sub-maze, then the path, if there is one, continues from
  408. ; one of the neighbours and is within the partial maze with start-point removed. If one of
  409. ; those four neighbours produces a (non-empty) path then adding start-point to that path
  410. ; produces the whole path.
  411. ; Otherwise, we know already that there is no path.
  412. ; One of the simple cases:
  413. #;(check-expect (path (list (point 0 0) (point 0 1) (point 1 1) (point 1 2))
  414. (point 0 1)
  415. (point 0 1))
  416. (list (point 0 1)))
  417. ; Another kind of simple case:
  418. #;(check-expect (path (list (point 0 0) (point 0 1) (point 1 1) (point 1 2))
  419. (point 1 0)
  420. (point 0 1))
  421. (list))
  422. ; When there's a path from one of the neighbours:
  423. #;(check-expect (path (list (point 0 0) (point 0 1) (point 1 1) (point 1 2))
  424. (point 0 1)
  425. (point 1 2))
  426. (local [(define (rest-of-path a-neighbour)
  427. (path (list (point 0 0) (point 1 1) (point 1 2))
  428. a-neighbour
  429. (point 1 2)))
  430. (define maybe-rest-of-path
  431. (join (rest-of-path (point 0 0))
  432. (rest-of-path (point 0 2))
  433. (rest-of-path (point -1 1))
  434. (rest-of-path (point 1 1))))]
  435. (adjoin (point 0 1) maybe-rest-of-path)))
  436. ; When there's no path from one of the neighbours:
  437. #;(check-expect (path (list (point 0 0) (point 0 1) #;(point 1 1) (point 1 2))
  438. (point 0 1)
  439. (point 1 2))
  440. (local [(define (rest-of-path a-neighbour)
  441. (path (list (point 0 0) (point 1 2))
  442. a-neighbour
  443. (point 1 2)))
  444. (define maybe-rest-of-path
  445. (join (rest-of-path (point 0 0))
  446. (rest-of-path (point 0 2))
  447. (rest-of-path (point -1 1))
  448. (rest-of-path (point 1 1))))]
  449. (list)))
  450. ; ★ Write Full Design check-expects for the two previous non-simple cases:
  451. ; ★ Fix path:
  452. (define (path sub-maze start-point end-point)
  453. (local[(define(rest-of-path a-neighbour)(path (remove start-point sub-maze)a-neighbour end-point))
  454. (define (maybe-rest-of-path x-point)
  455. (apply join (map rest-of-path (neighbours x-point))))]
  456. (if[(not (and (element? start-point sub-maze) (element? end-point sub-maze))) (list)]
  457. [(same? start-point end-point) (list start-point)]
  458. [(>(length (maybe-rest-of-path start-point)) 0) (adjoin start-point (maybe-rest-of-path start-point))]
  459. [else (list)])))
  460. ; Launch the Animation
  461. ; ====================
  462. (define make-state list)
  463. (define maze first)
  464. (define kat-point second)
  465. (define path-point third)
  466. (define (key state a-key)
  467. (make-state (maze state) (move (kat-point state) a-key (maze state)) (path-point state)))
  468. (define (draw state)
  469. (apply draw-all state))
  470. (define (tick state)
  471. (make-state (try-grow (maze state)) (kat-point state) (path-point state)))
  472. (define (click state x y type)
  473. (make-state (maze state) (kat-point state) (click-point (path-point state) x y type)))
  474. (big-bang (make-state (list (point 0 0))
  475. (point 0 0)
  476. (point 0 0))
  477. [to-draw draw]
  478. [on-tick tick]
  479. [on-mouse click]
  480. [on-key key])
  481.