;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname lect03b) (read-case-sensitive #t) (teachpacks ((lib "universe.ss" "teachpack" "2htdp") (lib "image.ss" "teachpack" "2htdp"))) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ((lib "universe.ss" "teachpack" "2htdp") (lib "image.ss" "teachpack" "2htdp"))))) ;;;;; lect03a.rkt ;;; Code from last time: ;;; Since we're handling data that can be integer OR character, ;;; we'll use "cond", which is like if-else-if: #;(define (func-for-c-ranks a-cr) (cond [(integer? a-cr) ...] [(character? a-cr) ...])) ;;; In bridge: ;;; you assign "bridge values" to card-ranks: ;;; most cards are 0, but jack is 1, queen is 2, king is 3, ace is 4. ;;; test cases (write 'em first!) (check-expect (crank-bridge-value 5) 0) (check-expect (crank-bridge-value 'queen) 2) ; crank-value : c-rank -> int ; compute the bridge-playing value for a given c-rank. (define (crank-bridge-value a-cr) (cond [(integer? a-cr) 0] [(symbol? a-cr) (cond [(symbol=? a-cr 'jack) 1] [(symbol=? a-cr 'queen) 2] [(symbol=? a-cr 'king) 3] [(symbol=? a-cr 'ace) 4])])) (check-expect (crank->string 5) "5") (check-expect (crank->string 10) "10") (check-expect (crank->string 'queen) "Q") ; crank->string : c-rank -> string ; (define (crank->string a-cr) (cond [(integer? a-cr) (number->string a-cr)] [(symbol? a-cr) (string (char-upcase (string-ref (symbol->string a-cr) 0)))])) ; A c-rank is either: ; - an integer (2..10) ; or - a symbol ('jack, 'queen, 'king, 'ace) ; OPTIONAL: ; Btw, we can write: ; crank? ANY -> boolean ; (define (crank? any) (or (and (integer? any) (<= 2 any 10)) (symbol? any))) ; ; The design recipe: ; http://htdp.org/2003-09-26/Book/curriculum-Z-H-7.html#node_sec_4.4 ; --- per (abstract) data type: ; - data def'n ; - examples of data ; - template (case analysis) ; --- per function: ; - contract, purpose, header ; - test-cases (check-expect) ; - complete function-body ; - case analysis (cond-questions, 1 per data variant) ; - answer for each cases ; - run the tests (trivial) ;;;;;;;;;;;;;;;;; Next stage: define-struct (product type, compound) ; ; Example: (define-struct card (rank suit)) ; rank : card-rank ; suit : symbol (make-card 4 'spades) (make-card 'queen 'diamonds) #| The corresponding Java: class Card { CRank rank; String suit; } ... new Card( 4, "hearts" ) ... |# ; When I define-struct, racket creates four functions for me: ; make-card -- constructor ; card-rank -- accessor ; card-suit -- accessor ; card? -- predicate ; have-a-heart : c-rank -> card ; Return a card of the given rank, in hearts. (check-expect (have-a-heart 3) (make-card 3 'hearts)) (check-expect (have-a-heart 'jack) (make-card 'jack 'hearts)) #| In Java: Card haveAHeart( CardRank aCr ) { return new Card(aCr, "hearts"); } |# ; (define (have-a-heart a-cr) (make-card a-cr 'hearts)) (check-expect (have-a-heart 5) (make-card 5 'hearts)) (check-expect (have-a-heart 'queen) (make-card 'queen 'hearts)) ; turn-to-spades: Given a card, return a new card of the same rank, and suit 'spades. ; ; turn-to-spades : card -> card (define (turn-to-spades a-card) ;...(card-rank a-card)... ; type: card-rank ;...(card-suit a-card)... ; type: symbol (make-card (card-rank a-card) 'spades) ) (check-expect (turn-to-spades (make-card 7 'hearts)) (make-card 7 'spades)) (check-expect (turn-to-spades (make-card 7 'spades)) (make-card 7 'spades)) ;;;; What about: ;;;; A structure that contains other structures? ;;;; A hand is (say) two cards, plus whether or not ;;;; those cards has been revealed to all: ;;;; (define-struct hand (c1 c2 revealed?)) ; c1 : card ; c2 : card ; revealed? : boolean ;;; examples of the data: (make-hand (make-card 4 'spades) (make-card 'queen 'diamonds) true) (make-hand (make-card 'queen 'diamonds) (make-card 4 'spades) false) ; hand-revealed? : hand -> boolean ; hand-c1 : hand -> card ;; func-for-hand: hand -> ...??... ;; #;(define (func-for-hand h) ... (hand-c1 h) ; card turn-to-spades card->string ... (hand-c2 h) ; card turn-to-spades ... (hand-revealed? h)) ; boolean cond, if, or, and, not ;;; Step: inventory the fields and what you can do with them ;;; HOWEVER: do NOT call any further selectors on cards: ;;; DOn't call card-suit, don't call card-rank ... call a helper instead. ;; hand->string : hand -> string ;; (define (hand->string h) (string-append (card->string (hand-c1 h)) "," (card->string (hand-c2 h)) "," (if (hand-revealed? h) "revealed" "hidden") )) #| In Java: class Hand { public String toString( /* Hand this, */ ) { return this.c1.toString() + "," + this.c2.toString() + "," + (this.revealed ? "revealed" : "hidden"); } } |# (check-expect (hand->string (make-hand (make-card 4 'spades) (make-card 'queen 'diamonds) true)) "4S,QD,revealed") ; design recipe step: inventory ; card>? ; card<=? ;;;;;;; ; list