Compare commits
10 Commits
231612cce4
...
1bb8bdc6b0
Author | SHA1 | Date | |
---|---|---|---|
1bb8bdc6b0 | |||
227fa8a257 | |||
06231936fb | |||
f6c80ebcfa | |||
dccf9b3616 | |||
8e279b4800 | |||
ba7db7a04e | |||
3555c49ad4 | |||
775398f456 | |||
98c245fb9e |
16
README.md
16
README.md
@ -0,0 +1,16 @@
|
|||||||
|
# Sudoku in Löve
|
||||||
|
|
||||||
|
## Shortcuts
|
||||||
|
|
||||||
|
- l: go right
|
||||||
|
- k: go up
|
||||||
|
- j: go down
|
||||||
|
- h: go left
|
||||||
|
- tab: toggle editing bit / small numbers
|
||||||
|
- s: show search space
|
||||||
|
- a: insert certain numbers
|
||||||
|
- u: undo
|
||||||
|
- f: save current state to "lastBoard.txt"
|
||||||
|
- c: solve the puzzle
|
||||||
|
- -: zoom out
|
||||||
|
- =: zoom in
|
@ -7,3 +7,13 @@
|
|||||||
7 0 0 0 0 0 0 3 0
|
7 0 0 0 0 0 0 3 0
|
||||||
0 0 1 2 3 0 8 6 0
|
0 0 1 2 3 0 8 6 0
|
||||||
0 0 0 0 0 0 2 0 1
|
0 0 0 0 0 0 2 0 1
|
||||||
|
|
||||||
|
2 3 4 7 6 5 1 9 8
|
||||||
|
1 8 7 9 4 2 6 5 3
|
||||||
|
9 5 6 3 8 1 7 2 4
|
||||||
|
4 7 8 5 2 3 9 1 6
|
||||||
|
6 2 5 1 9 8 3 4 7
|
||||||
|
3 1 9 4 7 6 5 8 2
|
||||||
|
7 6 2 8 1 9 4 3 5
|
||||||
|
5 4 1 2 3 7 8 6 9
|
||||||
|
8 9 3 6 5 4 2 7 1
|
||||||
|
9
boards/041.txt
Normal file
9
boards/041.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
0 0 4 3 0 0 2 0 9
|
||||||
|
0 0 5 0 0 9 0 0 1
|
||||||
|
0 7 0 0 6 0 0 4 3
|
||||||
|
0 0 6 0 0 2 0 8 7
|
||||||
|
1 9 0 0 0 7 4 0 0
|
||||||
|
0 5 0 0 8 3 0 0 0
|
||||||
|
6 0 0 0 0 0 1 0 5
|
||||||
|
0 0 3 5 0 8 6 9 0
|
||||||
|
0 4 2 9 1 0 3 0 0
|
19
boards/042.txt
Normal file
19
boards/042.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
9 2 6 0 0 0 0 0 1
|
||||||
|
0 5 0 0 0 0 0 2 0
|
||||||
|
0 0 0 4 9 0 0 0 7
|
||||||
|
0 6 0 0 4 0 0 1 0
|
||||||
|
2 0 0 0 0 7 0 0 0
|
||||||
|
0 4 5 0 3 0 7 0 0
|
||||||
|
0 0 0 0 0 4 0 0 9
|
||||||
|
0 9 3 0 0 0 5 0 0
|
||||||
|
0 0 0 0 0 0 8 0 6
|
||||||
|
|
||||||
|
9 2 6 3 7 5 4 8 1
|
||||||
|
7 5 4 1 6 8 9 2 3
|
||||||
|
8 3 1 4 9 2 6 5 7
|
||||||
|
3 6 7 8 4 9 2 1 5
|
||||||
|
2 8 9 5 1 7 3 6 4
|
||||||
|
1 4 5 2 3 6 7 9 8
|
||||||
|
5 7 8 6 2 4 1 3 9
|
||||||
|
6 9 3 7 8 1 5 4 2
|
||||||
|
4 1 2 9 5 3 8 7 6
|
19
boards/043.txt
Normal file
19
boards/043.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 0 0 0 7 0 0 0 6
|
||||||
|
0 6 0 4 0 9 0 8 7
|
||||||
|
0 1 0 8 0 0 0 0 9
|
||||||
|
0 0 0 0 0 0 4 0 0
|
||||||
|
0 0 0 1 0 4 6 0 0
|
||||||
|
0 0 4 0 5 0 0 0 0
|
||||||
|
3 8 0 5 0 0 0 0 0
|
||||||
|
0 0 0 0 0 2 0 7 0
|
||||||
|
9 0 6 0 0 0 5 0 2
|
||||||
|
|
||||||
|
4 9 8 2 7 1 3 5 6
|
||||||
|
2 6 5 4 3 9 1 8 7
|
||||||
|
7 1 3 8 6 5 2 4 9
|
||||||
|
6 5 9 7 8 3 4 2 1
|
||||||
|
8 3 7 1 2 4 6 9 5
|
||||||
|
1 2 4 9 5 6 7 3 8
|
||||||
|
3 8 2 5 1 7 9 6 4
|
||||||
|
5 4 1 6 9 2 8 7 3
|
||||||
|
9 7 6 3 4 8 5 1 2
|
19
boards/044.txt
Normal file
19
boards/044.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
5 8 4 0 2 3 0 7 0
|
||||||
|
0 0 0 8 0 0 0 0 4
|
||||||
|
0 0 0 0 0 4 0 0 8
|
||||||
|
3 0 6 7 0 0 0 4 0
|
||||||
|
4 0 0 0 3 0 0 0 9
|
||||||
|
0 1 0 0 0 9 3 0 5
|
||||||
|
2 0 0 5 0 0 0 0 0
|
||||||
|
6 0 0 0 0 2 0 0 0
|
||||||
|
0 4 0 9 7 0 6 2 3
|
||||||
|
|
||||||
|
5 8 4 1 2 3 9 7 6
|
||||||
|
1 6 3 8 9 7 2 5 4
|
||||||
|
9 2 7 6 5 4 1 3 8
|
||||||
|
3 9 6 7 1 5 8 4 2
|
||||||
|
4 5 8 2 3 6 7 1 9
|
||||||
|
7 1 2 4 8 9 3 6 5
|
||||||
|
2 3 1 5 6 8 4 9 7
|
||||||
|
6 7 9 3 4 2 5 8 1
|
||||||
|
8 4 5 9 7 1 6 2 3
|
19
boards/045.txt
Normal file
19
boards/045.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 6 0 0 0 0 9 5 8
|
||||||
|
0 0 0 0 0 0 0 0 7
|
||||||
|
0 0 0 3 0 0 2 0 0
|
||||||
|
0 0 0 0 0 5 3 0 0
|
||||||
|
7 0 0 0 0 6 0 0 0
|
||||||
|
8 0 4 0 1 0 6 0 0
|
||||||
|
1 0 0 0 0 0 0 0 3
|
||||||
|
5 9 0 0 7 0 0 0 6
|
||||||
|
0 2 0 0 0 0 4 0 0
|
||||||
|
|
||||||
|
3 6 2 1 4 7 9 5 8
|
||||||
|
4 8 5 6 9 2 1 3 7
|
||||||
|
9 7 1 3 5 8 2 6 4
|
||||||
|
2 1 6 7 8 5 3 4 9
|
||||||
|
7 3 9 4 2 6 5 8 1
|
||||||
|
8 5 4 9 1 3 6 7 2
|
||||||
|
1 4 8 5 6 9 7 2 3
|
||||||
|
5 9 3 2 7 4 8 1 6
|
||||||
|
6 2 7 8 3 1 4 9 5
|
19
boards/046.txt
Normal file
19
boards/046.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
8 9 0 0 0 2 0 4 0
|
||||||
|
5 0 0 0 0 0 0 0 3
|
||||||
|
0 0 0 0 0 1 0 5 0
|
||||||
|
0 0 5 6 0 0 0 9 0
|
||||||
|
0 0 2 0 0 0 5 0 0
|
||||||
|
0 4 0 0 0 0 0 0 8
|
||||||
|
0 0 1 0 4 0 2 0 9
|
||||||
|
7 0 0 8 0 0 0 0 6
|
||||||
|
0 0 0 3 0 0 0 0 0
|
||||||
|
|
||||||
|
8 9 7 5 3 2 6 4 1
|
||||||
|
5 1 6 4 7 8 9 2 3
|
||||||
|
2 3 4 9 6 1 8 5 7
|
||||||
|
1 7 5 6 8 4 3 9 2
|
||||||
|
6 8 2 1 9 3 5 7 4
|
||||||
|
9 4 3 2 5 7 1 6 8
|
||||||
|
3 5 1 7 4 6 2 8 9
|
||||||
|
7 2 9 8 1 5 4 3 6
|
||||||
|
4 6 8 3 2 9 7 1 5
|
19
boards/047.txt
Normal file
19
boards/047.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 0 0 0 0 1 8 0 7
|
||||||
|
4 0 0 0 0 5 0 2 0
|
||||||
|
0 0 0 0 2 0 0 5 9
|
||||||
|
0 3 0 0 0 0 2 1 4
|
||||||
|
1 0 0 4 3 7 0 0 6
|
||||||
|
6 4 5 0 0 0 0 8 0
|
||||||
|
5 2 0 0 6 0 0 0 0
|
||||||
|
0 1 0 7 0 0 0 0 2
|
||||||
|
7 0 6 2 0 0 0 0 0
|
||||||
|
|
||||||
|
2 5 3 6 9 1 8 4 7
|
||||||
|
4 6 9 8 7 5 3 2 1
|
||||||
|
8 7 1 3 2 4 6 5 9
|
||||||
|
9 3 7 5 8 6 2 1 4
|
||||||
|
1 8 2 4 3 7 5 9 6
|
||||||
|
6 4 5 9 1 2 7 8 3
|
||||||
|
5 2 4 1 6 3 9 7 8
|
||||||
|
3 1 8 7 5 9 4 6 2
|
||||||
|
7 9 6 2 4 8 1 3 5
|
19
boards/048.txt
Normal file
19
boards/048.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
8 0 0 6 1 0 0 0 0
|
||||||
|
0 2 7 0 0 0 4 0 6
|
||||||
|
0 1 6 0 7 0 8 0 0
|
||||||
|
0 3 0 0 6 5 2 0 0
|
||||||
|
0 0 0 0 9 0 0 0 0
|
||||||
|
0 0 4 8 2 0 0 5 0
|
||||||
|
0 0 1 0 8 0 6 4 0
|
||||||
|
4 0 9 0 0 0 7 8 0
|
||||||
|
0 0 0 0 4 6 0 0 9
|
||||||
|
|
||||||
|
8 4 3 6 1 2 9 7 5
|
||||||
|
9 2 7 5 3 8 4 1 6
|
||||||
|
5 1 6 4 7 9 8 2 3
|
||||||
|
1 3 8 7 6 5 2 9 4
|
||||||
|
2 7 5 3 9 4 1 6 8
|
||||||
|
6 9 4 8 2 1 3 5 7
|
||||||
|
3 5 1 9 8 7 6 4 2
|
||||||
|
4 6 9 2 5 3 7 8 1
|
||||||
|
7 8 2 1 4 6 5 3 9
|
19
boards/049.txt
Normal file
19
boards/049.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 1 0 6 0 0 0 7 3
|
||||||
|
9 0 0 0 0 0 0 0 4
|
||||||
|
0 4 0 2 0 0 0 0 0
|
||||||
|
0 7 0 0 0 8 4 0 0
|
||||||
|
0 0 4 0 0 0 6 0 0
|
||||||
|
3 0 0 0 0 0 0 1 0
|
||||||
|
7 0 6 0 1 0 2 0 0
|
||||||
|
8 0 0 0 0 3 0 0 5
|
||||||
|
0 0 0 0 0 9 0 0 0
|
||||||
|
|
||||||
|
2 1 8 6 9 4 5 7 3
|
||||||
|
9 6 7 3 5 1 8 2 4
|
||||||
|
5 4 3 2 8 7 1 9 6
|
||||||
|
6 7 9 1 3 8 4 5 2
|
||||||
|
1 5 4 9 7 2 6 3 8
|
||||||
|
3 8 2 5 4 6 9 1 7
|
||||||
|
7 3 6 8 1 5 2 4 9
|
||||||
|
8 9 1 4 2 3 7 6 5
|
||||||
|
4 2 5 7 6 9 3 8 1
|
19
boards/050.txt
Normal file
19
boards/050.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 4 0 0 7 2 1 0 8
|
||||||
|
0 0 0 3 0 6 5 4 0
|
||||||
|
0 0 0 0 0 4 0 0 3
|
||||||
|
0 0 0 0 8 0 0 5 6
|
||||||
|
0 0 7 0 9 0 4 0 0
|
||||||
|
4 8 0 0 2 0 0 0 0
|
||||||
|
7 0 0 5 0 0 0 0 0
|
||||||
|
0 6 4 2 0 9 0 0 0
|
||||||
|
8 0 5 7 6 0 0 2 0
|
||||||
|
|
||||||
|
5 4 3 9 7 2 1 6 8
|
||||||
|
9 7 8 3 1 6 5 4 2
|
||||||
|
6 2 1 8 5 4 7 9 3
|
||||||
|
3 1 9 4 8 7 2 5 6
|
||||||
|
2 5 7 6 9 3 4 8 1
|
||||||
|
4 8 6 1 2 5 9 3 7
|
||||||
|
7 3 2 5 4 8 6 1 9
|
||||||
|
1 6 4 2 3 9 8 7 5
|
||||||
|
8 9 5 7 6 1 3 2 4
|
19
boards/051.txt
Normal file
19
boards/051.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
3 4 0 0 0 0 7 6 0
|
||||||
|
2 0 0 0 0 0 0 0 0
|
||||||
|
5 0 1 7 0 6 0 0 8
|
||||||
|
0 0 0 2 6 0 0 0 0
|
||||||
|
0 0 0 0 0 9 0 4 0
|
||||||
|
0 0 7 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 8 0 0 0
|
||||||
|
6 0 0 0 0 0 0 5 1
|
||||||
|
0 0 0 0 4 3 9 2 0
|
||||||
|
|
||||||
|
3 4 8 5 9 1 7 6 2
|
||||||
|
2 7 6 8 3 4 1 9 5
|
||||||
|
5 9 1 7 2 6 4 3 8
|
||||||
|
4 1 3 2 6 7 5 8 9
|
||||||
|
8 5 2 3 1 9 6 4 7
|
||||||
|
9 6 7 4 8 5 2 1 3
|
||||||
|
1 2 9 6 5 8 3 7 4
|
||||||
|
6 3 4 9 7 2 8 5 1
|
||||||
|
7 8 5 1 4 3 9 2 6
|
19
boards/052.txt
Normal file
19
boards/052.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 6 0 0 0 0 5 9 3
|
||||||
|
0 0 0 0 0 0 0 0 4
|
||||||
|
0 0 0 7 0 0 2 0 0
|
||||||
|
0 0 0 0 0 9 7 0 0
|
||||||
|
4 0 0 0 0 6 0 0 0
|
||||||
|
3 0 8 0 1 0 6 0 0
|
||||||
|
1 0 0 0 0 0 0 0 7
|
||||||
|
9 5 0 0 4 0 0 0 6
|
||||||
|
0 2 0 0 0 0 8 0 0
|
||||||
|
|
||||||
|
7 6 2 1 8 4 5 9 3
|
||||||
|
8 3 9 6 5 2 1 7 4
|
||||||
|
5 4 1 7 9 3 2 6 8
|
||||||
|
2 1 6 4 3 9 7 8 5
|
||||||
|
4 7 5 8 2 6 9 3 1
|
||||||
|
3 9 8 5 1 7 6 4 2
|
||||||
|
1 8 3 9 6 5 4 2 7
|
||||||
|
9 5 7 2 4 8 3 1 6
|
||||||
|
6 2 4 3 7 1 8 5 9
|
19
boards/053.txt
Normal file
19
boards/053.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 0 0 0 5 8 0 0 4
|
||||||
|
8 0 7 0 0 0 1 3 0
|
||||||
|
0 0 4 0 1 0 8 5 0
|
||||||
|
0 0 3 2 8 0 0 9 0
|
||||||
|
0 0 0 0 6 0 0 0 0
|
||||||
|
0 2 0 0 3 4 7 0 0
|
||||||
|
0 7 8 0 4 0 5 0 0
|
||||||
|
0 4 1 0 0 0 6 0 7
|
||||||
|
6 0 0 8 7 0 0 0 0
|
||||||
|
|
||||||
|
2 1 6 3 5 8 9 7 4
|
||||||
|
8 5 7 4 9 2 1 3 6
|
||||||
|
9 3 4 6 1 7 8 5 2
|
||||||
|
7 6 3 2 8 1 4 9 5
|
||||||
|
4 8 5 7 6 9 2 1 3
|
||||||
|
1 2 9 5 3 4 7 6 8
|
||||||
|
3 7 8 1 4 6 5 2 9
|
||||||
|
5 4 1 9 2 3 6 8 7
|
||||||
|
6 9 2 8 7 5 3 4 1
|
19
boards/054.txt
Normal file
19
boards/054.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 3 6 0 7 8 0 0 1
|
||||||
|
7 0 0 5 0 0 0 0 4
|
||||||
|
0 0 0 0 0 3 0 0 7
|
||||||
|
9 0 1 0 0 2 0 4 0
|
||||||
|
2 0 0 0 8 0 0 0 6
|
||||||
|
0 6 0 9 0 0 7 0 8
|
||||||
|
3 0 0 8 0 0 0 0 0
|
||||||
|
6 0 0 0 0 7 0 0 2
|
||||||
|
8 0 0 1 9 0 4 7 0
|
||||||
|
|
||||||
|
4 3 6 2 7 8 9 5 1
|
||||||
|
7 2 8 5 1 9 6 3 4
|
||||||
|
1 9 5 6 4 3 2 8 7
|
||||||
|
9 8 1 7 6 2 3 4 5
|
||||||
|
2 7 3 4 8 5 1 9 6
|
||||||
|
5 6 4 9 3 1 7 2 8
|
||||||
|
3 1 7 8 2 4 5 6 9
|
||||||
|
6 4 9 3 5 7 8 1 2
|
||||||
|
8 5 2 1 9 6 4 7 3
|
19
boards/055.txt
Normal file
19
boards/055.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
0 8 0 0 0 2 4 5 0
|
||||||
|
9 0 3 4 0 0 0 0 0
|
||||||
|
0 0 0 0 3 0 1 0 0
|
||||||
|
1 0 6 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 9 0 0
|
||||||
|
0 0 0 5 0 0 0 2 8
|
||||||
|
0 0 0 3 1 0 6 0 0
|
||||||
|
4 0 0 0 0 9 0 0 0
|
||||||
|
2 3 0 0 0 0 0 7 0
|
||||||
|
|
||||||
|
6 8 7 1 9 2 4 5 3
|
||||||
|
9 1 3 4 7 5 2 8 6
|
||||||
|
5 4 2 8 3 6 1 9 7
|
||||||
|
1 2 6 9 8 7 5 3 4
|
||||||
|
8 7 5 2 4 3 9 6 1
|
||||||
|
3 9 4 5 6 1 7 2 8
|
||||||
|
7 5 9 3 1 8 6 4 2
|
||||||
|
4 6 8 7 2 9 3 1 5
|
||||||
|
2 3 1 6 5 4 8 7 9
|
19
boards/056.txt
Normal file
19
boards/056.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
8 2 0 0 0 0 7 0 3
|
||||||
|
7 0 0 5 4 0 1 0 0
|
||||||
|
5 6 0 0 0 7 0 0 0
|
||||||
|
0 0 3 0 0 0 0 0 0
|
||||||
|
0 0 0 0 5 0 0 0 9
|
||||||
|
0 0 0 4 0 1 0 0 0
|
||||||
|
9 0 0 0 0 0 0 2 0
|
||||||
|
0 0 7 8 2 0 3 1 0
|
||||||
|
0 0 0 0 0 0 8 0 7
|
||||||
|
|
||||||
|
8 2 4 9 1 6 7 5 3
|
||||||
|
7 3 9 5 4 8 1 6 2
|
||||||
|
5 6 1 2 3 7 9 8 4
|
||||||
|
4 9 3 6 8 2 5 7 1
|
||||||
|
1 8 6 7 5 3 2 4 9
|
||||||
|
2 7 5 4 9 1 6 3 8
|
||||||
|
9 1 8 3 7 5 4 2 6
|
||||||
|
6 4 7 8 2 9 3 1 5
|
||||||
|
3 5 2 1 6 4 8 9 7
|
9
boards/057.txt
Normal file
9
boards/057.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
0 6 0 0 0 0 0 0 9
|
||||||
|
0 0 0 0 0 3 5 8 0
|
||||||
|
0 4 5 6 0 0 1 7 0
|
||||||
|
0 0 0 9 0 0 0 0 1
|
||||||
|
6 0 9 8 4 1 7 0 5
|
||||||
|
1 0 0 0 0 2 0 0 0
|
||||||
|
0 7 1 0 0 8 9 6 0
|
||||||
|
0 9 6 2 0 0 0 0 0
|
||||||
|
4 0 0 0 0 0 0 1 0
|
@ -1,6 +1,6 @@
|
|||||||
return {
|
return {
|
||||||
board = {
|
board = {
|
||||||
filePath = "boards/040.txt",
|
filePath = "boards/057.txt",
|
||||||
},
|
},
|
||||||
window = {
|
window = {
|
||||||
bgColor = "FFFFFF",
|
bgColor = "FFFFFF",
|
||||||
|
8
main.lua
8
main.lua
@ -1,4 +1,4 @@
|
|||||||
require "sudoku.utils"
|
sudoku = require "sudoku.sudoku"
|
||||||
uiUtils = require "ui.utils"
|
uiUtils = require "ui.utils"
|
||||||
config = require "config"
|
config = require "config"
|
||||||
SudokuCanvas = require "ui.sudokucanvas"
|
SudokuCanvas = require "ui.sudokucanvas"
|
||||||
@ -11,10 +11,10 @@ function love.load()
|
|||||||
love.mouse.setGrabbed(false)
|
love.mouse.setGrabbed(false)
|
||||||
love.keyboard.setKeyRepeat(true)
|
love.keyboard.setKeyRepeat(true)
|
||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
local board = loadBoard(config.board.filePath)
|
board = sudoku.loadBoard(config.board.filePath)
|
||||||
local width, height = love.graphics.getDimensions()
|
local width, height = love.graphics.getDimensions()
|
||||||
sudokuCanvas = SudokuCanvas:new(200, 100, height/1.5, config.SudokuCanvas)
|
sudokuCanvas = SudokuCanvas:new(500, 50, height/1.1, config.SudokuCanvas)
|
||||||
sudokuCanvas:setBoard(board)
|
sudokuCanvas:setBoard(board[1])
|
||||||
myFont = love.graphics.newFont(24)
|
myFont = love.graphics.newFont(24)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
132
sudoku/check.lua
132
sudoku/check.lua
@ -1,132 +0,0 @@
|
|||||||
local function checkCT(ct)
|
|
||||||
local r = {}
|
|
||||||
for i = 1, 8 do
|
|
||||||
for j = i+1, 9 do
|
|
||||||
if ct[i] == ct[j] and ct[i] ~= 0 then
|
|
||||||
table.insert(r, {i, j})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #r > 0 then return false, r end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function findThisTable(this, that)
|
|
||||||
for i = 1, #that do
|
|
||||||
if #that[i] == #this then
|
|
||||||
local flag = true
|
|
||||||
for j = 1, #this do
|
|
||||||
if this[j] ~= that[i][j] then flag = false; break end
|
|
||||||
end
|
|
||||||
if flag then return true, i end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function check(board)
|
|
||||||
local rr = {}
|
|
||||||
for x = 1, 9 do
|
|
||||||
local ct = {}
|
|
||||||
for y = 1, 9 do
|
|
||||||
ct[y] = board[x][y]
|
|
||||||
end
|
|
||||||
local ok, r = checkCT(ct)
|
|
||||||
if not ok then
|
|
||||||
for _, p in ipairs(r) do
|
|
||||||
local t = {x, p[1], x, p[2], board[x][p[1]]}
|
|
||||||
if not findThisTable(t, rr) then
|
|
||||||
table.insert(rr, t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for y = 1, 9 do
|
|
||||||
local ct = {}
|
|
||||||
for x = 1, 9 do
|
|
||||||
ct[x] = board[x][y]
|
|
||||||
end
|
|
||||||
local ok, r = checkCT(ct)
|
|
||||||
if not ok then
|
|
||||||
for _, p in ipairs(r) do
|
|
||||||
local t = {p[1], y, p[2], y, board[p[1]][y]}
|
|
||||||
if not findThisTable(t, rr) then
|
|
||||||
table.insert(rr, t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i = 0, 2 do
|
|
||||||
for j = 0, 2 do
|
|
||||||
local ct = {}
|
|
||||||
for x = 1, 3 do
|
|
||||||
for y = 1, 3 do
|
|
||||||
ct[(x-1)*3+y] = board[x+i*3][y+j*3]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local ok, r = checkCT(ct)
|
|
||||||
if not ok then
|
|
||||||
for _, p in ipairs(r) do
|
|
||||||
-- local x1 = ((p[1] - 1) // 3 + 1) + i * 3
|
|
||||||
local x1 = math.floor((p[1] - 1) / 3 + 1) + i * 3
|
|
||||||
local y1 = ((p[1] - 1) % 3 + 1) + j * 3
|
|
||||||
-- local x2 = ((p[2] - 1) // 3 + 1) + i * 3
|
|
||||||
local x2 = math.floor((p[2] - 1) / 3 + 1) + i * 3
|
|
||||||
local y2 = ((p[2] - 1) % 3 + 1) + j * 3
|
|
||||||
local t = {x1, y1, x2, y2, board[x1][y1]}
|
|
||||||
if not findThisTable(t, rr) then
|
|
||||||
table.insert(rr, t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #rr > 0 then
|
|
||||||
return false, rr
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function checkSolved(board)
|
|
||||||
local r = {}
|
|
||||||
for i = 1, 9 do
|
|
||||||
for j = 1, 9 do
|
|
||||||
if board[i][j] < 1 or board[i][j] > 9 then
|
|
||||||
table.insert(r, {i, j, board[i][j]})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local ok, rr = check(board)
|
|
||||||
if #r > 0 or (rr and #rr > 0) then
|
|
||||||
return false, r, rr
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function pcheck(board)
|
|
||||||
local ok, r, rr = checkSolved(board)
|
|
||||||
if ok then
|
|
||||||
print("Board is solved!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
for _, p in ipairs(r) do
|
|
||||||
print(S("(%d, %d) = %d", unpack(p)))
|
|
||||||
end
|
|
||||||
for _, p in ipairs(rr) do
|
|
||||||
print(S("(%d, %d) = (%d, %d) = %d", unpack(p)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function scheck(board)
|
|
||||||
local msg = {}
|
|
||||||
local ok, r = check(board)
|
|
||||||
if ok then
|
|
||||||
return {"No Error!"}
|
|
||||||
end
|
|
||||||
for _, p in ipairs(r) do
|
|
||||||
local s = string.format("(%d, %d) = (%d, %d) = %d", unpack(p))
|
|
||||||
print(s)
|
|
||||||
table.insert(msg, s)
|
|
||||||
end
|
|
||||||
return msg
|
|
||||||
end
|
|
@ -1,47 +1,510 @@
|
|||||||
require "sudoku.utils"
|
-- dbg = require ("debugger")
|
||||||
require "sudoku.check"
|
-- dbg.auto_where = 2
|
||||||
|
|
||||||
function calValidOptions(b, x, y)
|
function table2string(t)
|
||||||
if b[x][y] ~= 0 then return {} end
|
local myself = table2string
|
||||||
local elm
|
local l = {}
|
||||||
local u = {}
|
local n = 0
|
||||||
local v = {}
|
for k, v in pairs(t) do
|
||||||
for i = 1, 9 do
|
n = n + 1
|
||||||
elm = b[x][i]
|
if type(v) == "table" then
|
||||||
if elm ~= 0 and find(u, elm) == 0 then
|
l[n] = k .. ': ' .. myself(v)
|
||||||
table.insert(u, elm)
|
elseif type(v) == "string" then
|
||||||
end
|
l[n] = k .. ': ' .. '"' .. v .. '"'
|
||||||
elm = b[i][y]
|
else
|
||||||
if elm ~= 0 and find(u, elm) == 0 then
|
l[n] = k .. ': ' .. v
|
||||||
table.insert(u, elm)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- local xc = ((x - 1) // 3) * 3
|
return "{" .. table.concat(l, ", ") .. "}"
|
||||||
-- local yc = ((y - 1) // 3) * 3
|
end
|
||||||
local xc = math.floor((x - 1) / 3) * 3
|
|
||||||
local yc = math.floor((y - 1) / 3) * 3
|
function find(array, element)
|
||||||
for i = 1, 3 do
|
local index = 0
|
||||||
for j = 1, 3 do
|
for i = 1, #array do
|
||||||
elm = b[i+xc][j+yc]
|
if array[i] == element then
|
||||||
if elm ~= 0 and find(u, elm) == 0 then
|
index = i
|
||||||
table.insert(u, elm)
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return index
|
||||||
|
end
|
||||||
|
|
||||||
|
function createEmptyBoard()
|
||||||
|
local b = {}
|
||||||
|
for i = 1, 9 do
|
||||||
|
b[i] = {}
|
||||||
|
for j = 1, 9 do
|
||||||
|
b[i][j] = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return b
|
||||||
|
end
|
||||||
|
|
||||||
|
function cloneBoard(b)
|
||||||
|
local c = {}
|
||||||
|
for i = 1, 9 do
|
||||||
|
c[i] = {}
|
||||||
|
for j = 1, 9 do
|
||||||
|
c[i][j] = b[i][j]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
function loadBoard(fn)
|
||||||
|
local boards = {}
|
||||||
|
local r = 0
|
||||||
|
local board = {}
|
||||||
|
for line in io.lines(fn) do
|
||||||
|
if line:gsub("%s+", "") == "" then
|
||||||
|
table.insert(boards, board)
|
||||||
|
board = {}
|
||||||
|
r = 0
|
||||||
|
else
|
||||||
|
r = r + 1
|
||||||
|
local c = 0
|
||||||
|
board[r] = {}
|
||||||
|
for item in line:gmatch("%w+") do
|
||||||
|
c = c + 1
|
||||||
|
board[r][c] = tonumber(item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
table.insert(boards, board)
|
||||||
|
return boards
|
||||||
|
end
|
||||||
|
|
||||||
|
function saveBoard(fn, b1, b2)
|
||||||
|
local f = io.open(fn, "w")
|
||||||
|
for row = 1, 9 do
|
||||||
|
f:write(table.concat(b1[row], " "))
|
||||||
|
f:write("\n")
|
||||||
|
end
|
||||||
|
f:write("\n")
|
||||||
|
for row = 1, 9 do
|
||||||
|
f:write(table.concat(b2[row], " "))
|
||||||
|
f:write("\n")
|
||||||
|
end
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
function showBoard(board)
|
||||||
|
for row = 1, 9 do
|
||||||
|
print(table.concat(board[row], " "))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function checkBoardsEqual(b1, b2)
|
||||||
for i = 1, 9 do
|
for i = 1, 9 do
|
||||||
if find(u, i) == 0 then table.insert(v, i) end
|
for j = 1, 9 do
|
||||||
|
if b1[i][j] ~= b2[i][j] then return false end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function iterZones(board)
|
||||||
|
local row = 0
|
||||||
|
local column = 0
|
||||||
|
local block = 0
|
||||||
|
return function()
|
||||||
|
local a = {}
|
||||||
|
local p = {}
|
||||||
|
if row < 9 then
|
||||||
|
row = row + 1
|
||||||
|
for i = 1, 9 do
|
||||||
|
a[i] = board[row][i]
|
||||||
|
p[i] = {row, i}
|
||||||
|
end
|
||||||
|
return a, p
|
||||||
|
end
|
||||||
|
if column < 9 then
|
||||||
|
column = column + 1
|
||||||
|
for i = 1, 9 do
|
||||||
|
a[i] = board[i][column]
|
||||||
|
p[i] = {i, column}
|
||||||
|
end
|
||||||
|
return a, p
|
||||||
|
end
|
||||||
|
if block < 9 then
|
||||||
|
block = block + 1
|
||||||
|
local dx = math.floor((block - 1) / 3)
|
||||||
|
local dy = (block - 1) % 3
|
||||||
|
local n = 0
|
||||||
|
for i = 1, 3 do
|
||||||
|
for j = 1, 3 do
|
||||||
|
local x = i + 3 * dx
|
||||||
|
local y = j + 3 * dy
|
||||||
|
n = n + 1
|
||||||
|
a[n] = board[x][y]
|
||||||
|
p[n] = {x, y}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return a, p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function checkAUX(zone, pos)
|
||||||
|
local isComplete = true
|
||||||
|
local ok = true
|
||||||
|
local conflictList = {}
|
||||||
|
local n = 0
|
||||||
|
for i = 1, 8 do
|
||||||
|
for j = i+1, 9 do
|
||||||
|
if zone[i] == 0 then
|
||||||
|
isComplete = false
|
||||||
|
elseif zone[i] == zone[j] then
|
||||||
|
ok = false
|
||||||
|
n = n + 1
|
||||||
|
conflictList[n] = {x1=pos[i][1], y1=pos[i][2], x2=pos[j][1], y2=pos[j][2]}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ok, isComplete, conflictList
|
||||||
|
end
|
||||||
|
|
||||||
|
function checkBoard(board)
|
||||||
|
local ok = true
|
||||||
|
local isComplete = true
|
||||||
|
local conflictList = {}
|
||||||
|
for zone, pos in iterZones(board) do
|
||||||
|
local tOk, tIsComplete, tConflictList = checkAUX(zone, pos)
|
||||||
|
if not tOk then ok = false end
|
||||||
|
if not tIsComplete then isComplete = false end
|
||||||
|
for _, conflict in ipairs(tConflictList) do
|
||||||
|
table.insert(conflictList, conflict)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not ok then isComplete = false end
|
||||||
|
return ok, isComplete, conflictList
|
||||||
|
end
|
||||||
|
|
||||||
|
function calCellValidOptions(board, x, y)
|
||||||
|
if board[x][y] ~= 0 then return {} end
|
||||||
|
local u = {}
|
||||||
|
local v = {}
|
||||||
|
for i = 1, 9 do
|
||||||
|
if board[x][i] ~= 0 then table.insert(u, board[x][i]) end
|
||||||
|
if board[i][y] ~= 0 then table.insert(u, board[i][y]) end
|
||||||
|
end
|
||||||
|
local dx = math.floor((x - 1) / 3) * 3
|
||||||
|
local dy = math.floor((y - 1) / 3) * 3
|
||||||
|
for i = 1, 3 do
|
||||||
|
for j = 1, 3 do
|
||||||
|
local a = board[i+dx][j+dy]
|
||||||
|
if a ~= 0 then table.insert(u, a) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i = 1, 9 do
|
||||||
|
local found = false
|
||||||
|
for _, elm in ipairs(u) do
|
||||||
|
if elm == i then found = true; break end
|
||||||
|
end
|
||||||
|
if not found then table.insert(v, i) end
|
||||||
end
|
end
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
function buildSearchSpace(b)
|
function buildSearchSpace(board)
|
||||||
local s = {}
|
local s = {}
|
||||||
for i = 1, 9 do
|
for i = 1, 9 do
|
||||||
s[i] = {}
|
s[i] = {}
|
||||||
for j = 1, 9 do
|
for j = 1, 9 do
|
||||||
s[i][j] = calValidOptions(b, i, j)
|
s[i][j] = calCellValidOptions(board, i, j)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function findPairsIndSearchSpace(board, searchSpace)
|
||||||
|
local r = {}
|
||||||
|
local zoneIndex = 0
|
||||||
|
for zone, pos in iterZones(board) do
|
||||||
|
zoneIndex = zoneIndex + 1
|
||||||
|
for i = 1, 8 do
|
||||||
|
local x1 = pos[i][1]
|
||||||
|
local y1 = pos[i][2]
|
||||||
|
local s1 = searchSpace[x1][y1]
|
||||||
|
if #s1 == 2 then
|
||||||
|
for j = i + 1, 9 do
|
||||||
|
local x2 = pos[j][1]
|
||||||
|
local y2 = pos[j][2]
|
||||||
|
local s2 = searchSpace[x2][y2]
|
||||||
|
if #s2 == 2 then
|
||||||
|
if s1[1] == s2[1] and s1[2] == s2[2] then
|
||||||
|
-- if zoneIndex <= 18 or x1 ~= x2 and y1 ~= y2 then
|
||||||
|
table.insert(r, {zoneIndex=zoneIndex, cells={i, j}, pair=s1})
|
||||||
|
-- print("----------")
|
||||||
|
-- print("zone: ", zoneIndex)
|
||||||
|
-- print(table2string(zone))
|
||||||
|
-- print(i, j)
|
||||||
|
-- print(table2string(s1))
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
function showSearchSpace(s)
|
||||||
|
local hl = ("+-------+-------+-------+-------+-------+-------+-------+-------+-------+")
|
||||||
|
print(hl)
|
||||||
|
for i = 1, 27 do
|
||||||
|
local x = math.floor((i - 1) / 3) + 1
|
||||||
|
local a = (i - 1) % 3
|
||||||
|
local row = {}
|
||||||
|
for j = 1, 27 do
|
||||||
|
local y = math.floor((j - 1) / 3) + 1
|
||||||
|
local k = ((j - 1) % 3 + 1) + 3 * a
|
||||||
|
local found = false
|
||||||
|
for _, m in ipairs(s[x][y]) do
|
||||||
|
if m == k then found = true; break end
|
||||||
|
end
|
||||||
|
if found then
|
||||||
|
table.insert(row, k)
|
||||||
|
else
|
||||||
|
table.insert(row, " ")
|
||||||
|
end
|
||||||
|
if j % 3 == 0 then table.insert(row, "|") end
|
||||||
|
end
|
||||||
|
print("| "..table.concat(row, " "))
|
||||||
|
if i % 3 == 0 then print(hl) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function getZoneByIndex(board, zoneIndex)
|
||||||
|
local index = (zoneIndex - 1) % 9 + 1
|
||||||
|
local block = math.floor((zoneIndex - 1) / 9) + 1
|
||||||
|
local a = {}
|
||||||
|
local p = {}
|
||||||
|
if block == 1 then
|
||||||
|
for i = 1, 9 do
|
||||||
|
a[i] = board[index][i]
|
||||||
|
p[i] = {index, i}
|
||||||
|
end
|
||||||
|
elseif block == 2 then
|
||||||
|
for i = 1, 9 do
|
||||||
|
a[i] = board[i][index]
|
||||||
|
p[i] = {index, i}
|
||||||
|
end
|
||||||
|
elseif block == 3 then
|
||||||
|
local dx = math.floor((index - 1) / 3)
|
||||||
|
local dy = (index - 1) % 3
|
||||||
|
local n = 0
|
||||||
|
for i = 1, 3 do
|
||||||
|
for j = 1, 3 do
|
||||||
|
local x = i + 3 * dx
|
||||||
|
local y = j + 3 * dy
|
||||||
|
n = n + 1
|
||||||
|
a[n] = board[x][y]
|
||||||
|
p[n] = {x, y}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return a, p
|
||||||
|
end
|
||||||
|
|
||||||
|
function getZonePosByIndex(zoneIndex)
|
||||||
|
local index = (zoneIndex - 1) % 9 + 1
|
||||||
|
local block = math.floor((zoneIndex - 1) / 9) + 1
|
||||||
|
local p = {}
|
||||||
|
if block == 1 then
|
||||||
|
for i = 1, 9 do
|
||||||
|
p[i] = {index, i}
|
||||||
|
end
|
||||||
|
elseif block == 2 then
|
||||||
|
for i = 1, 9 do
|
||||||
|
p[i] = {index, i}
|
||||||
|
end
|
||||||
|
elseif block == 3 then
|
||||||
|
local dx = math.floor((index - 1) / 3)
|
||||||
|
local dy = (index - 1) % 3
|
||||||
|
local n = 0
|
||||||
|
for i = 1, 3 do
|
||||||
|
for j = 1, 3 do
|
||||||
|
local x = i + 3 * dx
|
||||||
|
local y = j + 3 * dy
|
||||||
|
n = n + 1
|
||||||
|
p[n] = {x, y}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return p
|
||||||
|
end
|
||||||
|
|
||||||
|
function iterZonePos(zoneIndex)
|
||||||
|
local p = getZonePosByIndex(zoneIndex)
|
||||||
|
local i = 0
|
||||||
|
return function()
|
||||||
|
if i < 9 then
|
||||||
|
i = i + 1
|
||||||
|
return p[i][1], p[i][2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function fillSingles(board, searchSpace)
|
||||||
|
local count = 0
|
||||||
|
for i = 1, 9 do
|
||||||
|
for j = 1, 9 do
|
||||||
|
if #searchSpace[i][j] == 1 then
|
||||||
|
board[i][j] = searchSpace[i][j][1]
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
function applyFillSinglesRepeatedly(board, s)
|
||||||
|
local s = s or buildSearchSpace(board)
|
||||||
|
local count = fillSingles(board, s)
|
||||||
|
local total = count
|
||||||
|
while count ~= 0 do
|
||||||
|
s = buildSearchSpace(board)
|
||||||
|
count = fillSingles(board, s)
|
||||||
|
total = total + count
|
||||||
|
end
|
||||||
|
return total
|
||||||
|
end
|
||||||
|
|
||||||
|
function eliminatePairsInSearchSpaceAUX(board, searchSpace, pair, zoneIndex, cells)
|
||||||
|
local _, pos = getZoneByIndex(board, zoneIndex)
|
||||||
|
local count = 0
|
||||||
|
for i = 1, 9 do
|
||||||
|
if i ~= cells[1] and i ~= cells[2] then
|
||||||
|
local x = pos[i][1]
|
||||||
|
local y = pos[i][2]
|
||||||
|
local del = {}
|
||||||
|
for index, v in ipairs(searchSpace[x][y]) do
|
||||||
|
if v == pair[1] or v == pair[2] then
|
||||||
|
count = count + 1
|
||||||
|
table.insert(del, index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, index in ipairs(del) do
|
||||||
|
table.remove(searchSpace[x][y], index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
function eliminatePairsInSearchSpace(board, searchSpace)
|
||||||
|
local p = findPairsIndSearchSpace(board, searchSpace)
|
||||||
|
local count = 0
|
||||||
|
for _, m in ipairs(p) do
|
||||||
|
count = count + eliminatePairsInSearchSpaceAUX(board, searchSpace, m.pair, m.zoneIndex, m.cells)
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
function allPairs(board)
|
||||||
|
local s = buildSearchSpace(board)
|
||||||
|
applyFillSinglesRepeatedly(board, s)
|
||||||
|
eliminatePairsInSearchSpace(board, s)
|
||||||
|
local count = applyFillSinglesRepeatedly(board, s)
|
||||||
|
while count ~= 0 do
|
||||||
|
-- print("--------------------------------------------------")
|
||||||
|
-- showBoard(board)
|
||||||
|
-- showSearchSpace(s)
|
||||||
|
-- print(count)
|
||||||
|
-- io.read(1)
|
||||||
|
s = buildSearchSpace(board)
|
||||||
|
eliminatePairsInSearchSpace(board, s)
|
||||||
|
count = applyFillSinglesRepeatedly(board, s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function findFirstEmptyCell(board)
|
||||||
|
for i = 1, 9 do
|
||||||
|
for j = 1, 9 do
|
||||||
|
if board[i][j] == 0 then
|
||||||
|
return i, j
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function checkSearchSpace(board, searchSpace)
|
||||||
|
local s = searchSpace or buildSearchSpace(board)
|
||||||
|
for i = 1, 9 do
|
||||||
|
for j = 1, 9 do
|
||||||
|
if board[i][j] == 0 then
|
||||||
|
if #s[i][j] == 0 then return false end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function findFirstLeastOption(searchSpace)
|
||||||
|
local min = 9
|
||||||
|
local x, y
|
||||||
|
for i = 1, 9 do
|
||||||
|
for j = 1, 9 do
|
||||||
|
local len = #searchSpace[i][j]
|
||||||
|
if len > 0 and len < min then
|
||||||
|
min = len
|
||||||
|
x = i
|
||||||
|
y = j
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return x, y, min
|
||||||
|
end
|
||||||
|
|
||||||
|
function backTrace(trace)
|
||||||
|
while true do
|
||||||
|
local currentStep = trace[#trace]
|
||||||
|
applyFillSinglesRepeatedly(currentStep.board)
|
||||||
|
local ok, finished = checkBoard(currentStep.board)
|
||||||
|
if not ok then rollBack(trace); goto endOfTheLoop end
|
||||||
|
if finished then return currentStep.board end
|
||||||
|
local s = buildSearchSpace(currentStep.board)
|
||||||
|
ok = checkSearchSpace(currentStep.board, s)
|
||||||
|
if not ok then rollBack(trace); goto endOfTheLoop end
|
||||||
|
if not currentStep.pointer then
|
||||||
|
local x, y = findFirstLeastOption(s)
|
||||||
|
currentStep.options = s[x][y]
|
||||||
|
currentStep.pointer = 0
|
||||||
|
currentStep.x = x
|
||||||
|
currentStep.y = y
|
||||||
|
end
|
||||||
|
currentStep.pointer = currentStep.pointer + 1
|
||||||
|
if currentStep.pointer > #currentStep.options then rollBack(trace); goto endOfTheLoop end
|
||||||
|
local nextStep = {}
|
||||||
|
nextStep.board = cloneBoard(currentStep.board)
|
||||||
|
nextStep.board[currentStep.x][currentStep.y] = currentStep.options[currentStep.pointer]
|
||||||
|
trace[#trace+1] = nextStep
|
||||||
|
::endOfTheLoop::
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function rollBack(trace)
|
||||||
|
assert(#trace > 1, "Something is very wrong!")
|
||||||
|
table.remove(trace)
|
||||||
|
end
|
||||||
|
|
||||||
|
function solve(board)
|
||||||
|
local t = {}
|
||||||
|
t[1] = {board=cloneBoard(board),}
|
||||||
|
return backTrace(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
loadBoard = loadBoard,
|
||||||
|
cloneBoard = cloneBoard,
|
||||||
|
createEmptyBoard = createEmptyBoard,
|
||||||
|
calCellValidOptions = calCellValidOptions,
|
||||||
|
checkBoard = checkBoard,
|
||||||
|
applyFillSinglesRepeatedly = applyFillSinglesRepeatedly,
|
||||||
|
showBoard = showBoard,
|
||||||
|
checkBoardsEqual = checkBoardsEqual,
|
||||||
|
saveBoard = saveBoard,
|
||||||
|
solve = solve,
|
||||||
|
}
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
function find(array, element)
|
|
||||||
local index = 0
|
|
||||||
for i = 1, #array do
|
|
||||||
if array[i] == element then
|
|
||||||
index = i
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return index
|
|
||||||
end
|
|
||||||
|
|
||||||
function showBoard(board)
|
|
||||||
for row = 1, 9 do
|
|
||||||
print(table.concat(board[row], " "))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function cloneBoard(b)
|
|
||||||
local c = {}
|
|
||||||
for i = 1, 9 do
|
|
||||||
c[i] = {}
|
|
||||||
for j = 1, 9 do
|
|
||||||
c[i][j] = b[i][j]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
|
|
||||||
function loadBoard(fn)
|
|
||||||
local problem = {}
|
|
||||||
local solution = {}
|
|
||||||
local board = problem
|
|
||||||
local r = 0
|
|
||||||
for line in io.lines(fn) do
|
|
||||||
if line:gsub("%s+", "") == "" then
|
|
||||||
board = solution
|
|
||||||
r = 0
|
|
||||||
else
|
|
||||||
r = r + 1
|
|
||||||
local c = 0
|
|
||||||
board[r] = {}
|
|
||||||
for item in line:gmatch("%w+") do
|
|
||||||
c = c + 1
|
|
||||||
board[r][c] = tonumber(item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return problem, solution
|
|
||||||
end
|
|
@ -1,23 +1,65 @@
|
|||||||
function table2string(t)
|
|
||||||
local myself = table2string
|
|
||||||
local l = {}
|
|
||||||
local n = 0
|
|
||||||
for k, v in pairs(t) do
|
|
||||||
n = n + 1
|
|
||||||
if type(v) == "table" then
|
|
||||||
l[n] = k .. ': ' .. myself(v)
|
|
||||||
elseif type(v) == "string" then
|
|
||||||
l[n] = k .. ': ' .. '"' .. v .. '"'
|
|
||||||
else
|
|
||||||
l[n] = k .. ': ' .. v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return "{" .. table.concat(l, ", ") .. "}"
|
|
||||||
end
|
|
||||||
|
|
||||||
SudokuCanvas = {}
|
SudokuCanvas = {}
|
||||||
SudokuCanvas.__index = SudokuCanvas
|
SudokuCanvas.__index = SudokuCanvas
|
||||||
|
|
||||||
|
function SudokuCanvas:pushHistory()
|
||||||
|
if #self.history <= 1 then
|
||||||
|
table.insert(self.history, sudoku.cloneBoard(self.board[2]))
|
||||||
|
-- showHistory(self)
|
||||||
|
-- print("pushHistory: ", #self.history)
|
||||||
|
elseif not sudoku.checkBoardsEqual(self.board[2], self.history[#self.history]) then
|
||||||
|
table.insert(self.history, sudoku.cloneBoard(self.board[2]))
|
||||||
|
-- showHistory(self)
|
||||||
|
-- print("pushHistory: ", #self.history)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function showHistory(self)
|
||||||
|
for i, v in ipairs(self.history) do
|
||||||
|
print(string.format("-- [%03d] ----------", i))
|
||||||
|
sudoku.showBoard(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function undo(self)
|
||||||
|
if #self.history > 1 then
|
||||||
|
showHistory(self)
|
||||||
|
table.remove(self.history)
|
||||||
|
self.board[2] = sudoku.cloneBoard(self.history[#self.history])
|
||||||
|
self.board[3] = sudoku.cloneBoard(self.board[2])
|
||||||
|
|
||||||
|
-- self.board[2] = sudoku.cloneBoard(self.history[#self.history])
|
||||||
|
-- self.history[#self.history] = nil
|
||||||
|
|
||||||
|
self:checkBoard(true)
|
||||||
|
print"-------------------------------------------"
|
||||||
|
showHistory(self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function applyAllSingles(self)
|
||||||
|
sudoku.applyFillSinglesRepeatedly(self.board[2])
|
||||||
|
self.board[3] = sudoku.cloneBoard(self.board[2])
|
||||||
|
self:checkBoard()
|
||||||
|
end
|
||||||
|
|
||||||
|
function showValidOptionsForCurrentCell(self, x, y)
|
||||||
|
local s = sudoku.calCellValidOptions(self.board[2], y, x)
|
||||||
|
for num = 1, 9 do
|
||||||
|
self.smallNumbers[x][y][num].enabled = false
|
||||||
|
end
|
||||||
|
for _, num in ipairs(s) do
|
||||||
|
self.smallNumbers[x][y][num].enabled = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function showValidOptionsForAllCells(self)
|
||||||
|
for x = 1, 9 do
|
||||||
|
for y = 1, 9 do
|
||||||
|
showValidOptionsForCurrentCell(self, x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function selectSmallNumbersFont(cellSize)
|
local function selectSmallNumbersFont(cellSize)
|
||||||
local fntSize = 65
|
local fntSize = 65
|
||||||
local margin = 0
|
local margin = 0
|
||||||
@ -187,9 +229,11 @@ end
|
|||||||
function SudokuCanvas:setBoard(board, board2)
|
function SudokuCanvas:setBoard(board, board2)
|
||||||
local board2 = board2 or board
|
local board2 = board2 or board
|
||||||
self.board = {}
|
self.board = {}
|
||||||
self.board[1] = cloneBoard(board)
|
self.board[1] = sudoku.cloneBoard(board)
|
||||||
self.board[2] = cloneBoard(board2)
|
self.board[2] = sudoku.cloneBoard(board2)
|
||||||
self.board[3] = cloneBoard(board2)
|
self.board[3] = sudoku.cloneBoard(board2)
|
||||||
|
-- self.board[4] = createEmptyBoard()
|
||||||
|
self:checkBoard()
|
||||||
end
|
end
|
||||||
|
|
||||||
function SudokuCanvas:new(x, y, size, options)
|
function SudokuCanvas:new(x, y, size, options)
|
||||||
@ -208,6 +252,7 @@ function SudokuCanvas:new(x, y, size, options)
|
|||||||
colors = options.colors,
|
colors = options.colors,
|
||||||
enabled = true,
|
enabled = true,
|
||||||
focused = true,
|
focused = true,
|
||||||
|
history = {},
|
||||||
}
|
}
|
||||||
o.grid = buildGrid(x, y, cellSize)
|
o.grid = buildGrid(x, y, cellSize)
|
||||||
o.smallNumbers = calSmallNumbersCoordinates(o.grid)
|
o.smallNumbers = calSmallNumbersCoordinates(o.grid)
|
||||||
@ -225,6 +270,16 @@ end
|
|||||||
function SudokuCanvas:focus()
|
function SudokuCanvas:focus()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SudokuCanvas:checkBoard(hist)
|
||||||
|
if not hist then self:pushHistory() end
|
||||||
|
local ok, isComplete, conflictList = sudoku.checkBoard(self.board[2])
|
||||||
|
self.board[4] = sudoku.createEmptyBoard()
|
||||||
|
for _, c in ipairs(conflictList) do
|
||||||
|
self.board[4][c.x1][c.y1] = 1
|
||||||
|
self.board[4][c.x2][c.y2] = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function SudokuCanvas:draw()
|
function SudokuCanvas:draw()
|
||||||
local grid = self.grid
|
local grid = self.grid
|
||||||
|
|
||||||
@ -270,14 +325,22 @@ function SudokuCanvas:draw()
|
|||||||
local px = self.bigNumbers[x][y][num].typed.x
|
local px = self.bigNumbers[x][y][num].typed.x
|
||||||
local py = self.bigNumbers[x][y][num].typed.y
|
local py = self.bigNumbers[x][y][num].typed.y
|
||||||
love.graphics.setFont(self.bigNumbers.typedFont)
|
love.graphics.setFont(self.bigNumbers.typedFont)
|
||||||
uiUtils.setColor(self.colors.bigNumbersTyped)
|
if self.board[4][y][x] ~= 0 then
|
||||||
|
uiUtils.setColor(self.colors.bigNumbersError)
|
||||||
|
else
|
||||||
|
uiUtils.setColor(self.colors.bigNumbersTyped)
|
||||||
|
end
|
||||||
love.graphics.print(tostring(num), px, py)
|
love.graphics.print(tostring(num), px, py)
|
||||||
elseif self.board[2][y][x] ~= 0 then
|
elseif self.board[2][y][x] ~= 0 then
|
||||||
local num = self.board[2][y][x]
|
local num = self.board[2][y][x]
|
||||||
local px = self.bigNumbers[x][y][num].handWritten.x
|
local px = self.bigNumbers[x][y][num].handWritten.x
|
||||||
local py = self.bigNumbers[x][y][num].handWritten.y
|
local py = self.bigNumbers[x][y][num].handWritten.y
|
||||||
love.graphics.setFont(self.bigNumbers.handWrittenFont)
|
love.graphics.setFont(self.bigNumbers.handWrittenFont)
|
||||||
uiUtils.setColor(self.colors.bigNumbersHandWritten)
|
if self.board[4][y][x] ~= 0 then
|
||||||
|
uiUtils.setColor(self.colors.bigNumbersError)
|
||||||
|
else
|
||||||
|
uiUtils.setColor(self.colors.bigNumbersHandWritten)
|
||||||
|
end
|
||||||
love.graphics.print(tostring(num), px, py)
|
love.graphics.print(tostring(num), px, py)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -315,17 +378,25 @@ function SudokuCanvas:keypressed(key)
|
|||||||
local num = key:byte() - 48
|
local num = key:byte() - 48
|
||||||
if self.board[1][y][x] == 0 then
|
if self.board[1][y][x] == 0 then
|
||||||
if mode == "big" then
|
if mode == "big" then
|
||||||
self.board[2][y][x] = num
|
if self.board[2][y][x] == num then
|
||||||
self.board[3][y][x] = num
|
self.board[2][y][x] = 0
|
||||||
|
self.board[3][y][x] = 0
|
||||||
|
else
|
||||||
|
self.board[2][y][x] = num
|
||||||
|
self.board[3][y][x] = num
|
||||||
|
end
|
||||||
|
-- self:checkBoard()
|
||||||
else
|
else
|
||||||
self.smallNumbers[x][y][num].enabled = not self.smallNumbers[x][y][num].enabled
|
self.smallNumbers[x][y][num].enabled = not self.smallNumbers[x][y][num].enabled
|
||||||
end
|
end
|
||||||
|
self:checkBoard()
|
||||||
end
|
end
|
||||||
elseif key == "delete" or key == "0" then
|
elseif key == "delete" or key == "0" then
|
||||||
if self.board[1][y][x] == 0 then
|
if self.board[1][y][x] == 0 then
|
||||||
if mode == "big" then
|
if mode == "big" then
|
||||||
self.board[2][y][x] = 0
|
self.board[2][y][x] = 0
|
||||||
self.board[3][y][x] = 0
|
self.board[3][y][x] = 0
|
||||||
|
self:checkBoard()
|
||||||
else
|
else
|
||||||
for num = 1, 9 do
|
for num = 1, 9 do
|
||||||
self.smallNumbers[x][y][num].enabled = false
|
self.smallNumbers[x][y][num].enabled = false
|
||||||
@ -353,6 +424,18 @@ function SudokuCanvas:keypressed(key)
|
|||||||
self.board[2][y][x] = self.board[3][y][x]
|
self.board[2][y][x] = self.board[3][y][x]
|
||||||
mode = "big"
|
mode = "big"
|
||||||
end
|
end
|
||||||
|
elseif key == "s" then
|
||||||
|
-- showValidOptionsForCurrentCell(self, x, y)
|
||||||
|
showValidOptionsForAllCells(self)
|
||||||
|
elseif key == "a" then
|
||||||
|
applyAllSingles(self)
|
||||||
|
elseif key == "u" then
|
||||||
|
undo(self)
|
||||||
|
elseif key == "f" then
|
||||||
|
sudoku.saveBoard("lastBoard.txt", self.board[1], self.board[2])
|
||||||
|
elseif key == "c" then
|
||||||
|
self.board[2] = sudoku.solve(self.board[1])
|
||||||
|
self:checkBoard()
|
||||||
end
|
end
|
||||||
self.cursor.x = x
|
self.cursor.x = x
|
||||||
self.cursor.y = y
|
self.cursor.y = y
|
||||||
|
Loading…
Reference in New Issue
Block a user