Skip to content

Commit

Permalink
Add project files.
Browse files Browse the repository at this point in the history
  • Loading branch information
Simik31 committed Dec 28, 2021
1 parent 8fd88f2 commit 0dcc29e
Show file tree
Hide file tree
Showing 11 changed files with 646 additions and 0 deletions.
31 changes: 31 additions & 0 deletions Sudoku_CLI.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sudoku_CLI", "Sudoku_CLI\Sudoku_CLI.vcxproj", "{7DD30603-9CF4-4DFF-B8E2-5881E986964C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Debug|x64.ActiveCfg = Debug|x64
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Debug|x64.Build.0 = Debug|x64
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Debug|x86.ActiveCfg = Debug|Win32
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Debug|x86.Build.0 = Debug|Win32
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Release|x64.ActiveCfg = Release|x64
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Release|x64.Build.0 = Release|x64
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Release|x86.ActiveCfg = Release|Win32
{7DD30603-9CF4-4DFF-B8E2-5881E986964C}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E0FA3857-14A2-4097-B1C1-6E151A0AB389}
EndGlobalSection
EndGlobal
157 changes: 157 additions & 0 deletions Sudoku_CLI/Game.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include "Game.h"

void Game::main_menu()
{
int choice;
do
{
system("cls");
std::cout << "Welcome at SUDOKU CLI game.\nCopyright (C) 2021: Simik31 / https://github.com/Simik31/Sudoku_CLI / simik31@pm.me \n\n[1] Input sudoku by hand\n[2] Load sudoku from file\n[3] Load 'default' sudoku\n\n > ";
choice = std::cin.get() - 48;
} while (choice < 1 || choice > 3);

while (!this->loaded)
{
switch (choice)
{
case 1: this->load_by_hand(); break;
case 2: this->load_from_file(); break;
case 3: this->load_default(); break;
}
if (!this->loaded)
{
std::cout << "Press any key to repeat...";
_getch();
}
}
}

void Game::load_by_hand()
{
std::cout << "Enter sudoku by using arrows to navigate into cell and pressing corresponding number.\nWhen you are done enetering numbers, press Enter to start solving.\n\nPress any key to strart...";
_getch();

Utils::print_sudoku(this->sudoku);

Sudoku tmp;

while (true)
{
int fill = -1;

MOVE_CURSOR_TO_CELL(this->cursor_x, this->cursor_y);

int in = _getch();
switch (in)
{
case KEY_ENTER:
{
std::vector<int> init;
init.reserve(81);

for (int i = 0; i < 81; i++) init.push_back(Sudoku::get_state(tmp, i));

this->loaded = true;

return Utils::print_sudoku(this->sudoku = Sudoku(init));
};
case KEY_UP: this->cursor_y = WRAP(this->cursor_y - 1); break;
case KEY_RIGHT: this->cursor_x = WRAP(this->cursor_x + 1); break;
case KEY_DOWN: this->cursor_y = WRAP(this->cursor_y + 1); break;
case KEY_LEFT: this->cursor_x = WRAP(this->cursor_x - 1); break;
default: if (in >= 49 && in <= 57) tmp.fill_number(this->cursor_x, this->cursor_y, in - 48); // 49 = 1, 50 = 2, ... 57 = 9
}
}
}

void Game::load_from_file()
{
system("cls");
std::cout << "Please enter file path\n\n > ";
std::string path;
std::cin >> path;

std::vector<std::string> file_lines = Utils::read_lines_from_file(path);

if (file_lines.size() == 0)
{
std::cerr << "File not found or empty: " << std::filesystem::absolute(path) << std::endl;
return;
}
else if (file_lines.size() != 9)
{
std::cerr << "Sudoku must have exactly 9 lines. " << file_lines.size() << " given." << std::endl;
return;
}
else
{
for (int i = 0; i < 9; i++)
{
if (file_lines[i].size() != 9)
{
std::cerr << "Each sudoku line must have exactly 9 columns. On line " << (i + 1) << " only " << file_lines[i].size() << " columns given." << std::endl;
return;
}
}
}

std::vector<int> init;
init.reserve(81);

for (std::string line : file_lines)
for (char c : line)
init.push_back(c - '0');

this->sudoku = Sudoku(init);
this->loaded = true;
}

void Game::load_default()
{
int state[9][9]{
{ 0, 2, 0, 0, 0, 4, 3, 0, 0 },
{ 9, 0, 0, 0, 2, 0, 0, 0, 8 },
{ 0, 0, 0, 6, 0, 9, 0, 5, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 0, 7, 2, 5, 0, 3, 6, 8, 0 },
{ 6, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 8, 0, 2, 0, 5, 0, 0, 0 },
{ 1, 0, 0, 0, 9, 0, 0, 0, 3 },
{ 0, 0, 9, 8, 0, 0, 0, 6, 0 }
};

std::vector<int> init;
for (int (&row)[9] : state) for (int cell : row) init.push_back(cell);

this->sudoku = Sudoku(init);
this->loaded = true;
}

