;; 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-beginner-reader.ss" "lang")((modname dist-lect03) (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 ;;; syntax of cond: #;(cond [q1 a1] [q2 a2] ... [qn an]) ; where each q1..qn is an expression that evals to aboolean ; each a1..an is any expression. ;; A c-rank is either: ;; - a integer ;; - or a symbol ;;; 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) (symbol->first-Letter a-cr)])) ; new String( Character.upcase( aCr.charAt(0) )) (define (symbol->first-Letter sym) (string (char-upcase (string-ref (symbol->string sym) 0)))) (check-expect (symbol->first-Letter 'hello) "H") (check-expect (symbol->first-Letter 'WHOA) "W") ; 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, or field-extraction) ; --- per function: ; - contract, purpose, header ; - test-cases (check-expect) ; - complete function-body ; - for union types: cond-questions, 1 per data variant ; - for product types: inventory: ; extract each field, remind yourself of its type, list pertinent functions ; ;;; If a field is itself another complicated type (union or product), ; ;;; DO NOT handle it in the same function -- make a helper. ; - answer for each case ; - run the tests (trivial) ;;;;;;;;;;;;;;;;; Next stage: define-struct (product type, compound) ; ; Example: (define-struct card (rank suit)) ; rank : c-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 make-card : c-rank, symbol -> card ; card-rank -- accessor card-rank : card -> c-rank ; card-suit -- accessor card-suit : card -> symbol ; card? -- predicate card? : ANY -> boolean ; 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)) ; card->string : card -> string (define (card->string a-card) (string-append (crank->string (card-rank a-card)) (symbol->first-Letter (card-suit a-card)))) ; type: c-rank plausible function: crank->string crank-bridge-value ; type: symbol plausible function: symbol=? symbol->first-Letter (check-expect (card->string (make-card 7 'hearts)) "7H") (check-expect (card->string (make-card 'queen 'clubs)) "QC") ;;; PRACTICE: ;; Write the function card>? ;; which takes in *two* cards, and determines whether the first ;; has a higher bridge-value than the second. ;; (a card's rank depends only on its rank, not its suit, for this problem). (check-expect (card>? (make-card 7 'hearts) (make-card 'queen 'clubs)) false) (check-expect (card>? (make-card 'queen 'clubs ) (make-card 7 'hearts)) true) (check-expect (card>? (make-card 'queen 'hearts) (make-card 'queen 'clubs)) false) ; card>? : card, card -> boolean ; (define (card>? c1 c2) (> (crank-bridge-value (card-rank c1)) (crank-bridge-value (card-rank c2)))) ;;;; 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: ;;;; Make examples of the data (hands) (define-struct hand (card1 card2 revealed?)) ; card1 : card ; card2 : card ; revealed? : boolean ; Examples of data (define fave-card (make-card 'ace 'spades)) (make-hand (make-card 7 'spades) (make-card 7 'clubs) true) (make-hand fave-card (make-card 'queen 'clubs) false) ; func-for-hand : hand -> ??? ; (template) #;(define (func-for-hand a-hand) ...(hand-card1 a-hand) ; card: card->string turn-to-spaces card>? ...(hand-card2 a-hand) ; card: card->string turn-to-spaces card>? ...(hand-revealed? a-hand) ; boolean : or and if cond ) (define (hand->string a-hand) (if (hand-revealed? a-hand) (string-append "<" (card->string (hand-card1 a-hand)) "," (card->string (hand-card2 a-hand)) ">") "hidden")) (check-expect (hand->string (make-hand (make-card 7 'spades) (make-card 7 'clubs) true)) "<7S,7C>") (check-expect (hand->string (make-hand fave-card (make-card 'queen 'clubs) false)) "hidden") ;=========== Lists ============ ; Data Def'n: ; A list-of-numbers ("lon") is: ; - empty, ; OR ; - (cons num lon) ; where num is any number, ; and lon is any list-of-number. ; Examples of the data: ;empty ;(cons 7 empty) ;(cons 3 (cons 7 empty)) (define nums5 (cons 1 (cons 2 (cons 3 (cons 3 (cons 7 empty)))))) ; NOT (cons 1 2 3 4 5) -- since cons can only have two inputs. ; NOT (cons 23 45) -- since the 2nd input to cons must be a lon, and 45 isn't. #| 'cons' is a constructor -- it takes in two things, and returns a 'constructed list': (define-struct cons (first rest)) (make-cons 23 empty) |# ; To pull things *out* from a (constructed -- non-empty list): ; Use `first` and `rest`: ; first: cons -> number ; rest: cons -> lon ;(first (cons 7 empty)) = 7 ;(rest (cons 7 empty)) = empty ;(first (cons 3 (cons 7 empty))) = 3 ;(rest (cons 3 (cons 7 empty))) = (cons 7 empty) ; How to extract the second thing in the list?? (define nums2 (cons 3 (cons 7 empty))) (first nums2) ; 7 ; How about: ;(first (rest (first nums2))) = (first (rest 3)) and (rest 3) is error (3 isn't a list) (first (rest nums2)) ; Exercise: ; Write a function which processes a list: ; Write a function which returns ...the sum of the numbers in a list. ; sum: list-of-number -> number ; (define (sum data) (cond [(empty? data) 0] [(cons? data) (+ (first data) (sum (rest data)))])) (check-expect (sum empty) 0) (check-expect (sum (cons 7 empty)) 7) (check-expect (sum (cons 3 (cons 7 empty))) 10) (check-expect (sum nums5) 16) ; length : list-of-numbers -> number ; (define (length data) (cond [(empty? data) 0] [(cons? data) (+ 1 (length (rest data)))])) (check-expect (length empty) 0) (check-expect (length (cons 7 empty)) 1) (check-expect (length (cons 3 (cons 7 empty))) 2) (check-expect (length nums5) 5) ;;;;;;;;;;;;;;;;; #| hw: How to represent a spaceship, in racket? (or, in Java?) class Ship { double pointingAngle; // degrees clockwise, from North(up) //boolean thrust; double positionX, positionY; double speed; // pixels per tick } |#