Commit 51c445e0 authored by nrossol's avatar nrossol
Browse files

Cleaned up code and comments.

parent 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
Project Author: Nathan Rossol, Computer Science sophomore at the University of Michigan
Project Author: Nathan Rossol, Computer Science junior 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.
#GUI for sudoku solver by Nathan Rossol, Computer Science sophomore at the University of Michigan
from sudokuSolverPython import solveSudoku, solve
#GUI for sudoku solver by Nathan Rossol, Computer Science junior at the University of Michigan
from sudokuSolver import sudokuSolver
import pygame
import numpy as np
import os
tempGrid = [ [ 3, 2, 1, 0, 5, 0, 9, 4, 7 ],
grid = [ [ 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(tempGrid[i][j]), False, (0,0,0))
number_surface = font.render(str(grid[i][j]), False, (0,0,0))
screen.blit(number_surface, (7 + i*(box_size + margin), 7 + j*(box_size + margin)))
#update display
......
//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);
}
#Recursive/backtracking algorithm to solve sudoku puzzle if possible.
#By Nathan Rossol, Computer Science sophomore at the University of Michigan
#By Nathan Rossol, Computer Science junior 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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment