Advertisement
Guest User

Untitled

a guest
Dec 4th, 2016
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
F# 3.63 KB | None | 0 0
  1. let flatten (array2d: 'a[,]) = array2d |> Array2D.mapi (fun i j value -> (i, j, value)) |> Seq.cast<int*int*'a> |> Seq.toList
  2. let toLists array2d = List.init (Array2D.length1 array2d) (fun row -> List.init (Array2D.length2 array2d) (fun col -> array2d.[row, col]))
  3.  
  4. type Cell = {Number : int; PossibleNumbers : int list}
  5. let newCell = {Number = 0; PossibleNumbers = [1..9]}        
  6. let setNumber number cell = {cell with Number = number; PossibleNumbers = List<int>.Empty}            
  7. let removePossible number cell = {cell with PossibleNumbers = cell.PossibleNumbers |> List.filter (fun x -> x <> number)}                    
  8.  
  9. type Board = {Cells : Cell[,]}
  10. let newBoard = { Cells = Array2D.init<Cell> 9 9 (fun _ _ -> newCell) }            
  11.  
  12. let getAdjacentCells i j =
  13.     let rowIter = List.init 9 (fun index -> (i, index)) |> List.filter (fun tuple -> snd tuple <> j)
  14.     let colIter = List.init 9 (fun index -> (index, j)) |> List.filter (fun tuple -> fst tuple <> i)
  15.     let topLeft = (i-i%3, j-j%3)
  16.     let sqrIter = List.init 9 (fun index -> (fst topLeft + index/3, snd topLeft + index%3))|> List.filter (fun tuple -> fst tuple <> i || snd tuple <> j)
  17.     Seq.distinct(rowIter @ colIter @ sqrIter) |> Seq.toList    
  18.  
  19. let setCell i j value board =
  20.     let adjCells = getAdjacentCells i j
  21.     let newArray = board.Cells |> Array2D.mapi (fun row col cell ->
  22.         match (row, col, value) with        
  23.         | a, b, v when v <> 0 && a = i && b = j -> cell |> setNumber v
  24.         | a, b, v when v <> 0 && adjCells |> List.contains (a, b) -> cell |> removePossible v
  25.         | _, _, _ -> cell)
  26.     {board with Cells = newArray}
  27.    
  28. let rec setBoard values board =
  29.     match values with        
  30.         | [] -> board
  31.         | (i, j, value)::tail -> setBoard tail (setCell i j value board)  
  32.  
  33. let printBoard board = board.Cells |> toLists |> List.iter (fun row -> row |> List.iter (fun cell -> printf "%i " cell.Number); printfn "")    
  34.  
  35. let solveSudoku board =
  36.     let getUnknownCells board = Array2D.zeroCreate 9 9 |> flatten |> List.filter (fun (i, j, _) -> board.Cells.[i, j].Number = 0)        
  37.     let rec fillSudoku boardList board =        
  38.         let cellsWithPossible = board |> getUnknownCells |> List.map (fun (i, j, _) -> (i, j, board.Cells.[i, j].PossibleNumbers))
  39.         match cellsWithPossible with
  40.         | [(i, j, list)] -> boardList @ (list |> List.map (fun opt -> setCell i j opt board))
  41.         | (i, j, list)::_ -> boardList @ (list |> List.map (fun opt -> fillSudoku boardList (setCell i j opt board)) |> List.concat)
  42.         | [] -> boardList                
  43.     let possibleSolutions = (fillSudoku [] board) |> List.tryFind (fun board -> board |> getUnknownCells |> List.length = 0)
  44.     match possibleSolutions with
  45.     | None -> printfn "No solution"
  46.     | Some(b) -> (printfn "Solved"; printBoard b)
  47.      
  48. [<EntryPoint>]
  49. let main _ =
  50.     let start = array2D [
  51.                     [|0; 0; 7; 8; 6; 1; 0; 5; 0|];
  52.                     [|0; 1; 8; 4; 5; 3; 0; 0; 0|];
  53.                     [|5; 6; 0; 7; 9; 2; 8; 1; 0|];
  54.                     [|1; 0; 0; 0; 7; 6; 3; 8; 5|];
  55.                     [|0; 0; 0; 3; 4; 5; 0; 0; 1|];
  56.                     [|6; 3; 5; 0; 1; 8; 0; 0; 7|];
  57.                     [|0; 5; 0; 1; 2; 4; 0; 9; 8|];
  58.                     [|0; 0; 1; 6; 8; 9; 5; 0; 0|];
  59.                     [|0; 0; 0; 5; 3; 7; 1; 0; 0|]
  60.                 ]        
  61.     let board = newBoard |> setBoard (flatten start)
  62.     printBoard board    
  63.     let stopWatch = System.Diagnostics.Stopwatch.StartNew()
  64.     solveSudoku board
  65.     stopWatch.Stop()
  66.     printfn "Elapsed time: %f ms" stopWatch.Elapsed.TotalMilliseconds    
  67.     0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement