ナンプレを解くプログラムがバグっていて解けない問題があったので直しました。
このプログラムは人間的な解法で問題を解きます。総当りな方法は使いません。
(use util.list) (define nil '()) ;;; 汎用手続き (define (list->number lis) (fold (lambda (a b) (+ a (* b 10))) 0 lis)) (define (digit->integer c) (- (char->integer c) (char->integer #\0))) (define (number->list num) (map digit->integer (string->list (number->string num)))) (define (enumerate-interval low high) (if (> low high) nil (cons low (enumerate-interval (+ low 1) high)))) (define (filter pred items) (cond ((null? items) nil) ((pred (car items)) (cons (car items) (filter pred (cdr items)))) (else (filter pred (cdr items))))) (define (remove item seq) (filter (lambda (x) (not (equal? x item))) seq)) (define (element-of-set? x set) (cond ((null? set) #f) ((equal? x (car set)) #t) (else (element-of-set? x (cdr set))))) (define (uniq set) (define (iter x s) (if (null? x) s (iter (cdr x) (if (element-of-set? (car x) s) s (cons (car x) s))))) (iter set nil)) (define (subsets s) (if (null? s) (list '()) (let ((rest (subsets (cdr s)))) (append rest (map (lambda (x) (cons (car s) x)) rest))))) ;;; デバッグ出力の手続き (define *debugging* #f) (define (debug-on) (print "Debug mode is on.") (set! *debugging* #t)) (define (debug-off) (print "Debug mode is off.") (set! *debugging* #f)) (define (debug-print msg1 . msg2) (define (iter msg) (if (null? msg) (newline) (begin (display (car msg)) (iter (cdr msg))))) (and *debugging* (display msg1) (iter msg2))) ;;; グリッドの作成(読み込み) & グリッド-ハッシュテーブル変換をする手続き (define (make-grids filename) (define ip (open-input-file filename)) (define (read-line ip) (define (iter lis) (let ((c (read-char ip))) (cond ((eof-object? c) lis) ((eq? c #\cr) (read-char ip) lis) (else (iter (append lis (list (digit->integer c)))))))) (iter nil)) (define (read-grids) (define (iter lis c) (if (= c 0) (list lis) (let ((line (read-line ip))) (if (null? line) (begin (close-input-port ip) nil) (iter (append lis (list line)) (- c 1)))))) (read-line ip) (iter nil 9)) (define (iter lis) (if (port-closed? ip) lis (iter (append lis (read-grids))))) (iter nil)) (define (grid->hash grid) (define ht (make-hash-table 'equal?)) (define (list->hash lis y) (define (iter l x) (if (null? l) 'done (begin (if (> (car l) 0) (confirm ht (list x y) (car l)) (hash-table-put! ht (list x y) (car l))) (iter (cdr l) (+ x 1))))) (iter lis 1)) (define (init-hash lis y) (if (null? lis) ht (begin (list->hash (car lis) y) (init-hash (cdr lis) (+ y 1))))) (init-hash grid 1)) (define (hash->grid ht) (let ((nums (enumerate-interval 1 9))) (map (lambda (y) (map (lambda (x) (hash-table-get ht `(,x ,y))) nums)) nums))) (define (print-grid grids) (begin (map print grids) 'done)) (define (grid->excel grids) (define (lst->csv lst) (and (not (null? lst)) (display ",") (display (car lst)) (lst->csv (cdr lst)))) (define (output-proc lst) (if (null? lst) (newline) (begin (if (pair? (car lst)) (begin (display (caar lst)) (lst->csv (cdar lst))) (display (car lst))) (display "\t") (output-proc (cdr lst))))) (begin (map output-proc grids) 'done)) ;;; ナンバープレイス ;; グリッドの初期化。 ;; グリッドの値が 0 の箇所は init-val を設定する。 (define (init-grid ht) (define init-val '(1 2 3 4 5 6 7 8 9)) (define (init-proc key val) (if (= val 0) (hash-table-put! ht key init-val) val)) (hash-table-map ht init-proc) ht) ;; key が属するミニグリッド(9x9 マス)のキーリストを生成する (define (gen-keys-grd key) (define (get-keys n) (cond ((< n 4) '(1 2 3)) ((< n 7) '(4 5 6)) (else '(7 8 9)))) (let ((xs (get-keys (car key))) (ys (get-keys (cadr key)))) (define (iter x lis) (if (null? x) lis (iter (cdr x) (append lis (map (lambda (y) (list (car x) y)) ys))))) (iter xs nil))) ;; key が属する同じ行のキーリストを生成する (define (gen-keys-row key) (define keys (enumerate-interval 1 9)) (filter (lambda (k) (not (equal? k key))) (map (lambda (x) (list x (cadr key))) keys))) ;; key が属する同じ列のキーリストを生成する (define (gen-keys-col key) (define keys (enumerate-interval 1 9)) (filter (lambda (k) (not (equal? k key))) (map (lambda (y) (list (car key) y)) keys))) ;; key が属する同じ行と列のキーリストを生成する (define (gen-keys-row-and-col key) (define keys (enumerate-interval 1 9)) (append (map (lambda (x) (list x (cadr key))) keys) (map (lambda (y) (list (car key) y)) keys))) ;; append-keys1 と append-keys2 を append したキーリストから remove-keys を取り除く。 (define (append-and-remove-keys append-keys1 append-keys2 remove-keys) (define (iter keys rm-keys) (if (null? rm-keys) keys (iter (filter (lambda (k) (not (equal? k (car rm-keys)))) keys) (cdr rm-keys)))) (iter (append append-keys1 append-keys2) remove-keys)) ;; ハッシュテーブル ht の keys を val で更新する。 (define (update-vals ht keys val) (define (iter k) (if (null? k) 'done (let ((v (hash-table-get ht (car k)))) (if (pair? v) (let ((new-v (filter (lambda (x) (not (= x val))) v))) (if (null? new-v) (hash->grid ht)) (if (null? (cdr new-v)) (begin (confirm ht (car k) (car new-v)) (update-vals ht (append-and-remove-keys (gen-keys-grd (car k)) (gen-keys-row-and-col (car k)) (list (car k))) (car new-v))) (set-tentative ht (car k) new-v)))) (iter (cdr k))))) (iter keys)) ;; 更新フラグ (define *update-flag* #f) (define (clear-update-flag) (set! *update-flag* #f)) (define (set-update-flag) (set! *update-flag* #t)) (define (update?) *update-flag*) ;; val の値によって確定もしくは暫定設定を呼ぶ (define (update-val ht key val) (if (pair? val) (set-tentative ht key val) (confirm ht key val))) ;; 確定手続き (define (confirm ht key val) (debug-print ";;確定 key=" key " val=" val) (set-update-flag) (hash-table-put! ht key val)) ;; 暫定設定手続き (define (set-tentative ht key val) (let ((prev-val (hash-table-get ht key val))) (if (not (equal? prev-val val)) (begin (debug-print ";;暫定設定 key=" key " val=" val) (set-update-flag) (hash-table-put! ht key val))))) (define (bins->num bin-lis) (define (iter lis k num) (if (null? lis) num (iter (cdr lis) (* k 2) (+ num (* k (car lis)))))) (iter (reverse bin-lis) 1 0)) (define (num->bins num k) (define (iter n) (if (= n 0) nil (append (iter (quotient n 2)) (list (remainder n 2))))) (let ((bins (iter num))) (append (make-list (- k (length bins)) 0) bins))) (define (overlap-num lis) (if (null? (cdr lis)) #f (if (= (car lis) (cadr lis)) (car lis) (overlap-num (cdr lis))))) (define (find-val num lis) (define (iter l i vals) (if (null? l) vals (iter (cdr l) (+ i 1) (if (= (car l) num) (append vals `(,i)) vals)))) (iter lis 1 nil)) (define (find-vals lis lists) (define (iter l i vals) (if (null? l) vals (iter (cdr l) (+ i 1) (if (and (memq (car lis) (car l)) (memq (cadr lis) (car l))) (append vals `(,i)) vals)))) (iter lists 1 nil)) (define (find-lis lis lists) (define (iter l i vals) (if (null? l) vals (iter (cdr l) (+ i 1) (if (equal? (car l) lis) (append vals `(,i)) vals)))) (iter lists 1 nil)) (define (transpose grid) (define (iter lis new-lis) (if (null? (car lis)) new-lis (iter (map cdr lis) (append new-lis (list (map car lis)))))) (iter grid nil)) (define (check-grid grid) (map (lambda (l) (equal? l '(1 2 3 4 5 6 7 8 9))) (map sort grid))) ;;; ナンバープレイスを解く手続き群 ;; 解法レベル1 ;; 確定マスのある行列マスおよびミニグリッド(9x9マス)には、 ;; 確定マスと同じ値にはならないため候補値から取り除く。 (define (solve-level-1 ht) (define (proc key val) (if (not (pair? val)) (update-vals ht (append-and-remove-keys (gen-keys-grd key) (gen-keys-row-and-col key) (list key)) val) val)) (clear-update-flag) (debug-print "=== level 1 ===") (hash-table-map ht proc) (update?)) ;; 解法レベル2 ;; 行、列、ミニグリッドで候補値に 1 つしか表われない値を確定する。 ;; (行、列、ミニグリッドで別々に 3 回処理する) (define (solve-level-2 ht) (define (uniq-val target-vals vals) (if (null? vals) target-vals (uniq-val (remove (car vals) target-vals) (cdr vals)))) (define (proc key val) (if (pair? val) (let* ((row-vals (uniq (fold append nil (map (lambda (k) (let ((v (hash-table-get ht k))) (if (pair? v) v `(,v)))) (append-and-remove-keys (gen-keys-row key) nil (list key)))))) (col-vals (uniq (fold append nil (map (lambda (k) (let ((v (hash-table-get ht k))) (if (pair? v) v `(,v)))) (append-and-remove-keys (gen-keys-col key) nil (list key)))))) (grd-vals (uniq (fold append nil (map (lambda (k) (let ((v (hash-table-get ht k))) (if (pair? v) v `(,v)))) (append-and-remove-keys (gen-keys-grd key) nil (list key)))))) (draft-val-1 (uniq-val val row-vals)) (draft-val-2 (uniq-val val col-vals)) (draft-val-3 (uniq-val val grd-vals))) (cond ((= (length draft-val-1) 1) (confirm ht key (car draft-val-1))) ((= (length draft-val-2) 1) (confirm ht key (car draft-val-2))) ((= (length draft-val-3) 1) (confirm ht key (car draft-val-3))) (else 'nop))))) (clear-update-flag) (debug-print "=== level 2 ===") (hash-table-map ht proc) (update?)) ;; 解法レベル3 ;; 行、列、ミニグリッドで候補値に 1 つしか表われない値を確定する。 ;; (行、列、ミニグリッドをまとめて 1 回処理する) #;(define (solve-level-3 ht) (define (uniq-val target-vals vals) (if (null? vals) target-vals (uniq-val (remove (car vals) target-vals) (cdr vals)))) (define (proc key val) (if (pair? val) (let* ((vals (uniq (fold append nil (map (lambda (k) (let ((v (hash-table-get ht k))) (if (pair? v) v `(,v)))) (append-and-remove-keys (gen-keys-grd key) (gen-keys-row-and-col key) (list key)))))) (draft-val (uniq-val val vals))) (if (= (length draft-val) 1) (confirm ht key (car draft-val)))))) (clear-update-flag) (debug-print "=== level 3 ===") (hash-table-map ht proc) (update?)) ;; 解法レベル4 シンプルチェーン (define (solve-level-4 ht) (define (find-sc ht grid-keys) (define (sc keys) (define (one? lis) (null? (cdr lis))) (let ((x (uniq (map car keys))) (y (uniq (map cadr keys)))) (cond ((null? keys) '(0 0)) ((one? x) (list (car x) 0)) ((one? y) (list 0 (car y))) (else '(0 0))))) (define (key-iter num keys results) (if (null? keys) results (let ((val (hash-table-get ht (car keys)))) (if (pair? val) (let ((v (filter (lambda (v) (= v num)) val))) (key-iter num (cdr keys) (if (null? v) results (cons (car keys) results)))) (key-iter num (cdr keys) results))))) (define (num-iter nums) (if (null? nums) 'done (let ((key (sc (key-iter (car nums) grid-keys nil)))) (if (not (null? key)) (let ((val (car nums))) (and (not (= 0 (cadr key))) (update-vals ht (append-and-remove-keys (gen-keys-row key) nil grid-keys) val)) (and (not (= 0 (car key))) (update-vals ht (append-and-remove-keys (gen-keys-col key) nil grid-keys) val)) (num-iter (cdr nums))))))) (num-iter (enumerate-interval 1 9))) (define (iter keys) (if (null? keys) ht (begin (find-sc ht (gen-keys-grd (car keys))) (iter (cdr keys))))) (clear-update-flag) (debug-print "=== level 4 ===") (iter '((1 1) (4 1) (7 1) (1 4) (4 4) (7 4) (1 7) (4 7) (7 7))) (update?)) ;; 解法レベル5 2国同盟。4国同盟以上は未対応。 ;; 行、列、ミニグリッド内に同盟がある場合、同盟以外から候補値を削る。 ;; 例) ;; (1 2) (1 2) ... (2 5 9) (1 3 4 5) (1 2 7 8 9) ;; (1 2) と (1 2) は 2 国同盟が成立。 ;; 行、列およびミニグリッドにある、(1 2) 以外のマスに 1 および 2 が入る事は無い。 ;; したがって ;; (1 2) (1 2) ... (5 9) (3 4 5) (7 8 9) ;; のように除外できる。 (define (solve-level-5 ht) ;; val2 は val1 のサブセットか? ;; ただし val2 の要素数が 2 以上のものだけがチェック対象 (define (subsets? val1 val2) (let ((subsets-val1 (filter (lambda (v) (>= (length v) 2)) (subsets val1)))) (not (null? (filter (lambda (v) (equal? v val2)) subsets-val1))))) ;; val2 と val1 は互いにサブセットか (define (each-other-subsets? val1 val2) (and (= (length val1) (length val2)) (subsets? (sort (uniq (append val1 val2))) val2))) ;; items から remove-items を削除する (define (removes remove-items items) (if (null? remove-items) items (removes (cdr remove-items) (remove (car remove-items) items)))) ;; 同盟がある場合は、行、列もしくはグリッドから同盟の値を省く。 (define (remove-keys keys val) (define (iter k) (if (null? k) 'done (let ((v (hash-table-get ht (car k)))) (if (pair? v) (let ((nv (removes val v))) (update-val ht (car k) nv))) (iter (cdr k))))) (iter keys)) (define (append-vals ht keys) (if (null? keys) nil (append (hash-table-get ht (car keys)) (append-vals ht (cdr keys))))) ;; 同盟を探す。 ;; 例) ;; ・2国同盟 ;; (1 2) と同じ (1 2) が 1 つ(合計 2 つ) を見つけた場合。 ;; サブセットの処理はしない。 ;; ・3国同盟 ;; (1 2 3) (1 2) (1 3) (2 3) はいずれも (1 2 3) のサブセットである。 ;; サブセットのいずれか 2 つ(合計 3 つ)を見つけた場合は、3 国同盟と判断する。 ;; また、サブセット同士で以下のように3国同盟になる場合もある。 ;; (1 2) (1 3) (2 3) (define (find-alliance-2 ht key val) ;; フィルタ手続き (define (filter-proc k) (equal? val (hash-table-get ht k))) (let ((row-keys (filter filter-proc (append-and-remove-keys (gen-keys-row key) nil (list key)))) (col-keys (filter filter-proc (append-and-remove-keys (gen-keys-col key) nil (list key)))) (grd-keys (filter filter-proc (append-and-remove-keys (gen-keys-grd key) nil (list key))))) (and (not (null? row-keys)) (remove-keys (append-and-remove-keys (gen-keys-row key) nil (append (list key) row-keys)) val)) (and (not (null? col-keys)) (remove-keys (append-and-remove-keys (gen-keys-col key) nil (append (list key) col-keys)) val)) (and (not (null? grd-keys)) (remove-keys (append-and-remove-keys (gen-keys-grd key) nil (append (list key) grd-keys)) val)) )) (define (find-alliance-3 ht key val) ;; フィルタ手続き (define (filter-proc k) (let ((k-val (hash-table-get ht k))) (and (pair? k-val) (or (subsets? val k-val) (each-other-subsets? val k-val))))) (let ((row-keys (filter filter-proc (append-and-remove-keys (gen-keys-row key) nil (list key)))) (col-keys (filter filter-proc (append-and-remove-keys (gen-keys-col key) nil (list key)))) (grd-keys (filter filter-proc (append-and-remove-keys (gen-keys-grd key) nil (list key))))) ;; 3国同盟の場合、 ;; ・同盟として見付けた数が 2 箇所(key と合せて 3 箇所) ;; ・みつけた 3 箇所で使われている候補数が 3 つ ;; の場合に処理する。 (and (not (null? row-keys)) (= (length row-keys) 2) (= (length (uniq (append-vals ht (append row-keys (list key))))) 3) (remove-keys (append-and-remove-keys (gen-keys-row key) nil (append (list key) row-keys)) val)) (and (not (null? col-keys)) (= (length col-keys) 2) (= (length (uniq (append-vals ht (append col-keys (list key))))) 3) (remove-keys (append-and-remove-keys (gen-keys-col key) nil (append (list key) col-keys)) val)) (and (not (null? grd-keys)) (= (length grd-keys) 2) (= (length (uniq (append-vals ht (append grd-keys (list key))))) 3) (remove-keys (append-and-remove-keys (gen-keys-grd key) nil (append (list key) grd-keys)) val)) )) (define (proc key val) (and (pair? val) (or ;; 3国同盟を先に処理する。 (and (<= (length val) 3) (find-alliance-3 ht key val)) (and (= (length val) 2) (find-alliance-2 ht key val))))) (clear-update-flag) (debug-print "=== level 5 ===") (hash-table-map ht proc) (update?)) ;; 解法レベル6 XYウイング (define (solve-level-6 ht) (define (xy-wing lis) (let ((w (filter (lambda (l) (= 2 (apply + l))) lis))) (cond ((null? w) #f) ((null? (cdr w)) #f) (else (let ((bins (map bins->num w))) (let ((sb (sort bins))) (let ((usb (sort (uniq sb)))) (if (= (abs (- (length sb) (length usb))) 1) (num->bins (overlap-num sb) 9) #f )))))))) (define (xy-wing-upd-vals ht n r c) (let ((k1 (list (car c) (car r))) (k2 (list (cadr c) (cadr r)))) (let ((rk (list k1 k2 (list (car k2) (cadr k1)) (list (car k1) (cadr k2))))) ;;(print "n=" n " r=" r " c=" c " k1=" k1 " k2=" k2 " rk=" rk) (update-vals ht (append-and-remove-keys (gen-keys-row k1) (gen-keys-col k1) rk) n) (update-vals ht (append-and-remove-keys (gen-keys-row k2) (gen-keys-col k2) rk) n) ))) (define (find-xy-wing ht num keys) (define (iter vals results) (if (null? vals) results (if (pair? (car vals)) (if (null? (filter (lambda (n) (= n num)) (car vals))) (iter (cdr vals) (append results '(0))) (iter (cdr vals) (append results '(1)))) (iter (cdr vals) (append results '(0)))))) (let ((vals (map (lambda (k) (hash-table-get ht k)) keys))) ;;(print "num=" num " keys=" keys " vals=" vals) (iter vals nil))) (define (r-iter n nums results) (if (null? nums) results (let ((rk (list 1 (car nums)))) (r-iter n (cdr nums) (append results (list (find-xy-wing ht n (cons rk (gen-keys-row rk))))))))) (define (c-iter n nums results) (if (null? nums) results (let ((ck (list (car nums) 1))) (c-iter n (cdr nums) (append results (list (find-xy-wing ht n (cons ck (gen-keys-col ck))))))))) (define (iter nums) (if (null? nums) ht (begin (let ((r (r-iter (car nums) (enumerate-interval 1 9) nil))) (let ((rw (xy-wing r))) (and rw (xy-wing-upd-vals ht (car nums) (find-lis rw r) (find-val 1 rw))))) (let ((c (c-iter (car nums) (enumerate-interval 1 9) nil))) (let ((cw (xy-wing c))) (and cw (xy-wing-upd-vals ht (car nums) (find-val 1 cw) (find-lis cw c))))) (iter (cdr nums))))) (clear-update-flag) (debug-print "=== level 6 ===") (iter (enumerate-interval 1 9)) (update?)) ;; 仮置き法(未実装) (define (solve-level-7 ht) (clear-update-flag) (debug-print "=== level 7 ===") ;; 仮置きしないと解けない問題は邪道らしいです。 (update?)) ;; 問題が解けたか? (define (solve-end? ht) (let ((alis (hash-table->alist ht)) (grid (hash->grid ht))) (and (null? (filter pair? (map cdr alis))) (equal? (list #t) (uniq (append (check-grid grid) (check-grid (transpose grid)))))))) ;; メイン処理 ;; ハッシュテーブルは、キーに(行,列)情報を、val に候補値もしくは確定値のいずれかの値を持つ。 ;; 例) val=(1 2 3 6 7) ... val は現在未確定でありリスト内のいずれかの候補値に将来確定する事を表わす。 ;; val=5 ............. val は 5 で確定した事を表わす。 (define (solve-main ht c) (debug-print "ループ " c " 回目") (let ((result (or (solve-level-1 ht) (solve-level-2 ht) ;;(solve-level-3 ht) (solve-level-4 ht) (solve-level-5 ht) (solve-level-6 ht) ))) (if result (solve-main ht (+ c 1)) (if (solve-end? ht) ht (begin (print "解けませんでした") ht))))) (define (solve-test input-filename grid-no) (define grids (make-grids input-filename)) (define ht (grid->hash (list-ref grids (- grid-no 1)))) (debug-print "============") (solve-main (init-grid ht) 1))
完全に動作するコードを掲載するのがポリシーなので、全コードを掲載します。
Gauche をインストールして REPL(gosh) に丸ごと貼っ付けてください。
今回は過去に自分が書いたプログラムがイミフで大変だったので、
その反省を踏まえw、変数名や手続き名を見直しさらにコメントも書いてみましたw
同じフォルダに mondai.txt という名前で以下の内容のファイルを用意してください。
これはプロジェクトオイラーの問題96のナンプレ問題です。
Grid 01 003020600 900305001 001806400 008102900 700000008 006708200 002609500 800203009 005010300 Grid 02 200080300 060070084 030500209 000105408 000000000 402706000 301007040 720040060 004010003 Grid 03 000000907 000420180 000705026 100904000 050000040 000507009 920108000 034059000 507000000 Grid 04 030050040 008010500 460000012 070502080 000603000 040109030 250000098 001020600 080060020 Grid 05 020810740 700003100 090002805 009040087 400208003 160030200 302700060 005600008 076051090 Grid 06 100920000 524010000 000000070 050008102 000000000 402700090 060000000 000030945 000071006 Grid 07 043080250 600000000 000001094 900004070 000608000 010200003 820500000 000000005 034090710 Grid 08 480006902 002008001 900370060 840010200 003704100 001060049 020085007 700900600 609200018 Grid 09 000900002 050123400 030000160 908000000 070000090 000000205 091000050 007439020 400007000 Grid 10 001900003 900700160 030005007 050000009 004302600 200000070 600100030 042007006 500006800 Grid 11 000125400 008400000 420800000 030000095 060902010 510000060 000003049 000007200 001298000 Grid 12 062340750 100005600 570000040 000094800 400000006 005830000 030000091 006400007 059083260 Grid 13 300000000 005009000 200504000 020000700 160000058 704310600 000890100 000067080 000005437 Grid 14 630000000 000500008 005674000 000020000 003401020 000000345 000007004 080300902 947100080 Grid 15 000020040 008035000 000070602 031046970 200000000 000501203 049000730 000000010 800004000 Grid 16 361025900 080960010 400000057 008000471 000603000 259000800 740000005 020018060 005470329 Grid 17 050807020 600010090 702540006 070020301 504000908 103080070 900076205 060090003 080103040 Grid 18 080005000 000003457 000070809 060400903 007010500 408007020 901020000 842300000 000100080 Grid 19 003502900 000040000 106000305 900251008 070408030 800763001 308000104 000020000 005104800 Grid 20 000000000 009805100 051907420 290401065 000000000 140508093 026709580 005103600 000000000 Grid 21 020030090 000907000 900208005 004806500 607000208 003102900 800605007 000309000 030020050 Grid 22 005000006 070009020 000500107 804150000 000803000 000092805 907006000 030400010 200000600 Grid 23 040000050 001943600 009000300 600050002 103000506 800020007 005000200 002436700 030000040 Grid 24 004000000 000030002 390700080 400009001 209801307 600200008 010008053 900040000 000000800 Grid 25 360020089 000361000 000000000 803000602 400603007 607000108 000000000 000418000 970030014 Grid 26 500400060 009000800 640020000 000001008 208000501 700500000 000090084 003000600 060003002 Grid 27 007256400 400000005 010030060 000508000 008060200 000107000 030070090 200000004 006312700 Grid 28 000000000 079050180 800000007 007306800 450708096 003502700 700000005 016030420 000000000 Grid 29 030000080 009000500 007509200 700105008 020090030 900402001 004207100 002000800 070000090 Grid 30 200170603 050000100 000006079 000040700 000801000 009050000 310400000 005000060 906037002 Grid 31 000000080 800701040 040020030 374000900 000030000 005000321 010060050 050802006 080000000 Grid 32 000000085 000210009 960080100 500800016 000000000 890006007 009070052 300054000 480000000 Grid 33 608070502 050608070 002000300 500090006 040302050 800050003 005000200 010704090 409060701 Grid 34 050010040 107000602 000905000 208030501 040070020 901080406 000401000 304000709 020060010 Grid 35 053000790 009753400 100000002 090080010 000907000 080030070 500000003 007641200 061000940 Grid 36 006080300 049070250 000405000 600317004 007000800 100826009 000702000 075040190 003090600 Grid 37 005080700 700204005 320000084 060105040 008000500 070803010 450000091 600508007 003010600 Grid 38 000900800 128006400 070800060 800430007 500000009 600079008 090004010 003600284 001007000 Grid 39 000080000 270000054 095000810 009806400 020403060 006905100 017000620 460000038 000090000 Grid 40 000602000 400050001 085010620 038206710 000000000 019407350 026040530 900020007 000809000 Grid 41 000900002 050123400 030000160 908000000 070000090 000000205 091000050 007439020 400007000 Grid 42 380000000 000400785 009020300 060090000 800302009 000040070 001070500 495006000 000000092 Grid 43 000158000 002060800 030000040 027030510 000000000 046080790 050000080 004070100 000325000 Grid 44 010500200 900001000 002008030 500030007 008000500 600080004 040100700 000700006 003004050 Grid 45 080000040 000469000 400000007 005904600 070608030 008502100 900000005 000781000 060000010 Grid 46 904200007 010000000 000706500 000800090 020904060 040002000 001607000 000000030 300005702 Grid 47 000700800 006000031 040002000 024070000 010030080 000060290 000800070 860000500 002006000 Grid 48 001007090 590080001 030000080 000005800 050060020 004100000 080000030 100020079 020700400 Grid 49 000003017 015009008 060000000 100007000 009000200 000500004 000000020 500600340 340200000 Grid 50 300200000 000107000 706030500 070009080 900020004 010800050 009040301 000702000 000008006
用意できたら早速解いてみましょう。
50問をすべて解くには以下のようにします。
gosh> (begin (map (lambda (n) (print n) (print-grid (hash->grid (solve-test "./mondai.txt" n)))) (enumerate-interval 1 50)) 'done) 1 (4 8 3 9 2 1 6 5 7) (9 6 7 3 4 5 8 2 1) (2 5 1 8 7 6 4 9 3) (5 4 8 1 3 2 9 7 6) (7 2 9 5 6 4 1 3 8) (1 3 6 7 9 8 2 4 5) (3 7 2 6 8 9 5 1 4) (8 1 4 2 5 3 7 6 9) (6 9 5 4 1 7 3 8 2) 2 (2 4 5 9 8 1 3 7 6) (1 6 9 2 7 3 5 8 4) (8 3 7 5 6 4 2 1 9) (9 7 6 1 2 5 4 3 8) (5 1 3 4 9 8 6 2 7) (4 8 2 7 3 6 9 5 1) (3 9 1 6 5 7 8 4 2) (7 2 8 3 4 9 1 6 5) (6 5 4 8 1 2 7 9 3) 3 (4 6 2 8 3 1 9 5 7) (7 9 5 4 2 6 1 8 3) (3 8 1 7 9 5 4 2 6) (1 7 3 9 8 4 2 6 5) (6 5 9 3 1 2 7 4 8) (2 4 8 5 6 7 3 1 9) (9 2 6 1 7 8 5 3 4) (8 3 4 2 5 9 6 7 1) (5 1 7 6 4 3 8 9 2) 4 (1 3 7 2 5 6 8 4 9) (9 2 8 3 1 4 5 6 7) (4 6 5 8 9 7 3 1 2) (6 7 3 5 4 2 9 8 1) (8 1 9 6 7 3 2 5 4) (5 4 2 1 8 9 7 3 6) (2 5 6 7 3 1 4 9 8) (3 9 1 4 2 8 6 7 5) (7 8 4 9 6 5 1 2 3) 5 (5 2 3 8 1 6 7 4 9) (7 8 4 5 9 3 1 2 6) (6 9 1 4 7 2 8 3 5) (2 3 9 1 4 5 6 8 7) (4 5 7 2 6 8 9 1 3) (1 6 8 9 3 7 2 5 4) (3 4 2 7 8 9 5 6 1) (9 1 5 6 2 4 3 7 8) (8 7 6 3 5 1 4 9 2) 6 (1 7 6 9 2 3 5 8 4) (5 2 4 8 1 7 6 3 9) (8 9 3 6 5 4 2 7 1) (9 5 7 3 4 8 1 6 2) (6 3 8 1 9 2 4 5 7) (4 1 2 7 6 5 3 9 8) (2 6 5 4 8 9 7 1 3) (7 8 1 2 3 6 9 4 5) (3 4 9 5 7 1 8 2 6) 7 (1 4 3 9 8 6 2 5 7) (6 7 9 4 2 5 3 8 1) (2 8 5 7 3 1 6 9 4) (9 6 2 3 5 4 1 7 8) (3 5 7 6 1 8 9 4 2) (4 1 8 2 7 9 5 6 3) (8 2 1 5 6 7 4 3 9) (7 9 6 1 4 3 8 2 5) (5 3 4 8 9 2 7 1 6) 8 (4 8 7 1 5 6 9 3 2) (3 6 2 4 9 8 7 5 1) (9 1 5 3 7 2 8 6 4) (8 4 6 5 1 9 2 7 3) (5 9 3 7 2 4 1 8 6) (2 7 1 8 6 3 5 4 9) (1 2 4 6 8 5 3 9 7) (7 3 8 9 4 1 6 2 5) (6 5 9 2 3 7 4 1 8) 9 (8 1 4 9 7 6 5 3 2) (6 5 9 1 2 3 4 7 8) (7 3 2 8 5 4 1 6 9) (9 4 8 2 6 5 3 1 7) (2 7 5 3 4 1 8 9 6) (1 6 3 7 9 8 2 4 5) (3 9 1 6 8 2 7 5 4) (5 8 7 4 3 9 6 2 1) (4 2 6 5 1 7 9 8 3) 10 (7 6 1 9 2 8 4 5 3) (9 2 5 7 4 3 1 6 8) (4 3 8 6 1 5 9 2 7) (3 5 7 4 6 1 2 8 9) (8 9 4 3 7 2 6 1 5) (2 1 6 5 8 9 3 7 4) (6 8 9 1 5 4 7 3 2) (1 4 2 8 3 7 5 9 6) (5 7 3 2 9 6 8 4 1) 11 (9 7 6 1 2 5 4 3 8) (1 5 8 4 3 6 9 2 7) (4 2 3 8 7 9 1 5 6) (2 3 4 7 6 1 8 9 5) (8 6 7 9 5 2 3 1 4) (5 1 9 3 8 4 7 6 2) (7 8 2 5 1 3 6 4 9) (3 9 5 6 4 7 2 8 1) (6 4 1 2 9 8 5 7 3) 12 (9 6 2 3 4 1 7 5 8) (1 4 8 9 7 5 6 2 3) (5 7 3 2 6 8 1 4 9) (3 2 1 6 9 4 8 7 5) (4 8 7 5 1 2 9 3 6) (6 9 5 8 3 7 4 1 2) (8 3 4 7 2 6 5 9 1) (2 1 6 4 5 9 3 8 7) (7 5 9 1 8 3 2 6 4) 13 (3 9 7 6 8 1 5 2 4) (6 4 5 2 7 9 8 1 3) (2 1 8 5 3 4 9 7 6) (8 2 3 9 5 6 7 4 1) (1 6 9 7 4 2 3 5 8) (7 5 4 3 1 8 6 9 2) (4 7 2 8 9 3 1 6 5) (5 3 1 4 6 7 2 8 9) (9 8 6 1 2 5 4 3 7) 14 (6 3 9 2 1 8 4 5 7) (4 7 1 5 3 9 2 6 8) (8 2 5 6 7 4 1 3 9) (5 6 4 8 2 3 7 9 1) (7 9 3 4 5 1 8 2 6) (2 1 8 7 9 6 3 4 5) (3 5 2 9 8 7 6 1 4) (1 8 6 3 4 5 9 7 2) (9 4 7 1 6 2 5 8 3) 15 (6 9 7 1 2 8 3 4 5) (4 2 8 6 3 5 1 9 7) (3 1 5 4 7 9 6 8 2) (5 3 1 2 4 6 9 7 8) (2 8 6 3 9 7 4 5 1) (9 7 4 5 8 1 2 6 3) (1 4 9 8 5 2 7 3 6) (7 5 2 9 6 3 8 1 4) (8 6 3 7 1 4 5 2 9) 16 (3 6 1 7 2 5 9 4 8) (5 8 7 9 6 4 2 1 3) (4 9 2 8 3 1 6 5 7) (6 3 8 2 5 9 4 7 1) (1 7 4 6 8 3 5 9 2) (2 5 9 1 4 7 8 3 6) (7 4 6 3 9 2 1 8 5) (9 2 3 5 1 8 7 6 4) (8 1 5 4 7 6 3 2 9) 17 (3 5 9 8 6 7 1 2 4) (6 4 8 3 1 2 5 9 7) (7 1 2 5 4 9 8 3 6) (8 7 6 9 2 4 3 5 1) (5 2 4 7 3 1 9 6 8) (1 9 3 6 8 5 4 7 2) (9 3 1 4 7 6 2 8 5) (4 6 5 2 9 8 7 1 3) (2 8 7 1 5 3 6 4 9) 18 (7 8 6 9 4 5 3 1 2) (2 1 9 8 6 3 4 5 7) (5 3 4 2 7 1 8 6 9) (1 6 5 4 8 2 9 7 3) (3 2 7 6 1 9 5 4 8) (4 9 8 5 3 7 1 2 6) (9 5 1 7 2 8 6 3 4) (8 4 2 3 5 6 7 9 1) (6 7 3 1 9 4 2 8 5) 19 (7 4 3 5 1 2 9 8 6) (5 8 9 3 4 6 2 1 7) (1 2 6 9 8 7 3 4 5) (9 3 4 2 5 1 7 6 8) (6 7 1 4 9 8 5 3 2) (8 5 2 7 6 3 4 9 1) (3 9 8 6 7 5 1 2 4) (4 1 7 8 2 9 6 5 3) (2 6 5 1 3 4 8 7 9) 20 (7 8 2 6 1 4 3 5 9) (4 3 9 8 2 5 1 7 6) (6 5 1 9 3 7 4 2 8) (2 9 3 4 7 1 8 6 5) (5 6 8 3 9 2 7 1 4) (1 4 7 5 6 8 2 9 3) (3 2 6 7 4 9 5 8 1) (9 7 5 1 8 3 6 4 2) (8 1 4 2 5 6 9 3 7) 21 (4 2 8 5 3 1 7 9 6) (3 6 5 9 4 7 1 8 2) (9 7 1 2 6 8 4 3 5) (2 1 4 8 9 6 5 7 3) (6 9 7 4 5 3 2 1 8) (5 8 3 1 7 2 9 6 4) (8 4 9 6 1 5 3 2 7) (7 5 2 3 8 9 6 4 1) (1 3 6 7 2 4 8 5 9) 22 (4 2 5 7 8 1 9 3 6) (1 7 8 3 6 9 5 2 4) (3 6 9 5 2 4 1 8 7) (8 9 4 1 5 7 3 6 2) (6 5 2 8 4 3 7 9 1) (7 1 3 6 9 2 8 4 5) (9 8 7 2 1 6 4 5 3) (5 3 6 4 7 8 2 1 9) (2 4 1 9 3 5 6 7 8) 23 (3 4 8 2 6 7 9 5 1) (5 7 1 9 4 3 6 2 8) (2 6 9 1 8 5 3 7 4) (6 9 7 3 5 1 4 8 2) (1 2 3 8 7 4 5 9 6) (8 5 4 6 2 9 1 3 7) (4 1 5 7 9 8 2 6 3) (9 8 2 4 3 6 7 1 5) (7 3 6 5 1 2 8 4 9) 24 (1 2 4 9 8 6 7 3 5) (8 6 7 4 3 5 9 1 2) (3 9 5 7 1 2 6 8 4) (4 7 8 3 5 9 2 6 1) (2 5 9 8 6 1 3 4 7) (6 3 1 2 7 4 5 9 8) (7 1 2 6 9 8 4 5 3) (9 8 3 5 4 7 1 2 6) (5 4 6 1 2 3 8 7 9) 25 (3 6 1 5 2 4 7 8 9) (7 8 9 3 6 1 4 2 5) (5 2 4 8 7 9 3 6 1) (8 9 3 1 5 7 6 4 2) (4 1 2 6 8 3 5 9 7) (6 5 7 9 4 2 1 3 8) (1 4 8 7 9 6 2 5 3) (2 3 5 4 1 8 9 7 6) (9 7 6 2 3 5 8 1 4) 26 (5 8 1 4 7 9 2 6 3) (3 2 9 1 5 6 8 4 7) (6 4 7 3 2 8 1 5 9) (9 5 6 7 3 1 4 2 8) (2 3 8 9 6 4 5 7 1) (7 1 4 5 8 2 9 3 6) (1 7 2 6 9 5 3 8 4) (8 9 3 2 4 7 6 1 5) (4 6 5 8 1 3 7 9 2) 27 (3 8 7 2 5 6 4 1 9) (4 6 9 7 8 1 3 2 5) (5 1 2 4 3 9 8 6 7) (1 2 3 5 4 8 9 7 6) (7 5 8 9 6 3 2 4 1) (6 9 4 1 2 7 5 8 3) (8 3 5 6 7 4 1 9 2) (2 7 1 8 9 5 6 3 4) (9 4 6 3 1 2 7 5 8) 28 (3 4 5 8 7 1 2 6 9) (2 7 9 6 5 3 1 8 4) (8 6 1 4 2 9 5 3 7) (1 9 7 3 4 6 8 5 2) (4 5 2 7 1 8 3 9 6) (6 8 3 5 9 2 7 4 1) (7 3 8 2 6 4 9 1 5) (5 1 6 9 3 7 4 2 8) (9 2 4 1 8 5 6 7 3) 29 (2 3 5 7 6 1 4 8 9) (4 1 9 3 2 8 5 7 6) (8 6 7 5 4 9 2 1 3) (7 4 6 1 3 5 9 2 8) (5 2 1 8 9 6 7 3 4) (9 8 3 4 7 2 6 5 1) (3 9 4 2 8 7 1 6 5) (6 5 2 9 1 3 8 4 7) (1 7 8 6 5 4 3 9 2) 30 (2 9 8 1 7 5 6 4 3) (6 5 7 3 9 4 1 2 8) (1 3 4 2 8 6 5 7 9) (8 2 1 6 4 9 7 3 5) (5 7 3 8 2 1 4 9 6) (4 6 9 7 5 3 2 8 1) (3 1 2 4 6 8 9 5 7) (7 8 5 9 1 2 3 6 4) (9 4 6 5 3 7 8 1 2) 31 (7 6 1 5 4 3 2 8 9) (8 3 2 7 9 1 6 4 5) (5 4 9 6 2 8 1 3 7) (3 7 4 2 1 5 9 6 8) (1 2 8 9 3 6 5 7 4) (6 9 5 4 8 7 3 2 1) (4 1 7 3 6 9 8 5 2) (9 5 3 8 7 2 4 1 6) (2 8 6 1 5 4 7 9 3) 32 (1 3 2 6 4 9 7 8 5) (7 5 8 2 1 3 6 4 9) (9 6 4 7 8 5 1 2 3) (5 4 3 8 9 7 2 1 6) (2 7 6 5 3 1 8 9 4) (8 9 1 4 2 6 5 3 7) (6 1 9 3 7 8 4 5 2) (3 2 7 1 5 4 9 6 8) (4 8 5 9 6 2 3 7 1) 33 (6 9 8 1 7 3 5 4 2) (3 5 4 6 2 8 1 7 9) (1 7 2 5 4 9 3 6 8) (5 3 1 8 9 7 4 2 6) (9 4 6 3 1 2 8 5 7) (8 2 7 4 5 6 9 1 3) (7 6 5 9 3 1 2 8 4) (2 1 3 7 8 4 6 9 5) (4 8 9 2 6 5 7 3 1) 34 (8 5 2 7 1 6 9 4 3) (1 9 7 8 4 3 6 5 2) (4 6 3 9 2 5 1 8 7) (2 7 8 6 3 4 5 9 1) (6 4 5 1 7 9 3 2 8) (9 3 1 5 8 2 4 7 6) (7 8 6 4 9 1 2 3 5) (3 1 4 2 5 8 7 6 9) (5 2 9 3 6 7 8 1 4) 35 (4 5 3 2 1 8 7 9 6) (6 2 9 7 5 3 4 8 1) (1 7 8 4 9 6 5 3 2) (7 9 6 5 8 2 3 1 4) (3 1 4 9 6 7 8 2 5) (2 8 5 1 3 4 6 7 9) (5 4 2 8 7 9 1 6 3) (9 3 7 6 4 1 2 5 8) (8 6 1 3 2 5 9 4 7) 36 (5 1 6 2 8 9 3 4 7) (8 4 9 1 7 3 2 5 6) (7 3 2 4 6 5 9 1 8) (6 9 8 3 1 7 5 2 4) (3 2 7 9 5 4 8 6 1) (1 5 4 8 2 6 7 3 9) (9 6 1 7 3 2 4 8 5) (2 7 5 6 4 8 1 9 3) (4 8 3 5 9 1 6 7 2) 37 (9 4 5 6 8 1 7 2 3) (7 8 1 2 3 4 9 6 5) (3 2 6 7 5 9 1 8 4) (2 6 9 1 7 5 3 4 8) (1 3 8 9 4 2 5 7 6) (5 7 4 8 6 3 2 1 9) (4 5 7 3 2 6 8 9 1) (6 1 2 5 9 8 4 3 7) (8 9 3 4 1 7 6 5 2) 38 (3 6 5 9 4 2 8 7 1) (1 2 8 7 5 6 4 9 3) (9 7 4 8 1 3 5 6 2) (8 1 9 4 3 5 6 2 7) (5 3 7 2 6 8 1 4 9) (6 4 2 1 7 9 3 5 8) (2 9 6 3 8 4 7 1 5) (7 5 3 6 9 1 2 8 4) (4 8 1 5 2 7 9 3 6) 39 (1 3 4 5 8 7 2 9 6) (2 7 8 1 6 9 3 5 4) (6 9 5 2 3 4 8 1 7) (3 5 9 8 1 6 4 7 2) (8 2 1 4 7 3 5 6 9) (7 4 6 9 2 5 1 8 3) (9 1 7 3 4 8 6 2 5) (4 6 2 7 5 1 9 3 8) (5 8 3 6 9 2 7 4 1) 40 (1 9 3 6 7 2 4 8 5) (4 6 2 3 5 8 9 7 1) (7 8 5 9 1 4 6 2 3) (5 3 8 2 9 6 7 1 4) (6 7 4 1 3 5 2 9 8) (2 1 9 4 8 7 3 5 6) (8 2 6 7 4 1 5 3 9) (9 4 1 5 2 3 8 6 7) (3 5 7 8 6 9 1 4 2) 41 (8 1 4 9 7 6 5 3 2) (6 5 9 1 2 3 4 7 8) (7 3 2 8 5 4 1 6 9) (9 4 8 2 6 5 3 1 7) (2 7 5 3 4 1 8 9 6) (1 6 3 7 9 8 2 4 5) (3 9 1 6 8 2 7 5 4) (5 8 7 4 3 9 6 2 1) (4 2 6 5 1 7 9 8 3) 42 (3 8 4 5 6 7 9 2 1) (1 2 6 4 3 9 7 8 5) (7 5 9 8 2 1 3 4 6) (5 6 3 7 9 8 2 1 4) (8 4 7 3 1 2 6 5 9) (9 1 2 6 4 5 8 7 3) (2 3 1 9 7 4 5 6 8) (4 9 5 2 8 6 1 3 7) (6 7 8 1 5 3 4 9 2) 43 (4 6 9 1 5 8 3 7 2) (7 1 2 4 6 3 8 5 9) (5 3 8 2 9 7 6 4 1) (9 2 7 6 3 4 5 1 8) (3 8 5 7 1 9 4 2 6) (1 4 6 5 8 2 7 9 3) (6 5 3 9 4 1 2 8 7) (2 9 4 8 7 6 1 3 5) (8 7 1 3 2 5 9 6 4) 44 (3 1 6 5 4 9 2 7 8) (9 8 7 3 2 1 6 4 5) (4 5 2 6 7 8 9 3 1) (5 9 4 2 3 6 8 1 7) (2 3 8 4 1 7 5 6 9) (6 7 1 9 8 5 3 2 4) (8 4 5 1 6 2 7 9 3) (1 2 9 7 5 3 4 8 6) (7 6 3 8 9 4 1 5 2) 45 (5 8 6 1 2 7 9 4 3) (7 2 3 4 6 9 8 5 1) (4 9 1 8 5 3 2 6 7) (1 3 5 9 7 4 6 2 8) (2 7 9 6 1 8 5 3 4) (6 4 8 5 3 2 1 7 9) (9 1 7 2 4 6 3 8 5) (3 5 2 7 8 1 4 9 6) (8 6 4 3 9 5 7 1 2) 46 (9 5 4 2 1 3 6 8 7) (6 1 7 5 4 8 9 2 3) (8 3 2 7 9 6 5 4 1) (7 6 3 8 5 1 2 9 4) (1 2 8 9 7 4 3 6 5) (5 4 9 3 6 2 1 7 8) (2 8 1 6 3 7 4 5 9) (4 7 5 1 2 9 8 3 6) (3 9 6 4 8 5 7 1 2) 47 (1 5 9 7 4 3 8 6 2) (2 7 6 5 8 9 4 3 1) (3 4 8 6 1 2 7 5 9) (6 2 4 9 7 8 3 1 5) (9 1 7 2 3 5 6 8 4) (5 8 3 1 6 4 2 9 7) (4 3 5 8 2 1 9 7 6) (8 6 1 4 9 7 5 2 3) (7 9 2 3 5 6 1 4 8) 48 (8 6 1 3 5 7 2 9 4) (5 9 7 4 8 2 3 6 1) (4 3 2 6 1 9 7 8 5) (9 1 6 2 7 5 8 4 3) (3 5 8 9 6 4 1 2 7) (2 7 4 1 3 8 9 5 6) (7 8 9 5 4 1 6 3 2) (1 4 3 8 2 6 5 7 9) (6 2 5 7 9 3 4 1 8) 49 (2 9 4 8 6 3 5 1 7) (7 1 5 4 2 9 6 3 8) (8 6 3 7 5 1 4 9 2) (1 5 2 9 4 7 8 6 3) (4 7 9 3 8 6 2 5 1) (6 3 8 5 1 2 9 7 4) (9 8 6 1 3 4 7 2 5) (5 2 1 6 7 8 3 4 9) (3 4 7 2 9 5 1 8 6) 50 (3 5 1 2 8 6 4 9 7) (4 9 2 1 5 7 6 3 8) (7 8 6 9 3 4 5 1 2) (2 7 5 4 6 9 1 8 3) (9 3 8 5 2 1 7 6 4) (6 1 4 8 7 3 2 5 9) (8 2 9 6 4 5 3 7 1) (1 6 3 7 9 2 8 4 5) (5 4 7 3 1 8 9 2 6) done
すべて解けました。
1問だけ解きたい場合は以下のようにします。
gosh> (print-grid (hash->grid (solve-test "./mondai.txt" 1))) (4 8 3 9 2 1 6 5 7) (9 6 7 3 4 5 8 2 1) (2 5 1 8 7 6 4 9 3) (5 4 8 1 3 2 9 7 6) (7 2 9 5 6 4 1 3 8) (1 3 6 7 9 8 2 4 5) (3 7 2 6 8 9 5 1 4) (8 1 4 2 5 3 7 6 9) (6 9 5 4 1 7 3 8 2) done
ナンプレにおいて、仮置法を使用するのは問題を解く人の自由ですが、
仮置法を前提とする問題は「邪道」とする人が多い気がします。
本プログラムにおいても仮置法は実装していません。