Commit 902c970f by Jacqueline Lee

backgammon project

parent 347b50f7
#lang racket/base
(provide big-bang*)
(require (for-syntax racket/base
racket/list
racket/function
unstable/list
racket/syntax
syntax/parse)
2htdp/universe)
;; big-bang changes behavior based on whether or not clauses are present, which is inconvenient when
;; attempting to create a function wrapper. This automatically generates a cond form to handle all
;; possible cases.
(define-syntax (big-bang-cross-product stx)
(syntax-parse stx
[(_ world
(constant-clause ...)
(clause-condition clause-true (~optional clause-false #:defaults ([clause-false #f])))
...)
; wrap each condition with its true case and false case
(define clause-dict
(for/list ([condition (in-list (attribute clause-condition))]
[clause-t (in-list (attribute clause-true))]
[clause-f (in-list (attribute clause-false))])
(list condition (list clause-t clause-f))))
; all the possible cases (each clause-condition can be #t or #f)
(define case-pairs (map (curryr list #f) (attribute clause-condition)))
(define all-cases (apply cartesian-product case-pairs))
; convert the set of cases into cond clauses
(define/with-syntax (cond-case ...)
(for/list ([case (in-list all-cases)])
; all the non-#f conditions need to be considered for the cond condition
(define conditions (filter identity case))
(define/with-syntax cond-condition
(if (empty? conditions)
#'else
(with-syntax ([(c ...) conditions])
#'(and c ...))))
(define big-bang-clauses
(for/list ([condition (in-list case)]
[clause-t (in-list (attribute clause-true))]
[clause-f (in-list (attribute clause-false))])
(if condition clause-t clause-f)))
(define/with-syntax (case-clause ...) (filter identity big-bang-clauses))
#'[cond-condition
(big-bang
world
constant-clause ...
case-clause ...)]))
#'(cond cond-case ...)]))
(define (big-bang* world
#:to-draw renderer
#:on-tick [tick (λ (w) w)]
#:tick-rate [tick-rate 1/30]
#:tick-limit [tick-limit #f]
#:on-key [key (λ (w k) w)]
#:on-release [release (λ (w k) w)]
#:on-pad [pad #f]
#:on-mouse [mouse (λ (w x y e) w)]
#:stop-when [stop (λ (w) #f)]
#:last-picture [last-picture #f]
#:record? [record #f]
#:name [n "World"])
(big-bang-cross-product
world
([to-draw renderer]
[on-key key]
[on-release release]
[on-mouse mouse]
[record? record]
[name n])
(pad
[on-pad pad])
(tick-limit
[on-tick tick tick-rate tick-limit]
[on-tick tick tick-rate])
(last-picture
[stop-when stop last-picture]
[stop-when stop])))
#lang typed/racket
(: cs151-core-version : String)
(define cs151-core-version "A6.0")
(provide cs151-core-version)
(: cs151-core-date : String)
(define cs151-core-date "September 30, 2019")
(provide cs151-core-date)
(define-syntax cs151-core-define-struct
(syntax-rules ()
[(cs151-core-define-struct (name A ...) (fields ...))
(define-struct (A ...) name (fields ...) #:transparent)]
[(cs151-core-define-struct (name A ...) (fields ...) #:mutable)
(define-struct (A ...) name (fields ...) #:transparent #:mutable)]
[(cs151-core-define-struct name (fields ...) #:mutable)
(define-struct name (fields ...) #:transparent #:mutable)]
[(cs151-core-define-struct name (fields ...))
(define-struct name (fields ...) #:transparent)]))
(provide (rename-out [cs151-core-define-struct define-struct]))
;; NOTE Make sure the CS tutors know about this change to define-struct
;; error reporting
;;
(: cs151-core-error : String -> Nothing)
(define (cs151-core-error msg) (error msg))
(provide (rename-out [cs151-core-error error]))
(: cs151-core-cons : (All (A) (-> A (Listof A) (Listof A))))
(define (cs151-core-cons hd tl) (cons hd tl))
(provide (rename-out [cs151-core-cons cons]))
(: cs151-core-first : (All (A) (Listof A) -> A))
(define (cs151-core-first xs) (first xs))
(provide (rename-out [cs151-core-first first]))
(: cs151-core-map : (All (A B) (-> (-> A B) (Listof A) (Listof B))))
(define (cs151-core-map f xs) (map f xs))
(provide (rename-out [cs151-core-map map]))
(: cs151-core-filter : (All (A) (-> (-> A Boolean) (Listof A) (Listof A))))
(define (cs151-core-filter f xs) (filter f xs))
(provide (rename-out [cs151-core-filter filter]))
(: cs151-core-foldl : (All (A B) (-> (-> A B B) B (Listof A) B)))
(define (cs151-core-foldl f acc xs) (foldl f acc xs))
(provide (rename-out [cs151-core-foldl foldl]))
(: cs151-core-foldr : (All (A B) (-> (-> A B B) B (Listof A) B)))
(define (cs151-core-foldr f acc xs) (foldr f acc xs))
(provide (rename-out [cs151-core-foldr foldr]))
(: cs151-core-partition :
(All (A) (-> (-> A Boolean) (Listof A) (values (Listof A) (Listof A)))))
(define (cs151-core-partition f xs) (partition f xs))
(provide (rename-out [cs151-core-partition partition]))
(: cs151-core-andmap : (All (A) (-> (-> A Boolean) (Listof A) Boolean)))
(define (cs151-core-andmap f xs) (andmap f xs))
(provide (rename-out [cs151-core-andmap andmap]))
(: cs151-core-ormap : (All (A) (-> (-> A Boolean) (Listof A) Boolean)))
(define (cs151-core-ormap f xs) (ormap f xs))
(provide (rename-out [cs151-core-ormap ormap]))
(: cs151-core-vector-map : (All (A B) (A -> B) (Vectorof A) -> (Vectorof B)))
(define (cs151-core-vector-map f v) (vector-map f v))
(provide (rename-out [cs151-core-vector-map vector-map]))
(: cs151-core-vector-filter : (All (A) (A -> Boolean) (Vectorof A) -> (Vectorof A)))
(define (cs151-core-vector-filter f v) (vector-filter f v))
(provide (rename-out [cs151-core-vector-filter vector-filter]))
(: cs151-core-vector-count : (All (A) (A -> Boolean) (Vectorof A) -> Integer))
(define (cs151-core-vector-count pred v) (vector-count pred v))
(provide (rename-out [cs151-core-vector-count vector-count]))
(: cs151-core-sqrt : Real -> Real)
(define (cs151-core-sqrt x)
(if (not (negative? x))
(sqrt x)
(error
(string-append "sqrt expects a nonnegative real; given "
(number->string x)))))
(provide (rename-out [cs151-core-sqrt sqrt]))
(provide (rename-out [sqrt full-sqrt]))
;; forbidden builtin functions
;;
(: forbidden-function : String -> String)
(define (forbidden-function f)
(string-append "cs151-core: " f
": You may not use the built-in function " f
" in this course; you must write your own such function."))
(: cs151-core-argmax : (All (A) (A -> Real) (Listof A) -> A))
(define (cs151-core-argmax f xs)
(error (forbidden-function "argmax")))
(provide (rename-out [cs151-core-argmax argmax]))
(: cs151-core-argmin : (All (A) (A -> Real) (Listof A) -> A))
(define (cs151-core-argmin f xs)
(error (forbidden-function "argmin")))
(provide (rename-out [cs151-core-argmin argmin]))
(: cs151-core-apply : (All (a b) (a * -> b) (Listof a) -> b))
(define (cs151-core-apply f xs)
(error (forbidden-function "apply")))
(provide (rename-out [cs151-core-apply apply]))
(: cs151-core-vector-argmin : (All (X) (X -> Real) (Vectorof X) -> X))
(define (cs151-core-vector-argmin f xs)
(error (forbidden-function "vector-argmin")))
(provide (rename-out [cs151-core-vector-argmin vector-argmin]))
(: cs151-core-vector-argmax : (All (X) (X -> Real) (Vectorof X) -> X))
(define (cs151-core-vector-argmax f xs)
(error (forbidden-function "vector-argmax")))
(provide (rename-out [cs151-core-vector-argmax vector-argmax]))
(: cs151-core-object-name : Any -> Any)
(define (cs151-core-object-name x)
(error (string-append "cs151-core: object-name: "
"You may not use the built-in function object-name in this course; "
"you must adopt an approach that does not require it.")))
(provide (rename-out [cs151-core-object-name object-name]))
(: cs151-core-list-set : (All (A) (Listof A) Integer A -> (Listof A)))
(define (cs151-core-list-set xs i y)
(error (forbidden-function "list-set")))
(provide (rename-out [cs151-core-list-set list-set]))
(: cs151-core-list-update : (All (A) (Listof A) Integer (-> A A) ->
(Listof A)))
(define (cs151-core-list-update xs i fn)
(error (forbidden-function "list-update")))
(provide (rename-out [cs151-core-list-update list-update]))
(: cs151-core-append* : (All (a) (-> (Listof (Listof a)) (Listof a))))
(define (cs151-core-append* lst)
(error (forbidden-function "append*")))
(provide (rename-out [cs151-core-append* append*]))
(: cs151-core-remove : (All (a) (-> Any (Listof a) (Listof a))))
(define (cs151-core-remove a lst)
(error (forbidden-function "remove")))
(provide (rename-out [cs151-core-remove remove]))
(: cs151-core-remove* : (All (a b) (->* ((Listof a) (Listof b)) ((-> a b Boolean)) (Listof b))))
(define (cs151-core-remove* lst1 lst2 [f equal?])
(error (forbidden-function "remove*")))
(provide (rename-out [cs151-core-remove* remove*]))
(: cs151-core-remove-duplicates : (All (a b)
(case->
(->* ((Listof a)) ((-> a a Any) #:key (U (-> a a) False)) (Listof a))
(->* ((Listof a)) ((-> b b Any) #:key (U (-> a b) False)) (Listof a)))))
(define (cs151-core-remove-duplicates l [=? equal?] #:key [key #f])
(error (forbidden-function "remove-duplicates")))
(provide (rename-out [cs151-core-remove-duplicates remove-duplicates]))
(: cs151-core-take : (All (a) (-> (Listof a) Integer (Listof a))))
(define (cs151-core-take lst i)
(error (forbidden-function "take")))
(provide (rename-out [cs151-core-take take]))
(: cs151-core-drop : (All (a) (-> (Listof a) Integer (Listof a))))
(define (cs151-core-drop lst i)
(error (forbidden-function "drop")))
(provide (rename-out [cs151-core-drop drop]))
(: cs151-core-member : (All (a b)
(case->
(-> Any (Listof a) (U (Pairof a (Listof a)) False))
(-> b (Listof a) (-> b a Any) (U (Pairof a (Listof a)) False)))))
(define cs151-core-member
(case-lambda
[(a lst) (error (forbidden-function "member"))]
[(a lst b) (error (forbidden-function "member"))]))
(provide (rename-out [cs151-core-member member]))
(: cs151-core-list-tail : (All (a) (-> (Listof a) Integer (Listof a))))
(define (cs151-core-list-tail lst i)
(error (forbidden-function "list-tail")))
(provide (rename-out [cs151-core-list-tail list-tail]))
(: cs151-core-vector-append : (All (a) (-> (Vectorof a) * (Vectorof a))))
(define (cs151-core-vector-append . lst)
(error (string-append "cs151-core: vector-append: "
"You may not use the built-in function vector-append in this course; "
"efficiency dictates that you create a single vector of the "
"needed length from the start and fill it in, rather than "
"concatenating smaller vectors.")))
(provide (rename-out [cs151-core-vector-append vector-append]))
(: forbidden-equality : (-> String String))
(define (forbidden-equality f)
(string-append "cs151-core: " f
": You may not use the built-in function " f
" in this course; you must use a type-specific "
"comparison function, such as = for numeric types, "
"string=? for Strings, etc."))
(: cs151-core-equal? : (-> Any Any Boolean))
(define (cs151-core-equal? a b)
(error (forbidden-equality "equal?")))
(provide (rename-out [cs151-core-equal? equal?]))
(: cs151-core-eqv? : (-> Any Any Boolean))
(define (cs151-core-eqv? a b)
(error (forbidden-equality "eqv?")))
(provide (rename-out [cs151-core-eqv? eqv?]))
(: cs151-core-eq? : (-> Any Any Boolean))
(define (cs151-core-eq? a b)
(error (forbidden-equality "eq?")))
(provide (rename-out [cs151-core-eq? eq?]))
(define-syntax cs151-core-set!
(syntax-rules ()
[(cs151-core-set! var val)
(error
"you may not mutate the value of a variable binding in this course")]))
(provide (rename-out [cs151-core-set! set!]))
#lang typed/racket/base
(require (for-syntax racket/base
syntax/parse
racket/class
racket/draw)
(only-in typed/racket/gui
Bitmap%
Font-Family Font-Style Font-Weight)
typed/lang/posn)
; exposes the color names from racket/draw as a type
(define-syntax (define-color-database-types stx)
(syntax-parse stx
[(_ type-name:id)
(define color-names (send the-color-database get-names))
(with-syntax ([(color-name ...) (datum->syntax stx color-names)]
[(color-symbol ...) (datum->syntax stx (map string->symbol color-names))])
#'(define-type type-name (U color-name ... 'color-symbol ...)))]))
(define-color-database-types ColorDatabase-Color)
;; opaque types
;; ---------------------------------------------------------------------------------------------------
(require/typed/provide
2htdp/image
; 2.3.8 Image Predicates
[#:opaque htdp:image image?]
[#:opaque Color color?]
[#:opaque Pen pen?])
; provide capitalized predicates as well
(provide
(rename-out [color? Color?]
[pen? Pen?]))
;; simple exports
;; ---------------------------------------------------------------------------------------------------
(require/typed/provide
2htdp/image
; 2.3.1 Basic Images
;; [circle (Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;; [ellipse (Nonnegative-Real Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[line (Real Real (U Pen Image-Color) -> Image)]
;; [add-line (Image Real Real Real Real (U Pen Image-Color) -> Image)]
;; [add-curve (Image Real Real Angle Real Real Real Angle Real (U Pen Image-Color) -> Image)]
;; [add-solid-curve (Image Real Real Angle Real Real Real Angle Real (U Pen Image-Color) -> Image)]
;; [text (String Positive-Byte Image-Color -> Image)]
;; [text/font (String Positive-Byte Image-Color (Option String) Font-Family Font-Style Font-Weight Any -> Image)]
[empty-image Image]
; 2.3.2 Polygons
;; [triangle (Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;; [right-triangle (Nonnegative-Real Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[isosceles-triangle (Nonnegative-Real Angle Mode (U Pen Image-Color) -> Image)]
;;[triangle/sss (Nonnegative-Real Nonnegative-Real Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;; [triangle/ass (Angle Nonnegative-Real Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[triangle/sas (Nonnegative-Real Angle Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[triangle/ssa (Nonnegative-Real Nonnegative-Real Angle Mode (U Pen Image-Color) -> Image)]
;;[triangle/aas (Angle Angle Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[triangle/asa (Angle Nonnegative-Real Angle Mode (U Pen Image-Color) -> Image)]
;;[triangle/saa (Nonnegative-Real Angle Angle Mode (U Pen Image-Color) -> Image)]
;;[square (Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[rectangle (Nonnegative-Real Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;; [rhombus (Nonnegative-Real Angle Mode (U Pen Image-Color) -> Image)]
;;[star (Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[star-polygon (Nonnegative-Real Positive-Integer Positive-Integer Mode (U Pen Image-Color) -> Image)]
;;[radial-star (Positive-Integer Nonnegative-Real Nonnegative-Real Mode (U Pen Image-Color) -> Image)]
;;[regular-polygon (Nonnegative-Real Positive-Integer Mode (U Pen Image-Color) -> Image)]
;;[polygon ((Listof Posn) Mode (U Pen Image-Color) -> Image)]
;; [add-polygon (Image (Listof Posn) Mode (U Pen Image-Color) -> Image)]
;;[scene+polygon (Image (Listof Posn) Mode (U Pen Image-Color) -> Image)]
; 2.3.3 Overlaying Images
[overlay (Image Image Image * -> Image)]
[overlay/align (X-Place Y-Place Image Image Image * -> Image)]
[overlay/offset (Image Real Real Image -> Image)]
[overlay/align/offset (X-Place Y-Place Image Real Real Image -> Image)]
[overlay/xy (Image Real Real Image -> Image)]
[underlay (Image Image Image * -> Image)]
[underlay/align (X-Place Y-Place Image Image Image * -> Image)]
[underlay/offset (Image Real Real Image -> Image)]
[underlay/align/offset (X-Place Y-Place Image Real Real Image -> Image)]
[underlay/xy (Image Real Real Image -> Image)]
[beside (Image Image Image * -> Image)]
[beside/align (Y-Place Image Image Image * -> Image)]
[above (Image Image Image * -> Image)]
[above/align (X-Place Image Image Image * -> Image)]
; 2.3.4 Placing Images & Scenes
[empty-scene ((Nonnegative-Real Nonnegative-Real) (Image-Color) . ->* . Image)]
[place-image (Image Real Real Image -> Image)]
[place-image/align (Image Real Real X-Place Y-Place Image -> Image)]
[place-images ((Listof Image) (Listof Posn) Image -> Image)]
[place-images/align ((Listof Image) (Listof Posn) X-Place Y-Place Image -> Image)]
[scene+line (Image Real Real Real Real (U Pen Image-Color) -> Image)]
[scene+curve (Image Real Real Angle Real Real Real Angle Real (U Pen Image-Color) -> Image)]
; 2.3.5 Rotating, Scaling, Flipping, Cropping, and Framing Images
[rotate (Angle Image -> Image)]
;; [scale (Positive-Real Image -> Image)]
[scale (Real Image -> Image)] ;; uc151
;;[scale/xy (Positive-Real Positive-Real Image -> Image)]
[scale/xy (Real Real Image -> Image)] ;; uc151
[flip-horizontal (Image -> Image)]
[flip-vertical (Image -> Image)]
[crop (Real Real Nonnegative-Real Nonnegative-Real Image -> Image)]
[crop/align (X-Place Y-Place Nonnegative-Real Nonnegative-Real Image -> Image)]
[frame (Image -> Image)]
[color-frame ((U Pen Image-Color) Image -> Image)]
; 2.3.6 Bitmaps
; TODO: missing `bitmap` macro
[bitmap/url (String -> Image)]
[bitmap/file (Path-String -> Image)]
[image->color-list (Image -> (Listof Color))]
[color-list->bitmap ((Listof Color) Nonnegative-Real Nonnegative-Real -> Image)]
[freeze (case->
(Image -> Image)
(Nonnegative-Real Nonnegative-Real Image -> Image)
(Real Real Nonnegative-Real Nonnegative-Real Image -> Image))]
; 2.3.7 Image Properties
[image-width (Image -> Nonnegative-Integer)]
[image-height (Image -> Nonnegative-Integer)]
[image-baseline (Image -> Nonnegative-Integer)]
; 2.3.8 Image Predicates
[mode? (Any -> Boolean)]
[image-color? (Any -> Boolean)]
[color ((Byte Byte Byte) (Byte) . ->* . Color)]
[make-color ((Byte Byte Byte) (Byte) . ->* . Color)]
[y-place? (Any -> Boolean)]
[x-place? (Any -> Boolean)]
[angle? (Any -> Boolean)]
[side-count? (Any -> Boolean)]
[step-count? (Any -> Boolean)]
[real-valued-posn? (Any -> Boolean)]
[pen (Image-Color Nonnegative-Real Pen-Style Pen-Cap Pen-Join -> Pen)]
[make-pen (Image-Color Nonnegative-Real Pen-Style Pen-Cap Pen-Join -> Pen)]
; 2.3.10 Pinholes
[center-pinhole (Image -> Image)]
[put-pinhole (Integer Integer -> Image)]
[pinhole-x (Image -> (Option Integer))]
[pinhole-y (Image -> (Option Integer))]
[clear-pinhole (Image -> Image)]
[overlay/pinhole (Image Image Image * -> Image)]
[underlay/pinhole (Image Image Image * -> Image)]
; 2.3.11 Exporting Images to Disk
[save-image ((Image Path-String) (Nonnegative-Real Nonnegative-Real) . ->* . Boolean)]
[save-svg-image ((Image Path-String) (Nonnegative-Real Nonnegative-Real) . ->* . Boolean)])
;; derived / reimplemented exports
;; ---------------------------------------------------------------------------------------------------
(provide
Image image?
Image-Color Image-Color? image-color?
Mode Mode? mode?
Angle Angle?
X-Place Y-Place X-Place? Y-Place?
Pen-Style Pen-Cap Pen-Join Pen-Style? Pen-Cap? Pen-Join?
Font-Family Font-Style Font-Weight Font-Family? Font-Style? Font-Weight?)
;; derived type declarations
;; ---------------------------------------------------------------------------------------------------
(define-type Image (U htdp:image (Instance Bitmap%))) ; TODO: missing Image-Snip% instance possibility
(define-type Image-Color (U Color ColorDatabase-Color))
(define-type Mode (U 'solid "solid" 'outline "outline" Byte))
(define-type Angle Real) ; more specifically, Finite-NonNaN-Real, which isn't a type
(define-type X-Place (U 'left 'right 'middle 'center 'pinhole
"left" "right" "middle" "center" "pinhole"))
(define-type Y-Place (U 'top 'bottom 'middle 'center 'baseline 'pinhole
"top" "bottom" "middle" "center" "baseline" "pinhole"))
(define-type Pen-Style (U 'solid 'dot 'long-dash 'short-dash 'dot-dash
"solid" "dot" "long-dash" "short-dash" "dot-dash"))
(define-type Pen-Cap (U 'round 'projecting 'butt "round" "projecting" "butt"))
(define-type Pen-Join (U 'round 'bevel 'miter "round" "bevel" "miter"))
(define-predicate Image-Color? Image-Color)
(define-predicate Mode? Mode)
(define-predicate Angle? Angle)
(define-predicate X-Place? X-Place)
(define-predicate Y-Place? Y-Place)
(define-predicate Pen-Style? Pen-Style)
(define-predicate Pen-Cap? Pen-Cap)
(define-predicate Pen-Join? Pen-Join)
(define-predicate Font-Family? Font-Family)
(define-predicate Font-Style? Font-Style)
(define-predicate Font-Weight? Font-Weight)
;; UChicago CS 151 modifications
;; provide dynamic errors rather than static type errors
;; for potential negative dimensions or invalid color names
(: cs151-image-version : String)
(define cs151-image-version "1.0")
(provide cs151-image-version)
(: cs151-image-date : String)
(define cs151-image-date "September 26, 2017")
(provide cs151-image-date)
(require/typed 2htdp/image
[circle (Real Mode (U Pen Image-Color) -> Image)]
[triangle (Real Mode (U Pen Image-Color) -> Image)]
[square (Real Mode (U Pen Image-Color) -> Image)]
[rectangle (Real Real Mode (U Pen Image-Color) -> Image)]
[ellipse (Real Real Mode (U Pen Image-Color) -> Image)]
[line (Real Real (U Pen Image-Color) -> Image)]
[add-line (Image Real Real Real Real (U Pen Image-Color) -> Image)]
[add-curve (Image Real Real Angle Real Real Real Angle Real (U Pen Image-Color) -> Image)]
[add-solid-curve (Image Real Real Angle Real Real Real Angle Real (U Pen Image-Color) -> Image)]
[text (String Byte Image-Color -> Image)]
[text/font (String Byte Image-Color (Option String) Font-Family Font-Style Font-Weight Any -> Image)]
[right-triangle (Real Real Mode (U Pen Image-Color) -> Image)]
[isosceles-triangle (Real Angle Mode (U Pen Image-Color) -> Image)]
[triangle/sss (Real Real Real Mode (U Pen Image-Color) -> Image)]
[triangle/ass (Angle Real Real Mode (U Pen Image-Color) -> Image)]
[triangle/sas (Real Angle Real Mode (U Pen Image-Color) -> Image)]
[triangle/ssa (Real Real Angle Mode (U Pen Image-Color) -> Image)]
[triangle/aas (Angle Angle Real Mode (U Pen Image-Color) -> Image)]
[triangle/asa (Angle Real Angle Mode (U Pen Image-Color) -> Image)]
[triangle/saa (Real Angle Angle Mode (U Pen Image-Color) -> Image)]
[rhombus (Real Angle Mode (U Pen Image-Color) -> Image)]
[star (Real Mode (U Pen Image-Color) -> Image)]
[star-polygon (Real Integer Integer Mode (U Pen Image-Color) -> Image)]
[radial-star (Integer Real Real Mode (U Pen Image-Color) -> Image)]
[regular-polygon (Real Integer Mode (U Pen Image-Color) -> Image)]
[polygon ((Listof Posn) Mode (U Pen Image-Color) -> Image)]
[add-polygon (Image (Listof Posn) Mode (U Pen Image-Color) -> Image)]
[scene+polygon (Image (Listof Posn) Mode (U Pen Image-Color) -> Image)])
(: uchicago151-circle : Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-circle radius mode color)
(circle radius (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-circle circle]))
(: uchicago151-triangle : Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle side mode color)
(triangle side (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle triangle]))
(: uchicago151-square : Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-square side mode color)
(square side (cast mode Mode) (cast (cast color Image-Color) (U Pen Image-Color))))
(provide (rename-out [uchicago151-square square]))
(: uchicago151-rectangle : Real Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-rectangle width height mode color)
(rectangle width height (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-rectangle rectangle]))
(: uchicago151-ellipse : Real Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-ellipse a b mode color)
(ellipse a b (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-ellipse ellipse]))
(: uchicago151-line : Real Real (U String Pen Image-Color) -> Image)
(define (uchicago151-line a b color)
(line a b (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-line line]))
(: uchicago151-add-line : Image Real Real Real Real (U String Pen Image-Color) -> Image)
(define (uchicago151-add-line a b c d e color)
(add-line a b c d e (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-add-line add-line]))
(: uchicago151-add-curve : Image Real Real Angle Real Real Real Angle Real (U String Pen Image-Color) -> Image)
(define (uchicago151-add-curve a b c d e f g h i color)
(add-curve a b c d e f g h i (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-add-curve add-curve]))
(: uchicago151-add-solid-curve : Image Real Real Angle Real Real Real Angle Real (U String Pen Image-Color) -> Image)
(define (uchicago151-add-solid-curve a b c d e f g h i color)
(add-solid-curve a b c d e f g h i (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-add-solid-curve add-solid-curve]))
(: uchicago151-text : String Byte (U String Image-Color) -> Image)
(define (uchicago151-text str size color)
(text str size (cast color Image-Color)))
(provide (rename-out [uchicago151-text text]))
(: uchicago151-text/font : String Byte (U String Image-Color) (Option String) Font-Family Font-Style Font-Weight Any -> Image)
(define (uchicago151-text/font str size color opt family style weight any)
(text/font str size (cast color Image-Color) opt family style weight any))
(provide (rename-out [uchicago151-text/font text/font]))
(: uchicago151-right-triangle : Real Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-right-triangle a b mode color)
(right-triangle a b (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-right-triangle right-triangle]))
(: uchicago151-isosceles-triangle : Real Angle (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-isosceles-triangle s a mode color)
(isosceles-triangle s a (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-isosceles-triangle isosceles-triangle]))
(: uchicago151-triangle/sss : Real Real Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle/sss s1 s2 s3 mode color)
(triangle/sss s1 s2 s3 (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle/sss triangle/sss]))
(: uchicago151-triangle/ass : Angle Real Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle/ass a s1 s2 mode color)
(triangle/ass a s1 s2 (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle/ass triangle/ass]))
(: uchicago151-triangle/sas : Real Angle Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle/sas s1 a s2 mode color)
(triangle/sas s1 a s2 (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle/sas triangle/sas]))
(: uchicago151-triangle/ssa : Real Real Angle (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle/ssa s1 s2 a mode color)
(triangle/ssa s1 s2 a (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle/ssa triangle/ssa]))
(: uchicago151-triangle/aas : Angle Angle Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle/aas a1 a2 s mode color)
(triangle/aas a1 a2 s (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle/aas triangle/aas]))
(: uchicago151-triangle/asa : Angle Real Angle (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle/asa a1 s a2 mode color)
(triangle/asa a1 s a2 (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle/asa triangle/asa]))
(: uchicago151-triangle/saa : Real Angle Angle (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-triangle/saa s a1 a2 mode color)
(triangle/saa s a1 a2 (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-triangle/saa triangle/saa]))
(: uchicago151-rhombus : Real Angle (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-rhombus s a mode color)
(rhombus s a (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-rhombus rhombus]))
(: uchicago151-star : Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-star s mode color)
(star s (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-star star]))
(: uchicago151-star-polygon : Real Integer Integer (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-star-polygon a b c mode color)
(star-polygon a b c (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-star-polygon star-polygon]))
(: uchicago151-radial-star : Integer Real Real (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-radial-star a b c mode color)
(radial-star a b c (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-radial-star radial-star]))
(: uchicago151-regular-polygon : Real Integer (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-regular-polygon s n mode color)
(regular-polygon s n (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-regular-polygon regular-polygon]))
(: uchicago151-polygon : (Listof Posn) (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-polygon vs mode color)
(polygon vs (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-polygon polygon]))
(: uchicago151-add-polygon : Image (Listof Posn) (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-add-polygon n vs mode color)
(add-polygon n vs (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-add-polygon add-polygon]))
(: uchicago151-scene+polygon : Image (Listof Posn) (U String Mode) (U String Pen Image-Color) -> Image)
(define (uchicago151-scene+polygon s vs mode color)
(scene+polygon s vs (cast mode Mode) (cast color (U Pen Image-Color))))
(provide (rename-out [uchicago151-scene+polygon scene+polygon]))
#lang typed/racket/base
(require (for-syntax racket/base
racket/function
racket/syntax
syntax/parse)
"cs151-image.rkt"
(only-in 2htdp/universe
to-draw
on-tick
on-key
on-release
on-pad
on-mouse
stop-when
record?
name))
;; simple exports
;; ---------------------------------------------------------------------------------------------------
(require/typed/provide
2htdp/universe
; 2.4.2 Simple Simulations
[animate ((Natural -> Image) -> Natural)]
[run-simulation ((Natural -> Image) -> #t)]
[run-movie (Positive-Real (Listof Image) -> #t)]
; 2.4.3 Interactions
[key-event? (Any -> Boolean)]
[key=? (String String -> Boolean)]
[pad-event? (Any -> Boolean)]
[pad=? (String String -> Boolean)]
[mouse-event? (Any -> Boolean)]
[mouse=? (Mouse-Event Mouse-Event -> Boolean)])
;; derived/reimplemented exports
;; ---------------------------------------------------------------------------------------------------
(provide
Mouse-Event Mouse-Event?)
;; derived types
;; ---------------------------------------------------------------------------------------------------
; these would be nice, but due to how TR prints type aliases, they need to be ignored
; (define-type Scene Image)
; (define-type Key-Event String)
; (define-type Pad-Event Key-Event)
(define-type Mouse-Event (U "button-down" "button-up" "drag" "move" "enter" "leave"))
(define-predicate Mouse-Event? Mouse-Event)
;; typed big-bang
;; ---------------------------------------------------------------------------------------------------
(provide big-bang
to-draw
on-tick
on-key
on-release
on-pad
on-mouse
stop-when
record?
name)
(require/typed
"cs151-big-bang.rkt"
[big-bang*
(All [World]
(->* [World
#:to-draw (World -> Image)]
[#:on-tick (World -> World)
#:tick-rate Positive-Real
#:tick-limit (Option Positive-Integer)
#:on-key (World String -> World)
#:on-release (World String -> World)
#:on-pad (Option (World String -> World))
#:on-mouse (World Integer Integer Mouse-Event -> World)
#:stop-when (World -> Boolean)
#:last-picture (Option (World -> Image))
#:record? Any
#:name (U String Symbol)]
World))])
(define-syntax (big-bang stx)
(syntax-parse stx
#:literals (: to-draw on-tick on-key on-release on-pad on-mouse stop-when record? name)
[(_
(~describe "initial-world-state : world-state-type"
(~seq initial-state:expr : world-type:expr))
(~or (~once [to-draw draw:expr] #:name "to-draw clause")
(~optional (~or [on-tick tick:expr]
[on-tick tick:expr tick-rate:expr]
[on-tick tick:expr tick-rate:expr tick-limit:expr])
#:name "on-tick clause"
#:defaults ([tick #f] [tick-rate #f] [tick-limit #f]))
(~optional [on-key key:expr] #:name "on-key clause" #:defaults ([key #f]))
(~optional [on-release release:expr] #:name "on-release clause" #:defaults ([release #f]))
(~optional [on-pad pad:expr] #:name "on-pad clause" #:defaults ([pad #f]))
(~optional [on-mouse mouse:expr] #:name "on-mouse clause" #:defaults ([mouse #f]))
(~optional (~or [stop-when stop:expr]
[stop-when stop:expr last-picture:expr])
#:name "stop-when clause"
#:defaults ([stop #f] [last-picture #f]))
(~optional [record? record:expr] #:name "record? clause" #:defaults ([record #f]))
(~optional [name nm:expr] #:name "name clause" #:defaults ([nm #f])))
...)
(define clauses
(list #'[#:to-draw draw]
(and (attribute tick) #'[#:on-tick tick])
(and (attribute tick-rate) #'[#:tick-rate tick-rate])
(and (attribute tick-limit) #'[#:tick-limit tick-limit])
(and (attribute key) #'[#:on-key key])
(and (attribute release) #'[#:on-release release])
(and (attribute pad) #'[#:on-pad pad])
(and (attribute mouse) #'[#:on-mouse mouse])
(and (attribute stop) #'[#:stop-when stop])
(and (attribute last-picture) #'[#:last-picture last-picture])
(and (attribute record) #'[#:record? record])
(and (attribute nm) #'[#:name nm])))
(define/with-syntax (clause ...)
(apply append (map syntax->list (filter identity clauses))))
(quasisyntax/loc stx
((inst big-bang* world-type)
#,(syntax/loc stx (ann initial-state world-type))
clause ...))]))
#lang typed/racket
(require "../include/cs151-core.rkt")
(require "../include/cs151-image.rkt")
(require "../include/cs151-universe.rkt")
(require (only-in typed/racket/gui/base put-file get-file))
(require typed/test-engine/racket-tests)
;; === data definitions
(define-type Player (U 'Black 'White))
(define-struct OccupiedPoint
([color : Player]
[count : Integer]))
(define-type Point (U OccupiedPoint 'EmptyPoint))
(define-struct Board
([points : (Listof Point)]
[black-bar : Integer]
[white-bar : Integer]
[black-off : Integer]
[white-off : Integer]))
(define-struct Style
([checker-radius : Integer]
[spacing : Integer]
[black-checker : (Integer -> Image)]
[white-checker : (Integer -> Image)]
[dark-point : (Integer Boolean -> Image)]
[light-point : (Integer Boolean -> Image)]
[background : (Integer Integer -> Image)]
[label : (String Integer -> Image)]
[black-die : (Integer Integer -> Image)]
[white-die : (Integer Integer -> Image)]))
(define-struct Game
([board : Board]
[turn : Player]
[moves : (Listof Integer)]))
(define-struct World
([game : Game]
[style : Style]
[first-white-die : Integer]
[second-white-die : Integer]
[first-black-die : Integer]
[second-black-die : Integer]
[first-click : BoardLoc]
[history : (Listof Game)]))
(define-struct PointNum
([num : Integer]))
(define-type ClickLoc (U PointNum 'BlackBar 'WhiteBar 'BlackOff 'WhiteOff
'BlackDice 'WhiteDice 'Nowhere))
(define-type BoardLoc (U PointNum 'BlackBar 'WhiteBar 'BlackOff 'WhiteOff
'Nowhere))
(define none : Image-Color (color 255 255 255 0))
;; === general helper functions
(: player=? : Player Player -> Boolean)
;; player=?: return #t if players are the same, otherwise #f
;; parameter "one": the first player for comparison
;; parameter "two": the second player for comparison
;; output: #t if the players are the same, else #f
(define (player=? one two)
(local
{(define string1 : String (symbol->string one))
(define string2 : String (symbol->string two))}
(string=? string1 string2)))
(check-expect (player=? 'Black 'Black) #t)
(check-expect (player=? 'White 'White) #t)
(check-expect (player=? 'Black 'White) #f)
(check-expect (player=? 'White 'Black) #f)
(: list-max : (Listof Integer) -> Integer)
;; list-max: return the maximum value in a list of integers
;; parameter "xs": the list of integers
;; output: the maximum value in the list
(define (list-max xs)
(match xs
['() (error "list-max: no maximum in an empty list")]
[(cons hd '()) hd]
[(cons hd tl) (if (= (max hd (list-max tl)) hd) hd (list-max tl))]))
(check-expect (list-max (list 1)) 1)
(check-expect (list-max (list 1 3 2)) 3)
(check-expect (list-max (list 2 2 2)) 2)
(: list-min : (Listof Integer) -> Integer)
;; list-min: return the minimum value in a list of integers
;; parameter "xs": the list of integers
;; output: the minimum value in the list
(define (list-min xs)
(match xs
['() (error "list-min: no minimum in an empty list")]
[(cons hd '()) hd]
[(cons hd tl) (if (= (min hd (list-min tl)) hd) hd (list-min tl))]))
(check-expect (list-min (list 1)) 1)
(check-expect (list-min (list 2 1 3)) 1)
(check-expect (list-min (list 2 2 2)) 2)
(: replace-at : All (A) Integer A (Listof A) -> (Listof A))
;; replace-at: replace the list element at the given index with a given value
;; parameter "i": the list index
;; parameter "x": the new value
;; parameter "xs": the list
;; output: the list with the replaced value
(define (replace-at i x xs)
(match xs
['() '()]
[(cons hd tl)
(if (= i 0) (cons x (replace-at (- i 1) x tl))
(cons hd (replace-at (- i 1) x tl)))]))
(check-expect (replace-at 0 'Z '(a b c)) '(Z b c))
(check-expect (replace-at 1 'Z '(a b c)) '(a Z c))
(: sublist (All (A) (-> (Listof A) Integer Integer (Listof A))))
;; sublist: return a sublist of the original list given start and end indices
;; parameter "xs": the original list
;; parameter "start": the starting index for the sublist
;; parameter "end": the ending index for the sublist
;; output: the sublist
(define (sublist xs start end)
(local
{(: with-i : Integer -> (Listof A))
(define (with-i i)
(if (<= i end) (cons (list-ref xs i) (with-i (+ i 1))) '()))}
(with-i start)))
(check-expect (sublist (list "a" "b" "c" "d" "e") 1 3) (list "b" "c" "d"))
(check-expect (sublist (list 1 2 3 4 5 6 7 8) 0 3) (list 1 2 3 4))
(: string->integer : String -> Integer)
;; string->integer: convert a string representation of an integer to an integer
;; parameter "s": the string representation of an integer
;; output: the integer part of the resulting number only; raise an error if the
;; string is not a number (function intended to be used with only integers)
(define (string->integer s)
(local
{(define conv : (U Complex False) (string->number s))}
(if (complex? conv) (exact-round (real-part conv))
(error "string->integer: invalid integer"))))
(: remove-int : Integer (Listof Integer) -> (Listof Integer))
;; remove-int: remove a given integer from a list of integers
;; parameter "i": the integer to be removed from the list
;; parameter "is": the list of integers
;; output: the list of integers with the given value removed
(define (remove-int i is)
(match is
['() (error "remove-int: given integer is not in list")]
[(cons hd tl) (if (= hd i) tl (cons hd (remove-int i tl)))]))
(check-expect (remove-int 1 (list 1 2 3 4)) (list 2 3 4))
(check-expect (remove-int 1 (list 2 3 1 1 4)) (list 2 3 1 4))
(: remove-max-int : Integer (Listof Integer) -> (Listof Integer))
;; remove-max-int: remove, from a list of integers, the maximum of the values
;; greater than the given integer
;; parameter "i": the given integer
;; parameter "is": the list of integers
;; output: the list of integers with the appropriate value removed
(define (remove-max-int i is)
(local
{(define l : (Listof Integer) (filter (lambda ([m : Integer]) (> m i)) is))}
(if (= 1 (length l)) (remove-int (first l) is)
(remove-int (list-max l) is))))
(check-expect (remove-max-int 2 (list 1 6)) (list 1))
(check-expect (remove-max-int 2 (list 3 4)) (list 3))
(: align-top (-> (Listof Image) Image))
;; align-top: call 'beside/align "top"' on all images in a list of images
;; parameter "imgs": the list of images
;; output: the composite image result of having called 'beside/align "top"'
(define (align-top imgs)
(match imgs
['() empty-image]
[(cons hd tl) (beside/align "top" hd (align-top tl))]))
(: align-bottom (-> (Listof Image) Image))
;; align-bottom: call 'beside/align "bottom"' on all images in a list of images
;; parameter "imgs": the list of images
;; output: the composite image result of having called 'beside/align "bottom"'
(define (align-bottom imgs)
(match imgs
['() empty-image]
[(cons hd tl) (beside/align "bottom" hd (align-bottom tl))]))
;; === styling the backgammon board
(: checker : Image-Color Image-Color -> (Integer -> Image))
;; checker: return a checker image function, given two colors
;; parameter "c1": the main checker color
;; parameter "c2": the checker highlight color
;; output: a checker image function that takes argument radius
(define (checker c1 c2)
(lambda ([r : Integer])
(local
{(define r1 : Real (* 0.675 r))
(define r2 : Real (* 0.8 r))}
(overlay
(circle r1 "solid" c1) (circle r2 "solid" c2) (circle r "solid" c1)))))
(: die : Image-Color Image-Color -> (Integer Integer -> Image))
;; die: return a die image function, given two colors
;; parameter "c1": the die color
;; parameter "c2": the pip color
;; output: a die image function that takes arguments checker radius and pip
;; number
(define (die c1 c2)
(lambda ([r : Integer] [n : Integer])
(local
{(define s : Integer (* 2 r))
(define bg : Image (square s "solid" c1))
(define w : Real (/ s 5))
(define a : Real (* -0.5 w))
(define b : Real (- (* 1.5 w) s))
(define m : Real (* 0.5 (- w s)))
(define pip : Image (circle (/ w 2) "solid" c2))
(define one : Image (overlay pip bg))
(define two : Image (overlay/xy pip a b (overlay/xy pip b a bg)))
(define three : Image (overlay pip two))
(define four : Image (overlay/xy pip b b (overlay/xy pip a a two)))
(define five : Image (overlay pip four))
(define six : Image (overlay/xy pip m a (overlay/xy pip m b four)))}
(cond
[(= n 0) (square s "solid" none)]
[(= n 1) one]
[(= n 2) two]
[(= n 3) three]
[(= n 4) four]
[(= n 5) five]
[(= n 6) six]
[else (error "die: invalid die number")]))))
(: point : Image-Color -> (Integer Boolean -> Image))
;; point: return a point image function
;; parameter "c": the point color
;; output: a point image function that takes arguments checker radius and point
;; direction
(define (point c)
(lambda ([r : Integer] [point-up? : Boolean])
(local
{(define s : Real (sqrt (+ (sqr r) (* 100 (sqr r)))))
(define a : Real (* 2 (radians->degrees (atan (/ 1 10)))))
(define tri : Image (isosceles-triangle s a "solid" c))}
(rotate (if point-up? 0 180) tri))))
(: frame : Image-Color Image-Color -> (Integer Integer -> Image))
;; frame: return a board background image function
;; parameter "c1": the main background color
;; parameter "c2": the background border color
;; output: a background image function that takes arguments checker radius and
;; point spacing
(define (frame c1 c2)
(lambda ([r : Integer] [s : Integer])
(local
{(define w : Real (+ (* 14 s) (* 26 r)))
(define h : Real (* 25 r))
(define scene : Image (rectangle w h "solid" c1))
(define pocket : Image (rectangle (* 2 r) (* 10 r) "solid" c1))
(define break : Image (rectangle (* 2 r) (* 5 r) "solid" c2))
(define borne : Image
(overlay (above pocket break pocket) (rectangle (* 3 r) h "solid" c2)))
(define bar : Image (rectangle (* 2 r) h "solid" c2))
(define border : Image (rectangle (+ w (* 6 r)) (+ h r) "solid" c2))}
(overlay bar (beside borne scene borne) border))))
(: marker : Image-Color -> (String Integer -> Image))
;; marker: return a checker label image function
;; parameter "c": the color of the label text
;; output: a checker labeling function that takes arguments label text and
;; checker radius
(define (marker c)
(lambda ([s : String] [r : Integer])
(if (byte? r) (text s r c) (text s 255 c))))
;; === original style
(define black-checker : (Integer -> Image)
(checker 'steelblue (color 105 155 196)))
(define white-checker : (Integer -> Image)
(checker 'indianred (color 214 122 122)))
(define dark-point : (Integer Boolean -> Image) (point 'darkred))
(define light-point : (Integer Boolean -> Image) (point 'lightblue))
(define background : (Integer Integer -> Image) (frame 'tan 'darkred))
(define label : (String Integer -> Image) (marker 'white))
(define black-die : (Integer Integer -> Image) (die 'steelblue 'white))
(define white-die : (Integer Integer -> Image) (die 'indianred 'white))
;; === original style struct
(define original : Style
(Style 25 20 black-checker white-checker dark-point light-point background
label black-die white-die))
;; === classic style
(define c-black-checker : (Integer -> Image)
(checker 'chocolate (color 228 132 63)))
(define c-white-checker : (Integer -> Image)
(checker 'moccasin (color 255 247 232)))
(define c-dark-point : (Integer Boolean -> Image) (point 'chocolate))
(define c-light-point : (Integer Boolean -> Image) (point 'moccasin))
(define c-background : (Integer Integer -> Image)
(frame (color 63 16 16) (color 43 11 11)))
(define c-label : (String Integer -> Image) (marker 'black))
(define c-black-die : (Integer Integer -> Image) (die 'chocolate 'white))
(define c-white-die : (Integer Integer -> Image) (die 'moccasin 'black))
;; === classic style struct
(define classic : Style
(Style 30 10 c-black-checker c-white-checker c-dark-point c-light-point
c-background c-label c-black-die c-white-die))
;; === drawing the backgammon board
(: draw-board : Style Board -> Image)
;; draw-board: return image of backgammon board, given style and board structs
;; parameter "s": the board style
;; parameter "b": the board struct
;; output: a backgammon board image
(define (draw-board s b)
(match* (s b)
[((Style r s b-c w-c d-pt l-pt bg la _ _)
(Board pts b-bar w-bar b-off w-off))
(local
{(: six-points (-> Boolean (Listof Image)))
(define (six-points point-up?)
(local
{(define p : Image (square s "solid" none))
(define t-dark : Image (d-pt r #t))
(define f-dark : Image (d-pt r #f))
(define t-light : Image (l-pt r #t))
(define f-light : Image (l-pt r #f))}
(if point-up?
(append
(build-list 3 (lambda ([i : Integer])
(beside p t-light p t-dark))) (list p))
(append
(build-list 3 (lambda ([i : Integer])
(beside p f-dark p f-light))) (list p)))))
(: draw-checker : Player -> Image)
(define (draw-checker p) (if (player=? p 'Black) (b-c r) (w-c r)))
(: stack : Point -> Image)
(define (stack p)
(match p
['EmptyPoint (circle r "solid" none)]
[(OccupiedPoint c n)
(cond
[(<= n 5)
(foldr above empty-image
(build-list n (lambda ([i : Integer])
(draw-checker c))))]
[else
(overlay (la (number->string n) r)
(foldr above empty-image
(build-list 5 (lambda ([i : Integer])
(draw-checker c)))))])]))
(: int-stack : Player Integer -> Image)
(define (int-stack p n)
(cond
[(= n 0) (circle r "solid" none)]
[(<= n 5)
(foldr above empty-image (build-list n (lambda ([i : Integer])
(draw-checker p))))]
[else
(overlay (la (number->string n) r)
(foldr above empty-image
(build-list 5 (lambda ([i : Integer])
(draw-checker p)))))]))
(: space : (Listof Image) -> (Listof Image))
(define (space imgs)
(match imgs
['() '()]
[(cons hd tl) (cons (square s "solid" none) (cons hd (space tl)))]))
(define stacks : (Listof Image) (space (map stack pts)))
(define t-stack : Image
(align-top (list (align-top (sublist stacks 24 35))
(square (+ s (* 2 r)) "solid" none)
(align-top (sublist stacks 36 47)))))
(define b-stack : Image
(align-bottom (list (align-bottom (reverse (sublist stacks 12 23)))
(square (+ s (* 2 r)) "solid" none)
(align-bottom (reverse (sublist stacks 0 11))))))
(define t-points : Image (foldr beside empty-image (six-points #t)))
(define f-points : Image (foldr beside empty-image (six-points #f)))
(define all-points : Image
(above
(beside f-points (square (* 2 r) "solid" none) f-points)
(square (* 5 r) "solid" none)
(beside t-points (square (* 2 r) "solid" none) t-points)))
(define t-x : Real (/ (image-width t-stack) 2))
(define t-y : Real (/ (image-height t-stack) 2))
(define b-x : Real (/ (image-width b-stack) 2))
(define b-y : Real (/ (image-height b-stack) 2))
(define w : Real (image-width (bg r s)))
(define h : Real (image-height (bg r s)))
(define b-bar-stack : Image (int-stack 'Black b-bar))
(define w-bar-stack : Image (int-stack 'White w-bar))
(define b-off-stack : Image (int-stack 'Black b-off))
(define w-off-stack : Image (int-stack 'White w-off))}
(place-image
b-bar-stack
(+ (* 7 s) (* 16 r)) (- h (* 0.5 r) (/ (image-height b-bar-stack) 2))
(place-image
w-bar-stack
(+ (* 7 s) (* 16 r)) (+ (* 0.5 r) (/ (image-height w-bar-stack) 2))
(place-image
t-stack
(+ t-x (* 3 r)) (+ t-y (* 0.5 r))
(place-image
b-stack
(- w (* 3 r) b-x) (- h (* 0.5 r) b-y)
(place-image
w-off-stack
(- w (* 1.5 r)) (- h (* 0.5 r) (/ (image-height w-off-stack) 2))
(place-image
b-off-stack
(- w (* 1.5 r)) (+ (* 0.5 r) (/ (image-height b-off-stack) 2))
(overlay all-points (bg r s)))))))))]))
;; === sample backgammon boards
(define initial-board
(Board (append (list (OccupiedPoint 'Black 2))
(make-list 4 'EmptyPoint)
(list (OccupiedPoint 'White 5)
'EmptyPoint
(OccupiedPoint 'White 3))
(make-list 3 'EmptyPoint)
(list (OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5))
(make-list 3 'EmptyPoint)
(list (OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5))
(make-list 4 'EmptyPoint)
(list (OccupiedPoint 'White 2)))
0 0 0 0))
(define test-board
(Board (build-list 24
(lambda ([i : Integer])
(OccupiedPoint (if (even? i) 'Black 'White) (add1 i))))
2 26 25 4))
(define white-home
(Board (append (build-list 4 (lambda ([i : Integer])
(OccupiedPoint 'White (add1 i))))
(list (OccupiedPoint 'White 4) (OccupiedPoint 'White 1))
(make-list 18 'EmptyPoint))
0 0 0 0))
(define black-home
(Board (append (make-list 19 'EmptyPoint)
(build-list 4 (lambda ([i : Integer])
(OccupiedPoint 'Black (+ i 2))))
(list (OccupiedPoint 'White 1)))
0 0 1 0))
;; === universe support & game play
(: roll : Integer -> Integer)
;; roll: return sum of one and built-in 'random' function
;; parameter "max": upper-bound for built-in function 'random'
;; output: sum of one and result of built-in 'random' function
(define (roll max)
(+ (random max) 1))
(: click-where : Style Integer Integer -> ClickLoc)
;; click-where: return aspect of backgammon board clicked on
;; parameter "style": the style of the backgammon board
;; parameter "x": the x-coordinate of the click
;; parameter "y": the y-coordinate of the click
;; output: a ClickLoc that represents the aspect of the backgammon board clicked
(define (click-where style x y)
(match style
[(Style r s _ _ _ _ _ _ _ _)
(local
{(define a : Integer (- x (* 3 r)))
(define b : Integer (- x (* 17 r) (* 7 s)))
(define c : Integer (+ s (* 2 r)))
(define left : Integer
(if (> (remainder a c) s) (exact-ceiling (/ a c)) 0))
(define right : Integer
(if (> (remainder b c) s) (exact-ceiling (/ b c)) 0))}
(cond
[(< (* 0.5 r) y (* 10.5 r))
(cond
[(< (+ (* 3 r) s) x (+ (* 15 r) (* 7 s)))
(if (> left 0) (PointNum (+ 12 left)) 'Nowhere)]
[(< (+ (* 15 r) (* 7 s)) x (+ (* 17 r) (* 7 s))) 'WhiteBar]
[(< (+ (* 17 r) (* 7 s)) x (+ (* 29 r) (* 14 s)))
(if (> right 0) (PointNum (+ 18 right)) 'Nowhere)]
[(< (+ (* 29.5 r) (* 14 s)) x (+ (* 31.5 r) (* 14 s))) 'BlackOff]
[else 'Nowhere])]
[(< (* 10.5 r) y (* 15.5 r))
(cond
[(< (+ (* 7 r) (* 2.5 s)) x (+ (* 11 r) (* 4.5 s))) 'WhiteDice]
[(< (+ (* 21 r) (* 9.5 s)) x (+ (* 25 r) (* 11.5 s))) 'BlackDice]
[else 'Nowhere])]
[(< (* 15.5 r) y (* 25.5 r))
(cond
[(< (+ (* 3 r) s) x (+ (* 15 r) (* 7 s)))
(if (> left 0) (PointNum (- 13 left)) 'Nowhere)]
[(< (+ (* 15 r) (* 7 s)) x (+ (* 17 r) (* 7 s))) 'BlackBar]
[(< (+ (* 17 r) (* 7 s)) x (+ (* 29 r) (* 14 s)))
(if (> right 0) (PointNum (- 7 right)) 'Nowhere)]
[(< (+ (* 29.5 r) (* 14 s)) x (+ (* 31.5 r) (* 14 s))) 'WhiteOff]
[else 'Nowhere])]
[else 'Nowhere]))]))
(check-expect (click-where original 38 38) 'Nowhere)
(check-expect (click-where original 120 38) (PointNum 13))
(check-expect (click-where original 190 38) (PointNum 14))
(check-expect (click-where original 260 38) (PointNum 15))
(check-expect (click-where original 330 38) (PointNum 16))
(check-expect (click-where original 400 38) (PointNum 17))
(check-expect (click-where original 470 38) (PointNum 18))
(check-expect (click-where original 540 38) 'WhiteBar)
(check-expect (click-where original 610 38) (PointNum 19))
(check-expect (click-where original 680 38) (PointNum 20))
(check-expect (click-where original 750 38) (PointNum 21))
(check-expect (click-where original 820 38) (PointNum 22))
(check-expect (click-where original 890 38) (PointNum 23))
(check-expect (click-where original 960 38) (PointNum 24))
(check-expect (click-where original 1043 38) 'BlackOff)
(check-expect (click-where original 120 625) (PointNum 12))
(check-expect (click-where original 190 625) (PointNum 11))
(check-expect (click-where original 260 625) (PointNum 10))
(check-expect (click-where original 330 625) (PointNum 9))
(check-expect (click-where original 400 625) (PointNum 8))
(check-expect (click-where original 470 625) (PointNum 7))
(check-expect (click-where original 540 625) 'BlackBar)
(check-expect (click-where original 610 625) (PointNum 6))
(check-expect (click-where original 680 625) (PointNum 5))
(check-expect (click-where original 750 625) (PointNum 4))
(check-expect (click-where original 820 625) (PointNum 3))
(check-expect (click-where original 890 625) (PointNum 2))
(check-expect (click-where original 960 625) (PointNum 1))
(check-expect (click-where original 1043 625) 'WhiteOff)
(: distance : BoardLoc BoardLoc -> Integer)
;; distance: return the die roll needed to move from one location to another
;; parameter "loc1": the origin
;; parameter "loc2": the destination
;; output: the die roll needed to move from "loc1" to "loc2"
(define (distance loc1 loc2)
(match* (loc1 loc2)
[((PointNum p) (PointNum q)) (- q p)]
[((PointNum p) 'BlackOff) (- 25 p)]
[((PointNum p) 'WhiteOff) (- p)]
[('BlackBar (PointNum p)) p]
[('WhiteBar (PointNum p)) (- p 25)]
[(_ _) (error "distance: not applicable")]))
(check-expect (distance (PointNum 24) (PointNum 19)) -5)
(check-expect (distance (PointNum 19) 'BlackOff) 6)
(check-expect (distance (PointNum 6) 'WhiteOff) -6)
(check-expect (distance 'BlackBar (PointNum 3)) 3)
(check-expect (distance 'WhiteBar (PointNum 21)) -4)
(: home? : Game -> Boolean)
;; home?: return #t if the player whose turn it is has all checkers in the home
;; quadrant, including any borne off checkers, otherwise #f
;; parameter "game": the current game state
;; output: #t if the player has all checkers in the home quadrant, otherwise #f
(define (home? game)
(match game
[(Game (Board pts _ _ b-off w-off) turn _)
(local
{(: point->integer : Point -> Integer)
(define (point->integer pt)
(match pt
['EmptyPoint 0]
[(OccupiedPoint c n) (if (player=? c turn) n 0)]))
(define l : (Listof Point)
(if (player=? turn 'Black) (sublist pts 18 23) (sublist pts 0 5)))
(define off : Integer (if (player=? turn 'Black) b-off w-off))}
(= 15 (+ (foldr + 0 (map point->integer l)) off)))]))
(check-expect (home? (Game white-home 'White '())) #t)
(check-expect (home? (Game black-home 'Black '())) #t)
(check-expect (home? (Game initial-board 'White '())) #f)
(check-expect (home? (Game test-board 'Black '())) #f)
(: dice-match? : Game BoardLoc BoardLoc -> Boolean)
;; dice-match?: return #t if a player's proposed move is permitted by their dice
;; parameter "game": the current game state
;; parameter "loc1": the origin location of the move
;; parameter "loc2": the destination location of the move
;; output: #t if the player's proposed move is permitted, otherwise #f
(define (dice-match? game loc1 loc2)
(match game
[(Game (Board pts _ _ _ _) turn moves)
(local
{(define dist : Integer (distance loc1 loc2))
(define l : (Listof Point) (if (player=? turn 'Black)
(sublist pts 18 23)
(reverse (sublist pts 0 5))))
(: max-point : Integer (Listof Point) -> Integer)
(define (max-point i lpt)
(match lpt
['() (error "max-point: no maximum point")]
[(cons hd tl)
(match hd
['EmptyPoint (max-point (- i 1) tl)]
[(OccupiedPoint c _)
(if (player=? c turn) i (max-point (- i 1) tl))])]))}
(or (if (player=? turn 'Black)
(and (positive? dist)
(ormap (lambda ([i : Integer]) (= i (abs dist))) moves))
(and (negative? dist)
(ormap (lambda ([i : Integer]) (= i (abs dist))) moves)))
(match* (loc1 loc2)
[(_ 'BlackOff)
(and (ormap (lambda ([i : Integer]) (> i (max-point 6 l))) moves)
(= (abs dist) (max-point 6 l)))]
[(_ 'WhiteOff)
(and (ormap (lambda ([i : Integer]) (> i (max-point 6 l))) moves)
(= (abs dist) (max-point 6 l)))]
[(_ _) #f])))]))
;; separate check-expects not written for dice-match?, as it is central to
;; legal-move?
(: legal-move? : Game BoardLoc BoardLoc -> Boolean)
;; legal-move?: return #t if the proposed move is legal, otherwise #f
;; parameter "game": the current game state
;; parameter "loc1": the origin location of the move
;; parameter "loc2": the destination location of the move
;; output: #t if the proposed move is legal, otherwise #f
(define (legal-move? game loc1 loc2)
(match game
[(Game (Board pts b-bar w-bar _ _) turn _)
(if (or (and (player=? turn 'Black) (> b-bar 0))
(and (player=? turn 'White) (> w-bar 0)))
(if (player=? turn 'Black)
(match* (loc1 loc2)
[('BlackBar (PointNum p))
(match (list-ref pts (- p 1))
[(OccupiedPoint 'White 1) (dice-match? game loc1 loc2)]
[(OccupiedPoint 'White _) #f]
[_ (dice-match? game loc1 loc2)])]
[(_ _) #f])
(match* (loc1 loc2)
[('WhiteBar (PointNum p))
(match (list-ref pts (- p 1))
[(OccupiedPoint 'Black 1) (dice-match? game loc1 loc2)]
[(OccupiedPoint 'Black _) #f]
[_ (dice-match? game loc1 loc2)])]
[(_ _) #f]))
(match* (loc1 loc2)
[((PointNum p) (PointNum q))
(match* ((list-ref pts (- p 1)) (list-ref pts (- q 1)))
[('EmptyPoint _) #f]
[((OccupiedPoint c _) 'EmptyPoint)
(and (player=? c turn) (dice-match? game loc1 loc2))]
[((OccupiedPoint c1 _) (OccupiedPoint c2 n2))
(and (player=? c1 turn)
(if (player=? c1 c2) (dice-match? game loc1 loc2)
(and (= n2 1) (dice-match? game loc1 loc2))))])]
[((PointNum p) 'BlackOff)
(and (and (player=? turn 'Black) (home? game))
(match (list-ref pts (- p 1))
[(OccupiedPoint 'Black _) (dice-match? game loc1 loc2)]
[_ #f]))]
[((PointNum p) 'WhiteOff)
(and (and (player=? turn 'White) (home? game))
(match (list-ref pts (- p 1))
[(OccupiedPoint 'White _) (dice-match? game loc1 loc2)]
[_ #f]))]
[(_ _) #f]))]))
(check-expect (legal-move? (Game initial-board 'Black (list 2 4)) (PointNum 1)
(PointNum 3)) #t)
(check-expect (legal-move? (Game initial-board 'Black (list 3 4)) (PointNum 1)
(PointNum 3)) #f)
(check-expect (legal-move? (Game initial-board 'Black (list 2 4)) (PointNum 12)
(PointNum 10)) #f)
(check-expect (legal-move? (Game initial-board 'Black (list 1 4)) (PointNum 12)
(PointNum 13)) #f)
(check-expect (legal-move? (Game initial-board 'White (list 2 4)) (PointNum 24)
(PointNum 22)) #t)
(check-expect (legal-move? (Game initial-board 'White (list 3 4)) (PointNum 24)
(PointNum 22)) #f)
(check-expect (legal-move? (Game initial-board 'White (list 2 4)) (PointNum 13)
(PointNum 15)) #f)
(check-expect (legal-move? (Game initial-board 'White (list 1 4)) (PointNum 13)
(PointNum 12)) #f)
(check-expect (legal-move? (Game initial-board 'Black (list 1 6)) (PointNum 19)
'BlackOff) #f)
(check-expect (legal-move? (Game initial-board 'White (list 1 6)) (PointNum 6)
'WhiteOff) #f)
(check-expect (legal-move? (Game white-home 'White (list 1 6)) (PointNum 6)
'WhiteOff) #t)
(check-expect (legal-move? (Game black-home 'Black (list 1 5)) (PointNum 20)
'BlackOff) #t)
(check-expect (legal-move? (Game black-home 'Black (list 1 4)) (PointNum 20)
(PointNum 24)) #t)
(check-expect (legal-move? (Game test-board 'Black (list 3 4)) 'BlackBar
(PointNum 3)) #t)
(check-expect (legal-move? (Game test-board 'Black (list 2 4)) (PointNum 1)
(PointNum 3)) #f)
(check-expect (legal-move? (Game black-home 'Black (list 1 6)) (PointNum 20)
'BlackOff) #t)
(check-expect (legal-move? (Game black-home 'Black (list 1 2)) (PointNum 20)
'BlackOff) #f)
(check-expect (legal-move? (Game initial-board 'White '()) (PointNum 24)
(PointNum 20)) #f)
(: apply-move : Game BoardLoc BoardLoc -> Game)
;; apply-move: move checker from the proposed origin location to the proposed
;; destination location on the board, if the move is legal. otherwise, leave
;; the board unchanged.
;; parameter "game": the current game state
;; parameter "loc1": the origin location of the move
;; parameter "loc2": the destination location of the move
;; output: the game state with the move applied, if it is legal; otherwise an
;; error is raised
(define (apply-move game loc1 loc2)
(if (legal-move? game loc1 loc2)
(match game
[(Game (Board pts b-bar w-bar b-off w-off) turn moves)
(local
{(define dist : Integer (abs (distance loc1 loc2)))
(define moves-2 : (Listof Integer)
(if (ormap (lambda ([i : Integer]) (= i dist)) moves)
(remove-int dist moves)
(remove-max-int dist moves)))
(: pts-2 : Integer -> (Listof Point))
(define (pts-2 i)
(match (list-ref pts (- i 1))
[(OccupiedPoint _ 1) (replace-at (- i 1) 'EmptyPoint pts)]
[(OccupiedPoint c n)
(replace-at (- i 1) (OccupiedPoint c (- n 1)) pts)]
[_ pts]))}
(match* (loc1 loc2)
[((PointNum p) (PointNum q))
(match (list-ref pts (- q 1))
['EmptyPoint
(Game
(Board (replace-at (- q 1) (OccupiedPoint turn 1) (pts-2 p))
b-bar w-bar b-off w-off) turn moves-2)]
[(OccupiedPoint c n)
(if (player=? c turn)
(Game
(Board
(replace-at (- q 1) (OccupiedPoint c (+ n 1)) (pts-2 p))
b-bar w-bar b-off w-off) turn moves-2)
(if (player=? c 'Black)
(Game
(Board
(replace-at (- q 1) (OccupiedPoint turn 1) (pts-2 p))
(+ b-bar 1) w-bar b-off w-off) turn moves-2)
(Game
(Board
(replace-at (- q 1) (OccupiedPoint turn 1) (pts-2 p))
b-bar (+ w-bar 1) b-off w-off) turn moves-2)))])]
[((PointNum p) 'BlackOff)
(Game
(Board (pts-2 p) b-bar w-bar (+ b-off 1) w-off) turn moves-2)]
[((PointNum p) 'WhiteOff)
(Game
(Board (pts-2 p) b-bar w-bar b-off (+ w-off 1)) turn moves-2)]
[('BlackBar (PointNum p))
(match (list-ref pts (- p 1))
['EmptyPoint
(Game (Board (replace-at (- p 1) (OccupiedPoint turn 1) pts)
(- b-bar 1) w-bar b-off w-off) turn moves-2)]
[(OccupiedPoint c n)
(if (player=? c turn)
(Game
(Board (replace-at (- p 1) (OccupiedPoint c (+ n 1)) pts)
(- b-bar 1) w-bar b-off w-off) turn moves-2)
(Game
(Board (replace-at (- p 1) (OccupiedPoint turn 1) pts)
(- b-bar 1) (+ w-bar 1) b-off w-off) turn
moves-2))])]
[('WhiteBar (PointNum p))
(match (list-ref pts (- p 1))
['EmptyPoint
(Game (Board (replace-at (- p 1) (OccupiedPoint turn 1) pts)
b-bar (- w-bar 1) b-off w-off) turn moves-2)]
[(OccupiedPoint c n)
(if (player=? c turn)
(Game
(Board (replace-at (- p 1) (OccupiedPoint c (+ n 1)) pts)
b-bar (- w-bar 1) b-off w-off) turn moves-2)
(Game
(Board (replace-at (- p 1) (OccupiedPoint turn 1) pts)
(+ b-bar 1) (- w-bar 1) b-off w-off)
turn moves-2))])]))])
(error "apply-move: illegal move")))
(: available-moves? : Game -> Boolean)
;; available-moves?: return #t if it is possible for the player whose turn it is
;; to make a legal move, otherwise #f
;; parameter "game": the current game state
;; output: #t if it is possible for the player to make a move, otherwise #f
(define (available-moves? game)
(match game
[(Game (Board pts b-bar w-bar _ _) turn _)
(local
{(: start-point? : Point -> Boolean)
(define (start-point? pt)
(match pt
[(OccupiedPoint c _) (player=? c turn)]
[_ #f]))
(: start-points : (Listof Point) Integer -> (Listof PointNum))
(define (start-points lpt i)
(match lpt
['() '()]
[(cons hd tl)
(if (start-point? hd)
(cons (PointNum (+ i 1)) (start-points tl (+ i 1)))
(start-points tl (+ i 1)))]))
(define start-pts : (Listof PointNum) (start-points pts 0))
(define starts : (Listof BoardLoc)
(if (player=? turn 'Black)
(if (> b-bar 0) (append start-pts (list 'BlackBar)) start-pts)
(if (> w-bar 0) (append start-pts (list 'WhiteBar)) start-pts)))
(: end-point? : Point -> Boolean)
(define (end-point? pt)
(match pt
['EmptyPoint #t]
[(OccupiedPoint c n) (or (player=? c turn) (= n 1))]))
(: end-points : (Listof Point) Integer -> (Listof PointNum))
(define (end-points lpt i)
(match lpt
['() '()]
[(cons hd tl)
(if (end-point? hd)
(cons (PointNum (+ i 1)) (end-points tl (+ i 1)))
(end-points tl (+ i 1)))]))
(define end-pts : (Listof PointNum) (end-points pts 0))
(define ends : (Listof BoardLoc)
(if (player=? turn 'Black)
(if (home? game) (append end-pts (list 'BlackOff)) end-pts)
(if (home? game) (append end-pts (list 'WhiteOff)) end-pts)))
(: helper : (Listof BoardLoc) (Listof BoardLoc) -> Boolean)
(define (helper sts ens)
(ormap (lambda ([st : BoardLoc])
(ormap (lambda ([en : BoardLoc])
(legal-move? game st en)) ens)) sts))}
(helper starts ends))]))
(check-expect (available-moves? (Game initial-board 'Black (list 2 4))) #t)
(check-expect (available-moves? (Game
(Board
(list
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 1)
(OccupiedPoint 'White 1)
(OccupiedPoint 'White 7)
'EmptyPoint
(OccupiedPoint 'White 3)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2)
(OccupiedPoint 'White 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 2)
(OccupiedPoint 'Black 5)
(OccupiedPoint 'Black 3)
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 4)
'EmptyPoint)
0
1
0
0)
'White
'(5 2))) #f)
(: game-over? : Game -> Boolean)
;; game-over?: return #t if the game is over, otherwise #f
;; parameter "game": the current game state
;; output: #t if the game is over, otherwise #f
(define (game-over? game)
(match game
[(Game (Board _ _ _ b-off w-off) _ _) (or (= b-off 15) (= w-off 15))]))
(check-expect (game-over? (Game initial-board 'Black (list 2 4))) #f)
(check-expect (game-over? (Game (Board (make-list 24 'EmptyPoint) 0 0 15 0)
'Black '())) #t)
(: winner : Game -> Player)
;; winner: return the player that has won the game
;; parameter "game": the current game state
;; output: the winner of the game; if the game is not over, an error is raised
(define (winner game)
(if (game-over? game)
(if (= (Board-black-off (Game-board game)) 15) 'Black 'White)
(error "winner: game is not over")))
(check-expect (winner (Game (Board (make-list 24 'EmptyPoint) 0 0 15 0)
'Black '())) 'Black)
(check-expect (winner (Game (Board (make-list 24 'EmptyPoint) 0 0 0 15)
'White '())) 'White)
;; === universe
(: draw : World -> Image)
;; draw: draw the backgammon world
;; parameter "w": the World struct
;; output: an image of the backgammon world
(define (draw w)
(match w
[(World game (Style r s _ _ _ _ _ _ b-d w-d) w1 w2 b1 b2 cl _)
(local
{(define board : Image (draw-board (World-style w) (Game-board game)))
(define font : Integer (* 4 r))
(define fin : Image
(if (game-over? game)
(text (string-append (string-upcase
(symbol->string (winner game))) " " "WINS!")
(if (byte? font) font 255) 'white) empty-image))
(define w-dice : Image
(beside (w-d r w1) (square (/ r 2) "solid" none) (w-d r w2)))
(define b-dice : Image
(beside (b-d r b1) (square (/ r 2) "solid" none) (b-d r b2)))
(define w-dice-x : Real
(if (game-over? game) (* 5.25 r) (+ (* 9 r) (* 3.5 s))))
(define b-dice-x : Real
(if (game-over? game)
(- (image-width board) (* 5.25 r)) (+ (* 23 r) (* 10.5 s))))
(define highlight : Image
(rectangle (* 2 r) (* 10 r) "outline" 'white))
(define x : Integer
(match cl
[(PointNum p)
(cond
[(< p 7) (+ (* (+ (* -2 p) 30) r) (* (- 14 p) s))]
[(< p 13) (+ (* (+ (* -2 p) 28) r) (* (- 13 p) s))]
[(< p 19) (+ (* (- (* 2 p) 22) r) (* (- p 12) s))]
[else (+ (* (- (* 2 p) 20) r) (* (- p 11) s))])]
['BlackBar (+ (* 7 s) (* 16 r))]
['WhiteBar (+ (* 7 s) (* 16 r))]
[_ 0]))
(define y : Real
(match cl
[(PointNum p) (if (< p 13) (* 20.5 r) (* 5.5 r))]
['BlackBar (* 20.5 r)]
['WhiteBar (* 5.5 r)]
[_ 0]))
(define wrld : Image
(overlay
fin
(place-image
w-dice
w-dice-x (/ (image-height board) 2)
(place-image
b-dice
b-dice-x (/ (image-height board) 2) board))))}
(if (and (> x 0) (> y 0)) (place-image highlight x y wrld) wrld))]))
(: react-to-mouse : World Integer Integer Mouse-Event -> World)
;; react-to-mouse: manifest appropriate reactions in the backgammon world,
;; according to given click location(s)
;; parameter "w": the World struct
;; parameter "x": the x-coordinate of the click
;; parameter "y": the y-coordinate of the click
;; parameter "e": the click event type
;; output: the updated World struct, given the effect of the user click
(define (react-to-mouse w x y e)
(if (game-over? (World-game w)) w
(match* (w e)
[((World (Game board turn _) style w1 w2 b1 b2 cl h) "button-down")
(local
{(define loc : ClickLoc (click-where style x y))
(define game : Game (World-game w))}
(match* (cl loc)
[('Nowhere 'WhiteDice)
(if (and (player=? turn 'Black) (not (available-moves? game)))
(local
{(define roll1 : Integer (roll 6))
(define roll2 : Integer (roll 6))
(define moves-2 : (Listof Integer)
(if (= roll1 roll2)
(make-list 4 roll1) (list roll1 roll2)))}
(World (Game board 'White moves-2)
style roll1 roll2 b1 b2 'Nowhere (cons game h))) w)]
[('Nowhere 'BlackDice)
(if (and (player=? turn 'White) (not (available-moves? game)))
(local
{(define roll1 : Integer (roll 6))
(define roll2 : Integer (roll 6))
(define moves-2 : (Listof Integer)
(if (= roll1 roll2)
(make-list 4 roll1) (list roll1 roll2)))}
(World (Game board 'Black moves-2)
style w1 w2 roll1 roll2 'Nowhere (cons game h))) w)]
[('Nowhere 'WhiteBar)
(if (and (player=? turn 'White) (> (Board-white-bar board) 0))
(World game style w1 w2 b1 b2 'WhiteBar h) w)]
[('Nowhere 'BlackBar)
(if (and (player=? turn 'Black) (> (Board-black-bar board) 0))
(World game style w1 w2 b1 b2 'BlackBar h) w)]
[('Nowhere (PointNum p))
(match (list-ref (Board-points board) (- p 1))
[(OccupiedPoint c _)
(if (player=? c turn)
(World game style w1 w2 b1 b2 (PointNum p) h) w)]
[_ w])]
[('WhiteBar 'WhiteBar) (World game style w1 w2 b1 b2 'Nowhere h)]
[('WhiteBar (PointNum p))
(if (legal-move? game cl loc)
(World (apply-move game cl loc) style w1 w2 b1 b2 'Nowhere
(cons game h)) w)]
[('BlackBar 'BlackBar) (World game style w1 w2 b1 b2 'Nowhere h)]
[('BlackBar (PointNum p))
(if (legal-move? game cl loc)
(World (apply-move game cl loc) style w1 w2 b1 b2 'Nowhere
(cons game h)) w)]
[((PointNum p) 'WhiteOff)
(if (legal-move? game cl loc)
(World (apply-move game cl loc) style w1 w2 b1 b2 'Nowhere
(cons game h)) w)]
[((PointNum p) 'BlackOff)
(if (legal-move? game cl loc)
(World (apply-move game cl loc) style w1 w2 b1 b2 'Nowhere
(cons game h)) w)]
[((PointNum p) (PointNum p))
(World game style w1 w2 b1 b2 'Nowhere h)]
[((PointNum p) (PointNum q))
(if (legal-move? game cl loc)
(World (apply-move game cl loc) style w1 w2 b1 b2 'Nowhere
(cons game h)) w)]
[(_ _) w]))]
[(_ _) w])))
(: key : World String -> World)
;; key: manifest appropriate reactions in the backgammon world, according to
;; the given key press
;; parameter "w": the World struct
;; parameter "k": the key pressed
;; output: the updated World struct, given the effect of the user key press
(define (key w k)
(match k
["u" (undo w)]
["s" (begin (save-game! w) w)]
["l" (load-game (World-style w))]
[_ w]))
(: run : Style -> World)
;; run: run the backgammon game
;; parameter "style": board style, as specified by a Style struct
;; output: the interactive world program
(define (run style)
(local
{(: initial-roll : Integer -> (Listof Integer))
(define (initial-roll max)
(local
{(define rll : (Listof Integer) (list (roll max) (roll max)))}
(if (= (first rll) (second rll)) (initial-roll max) rll)))
(define i-rll : (Listof Integer) (initial-roll 6))
(define w1 : Integer (first i-rll))
(define b1 : Integer (second i-rll))
(define turn : Player (if (> w1 b1) 'White 'Black))}
(big-bang (World (Game initial-board turn i-rll) style w1 0 b1 0 'Nowhere
'()) : World
[to-draw draw]
[on-mouse react-to-mouse]
[on-key key])))
;; === undo
(: infer-dice : (Listof Game) -> (Listof Integer))
;; infer-dice: infer dice values that would be on display in the most recent
;; game state, given a history of game states
;; parameter "h": a list of previous game states (game history)
;; output: the inferred dice values, in a list
(define (infer-dice h)
(local
{(: helper : Player (Listof Game) -> (Listof Integer))
(define (helper p gs)
(match gs
['() (error "infer-dice: out of scope")]
[(cons (Game _ turn moves) '())
(if (player=? turn 'Black)
(if (player=? p 'White) (list (list-min moves) 0)
(list (list-max moves) 0))
(if (player=? p 'White) (list (list-max moves) 0)
(list (list-min moves) 0)))]
[(cons (Game _ turn moves) tl)
(if (and (player=? turn p) (> (length moves) 1)) (sublist moves 0 1)
(helper p tl))]))}
(append (helper 'White h) (helper 'Black h))))
(check-expect (infer-dice (list (Game
(Board
(list
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 1)
(OccupiedPoint 'White 6)
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 3))
0
0
0
0)
'Black
'(6 6 6 6))
(Game
(Board
(list
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 1)
(OccupiedPoint 'White 6)
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 3))
0
0
0
0)
'White
'())
(Game
(Board
(list
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 6)
(OccupiedPoint 'Black 1)
(OccupiedPoint 'White 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 3))
0
0
0
0)
'White
'(3))
(Game
(Board
(list
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 6)
(OccupiedPoint 'Black 1)
(OccupiedPoint 'White 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
1
0
0)
'White
'(1 3))
(Game
(Board
(list
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 6)
(OccupiedPoint 'Black 1)
(OccupiedPoint 'White 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
1
0
0)
'Black
'())
(Game
(Board
(list
(OccupiedPoint 'Black 1)
'EmptyPoint
(OccupiedPoint 'Black 1)
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 6)
(OccupiedPoint 'White 1)
(OccupiedPoint 'White 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
0
0
0)
'Black
'(4))
(Game
(Board
(list
(OccupiedPoint 'Black 2)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 6)
(OccupiedPoint 'White 1)
(OccupiedPoint 'White 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
0
0
0)
'Black
'(2 4))
(Game
(Board
(list
(OccupiedPoint 'Black 2)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 6)
(OccupiedPoint 'White 1)
(OccupiedPoint 'White 1)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
0
0
0)
'White
'())
(Game
(Board
(list
(OccupiedPoint 'Black 2)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 5)
(OccupiedPoint 'White 1)
(OccupiedPoint 'White 2)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
0
0
0)
'White
'(2))
(Game
(Board
(list
(OccupiedPoint 'Black 2)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 5)
'EmptyPoint
(OccupiedPoint 'White 3)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
0
0
0)
'White
'(2 1)))) (list 1 3 6 6))
(check-expect (infer-dice (list (Game
(Board
(list
(OccupiedPoint 'Black 2)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 5)
'EmptyPoint
(OccupiedPoint 'White 3)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 5)
(OccupiedPoint 'White 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'Black 3)
'EmptyPoint
(OccupiedPoint 'Black 5)
'EmptyPoint
'EmptyPoint
'EmptyPoint
'EmptyPoint
(OccupiedPoint 'White 2))
0
0
0
0)
'White
'(2 1)))) (list 2 0 1 0))
(: undo : World -> World)
;; undo: undo a move, unless the world is the starting world (in which case
;; nothing changes)
;; parameter "w": the current World struct
;; output: the World struct one move back, unless the given world was the
;; starting world (in which case the world remains unchanged)
(define (undo w)
(match w
[(World _ style _ _ _ _ 'Nowhere h)
(match h
['() w]
[(cons hd tl)
(local
{(define dice : (Listof Integer) (infer-dice h))
(define w1 : Integer (first dice))
(define w2 : Integer (second dice))
(define b1 : Integer (third dice))
(define b2 : Integer (fourth dice))}
(World hd style w1 w2 b1 b2 'Nowhere tl))])]
[_ w]))
;; === saving & loading a game
(: point->string : Point -> String)
;; point->string: convert a point into its string representation
;; parameter "pt": the point to be converted
;; output: the point's string representation
(define (point->string pt)
(match pt
['EmptyPoint "_"]
[(OccupiedPoint 'Black n) (string-append "B" (number->string n))]
[(OccupiedPoint 'White n) (string-append "W" (number->string n))]))
(check-expect (point->string 'EmptyPoint) "_")
(check-expect (point->string (OccupiedPoint 'Black 5)) "B5")
(check-expect (point->string (OccupiedPoint 'White 2)) "W2")
(: string->point : String -> Point)
;; string->point: convert a string representation of a point into a point
;; parameter "s": the string representation
;; output: the point
(define (string->point s)
(cond
[(string-prefix? s "B")
(OccupiedPoint 'Black (string->integer (substring s 1)))]
[(string-prefix? s "W")
(OccupiedPoint 'White (string->integer (substring s 1)))]
[(string=? s "_") 'EmptyPoint]
[else (error "string->point: string does not represent a point")]))
(check-expect (string->point "_") 'EmptyPoint)
(check-expect (string->point "B5") (OccupiedPoint 'Black 5))
(check-expect (string->point "W2") (OccupiedPoint 'White 2))
(: points->string : (Listof Point) -> String)
;; points->string: convert a list of points into its string representation
;; parameter "pts": the list of points to be converted
;; output: the point list's string representation
(define (points->string pts)
(string-trim
(foldr string-append ""
(map (lambda ([pt : Point]) (string-append (point->string pt) " "))
pts))))
(check-expect (points->string (Board-points initial-board))
"B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2")
(: string->points : String -> (Listof Point))
;; string->point: convert a string representation of a list of points into a
;; list of points
;; parameter "s": the string representation
;; output: the list of points
(define (string->points s) (map string->point (string-split s " ")))
(check-expect
(string->points "B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2")
(Board-points initial-board))
(: board->string : Board -> String)
;; board->string: convert a board into its string representation
;; parameter "brd": the board to be converted
;; output: the board's string representation
(define (board->string brd)
(match brd
[(Board pts b-bar w-bar b-off w-off)
(string-append (points->string pts) "|" (number->string b-bar) "|"
(number->string w-bar) "|" (number->string b-off) "|"
(number->string w-off))]))
(check-expect (board->string initial-board)
"B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0")
(: string->board : String -> Board)
;; string->board: convert a string representation of a board into a board
;; parameter "s": the string representation
;; output: the board
(define (string->board s)
(local
{(define l : (Listof String) (string-split s "|"))
(define pts : (Listof Point) (string->points (first l)))
(define is : (Listof Integer) (map string->integer (rest l)))}
(Board pts (first is) (second is) (third is) (fourth is))))
(check-expect
(string->board
"B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0")
initial-board)
(: game->string : Game -> String)
;; game->string: convert a game into its string representation
;; parameter "g": the game to be converted
;; output: the game's string representation
(define (game->string g)
(match g
[(Game brd trn mvs)
(string-append
(board->string brd) "@"
(if (player=? trn 'Black) "B" "W") "@"
(string-trim
(foldr string-append ""
(map (lambda ([m : Integer])
(string-append (number->string m) " ")) mvs))))]))
(check-expect
(game->string (Game initial-board 'White (list 2 6)))
"B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@W@2 6")
(check-expect
(game->string (Game initial-board 'White '()))
"B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@W@")
(: string->game : String -> Game)
;; string->game: convert a string representation of a game into a game
;; parameter "s": the string representation
;; output: the game
(define (string->game s)
(local
{(define l : (Listof String) (string-split s "@"))
(define brd : Board (string->board (first l)))
(define trn : Player (if (string=? (second l) "B") 'Black 'White))
(define mvs : (Listof Integer)
(if (> (length l) 2)
(map string->integer (string-split (third l) " ")) '()))}
(Game brd trn mvs)))
(check-expect
(string->game
"B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@W@2 6")
(Game initial-board 'White (list 2 6)))
(check-expect
(string->game
"B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@W@")
(Game initial-board 'White '()))
(: history->string : (Listof Game) -> String)
;; history->string: convert a history of games into its string representation
;; parameter "gs": the history of games to be converted
;; output: the history's string representation
(define (history->string gs)
(local
{(define l : (Listof String) (map game->string gs))
(: ins : (Listof String) -> (Listof String))
(define (ins ss)
(match ss
['() '()]
[(cons _ '()) ss]
[(cons hd tl) (cons hd (cons "!" (ins tl)))]))}
(foldr string-append "" (ins l))))
(: string->history : String -> (Listof Game))
;; string->history: convert a string representation of a history of games into a
;; history of games
;; parameter "s": the string representation
;; output: the history of games
(define (string->history s)
(local
{(define l : (Listof String) (string-split s "!"))}
(map string->game l)))
(: world->string : World -> String)
;; world->string: return a string of the history list of the current world, with
;; the current game state prepended
;; parameter "w": the current world
;; output: the world's string representation
(define (world->string w)
(match w [(World g _ _ _ _ _ _ h) (history->string (cons g h))]))
(: string->world : Style String -> World)
;; string->world: use the first game state in the game list as the current game
;; state. use the rest of the list as game history. infer dice values from the
;; game list. style according to given style.
(define (string->world style s)
(local
{(define l : (Listof Game) (string->history s))
(define g : Game (first l))
(define h : (Listof Game) (rest l))
(define dice : (Listof Integer) (infer-dice l))
(define w1 : Integer (first dice))
(define w2 : Integer (second dice))
(define b1 : Integer (third dice))
(define b2 : Integer (fourth dice))}
(World g style w1 w2 b1 b2 'Nowhere h)))
(: save-game! : World -> Void)
;; prompt the user for an output file location
;; then, save the game to that file
;; do nothing if the user cancels
(define (save-game! w)
(local
{(define path : (U Path False) (put-file))}
(if (path? path)
(begin
(write-string (world->string w)
(open-output-file path))
(void))
(void))))
(: load-game : Style -> World)
;; prompt the user to choose a file
;; then load an in-progress game from that file
;; use the provided Style to make a new World
;; raise an error if the user cancels or if something goes wrong
(define (load-game s)
(local
{(define path : (U Path False) (get-file))}
(if (path? path)
(string->world s (port->string (open-input-file path)))
(error "load-game: user cancelled"))))
(test)
\ No newline at end of file
W1 W1 W1 _ _ W7 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|0|0|15|5@B@2!W1 W1 W1 _ _ W7 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1|0|0|14|5@B@3 2!W1 W1 W1 _ _ W7 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1|0|0|14|5@W@!W1 _ W1 _ _ W8 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1|0|0|14|5@W@4!W1 _ W2 _ _ W8 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1|0|0|14|4@W@3 4!W1 _ W2 _ _ W8 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1|0|0|14|4@B@!W1 _ W2 _ _ W8 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1 B1|0|0|13|4@B@2!W1 _ W2 _ _ W8 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 B1|0|0|12|4@B@2 5!W1 _ W2 _ _ W8 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 B1|0|0|12|4@W@!W1 _ W3 _ _ W8 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 B1|0|0|12|3@W@3!W1 _ W3 _ _ W9 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 B1|0|0|12|2@W@6 3!W1 _ W3 _ _ W9 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 B1|0|0|12|2@B@!W1 _ W3 _ _ W9 _ _ _ _ _ _ _ _ _ _ _ _ B1 _ _ _ B1 B1|0|0|12|2@B@3!W1 _ W3 _ _ W9 _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 _ _ B1 B1|0|0|11|2@B@3 5!W1 _ W3 _ _ W9 _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 _ _ B1 B1|0|0|11|2@W@!W1 _ W3 W1 _ W9 _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 _ _ B1 B1|0|0|11|1@W@4!W1 _ W3 W1 W1 W9 _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 _ _ B1 B1|0|0|11|0@W@5 4!W1 _ W3 W1 W1 W9 _ _ _ _ _ _ _ _ _ _ _ _ B1 B1 _ _ B1 B1|0|0|11|0@B@!W1 _ W3 W1 W1 W9 _ _ _ _ _ _ _ _ _ _ _ _ B1 B2 _ _ _ B1|0|0|11|0@B@3!W1 _ W3 W1 W1 W9 _ _ _ _ _ _ _ _ _ _ _ _ B2 B2 _ _ _ B1|0|0|10|0@B@6 3!W1 _ W3 W1 W1 W9 _ _ _ _ _ _ _ _ _ _ _ _ B2 B2 _ _ _ B1|0|0|10|0@W@!_ W1 W3 W1 W1 W9 _ _ _ _ _ _ _ _ _ _ _ _ B2 B2 _ _ _ B1|0|0|10|0@W@1!_ W1 W2 W1 W1 W9 _ W1 _ _ _ _ _ _ _ _ _ _ B2 B2 _ _ _ B1|0|0|10|0@W@5 1!_ W1 W2 W1 W1 W9 _ W1 _ _ _ _ _ _ _ _ _ _ B2 B2 _ _ _ B1|0|0|10|0@B@!_ W1 W2 W1 W1 W9 _ W1 _ _ _ _ _ _ _ _ _ _ B2 B2 _ _ B1 B1|0|0|9|0@B@2!_ W1 W2 W1 W1 W9 _ W1 _ _ _ _ _ _ _ _ _ _ B2 B3 _ _ B1 B1|0|0|8|0@B@5 2!_ W1 W2 W1 W1 W9 _ W1 _ _ _ _ _ _ _ _ _ _ B2 B3 _ _ B1 B1|0|0|8|0@W@!_ W1 W2 _ W1 W9 _ W2 _ _ _ _ _ _ _ _ _ _ B2 B3 _ _ B1 B1|0|0|8|0@W@4!_ _ W2 _ W1 W9 _ W3 _ _ _ _ _ _ _ _ _ _ B2 B3 _ _ B1 B1|0|0|8|0@W@4 6!_ _ W2 _ W1 W9 _ W3 _ _ _ _ _ _ _ _ _ _ B2 B3 _ _ B1 B1|0|0|8|0@B@!_ _ W2 _ W1 W9 _ W3 _ _ _ _ _ _ _ _ _ _ B2 B3 _ _ B2 B1|0|0|7|0@B@2!_ _ W2 _ W1 W9 _ W3 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B2 B1|0|0|6|0@B@2 6!_ _ W2 _ W1 W9 _ W3 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B2 B1|0|0|6|0@W@!_ _ W2 _ W1 W8 W1 W3 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B2 B1|0|0|6|0@W@1!_ _ W1 _ W1 W8 W1 W4 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B2 B1|0|0|6|0@W@1 5!_ _ W1 _ W1 W8 W1 W4 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B2 B1|0|0|6|0@B@!_ _ W1 _ W1 W8 W1 W4 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B3 B1|0|0|5|0@B@2!_ _ W1 _ W1 W8 W1 W4 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B3 B2|0|0|4|0@B@1 2!_ _ W1 _ W1 W8 W1 W4 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B3 B2|0|0|4|0@W@!_ _ _ _ W1 W8 W1 W5 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B3 B2|0|0|4|0@W@5!_ _ _ _ W1 W7 W2 W5 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B3 B2|0|0|4|0@W@1 5!_ _ _ _ W1 W7 W2 W5 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B3 B2|0|0|4|0@B@!_ _ _ _ W1 W7 W2 W5 _ _ _ _ _ _ _ _ _ _ B3 B3 _ _ B4 B2|0|0|3|0@B@2!_ _ _ _ W1 W7 W2 W5 _ _ _ _ _ _ _ _ _ _ B4 B3 _ _ B4 B2|0|0|2|0@B@2 6!_ _ _ _ W1 W7 W2 W5 _ _ _ _ _ _ _ _ _ _ B4 B3 _ _ B4 B2|0|0|2|0@W@!_ _ _ _ W1 W7 W2 W4 _ _ _ _ W1 _ _ _ _ _ B4 B3 _ _ B4 B2|0|0|2|0@W@5!_ _ _ _ W1 W7 W1 W4 _ _ _ _ W2 _ _ _ _ _ B4 B3 _ _ B4 B2|0|0|2|0@W@6 5!_ _ _ _ W1 W7 W1 W4 _ _ _ _ W2 _ _ _ _ _ B4 B3 _ _ B4 B2|0|0|2|0@B@!_ _ _ _ W1 W7 W1 W4 _ _ _ _ W2 _ _ _ _ _ B4 B4 _ _ B4 B1|0|0|2|0@B@4!_ _ _ _ W1 W7 W1 W4 _ _ _ _ W2 _ _ _ _ _ B4 B5 _ _ B4 _|0|0|2|0@B@4 4!_ _ _ _ W1 W7 W1 W4 _ _ _ _ W2 _ _ _ _ _ B4 B5 B1 _ B4 _|0|0|1|0@B@4 4 4!_ _ _ _ W1 W7 W1 W4 _ _ _ _ W2 _ _ _ _ _ B4 B5 B2 _ B4 _|0|0|0|0@B@4 4 4 4!_ _ _ _ W1 W7 W1 W4 _ _ _ _ W2 _ _ _ _ _ B4 B5 B2 _ B4 _|0|0|0|0@W@!_ _ _ _ W1 W7 _ W4 _ _ _ _ W3 _ _ _ _ _ B4 B5 B2 _ B4 _|0|0|0|0@W@6!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W3 _ _ _ _ _ B4 B5 B2 _ B4 _|0|0|0|0@W@4 6!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W3 _ _ _ _ _ B4 B5 B2 _ B4 _|0|0|0|0@B@!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W3 _ _ _ _ _ B5 B5 B1 _ B4 _|0|0|0|0@B@2!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W3 _ _ _ _ B1 B5 B4 B1 _ B4 _|0|0|0|0@B@2 2!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W3 _ _ B1 _ _ B5 B4 B1 _ B4 _|0|0|0|0@B@2 2 2!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W3 _ _ B1 _ B1 B5 B3 B1 _ B4 _|0|0|0|0@B@2 2 2 2!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W3 _ _ B1 _ B1 B5 B3 B1 _ B4 _|0|0|0|0@W@!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W2 _ _ B1 W1 B1 B5 B3 B1 _ B4 _|0|0|0|0@W@4!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W2 _ _ B1 _ B1 B5 B3 B1 W1 B4 _|0|0|0|0@W@5 4!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W2 _ _ B1 _ B1 B5 B3 B1 W1 B4 _|0|0|0|0@B@!_ _ _ _ W1 W7 _ W3 _ _ _ W1 W2 _ B1 _ _ B1 B5 B3 B1 W1 B4 _|0|0|0|0@B@1!_ _ _ _ W1 W7 _ W3 _ B1 _ W1 W2 _ _ _ _ B1 B5 B3 B1 W1 B4 _|0|0|0|0@B@1 5!_ _ _ _ W1 W7 _ W3 _ B1 _ W1 W2 _ _ _ _ B1 B5 B3 B1 W1 B4 _|0|0|0|0@W@!_ _ _ _ W1 W7 _ W3 _ B1 _ _ W2 W1 _ _ _ B1 B5 B3 B1 W1 B4 _|0|0|0|0@W@2!_ _ _ _ W1 W7 _ W3 _ B1 _ _ W2 W1 _ _ _ B1 B5 B3 B1 _ B4 _|0|1|0|0@W@2 3!_ _ _ _ W1 W7 _ W3 _ B1 _ _ W2 W1 _ _ _ B1 B5 B3 B1 _ B4 _|0|1|0|0@B@!_ _ _ _ W1 W7 _ W3 _ B1 _ _ W2 W1 _ _ _ B2 B5 B3 _ _ B4 _|0|1|0|0@B@3!_ _ _ B1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B2 B5 B3 _ _ B4 _|0|1|0|0@B@6 3!_ _ _ B1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B2 B5 B3 _ _ B4 _|0|1|0|0@W@5 2!_ _ _ B1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B2 B5 B3 _ _ B4 _|0|1|0|0@B@!_ _ _ B1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B3 B5 B2 _ _ B4 _|0|1|0|0@B@2!_ _ _ B1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B4 B5 B1 _ _ B4 _|0|1|0|0@B@2 2!_ B1 _ W1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B4 B5 B1 _ _ B4 _|0|0|0|0@B@2 2 2!_ _ _ W1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B4 B5 B1 _ _ B4 _|1|0|0|0@B@2 2 2 2!_ _ _ W1 W1 W7 _ W3 _ _ _ _ W2 W1 _ _ _ B4 B5 B1 _ _ B4 _|1|0|0|0@W@!_ _ _ W1 W1 W7 _ W3 _ _ _ _ W2 _ _ W1 _ B4 B5 B1 _ _ B4 _|1|0|0|0@W@2!_ _ _ W1 W1 W7 _ W3 _ _ _ _ W2 _ _ B1 _ B4 B5 B1 _ W1 B4 _|0|0|0|0@W@6 2!_ _ _ W1 W1 W7 _ W3 _ _ _ _ W2 _ _ B1 _ B4 B5 B1 _ W1 B4 _|0|0|0|0@B@!_ _ _ W1 W1 W7 _ W3 _ _ _ _ W2 _ B1 B1 _ B4 B5 _ _ W1 B4 _|0|0|0|0@B@5!_ _ _ W1 W1 W7 _ W3 B1 _ _ _ W2 _ _ B1 _ B4 B5 _ _ W1 B4 _|0|0|0|0@B@6 5!_ _ _ W1 W1 W7 _ W3 B1 _ _ _ W2 _ _ B1 _ B4 B5 _ _ W1 B4 _|0|0|0|0@W@!_ _ _ W1 W1 W7 _ W3 B1 _ _ _ W2 _ _ B1 _ B4 B5 _ _ _ B4 W1|0|0|0|0@W@2!_ _ _ W1 W1 W7 _ W2 B1 _ _ _ W2 W1 _ B1 _ B4 B5 _ _ _ B4 W1|0|0|0|0@W@2 6!_ _ _ W1 W1 W7 _ W2 B1 _ _ _ W2 W1 _ B1 _ B4 B5 _ _ _ B4 W1|0|0|0|0@B@!_ _ _ W1 W1 W7 _ W2 B1 B1 _ _ W2 W1 _ _ _ B4 B5 _ _ _ B4 W1|0|0|0|0@B@6!_ _ _ W1 W1 W7 B1 W2 _ B1 _ _ W2 W1 _ _ _ B4 B5 _ _ _ B4 W1|0|0|0|0@B@6 2!_ _ _ W1 W1 W7 B1 W2 _ B1 _ _ W2 W1 _ _ _ B4 B5 _ _ _ B4 W1|0|0|0|0@W@!_ _ _ W1 W1 W7 B1 W1 _ B1 _ _ W3 W1 _ _ _ B4 B5 _ _ _ B4 W1|0|0|0|0@W@5!_ _ _ W1 W1 W7 B1 _ _ B1 _ _ W3 W2 _ _ _ B4 B5 _ _ _ B4 W1|0|0|0|0@W@5 6!_ _ _ W1 W1 W7 B1 _ _ B1 _ _ W3 W2 _ _ _ B4 B5 _ _ _ B4 W1|0|0|0|0@B@!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 W2 _ _ _ B4 B5 _ _ _ B4 W1|0|0|0|0@B@3!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 W2 _ _ _ B4 B5 _ B1 _ B3 W1|0|0|0|0@B@3 2!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 W2 _ _ _ B4 B5 _ B1 _ B3 W1|0|0|0|0@W@!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 W1 W1 _ _ B4 B5 _ B1 _ B3 W1|0|0|0|0@W@1!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 W1 _ _ _ B4 B5 W1 B1 _ B3 W1|0|0|0|0@W@5 1!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 W1 _ _ _ B4 B5 W1 B1 _ B3 W1|0|0|0|0@B@!B1 _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 _ _ _ B4 B5 W1 B1 _ B3 W1|0|0|0|0@B@6!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 _ _ _ B4 B5 W1 B1 _ B3 W1|1|0|0|0@B@1 6!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 _ _ _ B4 B5 W1 B1 _ B3 W1|1|0|0|0@W@!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 _ _ _ B4 B5 B1 B1 W1 B3 W1|0|0|0|0@W@2!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 _ _ _ B4 B5 B1 B1 _ B3 W1|0|1|0|0@W@2 3!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 _ _ _ B4 B5 B1 B1 _ B3 W1|0|1|0|0@B@!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 _ _ _ B5 B5 _ B1 _ B3 W1|0|1|0|0@B@2!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 B1 _ _ B5 B5 _ W1 _ B3 W1|0|0|0|0@B@2 6!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 W1 B1 _ _ B5 B5 _ W1 _ B3 W1|0|0|0|0@W@!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 _ B1 W1 _ B5 B5 _ W1 _ B3 W1|0|0|0|0@W@2!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 _ B1 W1 _ B5 B5 _ _ _ B3 W2|0|0|0|0@W@3 2!_ _ _ W1 W1 W7 B1 _ _ _ _ _ W3 _ B1 W1 _ B5 B5 _ _ _ B3 W2|0|0|0|0@B@!_ _ _ W1 W1 W7 B1 _ B1 _ _ _ W3 _ _ W1 _ B5 B5 _ _ _ B3 W2|0|0|0|0@B@6!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 _ _ W1 _ B5 B5 _ _ _ B3 W2|0|0|0|0@B@6 2!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 _ _ W1 _ B5 B5 _ _ _ B3 W2|0|0|0|0@W@!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 _ _ _ _ B5 B5 _ W1 _ B3 W2|0|0|0|0@W@5!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 _ _ _ _ B5 B5 _ _ _ B3 W3|0|0|0|0@W@3 5!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 _ _ _ _ B5 B5 _ _ _ B3 W3|0|0|0|0@B@6 6 6!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 _ _ _ B1 B5 B5 _ _ _ B2 W3|0|0|0|0@B@6 6 6 6!_ _ _ W1 W1 W7 B2 _ _ _ _ _ W3 _ _ _ B1 B5 B5 _ _ _ B2 W3|0|0|0|0@W@!_ _ _ W1 W1 W6 B2 _ _ _ _ W1 W3 _ _ _ B1 B5 B5 _ _ _ B2 W3|0|0|0|0@W@6!_ _ _ W1 W1 W6 B2 _ _ _ _ _ W4 _ _ _ B1 B5 B5 _ _ _ B2 W3|0|0|0|0@W@6 1!_ _ _ W1 W1 W6 B2 _ _ _ _ _ W4 _ _ _ B1 B5 B5 _ _ _ B2 W3|0|0|0|0@B@!_ _ _ W1 W1 W6 B2 _ _ _ _ _ W4 _ _ _ B2 B5 B5 _ _ _ B1 W3|0|0|0|0@B@6!_ _ _ W1 W1 W6 B2 _ _ _ _ _ W4 _ _ _ B3 B5 B5 _ _ _ _ W3|0|0|0|0@B@6 6!_ _ _ W1 W1 W6 B2 _ _ _ _ B1 W4 _ _ _ B3 B4 B5 _ _ _ _ W3|0|0|0|0@B@6 6 6!_ _ _ W1 W1 W6 B2 _ _ _ _ B2 W4 _ _ _ B3 B3 B5 _ _ _ _ W3|0|0|0|0@B@6 6 6 6!_ _ _ W1 W1 W6 B2 _ _ _ _ B2 W4 _ _ _ B3 B3 B5 _ _ _ _ W3|0|0|0|0@W@!_ _ _ _ W1 W6 B2 _ _ W1 _ B2 W4 _ _ _ B3 B3 B5 _ _ _ _ W3|0|0|0|0@W@6!_ _ _ _ W1 W6 B2 _ _ _ _ B2 W5 _ _ _ B3 B3 B5 _ _ _ _ W3|0|0|0|0@W@3 6!_ _ _ _ W1 W6 B2 _ _ _ _ B2 W5 _ _ _ B3 B3 B5 _ _ _ _ W3|0|0|0|0@B@!_ _ _ _ W1 W6 B2 _ _ _ _ B3 W5 _ _ _ B3 B2 B5 _ _ _ _ W3|0|0|0|0@B@6!_ _ _ _ W1 W6 B2 _ _ _ _ B4 W5 _ _ _ B3 B1 B5 _ _ _ _ W3|0|0|0|0@B@6 6!_ _ _ _ W1 W6 B2 _ _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W3|0|0|0|0@B@6 6 6!B1 _ _ _ W1 W6 B1 _ _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W3|0|0|0|0@B@6 6 6 6!B1 _ _ _ W1 W6 B1 _ _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W3|0|0|0|0@W@!B1 _ _ _ _ W6 B1 W1 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W3|0|0|0|0@W@3!B1 _ _ _ _ W6 B1 W1 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|1|0|0@W@1 3!B1 _ _ _ _ W6 B1 W1 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|1|0|0@B@!B1 _ B1 _ _ W6 W1 W1 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@B@4!B2 _ _ _ _ W6 W1 W1 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@B@2 4!B2 _ _ _ _ W6 W1 W1 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@W@!B2 _ _ _ _ W5 W1 W2 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@W@2!B2 _ _ _ _ W5 _ W3 _ _ _ B5 W5 _ _ _ B3 _ B5 _ _ _ _ W2|0|0|0|0@W@2 1
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment