<sub class="descriptionSection">11-11-2024 12:33:pm // #Tag // [[Programmierung]]</sub>
____
```cpp
#include <iomanip>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
bool isInRow(map<pair<int,int>, pair<int,bool>> field, int y, int x, int value) {
for(int i = 0; i < 9; i++) {
if(field[make_pair(i, y)].first == value && x != i) {
return true;
}
}
return false;
}
bool isInCol(map<pair<int,int>, pair<int,bool>> field, int y, int x, int value) {
for(int i = 0; i < 9; i++) {
if(field[make_pair(x, i)].first == value && y != i) {
return true;
}
}
return false;
}
bool isInQuadrant(map<pair<int,int>, pair<int,bool>> field, int y, int x, int value) {
//get the top left corner of the quadrant
int xStart = x - (x % 3);
int yStart = y - (y % 3);
for(int i = yStart; i < yStart + 3; i++) {
for(int j = xStart; j < xStart + 3; j++) {
if(field[make_pair(j, i)].first == value && (x != j && y != i)) {
return true;
}
}
}
return false;
}
void renderTerm(map<pair<int,int>, pair<int,bool>> field) {
//system("clear");
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
cout << setw(2) << field[make_pair(x, y)].first;
if(x == 2 || x == 5) {
cout << " | ";
}
}
cout << endl;
if(y == 2 || y == 5) {
cout << "---------------------" << endl;
}
}
cout << endl;
}
int main() {
map<pair<int, int>, pair<int, bool>> field;
int givenField[9][9] = {
{4, 3, 0, 2, 1, 9, 5, 0, 8},
{5, 8, 1, 4, 6, 3, 2, 7, 9},
{0, 0, 0, 8, 7, 5, 4, 1, 3},
{9, 7, 8, 0, 5, 0, 6, 3, 0},
{0, 5, 3, 6, 4, 8, 0, 9, 7},
{1, 4, 6, 9, 3, 0, 8, 0, 5},
{7, 6, 0, 5, 0, 0, 3, 4, 2},
{0, 0, 5, 7, 2, 4, 9, 8, 6},
{8, 0, 4, 3, 9, 6, 7, 5, 1},
};
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
field[make_pair(x, y)] = make_pair(givenField[y][x], givenField[y][x] != 0);
}
}
int x = 0, y = 0;
bool skipped = false;
cout << "Pre-Checking Sudoku..." << endl;
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
pair<int, bool> cell = field[make_pair(x, y)];
if(cell.first == 0) {
continue;
}
if(isInRow(field, y, x, cell.first)) {
cout << "Row error at " << x << ", " << y << " for value: "<< cell.first << endl;
return 1;
}
if(isInCol(field, y, x, cell.first)) {
cout << "Column error at " << x << ", " << y << " for value: "<< cell.first << endl;
return 1;
}
if(isInQuadrant(field, y, x, cell.first)) {
cout << "Quadrant error at " << x << ", " << y << " for value: "<< cell.first << endl;
return 1;
}
}
}
cout << "Sudoku is valid!" << endl;
cout << "Calculating..." << endl;
do {
int mathOpsOnY = 1;
if(x == -120 && y >= 0) {
x = 8;
}
else {
x = 0;
}
do {
pair<int, bool> cell = field[make_pair(x, y)];
//Means cell is set, we cannot change it
if(cell.second && !skipped) {
x++;
continue;
}
if(cell.second && skipped) {
//Go back one step more
x--;
if(x < 0) {
x = -120;
mathOpsOnY = -1;
break;
}
continue;
}
if(skipped == true) {
skipped = false;
field[make_pair(x, y)].first++;
continue;
}
//make sure that we have at least a 1 in the cell
if(cell.first == 0) {
field[make_pair(x, y)].first++;
continue;
}
//check if the value is in the current row
//Doesn't increase the value of x as we need to check it again if(isInRow(field, y, x, cell.first)) {
field[make_pair(x, y)].first++;
continue;
}
//check if the value is in the current column
if(isInCol(field, y, x, cell.first)) {
field[make_pair(x, y)].first++;
continue;
}
//check if the value is in the current quadrant
if(isInQuadrant(field, y, x, cell.first)) {
field[make_pair(x, y)].first++;
continue;
}
//means we have an invalid number and need to reset this one and go back one step
if(cell.first > 9) {
field[make_pair(x, y)].first = 0;
//we only need to go back one, as we won't increase x after this
x--;
skipped = true;
if(x < 0) {
//set to absurd value so we can check it in the next iteration
x = -120;
mathOpsOnY = -1;
break;
}
continue;
}
x++;
}
while(x < 9);
y = y + mathOpsOnY;
if(y < 0) {
y = 0;
}
}
while(y < 9);
renderTerm(field);
return 0;
}
```
## With SFML
```cpp
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "./lib/sfml/sfmlLibFuncs.h"
#include <SFML/Graphics.hpp>
using namespace std;
using namespace sf;
bool isInRow(map<pair<int,int>, pair<int,bool>> field, int y, int x, int value) {
for(int i = 0; i < 9; i++) {
if(field[make_pair(i, y)].first == value && x != i) {
return true;
}
}
return false;
}
bool isInCol(map<pair<int,int>, pair<int,bool>> field, int y, int x, int value) {
for(int i = 0; i < 9; i++) {
if(field[make_pair(x, i)].first == value && y != i) {
return true;
}
}
return false;
}
bool isInQuadrant(map<pair<int,int>, pair<int,bool>> field, int y, int x, int value) {
//get the top left corner of the quadrant
int xStart = x - (x % 3);
int yStart = y - (y % 3);
for(int i = yStart; i < yStart + 3; i++) {
for(int j = xStart; j < xStart + 3; j++) {
if(field[make_pair(j, i)].first == value && (x != j && y != i)) {
return true;
}
}
}
return false;
}
void renderTerm(map<pair<int,int>, pair<int,bool>> field) {
//system("clear");
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
cout << setw(2) << field[make_pair(x, y)].first;
if(x == 2 || x == 5) {
cout << " | ";
}
}
cout << endl;
if(y == 2 || y == 5) {
cout << "---------------------" << endl;
}
}
cout << endl;
}
map<pair<int, int>, pair<int, bool>> calculateSudoku(map<pair<int, int>, pair<int, bool>> field, string &returnText, pair<int, int> &offendingCell){
int x = 0, y = 0;
bool skipped = false;
cout << "Pre-Checking Sudoku..." << endl;
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
pair<int, bool> cell = field[make_pair(x, y)];
if(cell.first == 0) {
continue;
}
if(isInRow(field, y, x, cell.first)) {
cout << "Row error at " << x << ", " << y << " for value: "<< cell.first << endl;
offendingCell = make_pair(x, y);
returnText = "Row error at " + to_string(x) + ", " + to_string(y);
return field;
}
if(isInCol(field, y, x, cell.first)) {
cout << "Column error at " << x << ", " << y << " for value: "<< cell.first << endl;
offendingCell = make_pair(x, y);
returnText = "Column error at " + to_string(x) + ", " + to_string(y);
return field;
}
if(isInQuadrant(field, y, x, cell.first)) {
cout << "Quadrant error at " << x << ", " << y << " for value: "<< cell.first << endl;
offendingCell = make_pair(x, y);
returnText = "Quadrant error at " + to_string(x) + ", " + to_string(y);
return field;
}
}
}
cout << "Sudoku is valid!" << endl;
cout << "Calculating..." << endl;
do {
int mathOpsOnY = 1;
if(x == -120 && y >= 0) {
x = 8;
}
else {
x = 0;
}
do {
pair<int, bool> cell = field[make_pair(x, y)];
//Means cell is set, we cannot change it
if(cell.second && !skipped) {
x++;
continue;
}
if(cell.second && skipped) {
//Go back one step more
x--;
if(x < 0) {
x = -120;
mathOpsOnY = -1;
break;
}
continue;
}
if(skipped == true) {
skipped = false;
field[make_pair(x, y)].first++;
continue;
}
//make sure that we have at least a 1 in the cell
if(cell.first == 0) {
field[make_pair(x, y)].first++;
continue;
}
//check if the value is in the current row
//Doesn't increase the value of x as we need to check it again if(isInRow(field, y, x, cell.first)) {
field[make_pair(x, y)].first++;
continue;
}
//check if the value is in the current column
if(isInCol(field, y, x, cell.first)) {
field[make_pair(x, y)].first++;
continue;
}
//check if the value is in the current quadrant
if(isInQuadrant(field, y, x, cell.first)) {
field[make_pair(x, y)].first++;
continue;
}
//means we have an invalid number and need to reset this one and go back one step
if(cell.first > 9) {
field[make_pair(x, y)].first = 0;
//we only need to go back one, as we won't increase x after this
x--;
skipped = true;
if(x < 0) {
//set to absurd value so we can check it in the next iteration
x = -120;
mathOpsOnY = -1;
break;
}
continue;
}
x++;
}
while(x < 9);
y = y + mathOpsOnY;
if(y < 0) {
y = 0;
}
}
while(y < 9);
return field;
}
int main() {
map<pair<int, int>, pair<int, bool>> field;
int givenField[9][9] = {
{4, 3, 0, 2, 1, 9, 5, 0, 8},
{5, 8, 1, 4, 6, 3, 2, 7, 9},
{0, 0, 0, 8, 7, 5, 4, 1, 3},
{9, 7, 8, 0, 5, 0, 6, 3, 0},
{0, 5, 3, 6, 4, 8, 0, 9, 7},
{1, 4, 6, 9, 3, 0, 8, 0, 5},
{7, 6, 0, 5, 0, 0, 3, 4, 2},
{0, 0, 5, 7, 2, 4, 9, 8, 6},
{8, 0, 4, 3, 9, 6, 7, 5, 1},
};
int givenFieldTwo[9][9] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
};
const int windowWidth = 1000;
const int windowHeight = 800;
RenderWindow window(VideoMode(windowWidth, windowHeight), "Sudoku Solver");
//field = calculateSudoku(field);
renderTerm(field);
pair<int, int> selectedCell = make_pair(0, 0);
pair<int, int> offendingCell = make_pair(-1, -1);
Font font;
font.loadFromFile("./Roboto-Regular.ttf");
//the error text shown
Text errorText = Text("", font, 15);
errorText.setFillColor(Color::Red);
errorText.setPosition(800, 200);
while(window.isOpen()) {
Event event;
while(window.pollEvent(event)) {
if(event.type == Event::Closed) {
window.close();
}
//handle input of chars
if(event.type == Event::TextEntered) {
if(event.text.unicode >= '0' && event.text.unicode <= '9') {
givenFieldTwo[selectedCell.second][selectedCell.first] = event.text.unicode - '0';
field[selectedCell].first = event.text.unicode - '0';
}
}
//check if the input was a tab key
if(event.type == Event::KeyPressed) {
if(event.key.code == Keyboard::Tab) {
selectedCell.first++;
if(selectedCell.first > 8) {
selectedCell.first = 0;
selectedCell.second++;
if(selectedCell.second > 8) {
selectedCell = make_pair(0, 0);
}
}
}
//check if the input was a backspace and then remove the value
if(event.key.code == Keyboard::BackSpace) {
givenFieldTwo[selectedCell.second][selectedCell.first] = 0;
field[selectedCell].first = 0;
}
//check if the input was an arrow key up
if(event.key.code == Keyboard::Up) {
selectedCell.second--;
if(selectedCell.second < 0) {
selectedCell.second = 8;
}
}
//check if the input was an arrow key down
if(event.key.code == Keyboard::Down) {
selectedCell.second++;
if(selectedCell.second > 8) {
selectedCell.second = 0;
}
}
//check if the input was an arrow key left
if(event.key.code == Keyboard::Left) {
selectedCell.first--;
if(selectedCell.first < 0) {
selectedCell.first = 8;
}
}
//check if the input was an arrow key right
if(event.key.code == Keyboard::Right) {
selectedCell.first++;
if(selectedCell.first > 8) {
selectedCell.first = 0;
}
}
}
//check if the mouse is clicked and the button is clicked
if(event.type == Event::MouseButtonPressed) {
if(event.mouseButton.button == Mouse::Left) {
if(event.mouseButton.x >= 800 && event.mouseButton.x <= 1000 && event.mouseButton.y >= 0 && event.mouseButton.y < 50) {
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
field[make_pair(x, y)] = make_pair(givenFieldTwo[y][x], givenFieldTwo[y][x] != 0);
}
}
string returnText = "";
field = calculateSudoku(field, returnText, offendingCell);
renderTerm(field);
//update the field
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
givenFieldTwo[y][x] = field[make_pair(x, y)].first;
}
}
//if the length of the returned text > 0 show a warning
if(returnText.length() > 0) {
errorText.setString(returnText);
errorText.setPosition(800, 200);
errorText.setCharacterSize(24);
errorText.setFillColor(Color::Red);
window.draw(errorText);
cout << returnText << endl;
}
else {
errorText.setString("");
offendingCell = make_pair(-1, -1);
cout << "Sudoku is valid!" << endl;
}
}
//reset the field
if(event.mouseButton.x > 800 && event.mouseButton.x <= 1000 && event.mouseButton.y > 50 && event.mouseButton.y < 100) {
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
givenFieldTwo[y][x] = 0;
}
}
for(int y = 0; y < 9; y++) {
for(int x = 0; x < 9; x++) {
field[make_pair(x, y)] = make_pair(givenFieldTwo[y][x], givenFieldTwo[y][x] != 0);
}
}
}
//check if the mouse click was inside one of the cells
if(event.mouseButton.x < 800 && event.mouseButton.y < 800) {
int x = event.mouseButton.x / (windowHeight / 9);
int y = event.mouseButton.y / (windowHeight / 9);
selectedCell = make_pair(x, y);
}
}
}
}
window.clear(Color::White);
Font font;
font.loadFromFile("./Roboto-Regular.ttf");
int x = 0, y = 0;
//render the field
for(y = 0; y < 9; y++){
for(x = 0; x < 9; x++){
int xPos = x * (windowHeight / 9);
int yPos = y * (windowHeight / 9);
if(x % 3 == 0 && x != 0){
xPos += 8;
}
if(y % 3 == 0 && y != 0){
yPos += 8;
}
RectangleShape cell(Vector2f(windowHeight / 9, windowHeight / 9));
cell.setPosition(xPos, yPos);
if(field[make_pair(x, y)].second) {
cell.setFillColor(Color::Green);
}
else {
cell.setFillColor(Color::White);
}
cell.setOutlineThickness(1);
if(selectedCell == make_pair(x, y)) {
cell.setOutlineColor(Color::Blue);
cell.setOutlineThickness(7);
}
else {
cell.setOutlineColor(Color::Black);
}
if(offendingCell.first == x && offendingCell.second == y) {
cell.setOutlineColor(Color::Red);
cell.setOutlineThickness(7);
cell.setFillColor(Color::Red);
}
window.draw(cell);
Text cellText;
cellText.setFont(font);
cellText.setString(to_string(givenFieldTwo[y][x]));
cellText.setCharacterSize(24);
cellText.setFillColor(Color::Black);
cellText.setPosition(cell.getPosition().x + 10, cell.getPosition().y + 10);
window.draw(cellText);
}
}
//re-draw the currently selected cell because it needs to be on top
int xPos = selectedCell.first * (windowHeight / 9);
int yPos = selectedCell.second * (windowHeight / 9);
if(selectedCell.first % 3 == 0 && selectedCell.first != 0){
xPos += 8;
}
if(selectedCell.second % 3 == 0 && selectedCell.second != 0){
yPos += 8;
}
RectangleShape cell(Vector2f(windowHeight / 9, windowHeight / 9));
cell.setPosition(xPos, yPos);
if(field[selectedCell].second) {
cell.setFillColor(Color::Green);
}
else {
cell.setFillColor(Color::White);
}
cell.setOutlineThickness(4);
cell.setOutlineColor(Color::Blue);
Text selectedCellText;
selectedCellText.setFont(font);
selectedCellText.setString(to_string(givenFieldTwo[selectedCell.second][selectedCell.first]));
selectedCellText.setCharacterSize(24);
selectedCellText.setFillColor(Color::Black);
selectedCellText.setPosition(cell.getPosition().x + 10, cell.getPosition().y + 10);
window.draw(cell);
window.draw(selectedCellText);
//add the button to solve the sudoku
RectangleShape solveButton(Vector2f(200, 50));
solveButton.setPosition(800, 0);
solveButton.setFillColor(Color::Blue);
solveButton.setOutlineThickness(1);
solveButton.setOutlineColor(Color::Black);
window.draw(solveButton);
//text on the button
Text buttonText = Text("Solve", font, 24);
buttonText.setFillColor(Color::White);
buttonText.setPosition(810, 10);
window.draw(buttonText);
//a button to reset the field
RectangleShape resetButton(Vector2f(200, 50));
solveButton.setPosition(800, 50);
solveButton.setFillColor(Color::Red);
solveButton.setOutlineThickness(1);
solveButton.setOutlineColor(Color::Black);
window.draw(solveButton);
//text on the button
Text buttonTextSolve = Text("Reset", font, 24);
buttonTextSolve.setFillColor(Color::White);
buttonTextSolve.setPosition(810, 60);
window.draw(buttonTextSolve);
window.draw(errorText);
window.display();
}
return 0;
}
```