(apply-generic op . args)

教育者, 将軍, 栄養士, 心理学者, 親はプログラムする. 軍隊, 学生, 一部の社会はプログラムされる. - 計算機プログラムの構造と解釈 序文

SICP 問題 2.42 エイトクイーンパズル

ex-2.42 エイトクイーンパズルが終わりました(2.43もエイトクイーンパズルだけど).

全く何も見ないで解くのは無理だなーと思ったので、答えを見て動かしながら手続きどの様に動作するのか?を理解するに留めました。 まぁこういうのは「知っているか、知らないか」「知っているけど、使いこなせない」「知っていてるし、使いこなせる(応用して実務で使える)」だと思うのでまずは「知れた」から良かったかなと。 (もちろん知らないで自力で解ける人はいるし凄い!僕には無理なだけ)

; ex-2.42
; rest-of-queensは最初のk-1列にk-1個のクイーンを置く方法である
; new-rowはk列目にクイーンの置ける行の案である
; - [x] adjoin-positionは盤上の位置の集合の表現を実装し、位置の集合に新しい場所の座標を連結する手続き
; - [x] empty-boardは場所のから集合を表現する
; - [x] safe?は他のクイーンに対してk番目のクイーンが安全な場所か?(他のクイーンは互いに安全である事が保証されているので新しいクイーンだけ調べれば良い)

; 参考 : https://www.serendip.ws/archives/776

