Skip to content

Commit

Permalink
New iteration with adding some comments and a bit more abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Jovanovic committed Dec 21, 2011
1 parent 8893910 commit 73cf36c
Showing 1 changed file with 57 additions and 43 deletions.
100 changes: 57 additions & 43 deletions 2.2/e-2.42.scm
Original file line number Diff line number Diff line change
Expand Up @@ -72,32 +72,55 @@
; the positions as list of pairs, then empty board means empty list
(define empty-board nil)

; The way we generate all the possible positions queen can be in the new
; iteration is defined by the rest of queens (valid solutions the
; smaller problem set) and new row injected into the problem. So we have
; to generate combinations.
; In order to manipulate positions easily, we have to create a position
; data structure with the constructor and selectors.
(define (make-position row column)
(cons row column))

; Fancy name for selector which pulls out data from the structure
(define (row<- position)
(car position))

(define (column<- position)
(cdr position))


; encapsulating details of position list structure so the details don't leak
; out of the abstraction. Afterwards, when I see how to make it simpler
; I can change the structure only here in the data structure and not
; affect the way queens problem is solved
(define (make-positions-list position)
(list (list position)))

(define (position-list-head position-list)
(caar position-list))

(define (position-list-tail position-list)
(cdar position-list))

(define (position-list-has-tail? position-list)
(not (null? (cdar position-list))))

; Position list is designed so new position goes first
(define (extend-position-list position position-list)
(cons position position-list))

; I kind of don't like how I manipulate the lists here. I had to make
; list in the list in the list so they properly append to form list of
; positions. I'd like to do this in a simpler and more robust manner.

(define (adjoin-position new-row k rest-of-queens)
(if (null? rest-of-queens)
(list (list (list new-row k)))
(make-positions-list (make-position new-row k))
(map (lambda (one-position-set)
; we'll put k-th position element in front for easier
; selection later
(append (list (list new-row k))
one-position-set))
(extend-position-list (make-position new-row k) one-position-set))
rest-of-queens)))

; Here we define filter that checks if k-th queen is placed on the safe
; place within the position set, taking that all previous elements of
; place within the given position set, taking that all previous elements of
; the set comprise a valid set.

(define (safe? k positions)
(if (null? (cdr (car positions)))
(if (not (position-list-has-tail? positions))
true
(not (colides? (caar positions) (cdr (car positions))))))
(not (colides? (position-list-head positions) (position-list-tail positions)))))

; here are defined set of methods to check for th ecollision of the
; newly placed queen with the already placed on board
Expand All @@ -108,7 +131,7 @@
; is it in the same row with other
(define (collides-row? position rest-of-positions)
(not (null? (filter (lambda (rest-position)
(= (car position) (car rest-position)))
(= (row<- position) (row<- rest-position)))
rest-of-positions))))

; does it collide in any diagonal
Expand All @@ -120,41 +143,32 @@
(define (collides-upper-diagonal? position rest-of-positions)
(not (null?
(filter (lambda (rest-position)
(= (cadr rest-position)
(+ (- (cadr position) (car position))
(car rest-position))))
(= (column<- rest-position)
(+ (- (column<- position) (row<- position))
(row<- rest-position))))
rest-of-positions))))

; check collision in lower diagonal
(define (collides-lower-diagonal? position rest-of-positions)
(not (null?
(filter (lambda (rest-position)
(= (cadr rest-position)
(+ (- (cadr position) (car rest-position))
(car position))))
(= (column<- rest-position)
(+ (- (column<- position) (row<- rest-position))
(row<- position))))
rest-of-positions))))

; compact version of collision detection which inlines all the cases in
; one mehtod.
(define (compact-colides? position rest-of-positions)
(not (null? (filter (lambda (rest-position)
(or (= (car position) (car rest-position))
(= (cadr rest-position)
(+ (- (cadr position) (car position))
(car rest-position)))
(= (cadr rest-position)
(+ (- (cadr position) (car rest-position))
(car position)))))
rest-of-positions))))

; redefining safe to use compact version of collision check
(define (safe? k positions)
(if (null? (cdr (car positions)))
true
(not (compact-colides? (caar positions) (cdr (car positions))))))

; (output (adjoin-position 2 3 (list)))
(output (queens 6))
; (output (adjoin-position 2 3 (list (cons 5 6))))
(output (queens 4))
; (output (row<- (make-position 2 2)))
; (output (collides-lower-diagonal? 3 (list 3 3) (list (list 4 2))))
; (output (enumerate-upper-diagonal 4 (list 3 4)))
; (output (enumerate-lower-diagonal 3 (list 3 3)))

; The implementation gives proper results.
; I'm pretty sure it can be optimized for speed. I'm executing on `heist` Ruby implementation
; of Scheme interpreter which is far from fast so I don't get very fast
; restult for size 8 but it gets there and renders all 92 results.
;
; I'm not satisfied how I solved the data structure that holds list of
; lists of positions, and it looks kind of non-intuitive and leaking.
; This is good exercise to make this properly implented.

0 comments on commit 73cf36c

Please sign in to comment.