sudoku_generator.sf 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #!/usr/bin/ruby
  2. # Recursive brute-force Sudoku solver.
  3. # See also:
  4. # https://rosettacode.org/wiki/Sudoku
  5. # https://en.wikipedia.org/wiki/Sudoku
  6. func check(i, j) is cached {
  7. var (id, im) = i.divmod(9)
  8. var (jd, jm) = j.divmod(9)
  9. jd == id && return true
  10. jm == im && return true
  11. (id//3 == jd//3) &&
  12. (jm//3 == im//3)
  13. }
  14. var lookup = []
  15. for i in (^81), j in (^81) {
  16. lookup[i][j] = check(i, j)
  17. }
  18. func solve_sudoku(callback, grid) {
  19. var digits = @(1..9)
  20. func {
  21. grid.each_kv {|i,v|
  22. v && next
  23. var t = Set(grid.grep_kv {|j| lookup[i][j] }...)
  24. digits.shuffle.each {|d|
  25. t.has(d) && next
  26. grid[i] = d
  27. __FUNC__()
  28. grid[i] = 0
  29. }
  30. return nil
  31. }
  32. callback(grid)
  33. }()
  34. }
  35. func generate_sudoku (known, solution_count = 1) {
  36. var grid = 81.of(0)
  37. solve_sudoku(
  38. {|solution|
  39. var picked = Set(solution.indices.pick(known)...)
  40. var candidate = solution.map_kv {|k,v| picked.has(k) ? v : 0 }
  41. var res = func {
  42. var count = 0
  43. solve_sudoku({ return -1 if (++count > solution_count) }, candidate)
  44. count
  45. }()
  46. if (res == solution_count) {
  47. return candidate
  48. }
  49. }, grid
  50. )
  51. return nil
  52. }
  53. func display_grid(grid) {
  54. for i in ^grid {
  55. print "#{grid[i]} "
  56. print " " if ( 3 -> divides(i+1))
  57. print "\n" if ( 9 -> divides(i+1))
  58. print "\n" if (27 -> divides(i+1))
  59. }
  60. }
  61. var known = 35 # number of known entries
  62. var solution_count = 1 # number of solutions the puzzle must have
  63. var sudoku = generate_sudoku(known, solution_count)
  64. say "\n:: Random Sudoku with #{known} known entries and #{solution_count} solutions:\n"
  65. display_grid(sudoku)
  66. say "\n:: Solution(s):\n";
  67. solve_sudoku({|solution| display_grid(solution) }, sudoku)
  68. __END__
  69. :: Random Sudoku with 35 known entries and 1 solutions:
  70. 0 0 9 0 0 0 0 0 0
  71. 4 0 7 0 0 0 2 0 0
  72. 3 0 0 1 8 0 6 9 0
  73. 0 5 3 0 9 0 1 0 2
  74. 2 0 4 6 0 3 0 0 9
  75. 0 0 0 5 0 7 0 0 0
  76. 0 3 6 7 0 5 8 2 0
  77. 5 0 0 0 3 0 9 0 0
  78. 0 0 8 2 6 0 5 7 0
  79. :: Solution(s):
  80. 8 6 9 3 7 2 4 1 5
  81. 4 1 7 9 5 6 2 3 8
  82. 3 2 5 1 8 4 6 9 7
  83. 7 5 3 4 9 8 1 6 2
  84. 2 8 4 6 1 3 7 5 9
  85. 6 9 1 5 2 7 3 8 4
  86. 9 3 6 7 4 5 8 2 1
  87. 5 7 2 8 3 1 9 4 6
  88. 1 4 8 2 6 9 5 7 3