Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
nrossol
Sudoku Backtracking
Commits
51c445e0
Commit
51c445e0
authored
Sep 02, 2021
by
nrossol
Browse files
Cleaned up code and comments.
parent
8a6c20f8
Changes
8
Hide whitespace changes
Inline
Side-by-side
.vscode/settings.json
deleted
100644 → 0
View file @
8a6c20f8
{
"files.associations"
:
{
"ostream"
:
"cpp"
,
"array"
:
"cpp"
,
"atomic"
:
"cpp"
,
"*.tcc"
:
"cpp"
,
"cctype"
:
"cpp"
,
"clocale"
:
"cpp"
,
"cmath"
:
"cpp"
,
"cstdarg"
:
"cpp"
,
"cstddef"
:
"cpp"
,
"cstdint"
:
"cpp"
,
"cstdio"
:
"cpp"
,
"cstdlib"
:
"cpp"
,
"cwchar"
:
"cpp"
,
"cwctype"
:
"cpp"
,
"deque"
:
"cpp"
,
"unordered_map"
:
"cpp"
,
"vector"
:
"cpp"
,
"exception"
:
"cpp"
,
"algorithm"
:
"cpp"
,
"map"
:
"cpp"
,
"memory"
:
"cpp"
,
"memory_resource"
:
"cpp"
,
"optional"
:
"cpp"
,
"set"
:
"cpp"
,
"string"
:
"cpp"
,
"string_view"
:
"cpp"
,
"system_error"
:
"cpp"
,
"tuple"
:
"cpp"
,
"type_traits"
:
"cpp"
,
"utility"
:
"cpp"
,
"fstream"
:
"cpp"
,
"initializer_list"
:
"cpp"
,
"iosfwd"
:
"cpp"
,
"iostream"
:
"cpp"
,
"istream"
:
"cpp"
,
"limits"
:
"cpp"
,
"new"
:
"cpp"
,
"sstream"
:
"cpp"
,
"stdexcept"
:
"cpp"
,
"streambuf"
:
"cpp"
,
"typeinfo"
:
"cpp"
},
"python.pythonPath"
:
"/usr/bin/python3"
}
\ No newline at end of file
README.txt
View file @
51c445e0
Project Author: Nathan Rossol, Computer Science
sophom
or
e
at the University of Michigan
Project Author: Nathan Rossol, Computer Science
juni
or at the University of Michigan
Project Description: The program will solve a given 9x9 sudoku puzzle using a recursive and backtracking algorithm.
Originally, this was implemented in C++, but was then moved over to Python in order to create
a GUI using pygame.
I included the C++ code due to this reason.
a
simple
GUI using pygame.
Python Version w/GUI Usage:
- Make sure you have the pygame module installed on your computer and run gui.py through your terminal.
- Ensure that gui.py and sudokuSolver.py are in the same directory!
- sudokuSolver.py will not run on its own since gui.py supplies the grid to be solved.
C++ Version:
- Compile sudokuSolver.cpp with g++
- Type: ./{executable_name} {grid_num}
- grid_num is between 1 and 3 inclusive.
\ No newline at end of file
Usage:
- Make sure you have PyGame and numpy installed and run gui.py through your terminal.
- Clicking a box containing a zero will solve that single square. Clicking the solve button will solve the entire grid.
__pycache__/sudokuSolver.cpython-38.pyc
0 → 100755
View file @
51c445e0
File added
__pycache__/sudokuSolverPython.cpython-36.pyc
deleted
100644 → 0
View file @
8a6c20f8
File deleted
__pycache__/sudokuSolverPython.cpython-38.pyc
deleted
100644 → 0
View file @
8a6c20f8
File deleted
gui.py
View file @
51c445e0
#GUI for sudoku solver by Nathan Rossol, Computer Science
sophom
or
e
at the University of Michigan
from
sudokuSolver
Python
import
s
olveS
udoku
,
s
olve
#GUI for sudoku solver by Nathan Rossol, Computer Science
juni
or at the University of Michigan
from
sudokuSolver
import
sudoku
S
olve
r
import
pygame
import
numpy
as
np
import
os
tempG
rid
=
[
[
3
,
2
,
1
,
0
,
5
,
0
,
9
,
4
,
7
],
g
rid
=
[
[
3
,
2
,
1
,
0
,
5
,
0
,
9
,
4
,
7
],
[
7
,
8
,
0
,
0
,
1
,
0
,
0
,
6
,
5
],
[
0
,
0
,
6
,
7
,
0
,
4
,
1
,
0
,
0
],
[
5
,
4
,
9
,
0
,
0
,
0
,
7
,
8
,
6
],
...
...
@@ -13,17 +14,9 @@ tempGrid = [ [ 3, 2, 1, 0, 5, 0, 9, 4, 7 ],
[
0
,
3
,
0
,
2
,
0
,
7
,
0
,
5
,
0
],
[
2
,
0
,
7
,
0
,
4
,
0
,
8
,
0
,
3
]
]
solvedGrid
=
[
[
3
,
2
,
1
,
0
,
5
,
0
,
9
,
4
,
7
],
[
7
,
8
,
0
,
0
,
1
,
0
,
0
,
6
,
5
],
[
0
,
0
,
6
,
7
,
0
,
4
,
1
,
0
,
0
],
[
5
,
4
,
9
,
0
,
0
,
0
,
7
,
8
,
6
],
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
9
,
0
,
6
,
0
,
0
,
0
],
[
1
,
0
,
5
,
0
,
6
,
0
,
4
,
0
,
2
],
[
0
,
3
,
0
,
2
,
0
,
7
,
0
,
5
,
0
],
[
2
,
0
,
7
,
0
,
4
,
0
,
8
,
0
,
3
]
]
solve
(
solvedGrid
)
gridToSolve
=
np
.
copy
(
grid
)
solver
=
sudokuSolver
()
solver
.
solve
(
gridToSolve
)
#Basic Colors:
BLACK
=
(
0
,
0
,
0
)
...
...
@@ -74,16 +67,14 @@ while not done:
if
pos
[
1
]
<
screen_height
:
#grid clicked
row
=
int
(
pos
[
0
]
/
(
box_size
+
margin
))
col
=
int
(
pos
[
1
]
/
(
box_size
+
margin
))
tempGrid
[
row
][
col
]
=
solvedGrid
[
row
][
col
]
print
(
"Grid Clicked"
)
grid
[
row
][
col
]
=
gridToSolve
[
row
][
col
]
elif
(
pos
[
1
]
>=
510
and
pos
[
1
]
<=
570
)
and
(
pos
[
0
]
>=
170
and
pos
[
0
]
<=
320
):
tempGrid
=
solvedGrid
print
(
"Solve Button Clicked"
)
grid
=
gridToSolve
#fill in grid:
for
i
in
range
(
0
,
9
):
for
j
in
range
(
0
,
9
):
number_surface
=
font
.
render
(
str
(
tempG
rid
[
i
][
j
]),
False
,
(
0
,
0
,
0
))
number_surface
=
font
.
render
(
str
(
g
rid
[
i
][
j
]),
False
,
(
0
,
0
,
0
))
screen
.
blit
(
number_surface
,
(
7
+
i
*
(
box_size
+
margin
),
7
+
j
*
(
box_size
+
margin
)))
#update display
...
...
sudokuSolver.cpp
deleted
100644 → 0
View file @
8a6c20f8
//Recursive backtracking algorithm that can solve any sudoku puzzle.
//Created by Nathan Rossol 8/16/20
#include <iostream>
#include <map>
#include <set>
//Main Algorithm:
bool
solveSudoku
(
int
(
&
grid
)[
9
][
9
]);
//Helper Functions:
bool
checkBox
(
const
int
(
&
grid
)[
9
][
9
],
const
int
&
row
,
const
int
&
col
);
bool
checkSolution
(
const
int
(
&
grid
)[
9
][
9
],
const
int
&
row
,
const
int
&
col
);
bool
findZero
(
const
int
(
&
grid
)[
9
][
9
],
std
::
pair
<
int
,
int
>
&
zeroIndex
);
void
printBoard
(
const
int
(
&
grid
)[
9
][
9
]);
void
solve
(
int
(
&
grid
)[
9
][
9
]);
/////////Main/////////
int
main
(
int
argc
,
char
*
argv
[])
{
//basic error checking:
if
(
argc
!=
2
){
std
::
cout
<<
"[ERROR] Correct Use: ./sudokuSolver.exe [grid number 1-3]"
<<
std
::
endl
;
return
-
1
;
}
std
::
string
arg
=
argv
[
1
];
if
(
arg
!=
"1"
&&
arg
!=
"2"
&&
arg
!=
"3"
)
{
std
::
cout
<<
"[ERROR] Correct Use: ./sudokuSolver.exe [grid number 1-3]"
<<
std
::
endl
;
return
-
1
;
}
//grid selection:
if
(
arg
==
"1"
){
int
grid
[
9
][
9
]
=
{
{
3
,
2
,
1
,
0
,
5
,
0
,
9
,
4
,
7
},
{
7
,
8
,
0
,
0
,
1
,
0
,
0
,
6
,
5
},
{
0
,
0
,
6
,
7
,
0
,
4
,
1
,
0
,
0
},
{
5
,
4
,
9
,
0
,
0
,
0
,
7
,
8
,
6
},
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
},
{
0
,
0
,
0
,
9
,
0
,
6
,
0
,
0
,
0
},
{
1
,
0
,
5
,
0
,
6
,
0
,
4
,
0
,
2
},
{
0
,
3
,
0
,
2
,
0
,
7
,
0
,
5
,
0
},
{
2
,
0
,
7
,
0
,
4
,
0
,
8
,
0
,
3
}
};
solve
(
grid
);
}
else
if
(
arg
==
"2"
){
int
grid
[
9
][
9
]
=
{
{
1
,
0
,
0
,
3
,
0
,
0
,
0
,
8
,
0
},
{
3
,
0
,
0
,
9
,
0
,
0
,
6
,
0
,
0
},
{
0
,
0
,
0
,
7
,
4
,
8
,
1
,
0
,
5
},
{
4
,
2
,
6
,
0
,
0
,
0
,
7
,
0
,
0
},
{
0
,
7
,
8
,
4
,
0
,
9
,
3
,
6
,
0
},
{
0
,
0
,
3
,
0
,
0
,
0
,
4
,
5
,
8
},
{
2
,
0
,
1
,
8
,
9
,
4
,
0
,
0
,
0
},
{
0
,
0
,
4
,
0
,
0
,
6
,
0
,
0
,
9
},
{
0
,
3
,
0
,
0
,
0
,
5
,
0
,
0
,
6
}
};
solve
(
grid
);
}
else
if
(
arg
==
"3"
){
int
grid
[
9
][
9
]
=
{
{
0
,
0
,
0
,
4
,
9
,
0
,
1
,
5
,
0
},
{
2
,
9
,
0
,
7
,
1
,
0
,
6
,
8
,
0
},
{
6
,
1
,
0
,
0
,
8
,
0
,
0
,
0
,
0
},
{
0
,
0
,
0
,
1
,
0
,
7
,
0
,
2
,
6
},
{
9
,
3
,
2
,
0
,
0
,
0
,
4
,
7
,
1
},
{
1
,
7
,
0
,
9
,
0
,
4
,
0
,
0
,
0
},
{
0
,
0
,
0
,
0
,
7
,
0
,
0
,
6
,
4
},
{
0
,
6
,
9
,
0
,
4
,
3
,
0
,
1
,
5
},
{
0
,
2
,
3
,
0
,
5
,
1
,
0
,
0
,
0
}
};
solve
(
grid
);
}
return
0
;
}
/////////Main Solving Algorithm/////////
//Sudoku rules: The grid has 81 squares: 9 boxes of 9 squares. Each box must contain
//all numbers 1-9 in its squares, and each number can appear only once in any row,
//column, or box.
bool
solveSudoku
(
int
(
&
grid
)[
9
][
9
]){
std
::
pair
<
int
,
int
>
zeroIndex
;
//row,col of the zero to be filled.
bool
foundZero
=
findZero
(
grid
,
zeroIndex
);
bool
solved
;
if
(
foundZero
){
for
(
int
i
=
1
;
i
<
10
;
++
i
){
grid
[
zeroIndex
.
first
][
zeroIndex
.
second
]
=
i
;
if
(
checkSolution
(
grid
,
zeroIndex
.
first
,
zeroIndex
.
second
)){
// std::cout<< zeroIndex.first << ", " << zeroIndex.second << " == " << grid[zeroIndex.first][zeroIndex.second] << std::endl;
solved
=
solveSudoku
(
grid
);
if
(
solved
)
{
return
true
;}
}
}
grid
[
zeroIndex
.
first
][
zeroIndex
.
second
]
=
0
;
return
false
;
}
else
{
return
true
;
//solved
}
}
/////////Helper functions/////////
//checks the boxes to assure no duplicate numbers
bool
checkBox
(
const
int
(
&
grid
)[
9
][
9
],
const
int
&
row
,
const
int
&
col
){
std
::
set
<
int
>
numbers
;
for
(
int
i
=
0
;
i
<
3
;
++
i
){
for
(
int
j
=
0
;
j
<
3
;
++
j
){
//std::cout << "ROW, COL: " << row+i << " ," << col + j << std::endl;
if
(
numbers
.
insert
(
grid
[
row
+
i
][
col
+
j
]).
second
==
false
&&
grid
[
row
+
i
][
col
+
j
]
!=
0
)
{
//duplicate detected!
//std::cout << "DUPLICATE!" << std::endl;
return
false
;
}
}
}
return
true
;
}
//checks the solution for a given index and returns true if valid.
bool
checkSolution
(
const
int
(
&
grid
)[
9
][
9
],
const
int
&
row
,
const
int
&
col
){
//check cols and rows:
for
(
int
i
=
0
;
i
<
9
;
++
i
){
if
(
grid
[
i
][
col
]
==
grid
[
row
][
col
]
&&
i
!=
row
)
{
return
false
;
}
else
if
(
grid
[
row
][
i
]
==
grid
[
row
][
col
]
&&
i
!=
col
){
return
false
;
}
}
//check boxes:
for
(
int
i
=
0
;
i
<
9
;
i
+=
3
){
for
(
int
j
=
0
;
j
<
9
;
j
+=
3
){
if
(
!
checkBox
(
grid
,
i
,
j
))
{
return
false
;}
}
}
return
true
;
}
//Finds the index of the next zero to be solved.
bool
findZero
(
const
int
(
&
grid
)[
9
][
9
],
std
::
pair
<
int
,
int
>
&
zeroIndex
){
for
(
int
i
=
0
;
i
<
9
;
++
i
){
for
(
int
j
=
0
;
j
<
9
;
++
j
){
if
(
grid
[
i
][
j
]
==
0
)
{
zeroIndex
.
first
=
i
;
zeroIndex
.
second
=
j
;
return
true
;
}
}
}
return
false
;
}
//Prints the board.
void
printBoard
(
const
int
(
&
grid
)[
9
][
9
]){
for
(
int
i
=
0
;
i
<
9
;
++
i
){
for
(
int
j
=
0
;
j
<
9
;
++
j
){
std
::
cout
<<
grid
[
i
][
j
]
<<
" "
;
}
std
::
cout
<<
std
::
endl
;
}
}
//Executes the algorithm:
void
solve
(
int
(
&
grid
)[
9
][
9
])
{
if
(
solveSudoku
(
grid
)
==
true
)
{
std
::
cout
<<
"Solved!"
<<
std
::
endl
;}
else
{
std
::
cout
<<
"Unsolvable :("
<<
std
::
endl
;}
printBoard
(
grid
);
}
sudokuSolver.py
View file @
51c445e0
#Recursive/backtracking algorithm to solve sudoku puzzle if possible.
#By Nathan Rossol, Computer Science
sophom
or
e
at the University of Michigan
#By Nathan Rossol, Computer Science
juni
or at the University of Michigan
#TO RUN THIS PROGRAM: Instal pygame and use terminal to run gui.py. Make sure this file and gui.py
#are in the same directory.
...
...
@@ -7,86 +7,71 @@
#Game rules: The grid has 81 squares: 9 boxes of 9 squares. Each box must contain
#all numbers 1-9 in its squares, and each number can appear only once in any row,
#column, or box.
def
solveSudoku
(
grid
):
zeroIndex
=
[
0
,
0
]
foundZero
=
findZero
(
grid
,
zeroIndex
)
#print(foundZero),
#print(zeroIndex[0]),
#print(zeroIndex[1])
solved
=
False
if
foundZero
:
for
i
in
range
(
1
,
10
):
grid
[
zeroIndex
[
0
]][
zeroIndex
[
1
]]
=
i
if
(
checkSolution
(
grid
,
zeroIndex
[
0
],
zeroIndex
[
1
])):
solved
=
solveSudoku
(
grid
)
if
(
solved
):
return
True
class
sudokuSolver
:
grid
[
zeroIndex
[
0
]][
zeroIndex
[
1
]]
=
0
return
False
#Check a single 3x3 box to ensure that it is solved.
def
checkBox
(
self
,
grid
,
row
,
col
):
numbers
=
[]
for
i
in
range
(
row
,
row
+
3
):
for
j
in
range
(
col
,
col
+
3
):
if
grid
[
i
][
j
]
not
in
numbers
and
grid
[
i
][
j
]
!=
0
:
numbers
.
insert
(
0
,
grid
[
i
][
j
])
elif
grid
[
i
][
j
]
in
numbers
and
grid
[
i
][
j
]
!=
0
:
return
False
else
:
return
True
def
checkBox
(
grid
,
row
,
col
):
numbers
=
[]
for
i
in
range
(
row
,
row
+
3
):
for
j
in
range
(
col
,
col
+
3
):
if
grid
[
i
][
j
]
not
in
numbers
and
grid
[
i
][
j
]
!=
0
:
numbers
.
insert
(
0
,
grid
[
i
][
j
])
elif
grid
[
i
][
j
]
in
numbers
and
grid
[
i
][
j
]
!=
0
:
#print("CheckBox FAILED")
#Check the entire board.
def
checkSolution
(
self
,
grid
,
row
,
col
):
#check cols and rows:
for
i
in
range
(
0
,
9
):
if
grid
[
i
][
col
]
==
grid
[
row
][
col
]
and
i
!=
row
:
return
False
elif
grid
[
row
][
i
]
==
grid
[
row
][
col
]
and
i
!=
col
:
return
False
#check boxes:
for
i
in
range
(
0
,
9
,
3
):
for
j
in
range
(
0
,
9
,
3
):
if
not
self
.
checkBox
(
grid
,
i
,
j
):
return
False
return
True
return
True
#find the next zero to solve
def
findZero
(
self
,
grid
,
zeroIndex
):
for
r
in
range
(
len
(
grid
)):
for
c
in
range
(
len
(
grid
[
r
])):
if
grid
[
r
][
c
]
==
0
:
zeroIndex
[
0
]
=
r
zeroIndex
[
1
]
=
c
return
True
return
False
def
checkSolution
(
grid
,
row
,
col
):
#check cols and rows:
for
i
in
range
(
0
,
9
):
if
grid
[
i
][
col
]
==
grid
[
row
][
col
]
and
i
!=
row
:
#print("ROW ALREADY CONTAINS")
#print the board
def
printBoard
(
self
,
grid
):
for
i
in
range
(
0
,
9
):
for
j
in
range
(
0
,
9
):
print
(
grid
[
i
][
j
],
end
=
' '
),
print
(
""
)
#main algorithm to solve the puzzle
def
solve
(
self
,
grid
):
zeroIndex
=
[
0
,
0
]
foundZero
=
self
.
findZero
(
grid
,
zeroIndex
)
solved
=
False
if
foundZero
:
for
i
in
range
(
1
,
10
):
grid
[
zeroIndex
[
0
]][
zeroIndex
[
1
]]
=
i
if
(
self
.
checkSolution
(
grid
,
zeroIndex
[
0
],
zeroIndex
[
1
])):
solved
=
self
.
solve
(
grid
)
if
(
solved
):
return
True
grid
[
zeroIndex
[
0
]][
zeroIndex
[
1
]]
=
0
return
False
elif
grid
[
row
][
i
]
==
grid
[
row
][
col
]
and
i
!=
col
:
#print("COL ALREADY CONTAINS")
return
False
#check boxes:
for
i
in
range
(
0
,
9
,
3
):
for
j
in
range
(
0
,
9
,
3
):
#print(i),
#print(j)
if
not
checkBox
(
grid
,
i
,
j
):
return
False
#print("PASSED")
return
True
def
findZero
(
grid
,
zeroIndex
):
for
r
in
range
(
len
(
grid
)):
for
c
in
range
(
len
(
grid
[
r
])):
if
grid
[
r
][
c
]
==
0
:
zeroIndex
[
0
]
=
r
zeroIndex
[
1
]
=
c
return
True
return
False
def
printBoard
(
grid
):
for
i
in
range
(
0
,
9
):
for
j
in
range
(
0
,
9
):
print
(
grid
[
i
][
j
],
end
=
' '
),
print
(
""
)
def
solve
(
grid
):
if
solveSudoku
(
grid
):
print
(
"Solveable :)!"
)
else
:
print
(
"Unsolvable :("
)
#printBoard(grid)
#
return
grid;
else
:
return
True
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment