  The first three lines of this file were inserted by  . They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-beginner-abbr-reader.ss" "lang")((modname ex207b) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f)))
; define the function block-generate, which randomly selects a
  column different from the current one ; see ex205 for inspiration .


(require 2htdp/image)
(require 2htdp/universe)


; physical constants
(define WIDTH 10)   ; the maximal number of blocks horizontally
(define HEIGHT 10)

; graphical constants
(define SIZE 10)   ; blocks are square
(define HALF (/ SIZE 2))
(define BLOCK      ; they are rendered as red squares with black rims
  (overlay (rectangle (- SIZE 1) (- SIZE 1) "solid" "red")
           (rectangle SIZE SIZE "outline" "black")))

(define SCENE-SIZE (* WIDTH SIZE))
(define MT (empty-scene SCENE-SIZE SCENE-SIZE))


  A Tetris is ( make - tetris Block Landscape )
(define-struct tetris [block landscape])
; A Landscape is one of:
; - '()
; - (cons Block Landscape)
  Block is ( make - block N N )
(define-struct block [x y])

; interpretation: given (make-tetris (make-block x y) (list b1 b2 ...))
; (x, y) is the logical position of the dropping block, while b1, b2, etc are
; the positions of the resting blocks
; A logical position (x, y) determines how many SIZEs the block is from the
; left-x-and from the top-y.

