ペントミノ パズル(明治ミルクチョコパズル)をGaucheで解く(1時間で解けるようになった)
Karetta|Cパズルプログラミング-再帰編|ペントミノを参考にアルゴリズムを改良した。
- ピースXを左上1/4に制限
- 近傍を予備的にチェック
- 使用済みピースを調べない(これは前回もそうだった)
ちゃんと2339通りが出力される。1時間(PenR E2140 Mem 2GB)で。
この限界を越えるには、solveの再帰を末尾再帰にするしかあるまい。
どう書く.orgに投稿しようかな。
(use srfi-1)
(use srfi-43)
(define count 0)
(define board (make-vector 60 #f))
(define (check-board-multiple5-space?)
(define (fill start)
(define l (list start))
(let propagete! ((x start))
(let ((m (remove! (lambda (p)
(or (not p) (vector-ref board p) (memq p l)))
(receive (row col) (quotient&remainder x 10)
(list (and (> row 0) (- x 10))
(and (< row 5) (+ x 10))
(and (> col 0) (- x 1))
(and (< col 9) (+ x 1)))))))
(unless (zero? (length m))
(set! l (append! m l))
(for-each propagete! m))))
l)
(let ((i (vector-index not board)))
(or (not i)
(zero? (remainder (length (fill i)) 5)))))
(define (plot mino index v)
(for-each (lambda (xy)
(vector-set! board (+ index (* (car xy) 10) (cdr xy)) v))
mino))
(define (solve remain-kind)
(let1 i (vector-index not board)
(if i
(receive (row col) (quotient&remainder i 10)
(for-each (lambda (kind)
(for-each (lambda (mino)
(when (every (lambda (xy)
(let ((r (+ (car xy) row))
(c (+ (cdr xy) col)))
(and (>= r 0) (< r 6) (>= c 0) (< c 10)
(not (vector-ref board (+ (* r 10) c))))))
mino)
(plot mino i kind)
(when (check-board-multiple5-space?)
(solve (delete kind remain-kind)))
(plot mino i #f)))
(vector-ref pentominos kind)))
remain-kind))
;; found answer
(print-board))))
(define (main args)
(for-each (lambda (i)
(plot (car (vector-ref pentominos 0)) i 0)
(solve (iota 11 1))
(plot (car (vector-ref pentominos 0)) i #f))
'(2 3 4 11 12 13 14)))
(define (print-board)
(print "Answer No." (inc! count))
(vector-for-each (lambda (i x)
(if x
(format #t "~X" x)
(display '*))
(when (= 9 (remainder i 10)) (newline)))
board)
(newline))
(define (to-data mino)
(let ((offset (string-scan (car mino) "#")))
(append-map (lambda (line row)
(filter-map (lambda (x col)
(if (char=? x #\space)
#f
(cons row (- col offset))))
(string->list line) (iota 5)))
mino (iota 5))))
(define pentominos
(list->vector
(map (cut map to-data <>)
'(((" #"
"###"
" #"))
((" #"
"###"
" #")
(" ##"
"##"
" #")
("#"
"###"
" #")
(" #"
" ##"
"##")
(" #"
"###"
"#")
(" #"
"##"
" ##")
(" #"
"###"
" #")
("##"
" ##"
" #"))
(("####"
"#")
("#"
"#"
"#"
"##")
(" #"
"####")
("##"
" #"
" #"
" #")
("####"
" #")
("##"
"#"
"#"
"#")
("#"
"####")
(" #"
" #"
" #"
"##"))
((" #"
"##"
"#"
"#")
("##"
" ###")
(" #"
" #"
"##"
"#")
("###"
" ##")
("#"
"##"
" #"
" #")
(" ###"
"##")
("#"
"#"
"##"
" #")
(" ##"
"###"))
(("##"
"##"
"#")
("##"
"###")
(" #"
"##"
"##")
("###"
" ##")
("##"
"##"
" #")
("###"
"##")
("#"
"##"
"##")
(" ##"
"###"))
((" #"
"##"
" #"
" #")
("####"
" #")
(" #"
"####")
("#"
"##"
"#"
"#")
(" #"
"####")
("#"
"#"
"##"
"#")
(" #"
" #"
"##"
" #")
("####"
" #"))
(("##"
" #"
" ##")
(" #"
"###"
"#")
("#"
"###"
" #")
(" ##"
" #"
"##"))
(("#"
"###"
"#")
(" #"
" #"
"###")
(" #"
"###"
" #")
("###"
" #"
" #"))
(("# #"
"###")
("##"
" #"
"##")
("###"
"# #")
("##"
"#"
"##"))
(("#"
"#"
"###")
(" #"
" #"
"###")
("###"
" #"
" #")
("###"
"#"
"#"))
(("#"
"##"
" ##")
(" #"
" ##"
"##")
("##"
" ##"
" #")
(" ##"
"##"
"#"))
(("#"
"#"
"#"
"#"
"#")
("#####"))))))