<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; } ```