From 73cf36cd903e33cd9024cd5b0cd9173e19917330 Mon Sep 17 00:00:00 2001 From: Ivan Jovanovic Date: Thu, 22 Dec 2011 00:15:36 +0100 Subject: [PATCH] New iteration with adding some comments and a bit more abstraction --- 2.2/e-2.42.scm | 100 ++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 43 deletions(-) diff --git a/2.2/e-2.42.scm b/2.2/e-2.42.scm index bf983ae..50bc686 100644 --- a/2.2/e-2.42.scm +++ b/2.2/e-2.42.scm @@ -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 @@ -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 @@ -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.