1 module SudokuSolver.GUI
5 open System.Collections.ObjectModel
11 module Solver = Version1
13 type DigitBox() as this =
15 let unselectedBgColor = Colors.LightSkyBlue
16 let selectedBgColor = Colors.Blue
17 let digitChanged = new Event<unit>()
18 let mutable manuallyAssigned = false
22 BackgroundColor = Colors.White,
24 TextAlignment = TextAlignment.Center,
25 VerticalAlignment = VerticalAlignment.Center,
26 Font = new Font("Monospace", 18.f
))
29 this.Padding <- Padding(2)
30 this.BackgroundColor <- unselectedBgColor
34 with set
(value: bool) =
35 this.BackgroundColor <- if value then selectedBgColor else unselectedBgColor
37 member this.ManuallyAssigned
38 with get
() : bool = manuallyAssigned
39 and private
set (value: bool) =
40 label.BackgroundColor <- if value then Colors.Orange else Colors.White
41 manuallyAssigned <- value
43 member this.DigitChanged = digitChanged.Publish
45 member this.Value = value
47 member this.SetValue(v
, manuallyAssigned) =
48 if manuallyAssigned || not this.ManuallyAssigned || v = 0 then
49 let changed = value <> v
51 label.Text <- if value > 0 && value <= 9 then string value else " "
52 this.ManuallyAssigned <- v <> 0 && manuallyAssigned
53 if manuallyAssigned && changed then
54 digitChanged.Trigger()
59 type MainForm() as this =
62 let mutable currentAsync : Async<Solver.Board> option = None
63 let mutable cancellation = new CancellationTokenSource()
65 this.Title <- "Sudoku Solver - gburri"
66 this.Size <- Size(400, 400)
67 let digitBoxes = Array2D.init
9 9 (fun _ _
-> new DigitBox())
69 let clearComputedDigits () =
70 digitBoxes |> Array2D.iter
72 if not d.ManuallyAssigned then
75 let computeSolution () =
77 cancellation.Dispose()
78 cancellation <- new CancellationTokenSource()
82 |> Array2D.map
(fun d -> if d.ManuallyAssigned then d.Value else 0))
84 clearComputedDigits ()
86 let token = cancellation.Token
88 let! result
= board.SolveAsync(token)
89 if not token.IsCancellationRequested then
90 Application.Instance.Invoke(
93 Array2D.iteri
(fun i j
v -> digitBoxes.[i
, j
].SetValue(v, false)) board.Values
95 clearComputedDigits ()) }
98 let mutable currentDigitBox = digitBoxes.[0,0]
99 digitBoxes.[0,0].Selected <- true
102 if e
.Key = Keys.Backspace || e.Key = Keys.Delete then
103 currentDigitBox.SetValue(0, true)
105 match Int32.TryParse(e.KeyChar.ToString()) with
106 | (true, digit
) when digit
>= 0 && digit
<= 9 -> currentDigitBox.SetValue(digit
, true)
109 let setCurrentDigitBox db
=
110 if db
<> currentDigitBox then
111 currentDigitBox.Selected <- false
113 currentDigitBox <- db
118 digitBox
.MouseDown.Add(fun _ -> setCurrentDigitBox digitBox
)
119 digitBox
.DigitChanged.Add (fun _ -> computeSolution ()))
121 let gridLayout = new Grid()
124 // Horizontal separations.
125 if i
= 3 || i = 6 then
126 let rowSeparation = new TableRow()
127 gridLayout.Rows.Add(rowSeparation)
129 rowSeparation.Cells.Add(new TableCell(new Panel(BackgroundColor = Colors.Black)))
130 let row = new TableRow(ScaleHeight = true)
131 gridLayout.Rows.Add(row)
133 // Vertical separations.
134 if j
= 3 || j = 6 then
135 row.Cells.Add(new TableCell(new Panel(BackgroundColor = Colors.Black)))
136 row.Cells.Add(new TableCell(digitBoxes.[i, j], true))
138 this.Content <- gridLayout
141 let showMainWindow () =
142 use app = new Application()
143 use form = new MainForm()
145 app.Run(form) |> ignore