096 Su Doku -- v2.jl 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #!/usr/bin/julia
  2. # Author: Trizen
  3. # Date: 12 February 2024
  4. # https://github.com/trizen
  5. # https://projecteuler.net/problem=96
  6. # Runtime: 1.023s
  7. function is_valid(board, row, col, num)
  8. # Check if the number is not present in the current row and column
  9. for i in 1:9
  10. if (board[row][i] == num) || (board[i][col] == num)
  11. return false
  12. end
  13. end
  14. # Check if the number is not present in the current 3x3 subgrid
  15. start_row, start_col = 3*div(row-1, 3), 3*div(col-1, 3)
  16. for i in 1:3, j in 1:3
  17. if board[start_row + i][start_col + j] == num
  18. return false
  19. end
  20. end
  21. return true
  22. end
  23. function find_empty_locations(board)
  24. positions = []
  25. # Find all empty positions (cells with 0)
  26. for i in 1:9, j in 1:9
  27. if board[i][j] == 0
  28. push!(positions, [i, j])
  29. end
  30. end
  31. return positions
  32. end
  33. function find_empty_location(board)
  34. # Find an empty positions (cell with 0)
  35. for i in 1:9, j in 1:9
  36. if board[i][j] == 0
  37. return [i,j]
  38. end
  39. end
  40. return (nothing, nothing)
  41. end
  42. function solve_sudoku_fallback(board)
  43. row, col = find_empty_location(board)
  44. if (row == nothing && col == nothing)
  45. return true # Puzzle is solved
  46. end
  47. for num in 1:9
  48. if is_valid(board, row, col, num)
  49. # Try placing the number
  50. board[row][col] = num
  51. # Recursively try to solve the rest of the puzzle
  52. if solve_sudoku_fallback(board)
  53. return true
  54. end
  55. # If placing the current number doesn't lead to a solution, backtrack
  56. board[row][col] = 0
  57. end
  58. end
  59. return false # No solution found
  60. end
  61. function solve_sudoku(board)
  62. while true
  63. # Return early when the first 3 values are solved
  64. if board[1][1] != 0 && board[1][2] != 0 && board[1][3] != 0
  65. return board
  66. end
  67. empty_locations = find_empty_locations(board)
  68. if length(empty_locations) == 0
  69. break # it's solved
  70. end
  71. found = false
  72. # Solve easy cases
  73. for (i,j) in empty_locations
  74. count = 0
  75. value = 0
  76. for n in 1:9
  77. if is_valid(board, i, j, n)
  78. count += 1
  79. value = n
  80. count > 1 && break
  81. end
  82. end
  83. if count == 1
  84. board[i][j] = value
  85. found = true
  86. end
  87. end
  88. found && continue
  89. # Solve more complex cases
  90. stats = Dict{String,Array}()
  91. for (i,j) in empty_locations
  92. arr = []
  93. for n in 1:9
  94. if is_valid(board, i, j, n)
  95. append!(arr, n)
  96. end
  97. end
  98. stats["$i $j"] = arr
  99. end
  100. cols = Dict{String,Int}()
  101. rows = Dict{String,Int}()
  102. subgrid = Dict{String,Int}()
  103. for (i,j) in empty_locations
  104. for v in stats["$i $j"]
  105. k1 = "$j $v"
  106. k2 = "$i $v"
  107. k3 = join([3*div(i-1,3), 3*div(j-1,3), v], " ")
  108. if !haskey(cols, k1)
  109. cols[k1] = 1
  110. else
  111. cols[k1] += 1
  112. end
  113. if !haskey(rows, k2)
  114. rows[k2] = 1
  115. else
  116. rows[k2] += 1
  117. end
  118. if !haskey(subgrid, k3)
  119. subgrid[k3] = 1
  120. else
  121. subgrid[k3] += 1
  122. end
  123. end
  124. end
  125. for (i,j) in empty_locations
  126. for v in stats["$i $j"]
  127. if (cols["$j $v"] == 1 ||
  128. rows["$i $v"] == 1 ||
  129. subgrid[join([3*div(i-1,3), 3*div(j-1,3), v], " ")] == 1)
  130. board[i][j] = v
  131. found = true
  132. end
  133. end
  134. end
  135. found && continue
  136. # Give up and try brute-force
  137. solve_sudoku_fallback(board)
  138. return board
  139. end
  140. return board
  141. end
  142. function euler_096()
  143. fh = open("p096_sudoku.txt")
  144. lines = filter((x)->occursin(r"^[0-9]+$",x), readlines(fh))
  145. total = 0
  146. while length(lines) > 0
  147. rows = splice!(lines, 1:9)
  148. grid = map((row) -> map((c)->parse(Int64, c), split(row, "")), rows)
  149. solution = solve_sudoku(grid)
  150. total += solution[1][1]*100 + solution[1][2]*10 + solution[1][3]
  151. end
  152. println(total)
  153. end
  154. euler_096()