Compare commits

..

No commits in common. "e57dcce50c03c094c00af74e5ae565762d37ceb8" and "670027c119f300b713d059567267a382d8b01833" have entirely different histories.

5 changed files with 59 additions and 190 deletions

View File

@ -1,13 +1,5 @@
# sudoku-solver # sudoku-solver
## Notes
Uses a single sudoku file as input
Tests were ran on sudoku-easy-50 split into individual files
All were successfully solved
## Compiling the project ## Compiling the project
Prerequisites Prerequisites
@ -26,10 +18,6 @@ Simply run the program using:
build/bin/sudoku build/bin/sudoku
## Testing the Project ## Testing the Project
Prerequisites
- Unity (Throw the Switch)
In order to compile the tests for the project, simply run these two commands: In order to compile the tests for the project, simply run these two commands:
cmake -DCMAKE_BUILD_TYPE=Debug -B build -S . cmake -DCMAKE_BUILD_TYPE=Debug -B build -S .
@ -39,4 +27,4 @@ The program should now be compiled at ./build/bin/sudoku
Simply run the tests using: Simply run the tests using:
build/bin/testing build/bin/sudoku-test

View File

@ -15,133 +15,71 @@ void Sudoku::FillBoard(std::string filePath) {
exit(1); exit(1);
} }
std::string line; std::string line;
int height = 0; while (!sudokuFile.eof()) {
while (!sudokuFile.eof() && height < 9) {
sudokuFile >> line; sudokuFile >> line;
for (int i = 0; i < 9; ++i) { board[height][i] = line[i] - '0'; } std::cout << line << std::endl;
++height;
} }
// TODO: Finish inputting sudoku file
// Really just needs to be split by digit then stored
} }
// Base global call for solving // TODO: Implement solving algorithm
void Sudoku::Solve(void) { void Sudoku::Solve(void) {
_Solve();
} }
// TODO: Add checking for full board completion
bool Sudoku::IsBoardSolved(void) { bool Sudoku::IsBoardSolved(void) {
int column, row;
if (!FindEmptyCell(&column, &row)) { return true; }
return false;
}
void Sudoku::Print(void) {
std::cout << "===================" << std::endl;
for (auto i : board) {
std::cout << '|';
for (auto j : i) {
std::cout << j << '|';
}
std::cout << std::endl;
}
std::cout << "===================" << std::endl;
}
void Sudoku::RawPrint(void) {
for (auto i : board) {
for (auto j : i) {
std::cout << j;
}
std::cout << std::endl;
}
}
// Recursive call for solving
bool Sudoku::_Solve(void) {
int column, row;
if (!FindEmptyCell(&column, &row)) { return true; }
for (int i : GetUnusedRow(row)) {
for (int j : GetUnusedColumn(column)) {
for (int k : GetUnusedSubgrid(column, row)) {
if (i == j == k) {
board[row][column] = i;
if (_Solve()) { return true; }
board[row][column] = 0;
}
}
}
}
return 0;
}
// Fills column and row of an empty cell and returns true
// If no empty cell is found, return false
bool Sudoku::FindEmptyCell(int* column, int* row) {
for (*row = 0; *row < 9; ++(*row)) {
for (*column = 0; *column < 9; ++(*column)) {
if (board[*row][*column] == 0) { return true; }
}
}
return false;
}
bool Sudoku::IsValidPlacement(int column, int row, int box) {
// Check column and row
for (int i = 0; i < 9; ++i) {
if (board[row][i] == box || board[i][column] == box) {
return false;
}
}
// Check subgrid
int startRow = row - row % 3;
int startColumn = column - column % 3;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (board[startRow + i][startColumn + j] == box) { return false; }
}
}
return true; return true;
} }
std::vector<int> Sudoku::GetUnusedRow(int row) { // TODO: Add printing of board for visuals
std::vector<int> leftOver{0,1,2,3,4,5,6,7,8,9}; // Maybe also print during solve?
int box; void Sudoku::Print(void) {
for (int i = 0; i < 9; i++) {
box = board[row][i];
if (leftOver[box] == box) { leftOver[box] = 0; }
}
for (auto it = leftOver.begin(); it != leftOver.end();) {
if (*it == 0) { it = leftOver.erase(it); }
else { ++it; }
}
return leftOver;
} }
std::vector<int> Sudoku::GetUnusedColumn(int column) { // TODO: Add checking for row completion
std::vector<int> leftOver{0,1,2,3,4,5,6,7,8,9}; bool Sudoku::IsRowComplete(int row) {
int box; return true;
for (int i = 0; i < 9; i++) {
box = board[i][column];
if (leftOver[box] == box) { leftOver[box] = 0; }
}
for (auto it = leftOver.begin(); it != leftOver.end();) {
if (*it == 0) { it = leftOver.erase(it); }
else { ++it; }
}
return leftOver;
} }
std::vector<int> Sudoku::GetUnusedSubgrid(int column, int row) { // TODO: Add checking for column completion
bool Sudoku::IsColumnComplete(int column) {
return true;
}
// WARNING: This function and one below could be swapped, untested
std::vector<int> Sudoku::GetUnusedInRow(int row) {
std::vector<int> leftOver{0,1,2,3,4,5,6,7,8,9}; std::vector<int> leftOver{0,1,2,3,4,5,6,7,8,9};
int box; int number;
int startRow = row - row % 3; for (int i = 0; i < 9; i++) {
int startColumn = column - column % 3; number = board[i][row];
for (int i = 0; i < 3; ++i) { if (leftOver[number] == number) {
for (int j = 0; j < 3; ++j) { leftOver[number] = 0;
box = board[row][column]; }
if (board[startRow + i][startColumn + j] == box) { if (leftOver[number] == 0) { // Two of same number was placed
leftOver[box] = 0; leftOver[number] = -1;
} }
}
for (auto it = leftOver.begin(); it != leftOver.end();) {
if (*it == 0) { it = leftOver.erase(it); }
else { ++it; }
}
return leftOver;
}
std::vector<int> Sudoku::GetUnusedInColumn(int column) {
std::vector<int> leftOver{0,1,2,3,4,5,6,7,8,9};
int number;
for (int i = 0; i < 9; i++) {
number = board[column][i];
if (leftOver[number] == number) {
leftOver[number] = 0;
}
if (leftOver[number] == 0) { // Two of same number was placed
leftOver[number] = -1;
} }
} }
for (auto it = leftOver.begin(); it != leftOver.end();) { for (auto it = leftOver.begin(); it != leftOver.end();) {

View File

@ -12,14 +12,11 @@ public:
void Solve(void); void Solve(void);
bool IsBoardSolved(void); bool IsBoardSolved(void);
void Print(void); void Print(void);
void RawPrint(void);
private: private:
bool _Solve(void); bool IsRowComplete(int row);
bool FindEmptyCell(int* column, int* row); bool IsColumnComplete(int column);
bool IsValidPlacement(int column, int row, int box); std::vector<int> GetUnusedInRow(int row);
std::vector<int> GetUnusedRow(int row); std::vector<int> GetUnusedInColumn(int column);
std::vector<int> GetUnusedColumn(int column);
std::vector<int> GetUnusedSubgrid(int column, int row);
}; };
#endif #endif

View File

@ -1,14 +1,9 @@
#include "sudoku.hpp" #include "sudoku.hpp"
#include <iostream>
int main(int argc, char* argv[]) { // TODO:
if (argc != 2) { // Take in sudoku file from arguments
std::cerr << "Usage: " << argv[0] << " path/to/sudoku" << std::endl; // Run solve
return 1; // Print solution
} int main(void) {
Sudoku newGame;
newGame.FillBoard(argv[1]);
newGame.Solve();
newGame.RawPrint();
return 0; return 0;
} }

View File

@ -10,55 +10,6 @@ void tearDown() { ; }
int main(void) { int main(void) {
UNITY_BEGIN(); UNITY_BEGIN();
RUN_TEST(test_SudokuEasy01); RUN_TEST(test_SudokuEasy01);
RUN_TEST(test_SudokuEasy02);
RUN_TEST(test_SudokuEasy03);
RUN_TEST(test_SudokuEasy04);
RUN_TEST(test_SudokuEasy05);
RUN_TEST(test_SudokuEasy06);
RUN_TEST(test_SudokuEasy07);
RUN_TEST(test_SudokuEasy08);
RUN_TEST(test_SudokuEasy09);
RUN_TEST(test_SudokuEasy10);
RUN_TEST(test_SudokuEasy11);
RUN_TEST(test_SudokuEasy12);
RUN_TEST(test_SudokuEasy13);
RUN_TEST(test_SudokuEasy14);
RUN_TEST(test_SudokuEasy15);
RUN_TEST(test_SudokuEasy16);
RUN_TEST(test_SudokuEasy17);
RUN_TEST(test_SudokuEasy18);
RUN_TEST(test_SudokuEasy19);
RUN_TEST(test_SudokuEasy20);
RUN_TEST(test_SudokuEasy21);
RUN_TEST(test_SudokuEasy22);
RUN_TEST(test_SudokuEasy23);
RUN_TEST(test_SudokuEasy24);
RUN_TEST(test_SudokuEasy25);
RUN_TEST(test_SudokuEasy26);
RUN_TEST(test_SudokuEasy27);
RUN_TEST(test_SudokuEasy28);
RUN_TEST(test_SudokuEasy29);
RUN_TEST(test_SudokuEasy30);
RUN_TEST(test_SudokuEasy31);
RUN_TEST(test_SudokuEasy32);
RUN_TEST(test_SudokuEasy33);
RUN_TEST(test_SudokuEasy34);
RUN_TEST(test_SudokuEasy35);
RUN_TEST(test_SudokuEasy36);
RUN_TEST(test_SudokuEasy37);
RUN_TEST(test_SudokuEasy38);
RUN_TEST(test_SudokuEasy39);
RUN_TEST(test_SudokuEasy40);
RUN_TEST(test_SudokuEasy41);
RUN_TEST(test_SudokuEasy42);
RUN_TEST(test_SudokuEasy43);
RUN_TEST(test_SudokuEasy44);
RUN_TEST(test_SudokuEasy45);
RUN_TEST(test_SudokuEasy46);
RUN_TEST(test_SudokuEasy47);
RUN_TEST(test_SudokuEasy48);
RUN_TEST(test_SudokuEasy49);
RUN_TEST(test_SudokuEasy50);
return UNITY_END(); return UNITY_END();
} }