void Game::run()
{
if (!loaded) return;

Utils::print_sudoku(this->sudoku);

while (!this->sudoku.is_solved())
{
int fill = -1;

MOVE_CURSOR_TO_CELL(this->cursor_x, this->cursor_y);

int in = _getch();
switch (in)
{
case KEY_UP: this->cursor_y = WRAP(this->cursor_y - 1); break;
case KEY_RIGHT: this->cursor_x = WRAP(this->cursor_x + 1); break;
case KEY_DOWN: this->cursor_y = WRAP(this->cursor_y + 1); break;
case KEY_LEFT: this->cursor_x = WRAP(this->cursor_x - 1); break;
default: if (in >= 49 && in <= 57)
{
this->sudoku.fill_number(this->cursor_x, this->cursor_y, in - 48); // 49 = 1, 50 = 2, ... 57 = 9
this->sudoku.test_if_solved();
}
}

}
}
37 changes: 37 additions & 0 deletions Sudoku_CLI/Game.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once
#ifndef GAME_H
#define GAME_H

#define KEY_ENTER 13
#define KEY_UP 72
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_DOWN 80

#include <vector>
#include <iostream>
#include <conio.h>
#include <string>

#include "Sudoku.h"
#include "Utils.h"

class Game
{
public:
void main_menu();
void run();

private:
void load_by_hand();
void load_from_file();
void load_default();

bool loaded = false;
Sudoku sudoku;
int cursor_x = 0, cursor_y = 0;
};

#endif


87 changes: 87 additions & 0 deletions Sudoku_CLI/Sudoku.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "Sudoku.h"
#include "Utils.h"

Sudoku::Sudoku()
{
this->state.reserve(81);
this->initial.reserve(81);

for (int i = 0; i < 81; i++)
{
this->state.push_back(0);
this->initial.push_back(false);
}
}

Sudoku::Sudoku(const std::vector<int>& initial_state)
{
this->state = initial_state;
for (int state : initial_state) this->initial.push_back(state > 0);
}

bool Sudoku::is_solved()
{
return this->solved;
}

int Sudoku::get_state(const Sudoku& sudoku, const int index)
{
return sudoku.state[index];
}

bool Sudoku::get_initial(const Sudoku& sudoku, const int index)
{
return sudoku.initial[index];
}

void Sudoku::fill_number(const int cell_x, const int cell_y, const int number)
{
int index = cell_y * 9 + cell_x;

if (this->initial[index]) return;

this->state[index] = this->state[index] == number ? 0 : number;

Utils::print_sudoku(*this);
}

void Sudoku::test_if_solved()
{
if (std::find(this->state.begin(), this->state.end(), 0) != this->state.end()) return;

this->solved = true;

for (int y = 0; y < 9; y++)
for (int x1 = 0; x1 < 8; x1++)
for (int x2 = x1 + 1; x2 < 9; x2++)
if (this->state[y * 9 + x1] == this->state[y * 9 + x2])
{
Utils::highlight_cell(*this, x1, y);
Utils::highlight_cell(*this, x2, y);
this->solved = false;
}

for (int x = 0; x < 9; x++)
for (int y1 = 0; y1 < 8; y1++)
for (int y2 = y1 + 1; y2 < 9; y2++)
if (this->state[y1 * 9 + x] == this->state[y2 * 9 + x])
{
Utils::highlight_cell(*this, x, y1);
Utils::highlight_cell(*this, x, y2);
this->solved = false;
}

for (int y = 0; y < 3; y++)
for (int x = 0; x < 3; x++)
for (int oY1 = 0; oY1 < 3; oY1++)
for (int oX1 = 0; oX1 < 3; oX1++)
for (int oY2 = 0; oY2 < 3; oY2++)
for (int oX2 = 0; oX2 < 3; oX2++)
if ((oX1 == oX2 && oY1 == oY2) == false)
if (this->state[(y * 3 + oY1) * 9 + x * 3 + oX1] == this->state[(y * 3 + oY2) * 9 + x * 3 + oX2])
{
Utils::highlight_cell(*this, x * 3 + oX1, y * 3 + oY1);
Utils::highlight_cell(*this, x * 3 + oX2, y * 3 + oY2);
this->solved = false;
}
}
27 changes: 27 additions & 0 deletions Sudoku_CLI/Sudoku.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once
#ifndef SUDOKU_H
#define SUDOKU_H

#include <vector>

class Sudoku
{
public:
Sudoku();
Sudoku(const std::vector<int>& initial_state);

bool is_solved();
static int get_state(const Sudoku& sudoku, const int index);
static bool get_initial(const Sudoku& sudoku, const int index);

void fill_number(const int cell_x, const int cell_y, const int number);
void test_if_solved();

private:
bool solved = false;

std::vector<int> state;
std::vector<bool> initial;
};

#endif
9 changes: 9 additions & 0 deletions Sudoku_CLI/Sudoku_CLI.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "Game.h"


int main()
{
Game game;
game.main_menu();
game.run();
}
Loading

0 comments on commit 0dcc29e

Please sign in to comment.