204 lines
6.2 KiB
Racket
204 lines
6.2 KiB
Racket
#lang racket
|
|
;; 2.40
|
|
(define (unique-pairs n)
|
|
(define (collect j)
|
|
(let loop [(j j) (i n) (acc '())]
|
|
(if (>= j i)
|
|
acc
|
|
(loop j (- i 1) (cons (list i j) acc)))))
|
|
(define (iter j acc)
|
|
(if (>= j n)
|
|
acc
|
|
(iter (+ j 1) (append (collect j) acc))))
|
|
(iter 1 '()))
|
|
|
|
;; 2.41
|
|
;; Note: this is kind of inefficient, as it generates a ton of
|
|
;; lists, but I presume that's what the book is kind of suggesting
|
|
;; in this chapter: i.e. the generate list, then filter approach.
|
|
(define (flatmap f l)
|
|
(foldr (λ (x y) (append (f x) y))
|
|
'()
|
|
l))
|
|
(define (triples n s)
|
|
(define (genlast l)
|
|
(map (λ (x) (cons x l))
|
|
(range 1 (if (null? l)
|
|
n
|
|
(first l)))))
|
|
(define (gentriples)
|
|
(flatmap genlast
|
|
(flatmap genlast
|
|
(flatmap genlast
|
|
'(())))))
|
|
(define (sum-s? l)
|
|
(= (foldl + 0 l) s))
|
|
(filter sum-s? (gentriples)))
|
|
|
|
;; 2.42
|
|
;; We represent a board as a linked-list of queen positions.
|
|
;; nth element is the position of the queen on column n.
|
|
;; each position is a list of (x y) coordinates (starting from 0).
|
|
(define empty-board '())
|
|
(define (adjoin-position r c board)
|
|
(append board (list (list c r))))
|
|
(define (kth-queen k board)
|
|
(list-ref board (- k 1)))
|
|
(define (threatens? p1 p2)
|
|
(let [(ydiff (abs (- (second p1) (second p2))))]
|
|
(cond
|
|
[(= (abs (- (first p1) (first p2))) ydiff) #t]
|
|
[(= ydiff 0) #t]
|
|
[else #f])))
|
|
(define (safe? c board)
|
|
(define (iter i)
|
|
(cond
|
|
[(< i 1) #t]
|
|
[(threatens? (kth-queen i board) (kth-queen c board)) #f]
|
|
[else (iter (- i 1))]))
|
|
(iter (- c 1)))
|
|
(define (enumerate-interval a b) (range a (+ b 1)))
|
|
(define (queens board-size)
|
|
(define (queen-cols k)
|
|
(if (= k 0)
|
|
(list empty-board)
|
|
(filter
|
|
(lambda (positions) (safe? k positions))
|
|
(flatmap
|
|
(lambda (rest-of-queens)
|
|
(map (lambda (new-row)
|
|
(adjoin-position
|
|
new-row k rest-of-queens))
|
|
(enumerate-interval 1 board-size)))
|
|
(queen-cols (- k 1))))))
|
|
(queen-cols board-size))
|
|
|
|
;; 2.43
|
|
;; The reason this causes the program to run slowly, is that
|
|
;; now the recursive queen-cols call is inside another map
|
|
;; call. This means that queen-cols will recursively call
|
|
;; itself again and again with the same value - for instance,
|
|
;; (queen-cols 8) will call (queen-cols 7) 8 times, (one for each
|
|
;; item in the result of the enumerate-interval call).
|
|
;; But (queen-cols 7) itself will call (queen-cols 6) 7 times,
|
|
;; and so on and so forth.
|
|
|
|
;; This makes the algorithm inefficient,
|
|
;; as the same work is unnecessarily repeated.
|
|
;; The runtime of this flawed algorithm should roughly
|
|
;; be proportional to T^2.
|
|
|
|
;; 2.44
|
|
;; we don't have definitions for these yet, so I'm providing
|
|
;; dummy procedures
|
|
(define (beside x y) #f)
|
|
(define (below x y) #f)
|
|
(define (right-split painter n)
|
|
(if (= n 0)
|
|
painter
|
|
(let ((smaller (right-split painter (- n 1))))
|
|
(beside painter (below smaller smaller)))))
|
|
|
|
(define (up-split painter n)
|
|
(if (= n 0)
|
|
painter
|
|
(let ((smaller (up-split painter (- n 1))))
|
|
(below painter (beside smaller smaller)))))
|
|
;; 2.45
|
|
(define (split f1 f2)
|
|
(define (inner painter n)
|
|
(if (= n 0)
|
|
painter
|
|
(let [(smaller (inner painter (- n 1)))]
|
|
(f1 painter (f2 smaller smaller)))))
|
|
inner)
|
|
;(define right-split (split beside below))
|
|
;(define up-split (split below beside))
|
|
|
|
;; 2.46
|
|
;; make-vect is defined by the define-struct form.
|
|
;; we could also define using a cons. literally the same,
|
|
;; performance-wise. But a little nicer I think.
|
|
(define-struct vect (xcoor ycoor))
|
|
(define xcoor-vect vect-xcoor)
|
|
(define ycoor-vect vect-ycoor)
|
|
|
|
(define (op-vect op)
|
|
(λ (v1 v2)
|
|
(make-vect (apply op (map vect-xcoor (list v1 v2)))
|
|
(apply op (map vect-ycoor (list v1 v2))))))
|
|
(define add-vect (op-vect +))
|
|
(define sub-vect (op-vect -))
|
|
(define (scale-vect v n)
|
|
(make-vect (* (vect-xcoor v) n)
|
|
(* (vect-ycoor v) n)))
|
|
;; 2.47
|
|
;; a list-of-three representation
|
|
(define (make-frame1 origin edge1 edge2)
|
|
(list origin edge1 edge2))
|
|
(define (frame-origin1 f)
|
|
(list-ref f 0))
|
|
(define (frame-edge1-1 f)
|
|
(list-ref f 1))
|
|
(define (frame-edge2-1 f)
|
|
(list-ref f 2))
|
|
|
|
; two cons representation
|
|
(define (make-frame2 origin edge1 edge2)
|
|
(cons origin (cons edge1 edge2)))
|
|
(define frame-origin2 car)
|
|
(define frame-edge1-2 cadr)
|
|
(define frame-edge2-2 cddr)
|
|
|
|
; choose one impl
|
|
(define origin-frame frame-origin2)
|
|
(define edge1-frame frame-edge1-2)
|
|
(define edge2-frame frame-edge2-2)
|
|
|
|
;; 2.48
|
|
;; decided to stop using define-struct for this, as it kinda
|
|
;; screws with the naming conventions
|
|
(define make-segment cons)
|
|
|
|
(define start-segment car)
|
|
(define end-segment cdr)
|
|
|
|
;; 2.49
|
|
(define (draw-line x y) #f)
|
|
(define (frame-coord-map frame)
|
|
(lambda (v)
|
|
(add-vect
|
|
(origin-frame frame)
|
|
(add-vect (scale-vect (xcoor-vect v) (edge1-frame frame))
|
|
(scale-vect (ycoor-vect v) (edge2-frame frame))))))
|
|
(define (segments->painter segment-list)
|
|
(lambda (frame)
|
|
(for-each
|
|
(lambda (segment)
|
|
(draw-line
|
|
((frame-coord-map frame)
|
|
(start-segment segment))
|
|
((frame-coord-map frame)
|
|
(end-segment segment))))
|
|
segment-list)))
|
|
|
|
; I really should have thought of making a better
|
|
; notation for these things, it would have been super easy too.
|
|
; but I've already written it, so it stays, I guess.
|
|
(define outline-painter
|
|
(segments->painter
|
|
(list (make-segment (make-vect 0 0) (make-vect 0 1))
|
|
(make-segment (make-vect 0 0) (make-vect 1 0))
|
|
(make-segment (make-vect 1 0) (make-vect 1 1))
|
|
(make-segment (make-vect 0 1) (make-vect 1 1)))))
|
|
(define x-painter
|
|
(segments->painter
|
|
(list (make-segment (make-vect 0 0) (make-vect 1 1))
|
|
(make-segment (make-vect 1 0) (make-vect 0 1)))))
|
|
(define diamond
|
|
(segments->painter
|
|
(list (make-segment (make-vect 0.5 0) (make-vect 0 0.5))
|
|
(make-segment (make-vect 0.5 0) (make-vect 1 0.5))
|
|
(make-segment (make-vect 0 0.5) (make-vect 0.5 1))
|
|
(make-segment (make-vect 1 0.5) (make-vect 0.5 1)))))
|