Guest User

Untitled

a guest
Jul 17th, 2018
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.80 KB | None | 0 0
  1. open Microsoft.SolverFoundation.Services
  2. open Microsoft.SolverFoundation.Common
  3. open System.Collections.Generic
  4. open Microsoft.SolverFoundation.SfsWrapper
  5.  
  6. // helper functions for grouping elements of the solution
  7. let flatten (matrix:'a[,]) = matrix |> Seq.cast<'a> |> Seq.toArray
  8.  
  9. let getColumn c (matrix:_[,]) =
  10. flatten matrix.[*,c..c]
  11.  
  12. let getRow r (matrix:_[,]) =
  13. flatten matrix.[r..r,*]
  14.  
  15. let getSquare s (vars: 'a[,]) =
  16. let x = s % 3
  17. let y = s / 3
  18. let startx, endx = x * 3, (x + 1) * 3 - 1
  19. let starty, endy = y * 3, (y + 1) * 3 - 1
  20. flatten vars.[startx .. endx, starty .. endy]
  21.  
  22.  
  23. // prints out a solution
  24. let printSolution (sol: int[,]) =
  25. for y in 0 .. 8 do
  26. if y % 3 = 0 then
  27. for _ in 1 .. 35 do printf "-"
  28. printfn ""
  29. getRow y sol |>
  30. Seq.iteri(fun x value ->
  31. if x % 3 = 0 then
  32. printf " | "
  33. printf " %i " value)
  34. printfn ""
  35.  
  36. let solveSudoku (input: seq<int>) =
  37. // sanity check on inputs
  38. let check setType i set =
  39. let set = Array.filter ((<>) 0) set
  40. let set' = Set.ofSeq set
  41. if set.Length <> set'.Count then
  42. failwith (sprintf "Error in %s[%i] contains non-unique number" setType i)
  43.  
  44. let input' = Array.ofSeq input
  45. let squareInput = Array2D.init 9 9 (fun x y -> input'.[ x + (9 * y)])
  46. for i in 0 .. 8 do
  47. getRow i squareInput |> check "row" i
  48. getColumn i squareInput |> check "col" i
  49. getSquare i squareInput |> check "square" i
  50.  
  51.  
  52. // get context and create the model
  53. let context = SolverContext.GetContext()
  54. let model = new SfsModel(context)
  55.  
  56. // create the variables that will represent each place in the puzzel
  57. let vars = Array2D.init 9 9 (fun _ _ -> model.CreateIntRangeVariable(1, 9))
  58.  
  59. // helper to add contraint to model that terms are all different
  60. let addVarsAllDiff varArray =
  61. let termArray = varArray |> Seq.cast<SfsIntTerm<1>> |> Array.ofSeq
  62. let contraint = model.AllDifferent termArray
  63. model.AddConstraint contraint |> ignore
  64.  
  65. // go though each column, rom, and square and add all diff contraint
  66. // i.e. these are the basic rules of the game
  67. for i in 0 .. 8 do
  68. addVarsAllDiff (getColumn i vars)
  69. addVarsAllDiff (getRow i vars)
  70. addVarsAllDiff (getSquare i vars)
  71.  
  72. // add the contraints from the inputs to the model
  73. let varsFlat = flatten vars
  74. input |>
  75. Seq.iteri(fun i x ->
  76. if x <> 0 then
  77. model.AddConstraint (varsFlat.[i] ==== x) |> ignore)
  78.  
  79. // tell the model to solve the problem, using a "Constraint Programming" solver
  80. let sol = model.Solve ConstraintProgramming
  81.  
  82. // print the solution quality and if apporiate the solution itself
  83. printfn "Solution: %A" sol.Quality
  84. if sol.Quality = SolverQuality.Feasible then
  85. context.PropagateDecisions()
  86. let res = vars |> Array2D.map (fun x -> x.Value)
  87. printSolution res
  88.  
  89. // generate a blank input
  90. let inputEmpty = [for _ in 1 .. 81 do yield 0]
  91.  
  92. // an explicit blank input, useful for creating new inputs from
  93. let inputBlank =
  94. [ 0; 0; 0; 0; 0; 0; 0; 0; 0;
  95. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  96. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  97.  
  98. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  99. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  100. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  101.  
  102. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  103. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  104. 0; 0; 0; 0; 0; 0; 0; 0; 0; ]
  105.  
  106. // an example puzzle
  107. let input =
  108. [ 0; 9; 4; 2; 8; 0; 0; 0; 0;
  109. 0; 3; 0; 1; 0; 6; 0; 0; 0;
  110. 6; 0; 0; 0; 0; 0; 2; 0; 0;
  111.  
  112. 0; 8; 2; 4; 9; 0; 7; 0; 0;
  113. 4; 0; 0; 0; 0; 7; 0; 9; 0;
  114. 0; 0; 0; 0; 0; 0; 0; 0; 0;
  115.  
  116. 0; 6; 0; 0; 0; 0; 0; 5; 2;
  117. 0; 0; 0; 0; 0; 0; 6; 4; 0;
  118. 7; 0; 0; 9; 0; 0; 0; 0; 1; ]
  119.  
  120. // solve the example puzzel
  121. solveSudoku input
Add Comment
Please, Sign In to add comment