(define landscape0 '())
(define block-dropping (make-block 4 0))
(define tetris0 (make-tetris block-dropping landscape0))
(define tetris0-drop (make-tetris (make-block 5 6) (list (make-block 5 9)
                                                         (make-block 7 9))))
(define block-landed (make-block 0 (- HEIGHT 1)))
(define block-on-block (make-block 0 (- HEIGHT 2)))



  Tetris - > Image
; turns given tetris t into an image
(check-expect (tetris-render tetris0)
              (place-image BLOCK
                           (+ HALF (* 4 SIZE)) (+ HALF (* 0 SIZE))
                           MT))
(check-expect (tetris-render tetris0-drop)
              (place-image BLOCK
                           (+ HALF (* 5 SIZE)) (+ HALF (* 6 SIZE))
                           (place-image BLOCK
                                        (+ HALF (* 5 SIZE)) (+ HALF (* 9 SIZE))
                                        (place-image BLOCK
                                                     (+ HALF (* 7 SIZE))
                                                     (+ HALF (* 9 SIZE))
                                                     MT))))

(define (tetris-render t)
  (render-block (tetris-block t)
                (render-landscape (tetris-landscape t))))


; Block Image -> Image
; add the image of Block at the position b onto the im
(check-expect (render-block (make-block 4 5) MT)
              (place-image BLOCK
                           (+ HALF (* 4 SIZE)) (+ HALF (* 5 SIZE))
                           MT))

(define (render-block b im)
  (place-image BLOCK
               (+ HALF (* (block-x b) SIZE)) (+ HALF (* (block-y b) SIZE))
               im))


; Landscape -> Image
; renders the landscape on the MT
(check-expect (render-landscape (list (make-block 5 9)
                                      (make-block 7 9)))
              (place-image BLOCK
                           (+ HALF (* 5 SIZE)) (+ HALF (* 9 SIZE))
                           (place-image BLOCK
                                        (+ HALF (* 7 SIZE))
                                        (+ HALF (* 9 SIZE))
                                        MT)))
(check-expect (render-landscape '()) MT)

(define (render-landscape l)
  (cond
    [(empty? l) MT]
    [else
     (render-block (first l)
                   (render-landscape (rest l)))]))


  Tetris - > Tetris
; computes tetris for next clock tick, with given t
(check-expect (tock tetris0-drop)
              (make-tetris (make-block 5 7)
                           (list (make-block 5 9) (make-block 7 9))))

(define (tock t)
  (if (landed? (tetris-block t) (tetris-landscape t))
      (make-tetris (new-block (block-x (tetris-block t)))
                   (cons (tetris-block t) (tetris-landscape t)))
      (make-tetris (drop (tetris-block t)) (tetris-landscape t))))


; Block Landscape -> Boolean
; discovers whether given block b already landed
(check-expect (landed? block-landed '()) #t)
(check-expect (landed? block-on-block (list block-landed)) #t)
(check-expect (landed? (make-block 4 5) '()) #f)

(define (landed? b l)
  (or (= (- HEIGHT 1) (block-y b))
      (member? (drop b) l)))


; Block -> Block
  adds 1 to the y field of given block b
(check-random (drop (make-block 0 0)) (make-block 0 1))
(check-random (drop (make-block 4 5)) (make-block 4 6))

(define (drop b)
  (make-block (block-x b) (add1 (block-y b))))


; Number -> Block
; generates new block -- v1: on the column to the right of the current one.
(define (new-block x)
  (block-generate x))


; Number -> Block
  generate a block at a random column different from the current one
(check-satisfied (block-generate 1) not-equal-1?)

(define (block-generate x)
  (block-check-generate x (make-block (random WIDTH) 0)))


; Number Block -> Block
; generative recursion
(define (block-check-generate x candidate)
  (if (equal? x (block-x candidate)) (block-generate x) candidate))


; Block -> Boolean
; use for testing only
(define (not-equal-1? b)
  (not (= 1 (block-x b))))


  Number - Tetris
; simple tetris game, with the clock ticking rate r
(define (tetris-main r)
  (big-bang tetris0
            [to-draw tetris-render]
            [on-tick tock r]))
 about the language level of this file in a form that our tools can easily process.
 define the function block-generate, which randomly selects a
 see ex205 for inspiration .
 physical constants
 the maximal number of blocks horizontally
 graphical constants
 blocks are square
 they are rendered as red squares with black rims
 A Landscape is one of:
 - '()
 - (cons Block Landscape)
 interpretation: given (make-tetris (make-block x y) (list b1 b2 ...))
 (x, y) is the logical position of the dropping block, while b1, b2, etc are
 the positions of the resting blocks
 A logical position (x, y) determines how many SIZEs the block is from the
 left-x-and from the top-y.
 turns given tetris t into an image
 Block Image -> Image
 add the image of Block at the position b onto the im
 Landscape -> Image
 renders the landscape on the MT
 computes tetris for next clock tick, with given t
 Block Landscape -> Boolean
 discovers whether given block b already landed
 Block -> Block
 Number -> Block
 generates new block -- v1: on the column to the right of the current one.
 Number -> Block
 Number Block -> Block
 generative recursion
 Block -> Boolean
 use for testing only
 simple tetris game, with the clock ticking rate r
  The first three lines of this file were inserted by  . They record metadata
#reader(lib "htdp-beginner-abbr-reader.ss" "lang")((modname ex207b) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f)))


(require 2htdp/image)
(require 2htdp/universe)


(define HEIGHT 10)

(define HALF (/ SIZE 2))
  (overlay (rectangle (- SIZE 1) (- SIZE 1) "solid" "red")
           (rectangle SIZE SIZE "outline" "black")))

(define SCENE-SIZE (* WIDTH SIZE))
(define MT (empty-scene SCENE-SIZE SCENE-SIZE))


  A Tetris is ( make - tetris Block Landscape )
(define-struct tetris [block landscape])
  Block is ( make - block N N )
(define-struct block [x y])


(define landscape0 '())
(define block-dropping (make-block 4 0))
(define tetris0 (make-tetris block-dropping landscape0))
(define tetris0-drop (make-tetris (make-block 5 6) (list (make-block 5 9)
                                                         (make-block 7 9))))
(define block-landed (make-block 0 (- HEIGHT 1)))
(define block-on-block (make-block 0 (- HEIGHT 2)))



  Tetris - > Image
(check-expect (tetris-render tetris0)
              (place-image BLOCK
                           (+ HALF (* 4 SIZE)) (+ HALF (* 0 SIZE))
                           MT))
(check-expect (tetris-render tetris0-drop)
              (place-image BLOCK
                           (+ HALF (* 5 SIZE)) (+ HALF (* 6 SIZE))
                           (place-image BLOCK
                                        (+ HALF (* 5 SIZE)) (+ HALF (* 9 SIZE))
                                        (place-image BLOCK
                                                     (+ HALF (* 7 SIZE))
                                                     (+ HALF (* 9 SIZE))
                                                     MT))))

(define (tetris-render t)
  (render-block (tetris-block t)
                (render-landscape (tetris-landscape t))))


(check-expect (render-block (make-block 4 5) MT)
              (place-image BLOCK
                           (+ HALF (* 4 SIZE)) (+ HALF (* 5 SIZE))
                           MT))

(define (render-block b im)
  (place-image BLOCK
               (+ HALF (* (block-x b) SIZE)) (+ HALF (* (block-y b) SIZE))
               im))


(check-expect (render-landscape (list (make-block 5 9)
                                      (make-block 7 9)))
              (place-image BLOCK
                           (+ HALF (* 5 SIZE)) (+ HALF (* 9 SIZE))
                           (place-image BLOCK
                                        (+ HALF (* 7 SIZE))
                                        (+ HALF (* 9 SIZE))
                                        MT)))
(check-expect (render-landscape '()) MT)

(define (render-landscape l)
  (cond
    [(empty? l) MT]
    [else
     (render-block (first l)
                   (render-landscape (rest l)))]))


  Tetris - > Tetris
(check-expect (tock tetris0-drop)
              (make-tetris (make-block 5 7)
                           (list (make-block 5 9) (make-block 7 9))))

(define (tock t)
  (if (landed? (tetris-block t) (tetris-landscape t))
      (make-tetris (new-block (block-x (tetris-block t)))
                   (cons (tetris-block t) (tetris-landscape t)))
      (make-tetris (drop (tetris-block t)) (tetris-landscape t))))


(check-expect (landed? block-landed '()) #t)
(check-expect (landed? block-on-block (list block-landed)) #t)
(check-expect (landed? (make-block 4 5) '()) #f)

(define (landed? b l)
  (or (= (- HEIGHT 1) (block-y b))
      (member? (drop b) l)))


  adds 1 to the y field of given block b
(check-random (drop (make-block 0 0)) (make-block 0 1))
(check-random (drop (make-block 4 5)) (make-block 4 6))

(define (drop b)
  (make-block (block-x b) (add1 (block-y b))))


(define (new-block x)
  (block-generate x))


  generate a block at a random column different from the current one
(check-satisfied (block-generate 1) not-equal-1?)

(define (block-generate x)
  (block-check-generate x (make-block (random WIDTH) 0)))


(define (block-check-generate x candidate)
  (if (equal? x (block-x candidate)) (block-generate x) candidate))


(define (not-equal-1? b)
  (not (= 1 (block-x b))))


  Number - Tetris
(define (tetris-main r)
  (big-bang tetris0
            [to-draw tetris-render]
            [on-tick tock r]))