solver.scm 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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-9x9-board)))
  22. (set-board-array! n-board (board-array board))
  23. (set-square! n-board
  24. (set-square-value min-square
  25. (car candidates))
  26. i j)
  27. (update-board-candidates n-board))
  28. return)
  29. (find-solution-from-candidates (cdr candidates)))))
  30. (cond
  31. ((null? min-square) (return board))
  32. ((zero? (length (square-candidates min-square))) board)
  33. (else (find-solution-from-candidates (square-candidates min-square))))))
  34. (define (find-min-square board)
  35. (let ((min-square-l
  36. (array-fold
  37. (lambda (item acc)
  38. (if (and (= 0 (square-value (car item)))
  39. (< (length (square-candidates (car item)))
  40. (length (square-candidates (car acc)))))
  41. item
  42. acc))
  43. (list (make-square 9) -1 -1)
  44. (board-array board))))
  45. (if (array-in-bounds? (board-array board)
  46. (cadr min-square-l) (last min-square-l))
  47. (values (car min-square-l) (cadr min-square-l) (last min-square-l))
  48. (values '() -1 -1))))
  49. (define (update-board-candidates board)
  50. (for-each (lambda (i)
  51. (update-row (update-col (update-box board i) i) i))
  52. (iota 9))
  53. board)
  54. (define-public (update-row board i)
  55. (update-group set-row! get-row board i)
  56. board)
  57. (define-public (update-col board j)
  58. (update-group set-col! get-col board j)
  59. board)
  60. (define-public (update-box board k)
  61. (update-group set-box! get-box board k)
  62. board)
  63. (define (update-group set-proc get-proc board i)
  64. (set-proc board
  65. (update-list
  66. (get-proc board i))
  67. i))
  68. (define (update-list l)
  69. (let ((vals (get-vals l)))
  70. (map (lambda (square)
  71. (update-candidates square vals))
  72. l)))
  73. (define (get-vals squares)
  74. (fold (lambda (square vals)
  75. (if (> (square-value square) 0)
  76. (cons (square-value square) vals)
  77. vals))
  78. '()
  79. squares))
  80. (define (update-candidates square vals)
  81. (set-square-candidates square
  82. (lset-difference eq?
  83. (square-candidates square)
  84. vals)))