diff --git a/public/generateSudoku.js b/public/generateSudoku.js new file mode 100644 index 0000000000000000000000000000000000000000..d308f16930e1d4c6c978730a6c11b0eb2c2d6b4c --- /dev/null +++ b/public/generateSudoku.js @@ -0,0 +1,69 @@ +function generateSudoku(numberOfZ) { + const grid = Array.from({ length: 9 }, () => Array(9).fill(0)); + + function isValid(num, row, col) { + for (let i = 0; i < 9; i++) { + if ( + grid[row][i] === num || + grid[i][col] === num || + grid[row - (row % 3) + Math.floor(i / 3)][col - (col % 3) + (i % 3)] === num + ) { + return false; + } + } + return true; + } + + function solve() { + const numbers = Array.from({ length: 9 }, (_, i) => i + 1); + shuffle(numbers); + + for (let row = 0; row < 9; row++) { + for (let col = 0; col < 9; col++) { + if (grid[row][col] === 0) { + for (const num of numbers) { + if (isValid(num, row, col)) { + grid[row][col] = num; + + if (solve()) { + return true; + } + + grid[row][col] = 0; + } + } + return false; + } + } + } + return true; + } + + function shuffle(array) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + } + + // Generate a complete Sudoku puzzle + solve(); + + // Create a copy of the grid before removing numbers + const puzzle = grid.map(row => row.slice()); + + // Randomly remove some numbers to create an unfinished Sudoku puzzle + if(numberOfZ>=82){throw new Error("Number greater than number of fields")} + + for (let i = 0; i < numberOfZ; i++) { + const row = Math.floor(Math.random() * 9); + const col = Math.floor(Math.random() * 9); + if(puzzle[row][col] ===0 ){i--} + puzzle[row][col] = 0; + } + + return puzzle; + } + + export { generateSudoku }; + \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..b904a4313295359caff6828ad1bd40c1214e5a84 --- /dev/null +++ b/public/index.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" href="styles.css"> +</head> +<body> + <h1>Leon macht Sudokus</h1> + + <label for="difficultySelector">Select a Difficulty:</label> + <select id="difficultySelector"> + <option value="easy">easy 20 empty cells</option> + <option value="mid">mid 40 empty cells</option> + <option value="hard">hard 55 empty cells</option> + </select> + + <button id="generateButton">Generate new Sudoku</button> + + <table id="noSolutionBoard"></table> + + <br> + <button id="toggleButton" onclick="solveTable('noSolutionBoard')">Show Solution</button> + + <table id="solutionTable"></table> + + <script type="module" src="./scripts.js"></script> + <script defer type="module" src="./generateSudoku.js"></script> + <script defer type="module" src="./solver.js"></script> + + <script type="module"> + // Import necessary functions from modules + import { GetNumberofZeroes } from "./scripts.js"; + import { solveSudoku } from "./solver.js"; + import { generateSudoku } from "./generateSudoku.js"; + + let sudokuBoard; + + function updateTable(tableId) { + let table = document.getElementById(tableId); + let numberOfZeros = GetNumberofZeroes(); + + sudokuBoard = generateSudoku(numberOfZeros); + const rawString = sudokuBoard + .map((row) => row.map((num) => `<td>${num}</td>`).join("")) + .map((row) => `<tr>${row}</tr>`) + .join(""); + + table.innerHTML = rawString; + console.log("Number of cells to figure out: " + numberOfZeros + "."); + } + + function solveTable(tableId) { + let table = document.getElementById(tableId); + + sudokuBoard = solveSudoku(sudokuBoard); + const rawString = sudokuBoard + .map((row) => row.map((num) => `<td>${num}</td>`).join("")) + .map((row) => `<tr>${row}</tr>`) + .join(""); + + table.innerHTML = rawString; + + } + + // Assign the function to the button click event after the function is defined + document.getElementById("generateButton").onclick = function () { + updateTable("noSolutionBoard"); + }; + document.getElementById("toggleButton").onclick = function () { + solveTable("noSolutionBoard"); + }; + </script> +</body> +</html> diff --git a/public/package.json b/public/package.json new file mode 100644 index 0000000000000000000000000000000000000000..97bb1a268a1001646761faef35dba45867e72a6b --- /dev/null +++ b/public/package.json @@ -0,0 +1,13 @@ +{ + "name": "public", + "version": "1.0.0", + "description": "", + "main": "generateSudoku.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module" +} diff --git a/public/scripts.js b/public/scripts.js new file mode 100644 index 0000000000000000000000000000000000000000..ade22c81afeb82ddb3b5a588ab028940504897e9 --- /dev/null +++ b/public/scripts.js @@ -0,0 +1,39 @@ + + +function GetNumberofZeroes() { + console.log("GetZeroes function called"); + // Get the <select> element by its ID + var selectElement = document.getElementById("difficultySelector"); + + // Get the selected option + var selectedOption = selectElement.options[selectElement.selectedIndex]; + + // Get the value of the selected option + let numberOfZeros; + + if (selectedOption.value === "hard") { + numberOfZeros = 55; + } else if (selectedOption.value === "mid") { + numberOfZeros = 40; + } else if (selectedOption.value === "easy"){ + numberOfZeros = 20; + } + return numberOfZeros; +} + + +export { GetNumberofZeroes } +// function displaySolution() { +// const solutionTable = document.getElementById("solutionTable"); +// if (solutionTable.style.display === "none") { +// solutionTable.style.display = "table"; // Show the solution table +// } else { +// solutionTable.style.display = "none"; // Hide the solution table +// } +// } + + + + + + diff --git a/public/solver.js b/public/solver.js new file mode 100644 index 0000000000000000000000000000000000000000..0652859729964740b2e7bdfc51f96116b08fc19a --- /dev/null +++ b/public/solver.js @@ -0,0 +1,50 @@ +function solveSudoku(board) { + const size = 9; + + function isValid(num, row, col) { + // Check if 'num' is not present in the current row, column, and 3x3 grid + for (let i = 0; i < size; i++) { + if ( + board[row][i] === num || + board[i][col] === num || + board[row - (row % 3) + Math.floor(i / 3)][col - (col % 3) + (i % 3)] === num + ) { + return false; + } + } + return true; + } + + function solve() { + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + if (board[row][col] === 0) { + for (let num = 1; num <= size; num++) { + if (isValid(num, row, col)) { + board[row][col] = num; + + if (solve()) { + return true; // If the current configuration leads to a solution + } + + // If the current configuration doesn't lead to a solution, backtrack + board[row][col] = 0; + } + } + return false; // If no number can be placed at this cell + } + } + } + return true; // If the entire board is filled + } + + if (solve()) { + return board; // Return the solved Sudoku board + } else { + return "No solution exists."; // Return a message if no solution exists + } + } + + + export {solveSudoku } + \ No newline at end of file diff --git a/public/styles.css b/public/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..d1dd61be3b854dc32911ecef4dca7872bef55abb --- /dev/null +++ b/public/styles.css @@ -0,0 +1,24 @@ +* { + margin-bottom: 20px; +} +button { + margin-top: 0px; + margin-bottom: 5px; +} + +#difficultySelector { + display: block; +} + +table { + border-collapse: collapse; + margin-bottom: 5px; +} + +td { + border: 1px solid black; + width: 30px; /* Adjust the width as needed */ + height: 30px; /* Adjust the height as needed */ + text-align: center; + +} \ No newline at end of file