1

クラスでスキームの行列ライブラリを作成しました (ドキュメントはこちら: http://www.cs.indiana.edu/cgi-pub/c211/wombat/docs/c211-matrix.htm

そこで、マトリックスを使って行うことにした小さなプロジェクトは、数独ソルバーです。(これは信用のためではありません。これは、テスト前の行列を使った一種の練習として与えられたものです)。

これまでのところ、ほとんどのプログラムを完了しましたが、いくつかの最終機能で立ち往生しています。

北西隅の行、北西隅の列、および値を取り、その値がそのブロックに入ることができるかどうかを確認する check-block という関数を書きたいと思います。したがって、基本的に数独 3X3 ボックスの 1 つの左上で、番号がすべて準備完了かどうかを確認する必要があります。以下の check-row および check-col 関数を使用して、特定の各行と列をチェックして、そこに数字が入るかどうかを確認しますが、毎回最初の列または正方形から開始します。開始する方法がわかりませんある北西の角から。

それは次のようなものから始まります:

(define (check-block nwr nwc val))

ブロックの各部分をチェックするには、ある種のループを使用する必要があると思います。

この後、valid? と呼ばれるものを書きたいと思います。これは、行インデックス r、列インデックス c、および値 val を取り、指定された位置に値を配置できるかどうかをチェックします。

私が本当に行き詰まっているこれらの2つは、アルゴリズムの観点から考える方法を知っています。つまり、さらに 4 つの関数 solve、try-row、try-cell、および try-value が必要です。

solve は単純に try-row 0 を呼び出し、行 0 からパズルを埋め始めるという考え方です。プロシージャ try-row は、前のすべての行が適切に埋められていることを前提としており、パズルが終了していない場合は、(トライセル r 0)。プロシージャ try-cell は、前のすべての行と左側の列が適切に入力されていることを前提としています。現在の行がいっぱいになると、次の行に進みます。現在のセルが空白でない場合はスキップされます。それ以外の場合、現在のセルが空白の場合は、現在のセルに 1 を入力しようとする (try-value rc 1) を呼び出します。プロシージャ try-value は、セルの座標と、指定された位置に配置される値 v を取得します。 . 値が 9 を超える場合、プロシージャは失敗して戻ります。指定された値を設定できる場合、プロシージャは次の値を試行します。与えられた値を入れることができる場合、ボードは変更され、次のセルを埋めようとして計算が続行されます。次の値を入力しようとして失敗した場合、追加された値が削除され、次の値が試行されます。

だからここに私がこれまで持っているコードがあります:

;This function defines an empty cell as _
(define empty #\_)

;This makes it so there are 9 rows in the matrix
(define rows 9)

;This makes it so there are 9 columns in the matrix
(define cols 9)

;This makes it soa block size is considered 3X3
(define block-size 3)

;This makes board be the matri
(define board (make-matrix rows cols empty))

;This function physically builds the matrix
(define read-puzzle
   (lambda (fname)
     (with-input-from-file
       fname
       (lambda ()
         (let row-loop ([r 0])
           (unless (= r rows)
             (let col-loop ([c 0])
               (if (= c cols)
                   (row-loop (add1 r))
                   (begin
                     (matrix-set! board r c (read-cell))
                     (col-loop (add1 c)))))))))))

;This reads what cell has what value
(define read-cell
   (lambda () (let ([c (read)]) (if (eq? c '-) empty c))))

;This function checks a specific cell to see if it is blank or has a value
(define (blank? r c)
  (equal? empty (matrix-ref board r c)))

;This clears the board to an empty 9x9 matrix
(define (clear-board)
  (set! board (make-matrix rows cols empty)))

;This function checks if the value given can be put in that row by checking
;if that value all ready occurs in that row giving #t if it doesnt occur and
;#f if it does occur
(define (check-row r val)
  (define (cr-helper r c val)
    (cond
      [(>= c cols) #t]
      [(equal? val (matrix-ref board r c)) #f]
      [else (cr-helper r (add1 c) val)]))
   (cr-helper r 0 val))

;This function checks if the value given can be put in that column by checking
;if that value all ready occurs in that column giving #t if it doesnt occur and
;#f if it does occur
(define (check-col c val)
 (define (cc-helper r c val)
   (cond
     [(>= r rows) #t]
     [(equal? val (matrix-ref board r c)) #f]
     [else (cc-helper (add1 r) c val)]))
  (cc-helper 0 c val))
4

1 に答える 1

2

check-block 関数には、ネストされた 2 つのループが必要です。1 つのループは行単位で進み、もう 1 つのループは列単位で、北西の角から始まります。2 つのループはそれぞれ、北西の角から 0、1、または 2 のオフセットにあるセルをチェックし、対象の数値と同じ場合は #f を返します。

行列ではなくリストに基づいて、多少異なる数独ソルバーを作成しました。以下のコードを繰り返します。私のブログで説明を見ることができます。

(define (sudoku puzzle)
  (define (safe? filled digit cell)
    (cond ((null? filled) #t)
          ((and (= (vector-ref (car filled) 0) (vector-ref cell 0))
                (char=? (vector-ref (car filled) 3) digit)) #f)
          ((and (= (vector-ref (car filled) 1) (vector-ref cell 1))
                (char=? (vector-ref (car filled) 3) digit)) #f)
          ((and (= (vector-ref (car filled) 2) (vector-ref cell 2))
                (char=? (vector-ref (car filled) 3) digit)) #f)
          (else (safe? (cdr filled) digit cell))))
  (define (next digit) (integer->char (+ (char->integer digit) 1)))
  (define (new old digit) (vector (vector-ref old 0) (vector-ref old 1) (vector-ref old 2) digit))
  (let scan ((s 0) (empty '()) (filled '()))
    (if (< s 81)
        (let* ((row (quotient s 9))
               (col (modulo s 9))
               (box (+ (* (quotient row 3) 3) (quotient col 3)))
               (digit (string-ref puzzle s))
               (cell (vector row col box digit)))
          (if (char=? digit #\0)
              (scan (+ s 1) (cons cell empty) filled)
              (scan (+ s 1) empty (cons cell filled))))
        (let solve ((empty empty) (filled filled))
          (if (pair? empty)
              (let try ((cell (car empty)) (digit (next (vector-ref (car empty) 3))))
                (cond ((char<? #\9 digit) ; backtrack
                        (solve (cons (car filled) (cons (new cell #\0) (cdr empty))) (cdr filled)))
                      ((safe? filled digit cell) ; advance
                        (solve (cdr empty) (cons (new cell digit) filled)))
                      (else (try cell (next digit))))) ; try next digit
              (let ((str (make-string 81 #\0)))
                (do ((filled filled (cdr filled))) ((null? filled) str)
                  (let* ((cell (car filled)) (s (+ (* (vector-ref cell 0) 9) (vector-ref cell 1))))
                    (string-set! str s (vector-ref cell 3))))))))))

数独パズルは行優先の 81 文字の文字列として表され、空のセルは 0 として表されます。サンプル ソリューションは次のとおりです。

> (sudoku "700100000020000015000006390200018000040090070000750003078500000560000040000001002")
"789135624623947815451286397237418569845693271916752483178524936562379148394861752"

プログラムは次の場所で実行できます。http://programmingpraxis.codepad.org/PB1czuyF . 私のStandard Preludeのマトリックス ライブラリもお楽しみいただけます。

于 2013-11-07T00:53:46.020 に答える