some more reformatting etc, at all levels (and the schememodname went away, again -- will get it back soon with the lifting of requires)

svn: r13649
This commit is contained in:
Eli Barzilay 2009-02-16 02:53:01 +00:00
parent 340035bef7
commit 8f0edfd6d5
3 changed files with 265 additions and 240 deletions

View File

@ -30,8 +30,6 @@ Problems:
build the documentation, ie, this file should eventually be merged
together with ../scribblings/chat-noir.scrbl.
- @chunks in the TOC
- hyperlink bound top-level identifiers to their bindings?

View File

@ -7,8 +7,6 @@
Chat Noir. What a game.
@schememodname[htdp/world]
@chunk[<main>
<init-junk>
<data-definitions>
@ -16,8 +14,8 @@ Chat Noir. What a game.
<everything-else>]
@section{The World}
The main data structure for Chat Noir is @tt{world}.
The main data structure for Chat Noir is @tt{world}.
@chunk[<data-definitions>
(define-struct world (board cat state size mouse-posn h-down?)
@ -26,23 +24,30 @@ The main data structure for Chat Noir is @tt{world}.
It consists of a structure with six fields:
@itemize[
@item{@tt{board}: representing the state of the board as a list of @tt{cell}s, one for each circle on the game. }
@item{@tt{cat}:
a @scheme[posn] indicating the position of the cat (interpreting the @scheme[posn] in the way
that they are interpreted for the @tt{board} field),}
@item{@tt{board}: representing the state of the board as a list of
@tt{cell}s, one for each circle on the game. }
@item{@tt{cat}: a @scheme[posn] indicating the position of the cat
(interpreting the @scheme[posn] in the way that they are interpreted
for the @tt{board} field),}
@item{@tt{state}: the state of the game, which can be one of
@itemize{
@item{@scheme['playing], indicating that the game is still going; this is the initial state.
}
@item{@scheme['cat-won], indicating that the game is over and the cat won, or}
@item{@scheme['cat-lost], indicating that the game is over and the cat lost.}}
}
@itemize[
@item{@scheme['playing], indicating that the game is still going; this is the
initial state.}
@item{@scheme['cat-won], indicating that the game is over and the
cat won, or}
@item{@scheme['cat-lost], indicating that the game is over and the
cat lost.}]}
@item{@tt{size}: an odd natural number indicating the size of the board}
@item{@tt{mouse-posn}:
a @scheme[posn] for the location of the mouse (or @scheme[#f] if the
mouse is not in the window), and}
@item{@tt{h-down?}: a boolean indicating if the @tt{h}
key is being pushed down.}
@item{@tt{mouse-posn}: a @scheme[posn] for the location of the
mouse (or @scheme[#f] if the mouse is not in the window), and}
@item{@tt{h-down?}: a boolean indicating if the @tt{h} key is being
pushed down.}
]
A @tt{cell} is a structure with two fields:
@ -50,50 +55,42 @@ A @tt{cell} is a structure with two fields:
@chunk[<data-definitions>
(define-struct cell (p blocked?) #:transparent)]
The first field contains a @scheme[posn] struct.
The coordinates of the posn indicate a position on the
hexagonal grid.
The @tt{y} field of the @scheme[posn]
refers to the row of the cell, and the
@tt{x} coordinate the position in the row.
This means that, for example,
@scheme[(make-posn 0 1)]
is centered above
@scheme[(make-posn 1 0)] and
@scheme[(make-posn 1 1)]. See @scheme[cell-center-x]
and @scheme[cell-center-y] below for the conversion
of those positions to screen coordinates.
The first field contains a @scheme[posn] struct. The coordinates of
the posn indicate a position on the hexagonal grid. The @tt{y} field
of the @scheme[posn] refers to the row of the cell, and the @tt{x}
coordinate the position in the row. This means that, for example,
@scheme[(make-posn 0 1)] is centered above @scheme[(make-posn 1 0)]
and @scheme[(make-posn 1 1)]. See @scheme[cell-center-x] and
@scheme[cell-center-y] below for the conversion of those positions to
screen coordinates.
The @tt{blocked?} field is a boolean indicating if
the cell has been clicked on, thus blocking the cat
from stepping there.
The @tt{blocked?} field is a boolean indicating if the cell has been
clicked on, thus blocking the cat from stepping there.
@section{Graph}
The cat's move decision is based on a breadth-first
search of a graph. The graph's nodes are the cells
on the board, and there are edges between each pair
of adjacent cells, unless one of the cells is blocked,
in which case there are no edges.
The cat's move decision is based on a breadth-first search of a graph.
The graph's nodes are the cells on the board, and there are edges
between each pair of adjacent cells, unless one of the cells is
blocked, in which case there are no edges.
The breadth-first function constructs a @scheme[distance-map],
which is a list of @scheme[dist-cell] structs:
The breadth-first function constructs a @scheme[distance-map], which
is a list of @scheme[dist-cell] structs:
@chunk[<graph>
(define-struct dist-cell (p n) #:transparent)]
Each @tt{p} field in the @scheme[dist-cell] is a position on the board
and the @tt{n} field is a natural number or @scheme['], indicating
the distance of the shortest path from the node to some fixed point
on the board. The fixed point is not represented in the @scheme[distance-map], but
is required when constructing one.
the distance of the shortest path from the node to some fixed point on
the board. The fixed point is not represented in the
@scheme[distance-map], but is required when constructing one.
The core of the breadth-first search is this function,
@scheme[bst]. It accepts a @scheme[queue] and a
@chunk[<bfs>
(define (bfs queue dist-table)
(cond
[(empty? queue) dist-table]
@ -103,8 +100,8 @@ The core of the breadth-first search is this function,
[(boolean? (hash-ref dist-table (queue-ent-posn hd) #f))
(local [(define dist (queue-ent-dist hd))
(define p (queue-ent-posn hd))]
(bfs
(append (rest queue)
(bfs
(append (rest queue)
(map (lambda (p) (make-queue-ent p (+ dist 1)))
(neighbors/w p)))
(hash-set dist-table p dist)))]
@ -113,7 +110,7 @@ The core of the breadth-first search is this function,
@chunk[<graph>
;; a distance-map is
;; a distance-map is
;; (listof dist-cells)
;; a dist-cell is
@ -126,12 +123,12 @@ The core of the breadth-first search is this function,
(local [;; posn : posn
;; dist : number
(define-struct queue-ent (posn dist) #:transparent)
(define neighbors/w (neighbors world))
<bfs>]
(hash-map
(hash-map
(bfs (list (make-queue-ent init-point 0))
(make-immutable-hash/list-init))
make-dist-cell)))
@ -149,41 +146,43 @@ The core of the breadth-first search is this function,
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(check-expect (same-sets?
(build-bfs-table (make-world (empty-board 3) (make-posn 1 1) 'playing 3 (make-posn 0 0) false)
(check-expect (same-sets?
(build-bfs-table (make-world (empty-board 3) (make-posn 1 1)
'playing 3 (make-posn 0 0) false)
'boundary)
(list
(make-dist-cell 'boundary 0)
(make-dist-cell (make-posn 1 0) 1)
(make-dist-cell (make-posn 2 0) 1)
(make-dist-cell (make-posn 0 1) 1)
(make-dist-cell (make-posn 1 1) 2)
(make-dist-cell (make-posn 2 1) 1)
(make-dist-cell (make-posn 1 2) 1)
(make-dist-cell (make-posn 2 2) 1)))
true)
(check-expect (same-sets?
(build-bfs-table (make-world (empty-board 3) (make-posn 1 1) 'playing 3 (make-posn 0 0) false)
(check-expect (same-sets?
(build-bfs-table (make-world (empty-board 3) (make-posn 1 1)
'playing 3 (make-posn 0 0) false)
(make-posn 1 1))
(list
(make-dist-cell 'boundary 2)
(make-dist-cell (make-posn 1 0) 1)
(make-dist-cell (make-posn 2 0) 1)
(make-dist-cell (make-posn 0 1) 1)
(make-dist-cell (make-posn 1 1) 0)
(make-dist-cell (make-posn 2 1) 1)
(make-dist-cell (make-posn 1 2) 1)
(make-dist-cell (make-posn 2 2) 1)))
true)
(check-expect (same-sets?
(check-expect (same-sets?
(build-bfs-table (make-world (list
(make-cell (make-posn 0 1) true)
(make-cell (make-posn 1 0) true)
@ -202,7 +201,7 @@ The core of the breadth-first search is this function,
(make-dist-cell 'boundary 0)))
true)
(check-expect (same-sets?
(check-expect (same-sets?
(build-bfs-table (make-world (empty-board 5)
(make-posn 2 2)
'playing
@ -217,13 +216,13 @@ The core of the breadth-first search is this function,
(make-dist-cell (make-posn 2 0) 1)
(make-dist-cell (make-posn 3 0) 1)
(make-dist-cell (make-posn 4 0) 1)
(make-dist-cell (make-posn 0 1) 1)
(make-dist-cell (make-posn 1 1) 2)
(make-dist-cell (make-posn 2 1) 2)
(make-dist-cell (make-posn 3 1) 2)
(make-dist-cell (make-posn 4 1) 1)
(make-dist-cell (make-posn 0 2) 1)
(make-dist-cell (make-posn 1 2) 2)
(make-dist-cell (make-posn 2 2) 3)
@ -236,14 +235,13 @@ The core of the breadth-first search is this function,
(make-dist-cell (make-posn 3 3) 2)
(make-dist-cell (make-posn 4 3) 1)
(make-dist-cell (make-posn 1 4) 1)
(make-dist-cell (make-posn 2 4) 1)
(make-dist-cell (make-posn 3 4) 1)
(make-dist-cell (make-posn 4 4) 1)))
true)
(check-expect (same-sets?
(check-expect (same-sets?
(build-bfs-table (make-world (block-cell
(make-posn 4 2)
(empty-board 5))
@ -260,13 +258,13 @@ The core of the breadth-first search is this function,
(make-dist-cell (make-posn 2 0) 1)
(make-dist-cell (make-posn 3 0) 1)
(make-dist-cell (make-posn 4 0) 1)
(make-dist-cell (make-posn 0 1) 1)
(make-dist-cell (make-posn 1 1) 2)
(make-dist-cell (make-posn 2 1) 2)
(make-dist-cell (make-posn 3 1) 2)
(make-dist-cell (make-posn 4 1) 1)
(make-dist-cell (make-posn 0 2) 1)
(make-dist-cell (make-posn 1 2) 2)
(make-dist-cell (make-posn 2 2) 3)
@ -278,14 +276,13 @@ The core of the breadth-first search is this function,
(make-dist-cell (make-posn 3 3) 2)
(make-dist-cell (make-posn 4 3) 1)
(make-dist-cell (make-posn 1 4) 1)
(make-dist-cell (make-posn 2 4) 1)
(make-dist-cell (make-posn 3 4) 1)
(make-dist-cell (make-posn 4 4) 1)))
true)
(check-expect (same-sets?
(check-expect (same-sets?
(build-bfs-table (make-world (empty-board 5)
(make-posn 2 2)
'playing
@ -295,18 +292,18 @@ The core of the breadth-first search is this function,
(make-posn 2 2))
(list
(make-dist-cell 'boundary 3)
(make-dist-cell (make-posn 1 0) 2)
(make-dist-cell (make-posn 2 0) 2)
(make-dist-cell (make-posn 3 0) 2)
(make-dist-cell (make-posn 4 0) 3)
(make-dist-cell (make-posn 0 1) 2)
(make-dist-cell (make-posn 1 1) 1)
(make-dist-cell (make-posn 2 1) 1)
(make-dist-cell (make-posn 3 1) 2)
(make-dist-cell (make-posn 4 1) 3)
(make-dist-cell (make-posn 0 2) 2)
(make-dist-cell (make-posn 1 2) 1)
(make-dist-cell (make-posn 2 2) 0)
@ -319,7 +316,6 @@ The core of the breadth-first search is this function,
(make-dist-cell (make-posn 3 3) 2)
(make-dist-cell (make-posn 4 3) 3)
(make-dist-cell (make-posn 1 4) 2)
(make-dist-cell (make-posn 2 4) 2)
(make-dist-cell (make-posn 3 4) 2)
@ -339,7 +335,7 @@ The core of the breadth-first search is this function,
;; lookup-in-table : distance-map posn -> number or '∞
;; looks for the distance as recorded in the table t,
;; looks for the distance as recorded in the table t,
;; if not found returns a distance of '∞
(define (lookup-in-table t p)
(cond
@ -360,14 +356,14 @@ The core of the breadth-first search is this function,
;; p : world -> posn -> boolean
;; returns true when the posn is on the shortest path
;; returns true when the posn is on the shortest path
;; from the cat to the edge of the board, in the given world
(define (on-cats-path? w)
(cond
[(world-h-down? w)
(local [(define edge-distance-map (build-bfs-table w 'boundary))
(define cat-distance-map (build-bfs-table w (world-cat w)))
(define cat-distance (lookup-in-table edge-distance-map
(define cat-distance (lookup-in-table edge-distance-map
(world-cat w)))]
(cond
[(equal? cat-distance ')
@ -380,13 +376,16 @@ The core of the breadth-first search is this function,
[else
(lambda (p) false)]))
(check-expect ((on-cats-path? (make-world (empty-board 5) (make-posn 1 1) 'playing 5 (make-posn 0 0) true))
(check-expect ((on-cats-path? (make-world (empty-board 5) (make-posn 1 1)
'playing 5 (make-posn 0 0) true))
(make-posn 1 0))
true)
(check-expect ((on-cats-path? (make-world (empty-board 5) (make-posn 1 1) 'playing 5 (make-posn 0 0) false))
(check-expect ((on-cats-path? (make-world (empty-board 5) (make-posn 1 1)
'playing 5 (make-posn 0 0) false))
(make-posn 1 0))
false)
(check-expect ((on-cats-path? (make-world (empty-board 5) (make-posn 1 1) 'playing 5 (make-posn 0 0) true))
(check-expect ((on-cats-path? (make-world (empty-board 5) (make-posn 1 1)
'playing 5 (make-posn 0 0) true))
(make-posn 2 1))
false)
(check-expect ((on-cats-path?
@ -409,18 +408,19 @@ The core of the breadth-first search is this function,
;; neighbors : world -> (or/c 'boundary posn) -> (listof (or/c 'boundary posn))
;; computes the neighbors of a posn, for a given board size
(define (neighbors w)
(local [(define blocked
(local [(define blocked
(map cell-p
(filter (lambda (c)
(filter (lambda (c)
(or (cell-blocked? c)
(equal? (cell-p c) (world-mouse-posn w))))
(world-board w))))
(define boundary-cells (filter (lambda (p)
(and (not (member p blocked))
(on-boundary? p (world-size w))))
(map cell-p (world-board w))))]
(define boundary-cells
(filter (lambda (p)
(and (not (member p blocked))
(on-boundary? p (world-size w))))
(map cell-p (world-board w))))]
(lambda (p)
(cond
(cond
[(member p blocked)
'()]
[(equal? p 'boundary)
@ -445,14 +445,14 @@ The core of the breadth-first search is this function,
(check-expect ((neighbors (empty-world 11)) (make-posn 2 2))
(adjacent (make-posn 2 2) 11))
(check-expect ((neighbors (empty-world 3)) 'boundary)
(list (make-posn 0 1)
(make-posn 1 0)
(make-posn 1 2)
(make-posn 2 0)
(make-posn 2 1)
(list (make-posn 0 1)
(make-posn 1 0)
(make-posn 1 2)
(make-posn 2 0)
(make-posn 2 1)
(make-posn 2 2)))
(check-expect ((neighbors (empty-world 11)) (make-posn 1 0))
(list 'boundary
(list 'boundary
(make-posn 2 0)
(make-posn 0 1)
(make-posn 1 1)))
@ -489,7 +489,7 @@ The core of the breadth-first search is this function,
;; adjacent : posn number -> (listof posn)
;; returns a list of the posns that are adjacent to
;; returns a list of the posns that are adjacent to
;; `p' on an infinite hex grid
(define (adjacent p board-size)
(local [(define x (posn-x p))
@ -575,7 +575,7 @@ The core of the breadth-first search is this function,
(cond
[(or (equal? x ') (equal? y '))
']
[else
[else
(+ x y)]))
(check-expect (+/f ' ') ')
@ -588,7 +588,7 @@ The core of the breadth-first search is this function,
@chunk[<init-junk>
(require htdp/world lang/posn)
(define-syntax (check-expect stx)
(define-syntax (check-expect stx)
(syntax-case stx ()
[(_ actual expected)
(with-syntax ([line (syntax-line stx)])
@ -615,7 +615,7 @@ The core of the breadth-first search is this function,
check-expects)))
(define (run-check-expects)
(for-each (λ (t) (t))
(for-each (λ (t) (t))
(reverse check-expects)))
(define (make-immutable-hash/list-init [init '()])
@ -665,7 +665,7 @@ The core of the breadth-first search is this function,
;; render-world : world -> image
(define (render-world w)
(chop-whiskers
(overlay (board->image (world-board w)
(overlay (board->image (world-board w)
(world-size w)
(on-cats-path? w)
(world-mouse-posn w))
@ -690,7 +690,7 @@ The core of the breadth-first search is this function,
2
(lambda (x) true)
false)
(move-pinhole thinking-cat
(move-pinhole thinking-cat
(- (cell-center-x (make-posn 0 1)))
(- (cell-center-y (make-posn 0 1))))))
@ -707,7 +707,7 @@ The core of the breadth-first search is this function,
2
(lambda (x) true)
false)
(move-pinhole happy-cat
(move-pinhole happy-cat
(- (cell-center-x (make-posn 0 1)))
(- (cell-center-y (make-posn 0 1))))))
@ -724,7 +724,7 @@ The core of the breadth-first search is this function,
2
(lambda (x) true)
false)
(move-pinhole sad-cat
(move-pinhole sad-cat
(- (cell-center-x (make-posn 0 1)))
(- (cell-center-y (make-posn 0 1))))))
@ -755,7 +755,7 @@ The core of the breadth-first search is this function,
3
(lambda (x) false)
false)
(move-pinhole sad-cat
(move-pinhole sad-cat
(- (cell-center-x (make-posn 1 1)))
(- (cell-center-y (make-posn 1 1))))))
@ -775,7 +775,7 @@ The core of the breadth-first search is this function,
(make-posn (cell-center-x (make-posn 0 1))
(cell-center-y (make-posn 0 1)))
true))
(overlay
(board->image (list
(make-cell (make-posn 0 1) false)
@ -789,17 +789,17 @@ The core of the breadth-first search is this function,
(lambda (x) true)
(make-posn (cell-center-x (make-posn 0 1))
(cell-center-y (make-posn 0 1))))
(move-pinhole sad-cat
(move-pinhole sad-cat
(- (cell-center-x (make-posn 1 1)))
(- (cell-center-y (make-posn 1 1))))))
;; chop-whiskers : image -> image
;; crops the image so that anything above or to the left of the pinhole is gone
(define (chop-whiskers img)
(shrink img
0
(shrink img
0
(- (image-width img) (pinhole-x img) 1)
0
(- (image-width img) (pinhole-x img) 1)
(- (image-height img) (pinhole-y img) 1)))
(check-expect (chop-whiskers (rectangle 5 5 'solid 'black))
@ -809,7 +809,7 @@ The core of the breadth-first search is this function,
(check-expect
(pinhole-x
(render-world
(render-world
(make-world
(empty-board 3)
(make-posn 0 0)
@ -838,15 +838,16 @@ The core of the breadth-first search is this function,
(world-height world-size)
'solid
'white)
(map (lambda (c) (cell->image c
(on-cat-path? (cell-p c))
(and (posn? mouse)
(equal? mouse (cell-p c)))
#;
(and (posn? mouse)
(point-in-this-circle? (cell-p c)
(posn-x mouse)
(posn-y mouse)))))
(map (lambda (c)
(cell->image c
(on-cat-path? (cell-p c))
(and (posn? mouse)
(equal? mouse (cell-p c)))
#;
(and (posn? mouse)
(point-in-this-circle? (cell-p c)
(posn-x mouse)
(posn-y mouse)))))
cs)))
(check-expect (board->image (list (make-cell (make-posn 0 0) false))
@ -927,20 +928,21 @@ The core of the breadth-first search is this function,
(define (cell->image c on-short-path? under-mouse?)
(local [(define x (cell-center-x (cell-p c)))
(define y (cell-center-y (cell-p c)))
(define main-circle
(define main-circle
(cond
[(cell-blocked? c)
(circle circle-radius 'solid blocked-color)]
[else
(circle circle-radius 'solid normal-color)]))]
(move-pinhole
(move-pinhole
(cond
[under-mouse?
(overlay main-circle
(circle (quotient circle-radius 2) 'solid under-mouse-color))]
[on-short-path?
(overlay main-circle
(circle (quotient circle-radius 2) 'solid on-shortest-path-color))]
(circle (quotient circle-radius 2) 'solid
on-shortest-path-color))]
[else
main-circle])
(- x)
@ -956,19 +958,21 @@ The core of the breadth-first search is this function,
(- circle-radius)))
(check-expect (cell->image (make-cell (make-posn 0 0) false) true false)
(move-pinhole (overlay (circle circle-radius 'solid normal-color)
(circle (quotient circle-radius 2) 'solid on-shortest-path-color))
(circle (quotient circle-radius 2) 'solid
on-shortest-path-color))
(- circle-radius)
(- circle-radius)))
(check-expect (cell->image (make-cell (make-posn 0 0) false) true true)
(move-pinhole (overlay (circle circle-radius 'solid normal-color)
(circle (quotient circle-radius 2) 'solid under-mouse-color))
(circle (quotient circle-radius 2) 'solid
under-mouse-color))
(- circle-radius)
(- circle-radius)))
;; world-width : number -> number
;; computes the width of the drawn world in terms of its size
(define (world-width board-size)
(local [(define rightmost-posn
(local [(define rightmost-posn
(make-posn (- board-size 1) (- board-size 2)))]
(+ (cell-center-x rightmost-posn) circle-radius)))
@ -1006,7 +1010,7 @@ The core of the breadth-first search is this function,
(define (cell-center-y p)
(local [(define y (posn-y p))]
(+ circle-radius
(* y circle-spacing 2
(* y circle-spacing 2
.866 ;; .866 is an exact approximate to sin(pi/3)
))))
@ -1043,8 +1047,8 @@ The core of the breadth-first search is this function,
(cond
[(and (equal? 'playing (world-state world))
(point-in-a-circle? (world-board world) x y))
(move-cat
(update-world-posn
(move-cat
(update-world-posn
(make-world (add-obstacle (world-board world) x y)
(world-cat world)
(world-state world)
@ -1099,11 +1103,13 @@ The core of the breadth-first search is this function,
1
(make-posn 0 0)
false))
(check-expect (clack (make-world '() (make-posn 0 0) 'playing 1 (make-posn 0 0) false)
(check-expect (clack (make-world '() (make-posn 0 0)
'playing 1 (make-posn 0 0) false)
1 1 'leave)
(make-world '() (make-posn 0 0) 'playing 1 false false))
(check-expect (clack (make-world '() (make-posn 0 0) 'playing 1 (make-posn 0 0) false)
(check-expect (clack (make-world '() (make-posn 0 0)
'playing 1 (make-posn 0 0) false)
10
10
'button-down)
@ -1116,7 +1122,7 @@ The core of the breadth-first search is this function,
3
(make-posn 0 0)
false)
(cell-center-x (make-posn 0 0))
(cell-center-x (make-posn 0 0))
(cell-center-y (make-posn 0 0))
'button-up)
(make-world (list (make-cell (make-posn 0 0) true)
@ -1128,12 +1134,14 @@ The core of the breadth-first search is this function,
false))
(check-expect (clack (make-world '() (make-posn 0 0) 'cat-lost 1 (make-posn 0 0) false)
(check-expect (clack (make-world '() (make-posn 0 0)
'cat-lost 1 (make-posn 0 0) false)
10
10
'button-up)
(make-world '() (make-posn 0 0) 'cat-lost 1 (make-posn 0 0) false))
(check-expect (clack
(make-world '() (make-posn 0 0)
'cat-lost 1 (make-posn 0 0) false))
(check-expect (clack
(make-world
(list (make-cell (make-posn 1 0) false)
(make-cell (make-posn 2 0) true)
@ -1150,7 +1158,7 @@ The core of the breadth-first search is this function,
(cell-center-x (make-posn 1 0))
(cell-center-y (make-posn 1 0))
'button-up)
(make-world
(make-world
(list (make-cell (make-posn 1 0) true)
(make-cell (make-posn 2 0) true)
(make-cell (make-posn 0 1) true)
@ -1164,7 +1172,7 @@ The core of the breadth-first search is this function,
(make-posn 1 0)
false))
(check-expect (clack
(check-expect (clack
(make-world
(list (make-cell (make-posn 1 0) false)
(make-cell (make-posn 2 0) false)
@ -1181,7 +1189,7 @@ The core of the breadth-first search is this function,
(cell-center-x (make-posn 1 0))
(cell-center-y (make-posn 1 0))
'button-up)
(make-world
(make-world
(list (make-cell (make-posn 1 0) true)
(make-cell (make-posn 2 0) false)
(make-cell (make-posn 0 1) true)
@ -1201,8 +1209,8 @@ The core of the breadth-first search is this function,
[(equal? (world-state w) 'playing)
(cond
[(posn? p)
(local [(define mouse-spot
(circle-at-point (world-board w)
(local [(define mouse-spot
(circle-at-point (world-board w)
(posn-x p)
(posn-y p)))]
(make-world (world-board w)
@ -1224,32 +1232,42 @@ The core of the breadth-first search is this function,
(world-h-down? w))])]
[else w]))
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'playing 1 false false)
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'playing 1 false false)
(make-posn (cell-center-x (make-posn 0 0))
(cell-center-y (make-posn 0 0))))
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'playing 1 (make-posn 0 0) false))
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'playing 1 (make-posn 0 0) false))
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 0) 'playing 1 false false)
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 0) 'playing 1 false false)
(make-posn (cell-center-x (make-posn 0 0))
(cell-center-y (make-posn 0 0))))
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 0) 'playing 1 false false))
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 0) 'playing 1 false false))
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'playing 1 (make-posn 0 0) false)
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'playing 1 (make-posn 0 0) false)
(make-posn 0 0))
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'playing 1 false false))
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'cat-won 1 false false)
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'playing 1 false false))
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'cat-won 1 false false)
(make-posn (cell-center-x (make-posn 0 0))
(cell-center-y (make-posn 0 0))))
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'cat-won 1 false false))
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'cat-lost 1 false false)
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'cat-won 1 false false))
(check-expect (update-world-posn
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'cat-lost 1 false false)
(make-posn (cell-center-x (make-posn 0 0))
(cell-center-y (make-posn 0 0))))
(make-world (list (make-cell (make-posn 0 0) false)) (make-posn 0 1) 'cat-lost 1 false false))
(make-world (list (make-cell (make-posn 0 0) false))
(make-posn 0 1) 'cat-lost 1 false false))
;; move-cat : world -> world
(define (move-cat world)
@ -1267,7 +1285,7 @@ The core of the breadth-first search is this function,
(list-ref next-cat-positions
(random (length next-cat-positions)))]))]
(make-world (world-board world)
(cond
(cond
[(boolean? next-cat-position)
cat-position]
[else next-cat-position])
@ -1288,25 +1306,25 @@ The core of the breadth-first search is this function,
(make-cell (make-posn 2 0) false)
(make-cell (make-posn 3 0) false)
(make-cell (make-posn 4 0) false)
(make-cell (make-posn 0 1) false)
(make-cell (make-posn 1 1) true)
(make-cell (make-posn 2 1) true)
(make-cell (make-posn 3 1) false)
(make-cell (make-posn 4 1) false)
(make-cell (make-posn 0 2) false)
(make-cell (make-posn 1 2) true)
(make-cell (make-posn 2 2) false)
(make-cell (make-posn 3 2) true)
(make-cell (make-posn 4 2) false)
(make-cell (make-posn 0 3) false)
(make-cell (make-posn 1 3) true)
(make-cell (make-posn 2 3) false)
(make-cell (make-posn 3 3) false)
(make-cell (make-posn 4 3) false)
(make-cell (make-posn 1 4) false)
(make-cell (make-posn 2 4) false)
(make-cell (make-posn 3 4) false)
@ -1320,25 +1338,25 @@ The core of the breadth-first search is this function,
(make-cell (make-posn 2 0) false)
(make-cell (make-posn 3 0) false)
(make-cell (make-posn 4 0) false)
(make-cell (make-posn 0 1) false)
(make-cell (make-posn 1 1) true)
(make-cell (make-posn 2 1) true)
(make-cell (make-posn 3 1) false)
(make-cell (make-posn 4 1) false)
(make-cell (make-posn 0 2) false)
(make-cell (make-posn 1 2) true)
(make-cell (make-posn 2 2) false)
(make-cell (make-posn 3 2) true)
(make-cell (make-posn 4 2) false)
(make-cell (make-posn 0 3) false)
(make-cell (make-posn 1 3) true)
(make-cell (make-posn 2 3) false)
(make-cell (make-posn 3 3) false)
(make-cell (make-posn 4 3) false)
(make-cell (make-posn 1 4) false)
(make-cell (make-posn 2 4) false)
(make-cell (make-posn 3 4) false)
@ -1349,7 +1367,8 @@ The core of the breadth-first search is this function,
(make-posn 0 0)
false))
;; find-best-positions : (nelistof posn) (nelistof number or '∞) -> (nelistof posn) or false
;; find-best-positions : (nelistof posn) (nelistof number or '∞)
;; -> (nelistof posn) or false
(define (find-best-positions posns scores)
(local [(define best-score (foldl (lambda (x sofar)
(if (<=/f x sofar)
@ -1390,7 +1409,7 @@ The core of the breadth-first search is this function,
(define (add-obstacle board x y)
(cond
[(empty? board) board]
[else
[else
(local [(define cell (first board))
(define cx (cell-center-x (cell-p cell)))
(define cy (cell-center-y (cell-p cell)))]
@ -1418,7 +1437,7 @@ The core of the breadth-first search is this function,
(define (circle-at-point board x y)
(cond
[(empty? board) false]
[else
[else
(cond
[(point-in-this-circle? (cell-p (first board)) x y)
(cell-p (first board))]
@ -1433,7 +1452,7 @@ The core of the breadth-first search is this function,
0 0)
false)
;; point-in-a-circle? : board number number -> boolean
(define (point-in-a-circle? board x y)
(posn? (circle-at-point board x y)))
@ -1459,7 +1478,7 @@ The core of the breadth-first search is this function,
true)
(check-expect (point-in-this-circle? (make-posn 0 0) 0 0)
false)
;; change : world key-event -> world
(define (change w ke)
(make-world (world-board w)
@ -1469,10 +1488,13 @@ The core of the breadth-first search is this function,
(world-mouse-posn w)
(key=? ke #\h)))
(check-expect (change (make-world '() (make-posn 1 1) 'playing 1 (make-posn 0 0) false)
(check-expect (change (make-world '() (make-posn 1 1)
'playing 1 (make-posn 0 0) false)
#\h)
(make-world '() (make-posn 1 1) 'playing 1 (make-posn 0 0) true))
(check-expect (change (make-world '() (make-posn 1 1) 'playing 1 (make-posn 0 0) true)
(make-world '() (make-posn 1 1)
'playing 1 (make-posn 0 0) true))
(check-expect (change (make-world '() (make-posn 1 1)
'playing 1 (make-posn 0 0) true)
'release)
(make-world '() (make-posn 1 1) 'playing 1 (make-posn 0 0) false))
@ -1502,24 +1524,24 @@ The core of the breadth-first search is this function,
;; cat : symbol -> image
(define (cat mode)
(local [(define face-color
(local [(define face-color
(cond
[(symbol=? mode 'sad) 'pink]
[else 'lightgray]))
(define left-ear (regular-polygon 3 8 'solid 'black (/ pi -3)))
(define right-ear (regular-polygon 3 8 'solid 'black 0))
(define ear-x-offset 14)
(define ear-y-offset 9)
(define eye (overlay (ellipse 12 8 'solid 'black)
(ellipse 6 4 'solid 'limegreen)))
(define eye-x-offset 8)
(define eye-y-offset 3)
(define nose (regular-polygon 3 5 'solid 'black (/ pi 2)))
(define mouth-happy
(define mouth-happy
(overlay (ellipse 8 8 'solid face-color)
(ellipse 8 8 'outline 'black)
(move-pinhole
@ -1530,14 +1552,14 @@ The core of the breadth-first search is this function,
(overlay (ellipse 8 8 'solid face-color)
(ellipse 8 8 'outline face-color)
(rectangle 10 5 'solid face-color)))
(define mouth
(define mouth
(cond
[(symbol=? mode 'happy) mouth-happy]
[else mouth-no-expression]))
(define mouth-x-offset 4)
(define mouth-y-offset -5)]
(add-line
(add-line
(add-line
@ -1618,15 +1640,17 @@ The core of the breadth-first search is this function,
(cond
[(zero? n) all-cells]
[else
(local [(define unblocked-cells
(filter (lambda (x)
(let ([cat-cell? (and (= (posn-x (cell-p x)) (quotient board-size 2))
(= (posn-y (cell-p x)) (quotient board-size 2)))])
(local [(define unblocked-cells
(filter (lambda (x)
(let ([cat-cell? (and (= (posn-x (cell-p x))
(quotient board-size 2))
(= (posn-y (cell-p x))
(quotient board-size 2)))])
(and (not (cell-blocked? x))
(not cat-cell?))))
all-cells))
(define to-block (list-ref unblocked-cells
(define to-block (list-ref unblocked-cells
(random (length unblocked-cells))))]
(add-n-random-blocked-cells
(sub1 n)
@ -1647,9 +1671,13 @@ The core of the breadth-first search is this function,
(make-cell (make-posn 1 1) true)
(make-cell (make-posn 2 2) false)))
(check-expect (add-n-random-blocked-cells 0 (list (make-cell (make-posn 0 0) true)) 10)
(check-expect (add-n-random-blocked-cells 0 (list (make-cell (make-posn 0 0)
true))
10)
(list (make-cell (make-posn 0 0) true)))
(check-expect (add-n-random-blocked-cells 1 (list (make-cell (make-posn 0 0) false)) 10)
(check-expect (add-n-random-blocked-cells 1 (list (make-cell (make-posn 0 0)
false))
10)
(list (make-cell (make-posn 0 0) true)))
;; empty-board : number -> (listof cell)
@ -1666,8 +1694,8 @@ The core of the breadth-first search is this function,
(lambda (i)
(build-list
board-size
(lambda (j)
(make-cell (make-posn i j)
(lambda (j)
(make-cell (make-posn i j)
false))))))))
(check-expect (empty-board 3)
@ -1721,11 +1749,11 @@ The core of the breadth-first search is this function,
board-size
false
false))]
(and
(and
(big-bang (world-width board-size)
(world-height board-size)
1
1
initial-world)
(on-redraw render-world)
(on-key-event change)

View File

@ -11,19 +11,19 @@
(define (mapping-get mapping id)
(free-identifier-mapping-get mapping id (lambda () '())))
;; maps a block identifier to its collected expressions
(define code-blocks (make-free-identifier-mapping))
(define chunks (make-free-identifier-mapping))
;; maps a block identifier to all identifiers that are used to define it
(define block-groups (make-free-identifier-mapping))
(define (get-block id)
(map syntax-local-introduce (mapping-get code-blocks id)))
(map syntax-local-introduce (mapping-get chunks id)))
(define (add-to-block! id exprs)
(unless main-id (set! main-id id))
(free-identifier-mapping-put!
block-groups id
(cons (syntax-local-introduce id) (mapping-get block-groups id)))
(free-identifier-mapping-put!
code-blocks id
`(,@(mapping-get code-blocks id) ,@(map syntax-local-introduce exprs)))))
chunks id
`(,@(mapping-get chunks id) ,@(map syntax-local-introduce exprs)))))
(define-syntax (chunk stx)
(syntax-case stx ()
@ -35,7 +35,7 @@
#f "chunk names must begin and end with angle brackets, <...>"
stx #'name)]
[else (add-to-block! #'name (syntax->list #'(expr ...)))
#`(void)])]))
#'(void)])]))
(define-syntax (tangle stx)
(define block-mentions '())
@ -44,15 +44,15 @@
(append-map
(lambda (expr)
(if (identifier? expr)
(let ([subs (get-block expr)])
(if (pair? subs)
(begin (set! block-mentions (cons expr block-mentions))
(loop subs))
(list expr)))
(let ([subs (syntax->list expr)])
(if subs
(list (loop subs))
(list expr)))))
(let ([subs (get-block expr)])
(if (pair? subs)
(begin (set! block-mentions (cons expr block-mentions))
(loop subs))
(list expr)))
(let ([subs (syntax->list expr)])
(if subs
(list (loop subs))
(list expr)))))
block)))
(with-syntax ([(body ...) body]
;; construct arrows manually
@ -67,34 +67,33 @@
(define-syntax (module-begin stx)
(syntax-case stx ()
[(module-begin expr ...)
(let ([body-code
(let loop ([exprs (syntax->list #'(expr ...))])
(cond
[(null? exprs) null]
[else
(let ([expanded
(local-expand (car exprs)
'module
(append (kernel-form-identifier-list)
(syntax->list #'(provide
require
#%provide
#%require))))])
(syntax-case expanded (begin)
[(begin rest ...)
(append (loop (syntax->list #'(rest ...)))
(loop (cdr exprs)))]
[(id . rest)
(ormap (lambda (kw) (free-identifier=? #'id kw))
(syntax->list #'(require
provide
chunk
#%require
#%provide)))
(cons expanded (loop (cdr exprs)))]
[else (loop (cdr exprs))]))]))])
(with-syntax ([(body-code ...) body-code])
#'(#%module-begin
body-code ...
(tangle))))]))
(with-syntax
([(body-code ...)
(let loop ([exprs (syntax->list #'(expr ...))])
(cond
[(null? exprs) null]
[else
(let ([expanded
(local-expand (car exprs)
'module
(append (kernel-form-identifier-list)
(syntax->list #'(provide
require
#%provide
#%require))))])
(syntax-case expanded (begin)
[(begin rest ...)
(append (loop (syntax->list #'(rest ...)))
(loop (cdr exprs)))]
[(id . rest)
(ormap (lambda (kw) (free-identifier=? #'id kw))
(syntax->list #'(require
provide
chunk
#%require
#%provide)))
(cons expanded (loop (cdr exprs)))]
[else (loop (cdr exprs))]))]))])
#'(#%module-begin
body-code ...
(tangle)))]))