Scheme 计划中的数独解算器?
我们在课堂上为scheme制作了一个矩阵库(这里的文档: 所以,作为一个小项目,我决定用矩阵做一个数独解算器(这不是为了学分,这是在测试前用矩阵做的练习) 到目前为止,我已经完成了大部分的程序,我只是停留在几个最后的函数上 我想写一个名为check block的函数,它将取一个西北角的行、一个西北角的列和一个值,然后检查该值是否可以放入该块中。因此基本上,数独3X3框的左上角需要检查数字是否已经出现。我有一个检查行,并检查col函数b下面,它检查每一行和每一列,看一个数字是否可以到达那里,但每次它都从第一列或第一个正方形开始,不知道如何使它从给定的西北角开始 它将从以下内容开始:Scheme 计划中的数独解算器?,scheme,Scheme,我们在课堂上为scheme制作了一个矩阵库(这里的文档: 所以,作为一个小项目,我决定用矩阵做一个数独解算器(这不是为了学分,这是在测试前用矩阵做的练习) 到目前为止,我已经完成了大部分的程序,我只是停留在几个最后的函数上 我想写一个名为check block的函数,它将取一个西北角的行、一个西北角的列和一个值,然后检查该值是否可以放入该块中。因此基本上,数独3X3框的左上角需要检查数字是否已经出现。我有一个检查行,并检查col函数b下面,它检查每一行和每一列,看一个数字是否可以到达那里,但每
(define (check-block nwr nwc val))
我假设我必须使用某种循环来检查块的每个部分
在此之后,我想写一个名为valid?的东西,它接受一个行索引r、一个列索引c和一个值val,并检查是否可以将该值放在给定的位置
这两个我真的被卡住了,最后我知道如何把它看作是一个算法的立足点,我还需要四个函数来求解,try row,try cell,try value
其思想是,solve只调用try row 0,该行从第0行开始填充谜题。try row过程假定前面的所有行都已正确填充,如果谜题未完成,则尝试通过调用(try cell r 0)来取得进展。try cell过程假定前面的所有行和左边的列都已正确填充。如果当前行已填充,则转到下一行。如果当前单元格不为空,则跳过它。否则,如果当前单元格为空,则调用(try值r c 1)它尝试用1填充当前单元格。过程try值获取单元格的坐标和要放置在给定位置的值v。如果该值超过9,则失败的过程返回。如果可以放置给定值,则该过程尝试下一个值。如果可以放置给定值,则board被修改,计算通过尝试填充下一个单元格进行。如果填充下一个单元格的尝试失败,则删除添加的值,并尝试下一个值
以下是我目前掌握的代码:
;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))
检查块函数将需要两个嵌套循环,一个按行前进的循环和一个按列前进的循环,从西北角开始。这两个循环中的每一个都在西北角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))))))))))
> (sudoku "700100000020000015000006390200018000040090070000750003078500000560000040000001002")
"789135624623947815451286397237418569845693271916752483178524936562379148394861752"