diff --git a/collects/games/chat-noir/README b/collects/games/chat-noir/README
index 5fbbf86504..4d401ef9d8 100644
--- a/collects/games/chat-noir/README
+++ b/collects/games/chat-noir/README
@@ -4,6 +4,9 @@ Games.
Problems:
+ - Run in the module language doesn't seem to work anymore, in that
+ definitions in the literate program don't show up in the REPL.
+
- Need to make 'a-chunk' be a real macro, I expect. (used in
scribble/private/lp.ss)
diff --git a/collects/games/chat-noir/chat-noir-literate.ss b/collects/games/chat-noir/chat-noir-literate.ss
index 5a951e0ff6..532b893805 100644
--- a/collects/games/chat-noir/chat-noir-literate.ss
+++ b/collects/games/chat-noir/chat-noir-literate.ss
@@ -1086,7 +1086,11 @@ the screen resolution.
@section{Handling Input}
+Input handling consists of handling two different kinds of events: key events, and mouse events,
+plus various helper functions.
+
@chunk[
+
@@ -1096,8 +1100,7 @@ the screen resolution.
-
- ]
+ ]
@chunk[
@@ -1109,8 +1112,21 @@ the screen resolution.
]
+The @scheme[change] function handles keyboard input and merely updates the @tt{h-down?} field
+based on the state of the key event.
+
+@chunk[
+ ;; change : world key-event -> world
+ (define (change w ke)
+ (make-world (world-board w)
+ (world-cat w)
+ (world-state w)
+ (world-size w)
+ (world-mouse-posn w)
+ (key=? ke #\h)))]
+
The @scheme[clack] function handles mouse input. It has three tasks and each corresponds
-to a specific helper function:
+to a helper function:
@itemize{
@item{block the clicked cell (@scheme[block-cell/world]),}
@item{move the cat (@scheme[move-cat]), and}
@@ -1140,7 +1156,9 @@ player's move (via the @scheme[player-moved?] function.
The @scheme[player-moved?] predicate returns
a @scheme[posn] indicating where the player chose
to move when the mouse event corresponds to a player move,
-and returns @scheme[#f].
+and returns @scheme[#f]. It first checks to see if the
+mouse event is a button up event and that the game
+is not over, and then it just calls @scheme[circle-at-point].
@chunk[
(define/contract (player-moved? world x y evt)
@@ -1150,6 +1168,71 @@ and returns @scheme[#f].
(equal? 'playing (world-state world))
(circle-at-point (world-board world) x y)))]
+The @scheme[circle-at-point] function returns a @scheme[posn] when
+the coordinate (@scheme[x],@scheme[y]) is inside a circle
+on the given board. Instead of computing the nearest
+circle to the coordinates, it simply iterates over the cells on the
+board and returns the @scheme[posn] of the matching cell.
+
+@chunk[
+ (define/contract (circle-at-point board x y)
+ (-> (listof cell?) real? real?
+ (or/c posn? #f))
+ (ormap (λ (cell)
+ (and (point-in-this-circle? (cell-p cell) x y)
+ (cell-p cell)))
+ board))]
+
+
+The @scheme[point-in-this-circle?] function returns @scheme[#t]
+when the point (@scheme[x],@scheme[y]) on the screen
+falls within the circle located at the @scheme[posn] @scheme[p].
+
+This is precise about checking the circles. For example,
+a point that is (14,14) away from the center of a circle
+is still in the circle:
+
+@chunk[
+ (test (point-in-this-circle?
+ (make-posn 1 0)
+ (+ (cell-center-x (make-posn 1 0)) 14)
+ (+ (cell-center-y (make-posn 1 0)) 14))
+ #t)]
+
+but one that is (15,15) away is no longer in the circle,
+since it crosses the boundary away from a circle of radius
+20 at that point.
+
+@chunk[
+ (test (point-in-this-circle?
+ (make-posn 1 0)
+ (+ (cell-center-x (make-posn 1 0)) 15)
+ (+ (cell-center-y (make-posn 1 0)) 15))
+ #f)]
+
+The implementation of @scheme[point-in-this-circle?] uses
+complex numbers to represent both points on the screen
+and directional vectors. In particular, the
+variable @scheme[center] is a complex number whose
+real part is the @tt{x} coordinate of the center of
+the cell at @scheme[p], and its imaginary part is
+@tt{y} coordinate. Similarly, @scheme[mp] is bound
+to a complex number corresponding to the position of
+the mouse, at (@scheme[x], @scheme[y]). Then, the
+function computes the vector between the two points
+by subtracting the complex numbers from each
+other and extracting the magnitude from that vector.
+
+@chunk[
+ (define/contract (point-in-this-circle? p x y)
+ (-> posn? real? real? boolean?)
+ (let ([center (+ (cell-center-x p)
+ (* (sqrt -1)
+ (cell-center-y p)))]
+ [mp (+ x (* (sqrt -1) y))])
+ (<= (magnitude (- center mp))
+ circle-radius)))]
+
In the event that @scheme[player-moved?] returns a @scheme[posn],
the @scheme[clack] function blocks the clicked on cell using
@scheme[block-cell/world], which simply calls @scheme[block-cell].
@@ -1222,8 +1305,43 @@ position and whether or not the cat won.
(world-mouse-posn world)
(world-h-down? world))]
+
+@chunk[
+ ;; find-best-positions : (nelistof posn) (nelistof number or '∞)
+ ;; -> (nelistof posn) or #f
+ (define (find-best-positions posns scores)
+ (local [(define best-score (foldl (lambda (x sofar)
+ (if (<=/f x sofar)
+ x
+ sofar))
+ (first scores)
+ (rest scores)))]
+ (cond
+ [(symbol? best-score) #f]
+ [else
+ (map
+ second
+ (filter (lambda (x) (equal? (first x) best-score))
+ (map list scores posns)))])))]
+
+
+
+@chunk[
+ ;; <=/f : (number or '∞) (number or '∞) -> boolean
+ (define (<=/f a b)
+ (cond
+ [(equal? b '∞) #t]
+ [(equal? a '∞) #f]
+ [else (<= a b)]))]
+
+
Finally, to complete the mouse event handling, the @scheme[update-world-posn]
-function is called from @scheme[clack]. It updates
+function is called from @scheme[clack]. It updates the @tt{mouse-down}
+field of the @scheme[world]. If the @scheme[p] argument is a @scheme[posn],
+it corresponds to the location of the mouse, in graphical coordinates.
+So, the function converts it to a cell position on the board and uses that.
+Otherwise, when @scheme[p] is @scheme[#f], the @tt{mouse-down} field
+is just updated to @scheme[#f].
@chunk[
(define/contract (update-world-posn w p)
@@ -1253,219 +1371,6 @@ function is called from @scheme[clack]. It updates
#f
(world-h-down? w))]))]
-@chunk[
-
- (test (update-world-posn
- (make-world (list (make-cell (make-posn 0 0) #f))
- (make-posn 0 1) 'playing 3 #f #f)
- (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) #f))
- (make-posn 0 1) 'playing 3 (make-posn 0 0) #f))
-
- (test (update-world-posn
- (make-world (list (make-cell (make-posn 0 0) #f))
- (make-posn 0 0) 'playing 3 #f #f)
- (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) #f))
- (make-posn 0 0) 'playing 3 #f #f))
-
- (test (update-world-posn
- (make-world (list (make-cell (make-posn 0 0) #f))
- (make-posn 0 1) 'playing 3 (make-posn 0 0) #f)
- (make-posn 0 0))
- (make-world (list (make-cell (make-posn 0 0) #f))
- (make-posn 0 1) 'playing 3 #f #f))]
-
-@chunk[
- (test
- (move-cat
- (make-world (list (make-cell (make-posn 1 0) #f)
- (make-cell (make-posn 2 0) #f)
- (make-cell (make-posn 3 0) #f)
- (make-cell (make-posn 4 0) #f)
-
- (make-cell (make-posn 0 1) #f)
- (make-cell (make-posn 1 1) #t)
- (make-cell (make-posn 2 1) #t)
- (make-cell (make-posn 3 1) #f)
- (make-cell (make-posn 4 1) #f)
-
- (make-cell (make-posn 0 2) #f)
- (make-cell (make-posn 1 2) #t)
- (make-cell (make-posn 2 2) #f)
- (make-cell (make-posn 3 2) #t)
- (make-cell (make-posn 4 2) #f)
-
- (make-cell (make-posn 0 3) #f)
- (make-cell (make-posn 1 3) #t)
- (make-cell (make-posn 2 3) #f)
- (make-cell (make-posn 3 3) #f)
- (make-cell (make-posn 4 3) #f)
-
- (make-cell (make-posn 1 4) #f)
- (make-cell (make-posn 2 4) #f)
- (make-cell (make-posn 3 4) #f)
- (make-cell (make-posn 4 4) #f))
- (make-posn 2 2)
- 'playing
- 5
- (make-posn 0 0)
- #f))
- (make-world (list (make-cell (make-posn 1 0) #f)
- (make-cell (make-posn 2 0) #f)
- (make-cell (make-posn 3 0) #f)
- (make-cell (make-posn 4 0) #f)
-
- (make-cell (make-posn 0 1) #f)
- (make-cell (make-posn 1 1) #t)
- (make-cell (make-posn 2 1) #t)
- (make-cell (make-posn 3 1) #f)
- (make-cell (make-posn 4 1) #f)
-
- (make-cell (make-posn 0 2) #f)
- (make-cell (make-posn 1 2) #t)
- (make-cell (make-posn 2 2) #f)
- (make-cell (make-posn 3 2) #t)
- (make-cell (make-posn 4 2) #f)
-
- (make-cell (make-posn 0 3) #f)
- (make-cell (make-posn 1 3) #t)
- (make-cell (make-posn 2 3) #f)
- (make-cell (make-posn 3 3) #f)
- (make-cell (make-posn 4 3) #f)
-
- (make-cell (make-posn 1 4) #f)
- (make-cell (make-posn 2 4) #f)
- (make-cell (make-posn 3 4) #f)
- (make-cell (make-posn 4 4) #f))
- (make-posn 2 3)
- 'playing
- 5
- (make-posn 0 0)
- #f))]
-
-@chunk[
- ;; find-best-positions : (nelistof posn) (nelistof number or '∞)
- ;; -> (nelistof posn) or #f
- (define (find-best-positions posns scores)
- (local [(define best-score (foldl (lambda (x sofar)
- (if (<=/f x sofar)
- x
- sofar))
- (first scores)
- (rest scores)))]
- (cond
- [(symbol? best-score) #f]
- [else
- (map
- second
- (filter (lambda (x) (equal? (first x) best-score))
- (map list scores posns)))])))]
-
-@chunk[
- (test (find-best-positions (list (make-posn 0 0)) (list 1))
- (list (make-posn 0 0)))
- (test (find-best-positions (list (make-posn 0 0)) (list '∞))
- #f)
- (test (find-best-positions (list (make-posn 0 0)
- (make-posn 1 1))
- (list 1 2))
- (list (make-posn 0 0)))
- (test (find-best-positions (list (make-posn 0 0)
- (make-posn 1 1))
- (list 1 1))
- (list (make-posn 0 0)
- (make-posn 1 1)))
- (test (find-best-positions (list (make-posn 0 0)
- (make-posn 1 1))
- (list '∞ 2))
- (list (make-posn 1 1)))
- (test (find-best-positions (list (make-posn 0 0)
- (make-posn 1 1))
- (list '∞ '∞))
- #f)]
-
-@chunk[
- ;; <=/f : (number or '∞) (number or '∞) -> boolean
- (define (<=/f a b)
- (cond
- [(equal? b '∞) #t]
- [(equal? a '∞) #f]
- [else (<= a b)]))]
-
-@chunk[
- (test (<=/f 1 2) #t)
- (test (<=/f 2 1) #f)
- (test (<=/f '∞ 1) #f)
- (test (<=/f 1 '∞) #t)
- (test (<=/f '∞ '∞) #t)]
-
-@chunk[
- ;; circle-at-point : board number number -> posn-or-#f
- ;; returns the posn corresponding to cell where the x,y coordinates are
- (define (circle-at-point board x y)
- (cond
- [(empty? board) #f]
- [else
- (cond
- [(point-in-this-circle? (cell-p (first board)) x y)
- (cell-p (first board))]
- [else
- (circle-at-point (rest board) x y)])]))]
-
-@chunk[
- (test (circle-at-point empty 0 0) #f)
- (test (circle-at-point (list (make-cell (make-posn 0 0) #f))
- (cell-center-x (make-posn 0 0))
- (cell-center-y (make-posn 0 0)))
- (make-posn 0 0))
- (test (circle-at-point (list (make-cell (make-posn 0 0) #f))
- 0 0)
- #f)]
-
-@chunk[
- ;; point-in-this-circle? : posn number number -> boolean
- (define (point-in-this-circle? p x y)
- (let ([center (+ (cell-center-x p)
- (* (sqrt -1)
- (cell-center-y p)))]
- [p2 (+ x (* (sqrt -1) y))])
- (<= (magnitude (- center p2))
- circle-radius)))]
-
-@chunk[
- (test (point-in-this-circle? (make-posn 0 0)
- (cell-center-x (make-posn 0 0))
- (cell-center-y (make-posn 0 0)))
- #t)
- (test (point-in-this-circle? (make-posn 0 0) 0 0)
- #f)]
-
-@chunk[
- ;; change : world key-event -> world
- (define (change w ke)
- (make-world (world-board w)
- (world-cat w)
- (world-state w)
- (world-size w)
- (world-mouse-posn w)
- (key=? ke #\h)))]
-
-@chunk[
- (test (change (make-world '() (make-posn 1 1)
- 'playing 3 (make-posn 0 0) #f)
- #\h)
- (make-world '() (make-posn 1 1)
- 'playing 3 (make-posn 0 0) #t))
- (test (change (make-world '() (make-posn 1 1)
- 'playing 3 (make-posn 0 0) #t)
- 'release)
- (make-world '() (make-posn 1 1) 'playing 3 (make-posn 0 0) #f))]
-
-
-]
@section{Tests}
@@ -2230,11 +2135,171 @@ for the other functions in this document
#f
#f))]
+@chunk[
+
+ (test (update-world-posn
+ (make-world (list (make-cell (make-posn 0 0) #f))
+ (make-posn 0 1) 'playing 3 #f #f)
+ (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) #f))
+ (make-posn 0 1) 'playing 3 (make-posn 0 0) #f))
+
+ (test (update-world-posn
+ (make-world (list (make-cell (make-posn 0 0) #f))
+ (make-posn 0 0) 'playing 3 #f #f)
+ (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) #f))
+ (make-posn 0 0) 'playing 3 #f #f))
+
+ (test (update-world-posn
+ (make-world (list (make-cell (make-posn 0 0) #f))
+ (make-posn 0 1) 'playing 3 (make-posn 0 0) #f)
+ (make-posn 0 0))
+ (make-world (list (make-cell (make-posn 0 0) #f))
+ (make-posn 0 1) 'playing 3 #f #f))]
+
+@chunk[
+ (test
+ (move-cat
+ (make-world (list (make-cell (make-posn 1 0) #f)
+ (make-cell (make-posn 2 0) #f)
+ (make-cell (make-posn 3 0) #f)
+ (make-cell (make-posn 4 0) #f)
+
+ (make-cell (make-posn 0 1) #f)
+ (make-cell (make-posn 1 1) #t)
+ (make-cell (make-posn 2 1) #t)
+ (make-cell (make-posn 3 1) #f)
+ (make-cell (make-posn 4 1) #f)
+
+ (make-cell (make-posn 0 2) #f)
+ (make-cell (make-posn 1 2) #t)
+ (make-cell (make-posn 2 2) #f)
+ (make-cell (make-posn 3 2) #t)
+ (make-cell (make-posn 4 2) #f)
+
+ (make-cell (make-posn 0 3) #f)
+ (make-cell (make-posn 1 3) #t)
+ (make-cell (make-posn 2 3) #f)
+ (make-cell (make-posn 3 3) #f)
+ (make-cell (make-posn 4 3) #f)
+
+ (make-cell (make-posn 1 4) #f)
+ (make-cell (make-posn 2 4) #f)
+ (make-cell (make-posn 3 4) #f)
+ (make-cell (make-posn 4 4) #f))
+ (make-posn 2 2)
+ 'playing
+ 5
+ (make-posn 0 0)
+ #f))
+ (make-world (list (make-cell (make-posn 1 0) #f)
+ (make-cell (make-posn 2 0) #f)
+ (make-cell (make-posn 3 0) #f)
+ (make-cell (make-posn 4 0) #f)
+
+ (make-cell (make-posn 0 1) #f)
+ (make-cell (make-posn 1 1) #t)
+ (make-cell (make-posn 2 1) #t)
+ (make-cell (make-posn 3 1) #f)
+ (make-cell (make-posn 4 1) #f)
+
+ (make-cell (make-posn 0 2) #f)
+ (make-cell (make-posn 1 2) #t)
+ (make-cell (make-posn 2 2) #f)
+ (make-cell (make-posn 3 2) #t)
+ (make-cell (make-posn 4 2) #f)
+
+ (make-cell (make-posn 0 3) #f)
+ (make-cell (make-posn 1 3) #t)
+ (make-cell (make-posn 2 3) #f)
+ (make-cell (make-posn 3 3) #f)
+ (make-cell (make-posn 4 3) #f)
+
+ (make-cell (make-posn 1 4) #f)
+ (make-cell (make-posn 2 4) #f)
+ (make-cell (make-posn 3 4) #f)
+ (make-cell (make-posn 4 4) #f))
+ (make-posn 2 3)
+ 'playing
+ 5
+ (make-posn 0 0)
+ #f))]
+
+@chunk[
+ (test (change (make-world '() (make-posn 1 1)
+ 'playing 3 (make-posn 0 0) #f)
+ #\h)
+ (make-world '() (make-posn 1 1)
+ 'playing 3 (make-posn 0 0) #t))
+ (test (change (make-world '() (make-posn 1 1)
+ 'playing 3 (make-posn 0 0) #t)
+ 'release)
+ (make-world '() (make-posn 1 1) 'playing 3 (make-posn 0 0) #f))]
+
+
+
+
+@chunk[
+ (test (point-in-this-circle? (make-posn 0 0)
+ (cell-center-x (make-posn 0 0))
+ (cell-center-y (make-posn 0 0)))
+ #t)
+ (test (point-in-this-circle? (make-posn 0 0) 0 0)
+ #f)]
+
+@chunk[
+ (test (find-best-positions (list (make-posn 0 0)) (list 1))
+ (list (make-posn 0 0)))
+ (test (find-best-positions (list (make-posn 0 0)) (list '∞))
+ #f)
+ (test (find-best-positions (list (make-posn 0 0)
+ (make-posn 1 1))
+ (list 1 2))
+ (list (make-posn 0 0)))
+ (test (find-best-positions (list (make-posn 0 0)
+ (make-posn 1 1))
+ (list 1 1))
+ (list (make-posn 0 0)
+ (make-posn 1 1)))
+ (test (find-best-positions (list (make-posn 0 0)
+ (make-posn 1 1))
+ (list '∞ 2))
+ (list (make-posn 1 1)))
+ (test (find-best-positions (list (make-posn 0 0)
+ (make-posn 1 1))
+ (list '∞ '∞))
+ #f)]
+
+@chunk[
+ (test (<=/f 1 2) #t)
+ (test (<=/f 2 1) #f)
+ (test (<=/f '∞ 1) #f)
+ (test (<=/f 1 '∞) #t)
+ (test (<=/f '∞ '∞) #t)]
+
+@chunk[
+ (test (circle-at-point empty 0 0) #f)
+ (test (circle-at-point (list (make-cell (make-posn 0 0) #f))
+ (cell-center-x (make-posn 0 0))
+ (cell-center-y (make-posn 0 0)))
+ (make-posn 0 0))
+ (test (circle-at-point (list (make-cell (make-posn 0 0) #f)
+ (make-cell (make-posn 0 1) #f))
+ (cell-center-x (make-posn 0 1))
+ (cell-center-y (make-posn 0 1)))
+ (make-posn 0 1))
+ (test (circle-at-point (list (make-cell (make-posn 0 0) #f))
+ 0 0)
+ #f)]
+
+
@section{Run, program, run}
@chunk[
- ;(printf "passed ~s tests\n" test-count)
- ;(flush-output)
+ (printf "passed ~s tests\n" test-count) (flush-output)
(let* ([board-size 11]
[initial-board