solver.scm 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. (define-module (sudoku solver))
  2. (use-modules (srfi srfi-1)
  3. (ice-9 receive)
  4. (ice-9 control)
  5. (sudoku utils)
  6. (sudoku square)
  7. (sudoku board))
  8. (define-public (solver board)
  9. (call/ec
  10. (lambda (return)
  11. (solver-loop board return))))
  12. ;; TODO; break up
  13. (define (solver-loop board return)
  14. (receive (min-square i j)
  15. (find-min-square board)
  16. (define (find-solution-from-candidates candidates)
  17. (if (null? candidates)
  18. #f
  19. (begin
  20. (solver-loop
  21. (let ((n-board (make-array 0 9 9)))
  22. (array-copy! board n-board)
  23. (update-board-candidates
  24. (set-square n-board (set-value min-square (car candidates)) i j)))
  25. return)
  26. (find-solution-from-candidates (cdr candidates)))))
  27. (cond
  28. ((null? min-square) (return board))
  29. ((zero? (length (get-candidates min-square))) board)
  30. (else (find-solution-from-candidates (get-candidates min-square))))))
  31. (define (find-min-square board)
  32. (let ((min-square-l
  33. (array-fold
  34. (lambda (item acc)
  35. (if (and (= 0 (get-value (car item)))
  36. (< (length (get-candidates (car item)))
  37. (length (get-candidates (car acc)))))
  38. item
  39. acc))
  40. (list (make-square) -1 -1)
  41. board)))
  42. (if (array-in-bounds? board (cadr min-square-l) (last min-square-l))
  43. (values (car min-square-l) (cadr min-square-l) (last min-square-l))
  44. (values '() -1 -1))))
  45. (define (update-board-candidates board)
  46. (fold (lambda (i n-board)
  47. (update-row (update-col (update-box n-board i) i) i))
  48. board
  49. (iota 9)))
  50. (define-public (update-row board i)
  51. (update-group set-row get-row board i))
  52. (define-public (update-col board j)
  53. (update-group set-col get-col board j))
  54. (define-public (update-box board k)
  55. (update-group set-box get-box board k))
  56. (define (update-group set-proc get-proc board i)
  57. (set-proc board
  58. (update-list
  59. (get-proc board i))
  60. i))
  61. (define (update-list l)
  62. (let ((vals (get-vals l)))
  63. (map (lambda (square)
  64. (update-candidates square vals))
  65. l)))
  66. (define (get-vals squares)
  67. (fold (lambda (square vals)
  68. (if (> (get-value square) 0)
  69. (cons (get-value square) vals)
  70. vals))
  71. '()
  72. squares))
  73. (define (update-candidates square vals)
  74. (set-candidates square
  75. (lset-difference eq?
  76. (get-candidates square)
  77. vals)))