; > (queens 4)
; (((2 . 1) (4 . 2) (1 . 3) (3 . 4)) ((3 . 1) (1 . 2) (4 . 3) (2 . 4)))
(define (queens board-size)
  (define (queen-cols k) ; 板の最初のk列にクイーンを置く全ての方法の並びを返す
    (if (= k 0)
      (list empty-board)
      (filter ; (fleter predicate sequence)
        (lambda (positions) (safe? k positions)) ; predicate
        ; (flatmap (lambda (rest-of-queens) (map (lambda (new-row) (adjoin-position new-row 2 rest-of-queens)) '(1 2 3 4))) '(((1 1))))
        ; (((1行目 2列目) (1行目 1列目)) ...)
        ; (((1 2) (1 1)) ((2 2) (1 1)) ((3 2) (1 1)) ((4 2) (1 1)))
        (flatmap ; sequence
          (lambda (rest-of-queens)
            ;                                    1,2,3,4    k        enumerate-intervalなnew-row(1 2 3 4)
            ; (map (lambda (new-row) (cons (list new-row 1) ())) (list 1 2 3 4))
            ; k = 1
            ;   行 列
            ; (((1 1)) ((2 1)) ((3 1)) ((4 1)))
            ; k = 2
            ; (((1 2)) ((2 2)) ((3 2)) ((4 2)))
            (map (lambda (new-row)
                   (adjoin-position new-row k rest-of-queens))
                 (enumerate-interval 1  board-size))); new-row
          (queen-cols (- k 1)))))) ; rest-of-queens, queen-colsの再帰
  (queen-cols board-size)) ; k

(define empty-board ())

; rowはクイーンを置く行の案. 1,2,3,4
; kは引数board-sizeと-1されていく値. 4,3,2,1
; rest-of-queensは()
; (cons (list 1or2or3or4 1) ())
(define (adjoin-position new-row k rest-of-queens)
  (cons (list new-row k) rest-of-queens))

(define (safe? k positions)
  (print "poisitions " positions)
  ;  行 列
  ; ((1 1))
  ; ((2 1))
  ; ((3 3) (1 2) (3 1))
  ;   kth  : (3 3)
  ;   rest : ((1 2) (3 1))
  (let ((kth (car positions)))
    (define (iter rest)
      (print "kth " kth ", rest: " rest)

      ; conflictsするかnullになるまでiterを回す
      ; nullになった = (3行 3列)と(1 2), (3 3)と(3 1)すべて問題なし
      (cond ((null? rest) #t)
            ((conflicts? (car rest) kth) #f)
            (else (iter (cdr rest)))))
    (iter (cdr positions))))

; a (3 3)
; b (1 2)
; なんでこれでconflicts判定できるのかよくわかってない。
; ここはこういうロジックなんだなーくらいで良いかも。
; 2週目やる時はここもちゃんと理解したいな(別ロジックでも良い)。
(define (conflicts? a b)
  (let (
        ;   (abs (-      3       1))   => 2
        (dx (abs (- (car a) (car b))))
        ;   (abs (-       3        2)) => 1
        (dy (abs (- (cadr a) (cadr b)))))
    (cond ((= dx 0) #t)
          ((= dy 0) #t)
          ((= dx dy) #t)
          (else #f))))

; いつもflatmapの挙動を忘れるのでメモ
(flatmap
  (lambda (rest-of-queens)
    (map (lambda (new-row)
           (cons (list new-row 1) rest-of-queens))
         (list 1 2 3 4)))
  (list 1 2 3))
; (((1 1) . 1) ((2 1) . 1) ((3 1) . 1) ((4 1) . 1)
;  ((1 1) . 2) ((2 1) . 2) ((3 1) . 2) ((4 1) . 2)
;  ((1 1) . 3) ((2 1) . 3) ((3 1) . 3) ((4 1) . 3))

結果

gosh$ (queens 4)
poisitions ((1 1))
kth (1 1), rest: ()
poisitions ((2 1))
kth (2 1), rest: ()
poisitions ((3 1))
kth (3 1), rest: ()
poisitions ((4 1))
kth (4 1), rest: ()
poisitions ((1 2) (1 1))
kth (1 2), rest: ((1 1))
poisitions ((2 2) (1 1))
kth (2 2), rest: ((1 1))
poisitions ((3 2) (1 1))
kth (3 2), rest: ((1 1))
kth (3 2), rest: ()
poisitions ((4 2) (1 1))
kth (4 2), rest: ((1 1))
kth (4 2), rest: ()
poisitions ((1 2) (2 1))
kth (1 2), rest: ((2 1))
poisitions ((2 2) (2 1))
kth (2 2), rest: ((2 1))
poisitions ((3 2) (2 1))
kth (3 2), rest: ((2 1))
poisitions ((4 2) (2 1))
kth (4 2), rest: ((2 1))
kth (4 2), rest: ()
poisitions ((1 2) (3 1))
kth (1 2), rest: ((3 1))
kth (1 2), rest: ()
poisitions ((2 2) (3 1))
kth (2 2), rest: ((3 1))
poisitions ((3 2) (3 1))
kth (3 2), rest: ((3 1))
poisitions ((4 2) (3 1))
kth (4 2), rest: ((3 1))
poisitions ((1 2) (4 1))
kth (1 2), rest: ((4 1))
kth (1 2), rest: ()
poisitions ((2 2) (4 1))
kth (2 2), rest: ((4 1))
kth (2 2), rest: ()
poisitions ((3 2) (4 1))
kth (3 2), rest: ((4 1))
poisitions ((4 2) (4 1))
kth (4 2), rest: ((4 1))
poisitions ((1 3) (3 2) (1 1))
kth (1 3), rest: ((3 2) (1 1))
kth (1 3), rest: ((1 1))
poisitions ((2 3) (3 2) (1 1))
kth (2 3), rest: ((3 2) (1 1))
poisitions ((3 3) (3 2) (1 1))
kth (3 3), rest: ((3 2) (1 1))
poisitions ((4 3) (3 2) (1 1))
kth (4 3), rest: ((3 2) (1 1))
poisitions ((1 3) (4 2) (1 1))
kth (1 3), rest: ((4 2) (1 1))
kth (1 3), rest: ((1 1))
poisitions ((2 3) (4 2) (1 1))
kth (2 3), rest: ((4 2) (1 1))
kth (2 3), rest: ((1 1))
kth (2 3), rest: ()
poisitions ((3 3) (4 2) (1 1))
kth (3 3), rest: ((4 2) (1 1))
poisitions ((4 3) (4 2) (1 1))
kth (4 3), rest: ((4 2) (1 1))
poisitions ((1 3) (4 2) (2 1))
kth (1 3), rest: ((4 2) (2 1))
kth (1 3), rest: ((2 1))
kth (1 3), rest: ()
poisitions ((2 3) (4 2) (2 1))
kth (2 3), rest: ((4 2) (2 1))
kth (2 3), rest: ((2 1))
poisitions ((3 3) (4 2) (2 1))
kth (3 3), rest: ((4 2) (2 1))
poisitions ((4 3) (4 2) (2 1))
kth (4 3), rest: ((4 2) (2 1))
poisitions ((1 3) (1 2) (3 1))
kth (1 3), rest: ((1 2) (3 1))
poisitions ((2 3) (1 2) (3 1))
kth (2 3), rest: ((1 2) (3 1))
poisitions ((3 3) (1 2) (3 1))
kth (3 3), rest: ((1 2) (3 1))
kth (3 3), rest: ((3 1))
poisitions ((4 3) (1 2) (3 1))
kth (4 3), rest: ((1 2) (3 1))
kth (4 3), rest: ((3 1))
kth (4 3), rest: ()
poisitions ((1 3) (1 2) (4 1))
kth (1 3), rest: ((1 2) (4 1))
poisitions ((2 3) (1 2) (4 1))
kth (2 3), rest: ((1 2) (4 1))
poisitions ((3 3) (1 2) (4 1))
kth (3 3), rest: ((1 2) (4 1))
kth (3 3), rest: ((4 1))
kth (3 3), rest: ()
poisitions ((4 3) (1 2) (4 1))
kth (4 3), rest: ((1 2) (4 1))
kth (4 3), rest: ((4 1))
poisitions ((1 3) (2 2) (4 1))
kth (1 3), rest: ((2 2) (4 1))
poisitions ((2 3) (2 2) (4 1))
kth (2 3), rest: ((2 2) (4 1))
poisitions ((3 3) (2 2) (4 1))
kth (3 3), rest: ((2 2) (4 1))
poisitions ((4 3) (2 2) (4 1))
kth (4 3), rest: ((2 2) (4 1))
kth (4 3), rest: ((4 1))
poisitions ((1 4) (2 3) (4 2) (1 1))
kth (1 4), rest: ((2 3) (4 2) (1 1))
poisitions ((2 4) (2 3) (4 2) (1 1))
kth (2 4), rest: ((2 3) (4 2) (1 1))
poisitions ((3 4) (2 3) (4 2) (1 1))
kth (3 4), rest: ((2 3) (4 2) (1 1))
poisitions ((4 4) (2 3) (4 2) (1 1))
kth (4 4), rest: ((2 3) (4 2) (1 1))
kth (4 4), rest: ((4 2) (1 1))
poisitions ((1 4) (1 3) (4 2) (2 1))
kth (1 4), rest: ((1 3) (4 2) (2 1))
poisitions ((2 4) (1 3) (4 2) (2 1))
kth (2 4), rest: ((1 3) (4 2) (2 1))
poisitions ((3 4) (1 3) (4 2) (2 1))
kth (3 4), rest: ((1 3) (4 2) (2 1))
kth (3 4), rest: ((4 2) (2 1))
kth (3 4), rest: ((2 1))
kth (3 4), rest: ()
poisitions ((4 4) (1 3) (4 2) (2 1))
kth (4 4), rest: ((1 3) (4 2) (2 1))
kth (4 4), rest: ((4 2) (2 1))
poisitions ((1 4) (4 3) (1 2) (3 1))
kth (1 4), rest: ((4 3) (1 2) (3 1))
kth (1 4), rest: ((1 2) (3 1))
poisitions ((2 4) (4 3) (1 2) (3 1))
kth (2 4), rest: ((4 3) (1 2) (3 1))
kth (2 4), rest: ((1 2) (3 1))
kth (2 4), rest: ((3 1))
kth (2 4), rest: ()
poisitions ((3 4) (4 3) (1 2) (3 1))
kth (3 4), rest: ((4 3) (1 2) (3 1))
poisitions ((4 4) (4 3) (1 2) (3 1))
kth (4 4), rest: ((4 3) (1 2) (3 1))
poisitions ((1 4) (3 3) (1 2) (4 1))
kth (1 4), rest: ((3 3) (1 2) (4 1))
kth (1 4), rest: ((1 2) (4 1))
poisitions ((2 4) (3 3) (1 2) (4 1))
kth (2 4), rest: ((3 3) (1 2) (4 1))
poisitions ((3 4) (3 3) (1 2) (4 1))
kth (3 4), rest: ((3 3) (1 2) (4 1))
poisitions ((4 4) (3 3) (1 2) (4 1))
kth (4 4), rest: ((3 3) (1 2) (4 1))
(((3 4) (1 3) (4 2) (2 1)) ((2 4) (4 3) (1 2) (3 1)))