Advertisement
bsddeamon

Samdoku.scm

Jun 11th, 2015
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scheme 5.99 KB | None | 0 0
  1. #| Samdoku (sudoku v27)
  2. Final version with comments
  3.  
  4. This program is published under the
  5. 3-clause BSD license.
  6. Copyright © 2015, Samuel Duclos
  7. All rights reserved.
  8. |#
  9.  
  10. ;; Minimal import declarations
  11. (import (scheme base)
  12.   (only (scheme char) digit-value)
  13.   (only (scheme process-context)
  14.     command-line exit)
  15.   (only (scheme write) display))
  16.  
  17. #| Parse command line input and
  18.     translate to row/col/val mappings
  19.     (matrix rows representing every
  20.     possibility) or return false (#f) if input
  21.     is invalid.
  22. |#
  23. (define input
  24.   (let f ([i 0] [j 0]
  25.            [ls (cdr (command-line))] [y (list)])
  26.     (cond [(> j 8) (f (+ i 1) 0 ls y)]
  27.       [(> i 8) (reverse y)]
  28.       [else
  29.        (and (pair? ls)
  30.          (let ([k (digit-value
  31.                       (string-ref (car ls) 0))])
  32.            (and k
  33.              (if (> k 0)
  34.                  (f i (+ j 1) (cdr ls)
  35.                    (cons (list i j (- k 1)) y))
  36.                  (let g ([k k] [y y])
  37.                    (if (> k 8) (f i (+ j 1) (cdr ls) y)
  38.                        (g (+ k 1)
  39.                          (cons (list i j k) y))))))))])))
  40.  
  41. ;; Test input validity before anything else
  42. (unless input
  43.   (display "Invalid input!\n") (exit))
  44.  
  45. ;; Matrix constructors
  46. (define-record-type <node>
  47.   (node h l u i j k r d s) #f
  48.   (h header set-header!) (l left set-left!)
  49.   (u up set-up!) (i ival) (j jval) (k kval)
  50.   (r right set-right!) (d down set-down!)
  51.   (s size set-size!))
  52.  
  53. (define (update-size! f x)
  54.   (let ([h (header x)])
  55.     (set-size! h (f (size h) 1))))
  56.  
  57. (define (horizontal-restore! x)
  58.   (set-right! (left x) x) (set-left! (right x) x))
  59.  
  60. (define (vertical-restore! x)
  61.   (update-size! + x)
  62.   (set-down! (up x) x)
  63.   (set-up! (down x) x))
  64.  
  65. (define (horizontal-delete! x)
  66.   (set-right! (left x) (right x))
  67.   (set-left! (right x) (left x)))
  68.  
  69. (define (vertical-delete! x)
  70.   (set-down! (up x) (down x))
  71.   (set-up! (down x) (up x))
  72.   (update-size! - x))
  73.  
  74. ;; Make (horizontal) headers.
  75. (define grid
  76.   (let ([g (node #f #f #f #f #f #f #f #f #f)])
  77.     (set-left! g g) (set-right! g g)
  78.     (do ([i 0 (+ i 1)]) ((> i 3))
  79.       (do ([j 0 (+ j 1)]) ((> j 8))
  80.         (do ([k 0 (+ k 1)]) ((> k 8))
  81.           (let ([h (node #f (left g) #f i j k
  82.                        g #f 0)]) (set-header! h h)
  83.             (set-up! h h) (set-down! h h)
  84.             (horizontal-restore! h))))) g))
  85.  
  86. #| Map constraints (matrix columns)
  87.     over possibilities (matrix rows).
  88. |#
  89. (define (make-row! r c v) (define i 0)
  90.   (define z (make-vector 4 #f))
  91.   (define constraints
  92.     (vector
  93.       (lambda (j k) (and (= j r) (= k c)))
  94.       (lambda (j k) (and (= j r) (= k v)))
  95.       (lambda (j k) (and (= j c) (= k v)))
  96.       (lambda (j k)
  97.         (and (= k v)
  98.           (= j (+ (* (floor-quotient r 3) 3)
  99.                   (floor-quotient c 3)))))))
  100.   (do ([h (right grid) (right h)])
  101.         ((vector-ref z 3) (vector->list z))
  102.     (and (= (ival h) i)
  103.       ((vector-ref constraints i)
  104.         (jval h) (kval h))
  105.       (vector-set! z i
  106.         (let ([x (node h #f (up h)
  107.                      r c v #f h #f)])
  108.           (vertical-restore! x) x))
  109.       (set! i (+ i 1)))))
  110.  
  111. ;; Insert rows up headers
  112. (for-each
  113.   (lambda (rcv)
  114.     (apply
  115.       (lambda (r c v)
  116.         (apply
  117.           (lambda (r-c r-v c-v b-v)
  118.             (set-left! r-c b-v)
  119.             (set-right! r-c r-v)
  120.             (set-left! r-v r-c)
  121.             (set-right! r-v c-v)
  122.             (set-left! c-v r-v)
  123.             (set-right! c-v b-v)
  124.             (set-left! b-v c-v)
  125.             (set-right! b-v r-c))
  126.           (make-row! r c v))) rcv)) input)
  127.  
  128. #| Matrix modifiers for backtracking
  129.     algorithm (they try).
  130. |#
  131. (define (vertical-cover! h)
  132.   (do ([r (down h) (down r)]) ((eq? r h))
  133.     (do ([c (right r) (right c)]) ((eq? c r))
  134.       (vertical-delete! c)))
  135.   (horizontal-delete! h))
  136.  
  137. (define (vertical-uncover! h)
  138.   (do ([r (up h) (up r)]) ((eq? r h))
  139.     (do ([c (right r) (right c)]) ((eq? c r))
  140.       (vertical-restore! c)))
  141.   (horizontal-restore! h))
  142.  
  143. (define (horizontal-cover! x)
  144.   (do ([c (right x) (right c)]) ((eq? c x))
  145.     (vertical-cover! (header c))))
  146.  
  147. (define (horizontal-uncover! x)
  148.   (do ([c (left x) (left c)]) ((eq? c x))
  149.     (vertical-uncover! (header c))))
  150.  
  151. (define (optimal-branch h)
  152.   (do ([c (right h) (right c)]
  153.          [m (right h)
  154.           (if (< (size c) (size m)) c m)])
  155.         ((or (= (size m) 1) (eq? c h)) m)))
  156.  
  157. ;; State of the matrix.
  158. (define solution (make-vector 9 #f))
  159. (do ([i 0 (+ i 1)]) ((> i 8))
  160.   (vector-set! solution i
  161.     (make-vector 9 #f)))
  162. (define max-depth 0) (define attempt '())
  163. (define nsolutions 0)
  164.  
  165. ;; Core search algorithm.
  166. (let search! ([k 0])
  167.   (cond
  168.     [(eq? (right grid) grid)
  169.      (set! nsolutions (+ nsolutions 1))
  170.      (unless (> nsolutions 1)
  171.        (for-each
  172.          (lambda (row)
  173.            (vector-set!
  174.              (vector-ref solution (ival row))
  175.              (jval row)
  176.              (string-append
  177.                (number->string
  178.                  (+ (kval row) 1)) " ")))
  179.          attempt))]
  180.     [else
  181.      (let ([c (optimal-branch grid)])
  182.        (vertical-cover! (header c))
  183.        (do ([r (down c) (down r)]) ((eq? r c))
  184.          (set! attempt (cons r attempt))
  185.          (horizontal-cover! r)
  186.          (let ([l (+ k 1)])
  187.            (when (> l max-depth)
  188.              (set! max-depth l)) (search! l))
  189.          (let ([x (car attempt)])
  190.            (set! attempt (cdr attempt))
  191.            (set! r x)) (set! c (header r))
  192.          (horizontal-uncover! r))
  193.        (vertical-uncover! (header c)))]))
  194.  
  195. ;; Display grid.
  196. (for-each
  197.   (lambda (x)
  198.     (for-each display (vector->list x))
  199.     (newline)) (vector->list solution))
  200.  
  201. ;; Display facts about the solved sudoku
  202. (display "Level: ")
  203. (display (number->string max-depth))
  204. (newline)
  205. (cond [(= nsolutions 0)
  206.            (display "Unsolvable sudoku!\n")]
  207.   [(= nsolutions 1)
  208.    (display "Proper sudoku\n")]
  209.   [else
  210.    (display
  211.      "This sudoku has many solutions: ")
  212.    (display (number->string nsolutions))
  213.    (newline)])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement