diff --git a/Web Development/Basic/Sudoku Game/README.md b/Web Development/Basic/Sudoku Game/README.md
new file mode 100644
index 000000000..497da93b0
--- /dev/null
+++ b/Web Development/Basic/Sudoku Game/README.md
@@ -0,0 +1,19 @@
+# Sudoku Game Website
+
+This is a Sudoku game website created using HTML, CSS, and JavaScript.
+
+## Overview
+
+Sudoku is a popular puzzle game that requires logic and critical thinking skills. This website provides a platform for users to play Sudoku online for free.
+
+## Features
+
+- Sudoku board generator that creates a unique puzzle every time
+- Ability to input numbers and track progress
+- Timer to track how long it takes to complete the puzzle
+- Check functionality to see if current solution is correct
+- Reset button to clear the board and start over
+
+## Usage
+
+To play the game, simply visit the website https://hypertext-workaholics.github.io/sudoku-game/ and click on the "New Game" button to generate a new Sudoku puzzle. Use the number buttons on the bottom side of the board to input your guesses.
\ No newline at end of file
diff --git a/Web Development/Basic/Sudoku Game/index.html b/Web Development/Basic/Sudoku Game/index.html
new file mode 100644
index 000000000..ed7fd4339
--- /dev/null
+++ b/Web Development/Basic/Sudoku Game/index.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+ Sudoku
+
+
+
+
Sudoku
+
+
Mistakes : 0
+
+ 00 : 00
+
+
+
+
+
+ 1 2
+ 3 4
+ 5 6
+ 7 8
+ 9
+
+
+
+
+
+ Sudoku
+
+ New Game
+ Continue
+ Easy
+ Medium
+ Hard
+ Insane
+
+
+
\ No newline at end of file
diff --git a/Web Development/Basic/Sudoku Game/script.js b/Web Development/Basic/Sudoku Game/script.js
new file mode 100644
index 000000000..a49bd5788
--- /dev/null
+++ b/Web Development/Basic/Sudoku Game/script.js
@@ -0,0 +1,301 @@
+
+import { generateSudoku } from "./sudokuGenerator.js";
+let board;
+let ans;
+// Globals
+let color_box;
+let clickFlag = -1;
+var boardPosition = { left: 0, top: 0 };
+let mp = {};
+let count = 0;
+let prevBox;
+let currSelect = -1;
+let Interval = undefined;
+//
+function startTimer(start) {
+ let minute = document.getElementById("minute");
+ let sec = document.getElementById("second");
+ Interval = setInterval(() => {
+ minute.innerText = parseInt(minute.innerText) + (sec.innerText == '59') ? 1 : 0;
+ sec.innerText = (parseInt(sec.innerText) + 1) % 60;
+ }, 1000);
+
+}
+function createGrid() {
+ let grid = document.createElement("div");
+ grid.classList.add("sudoku-board");
+ for (let i = 0; i < 9; i++) {
+ for (let j = 0; j < 9; j++) {
+ let div = document.createElement("div");
+ div.classList.add("box");
+ if (i == 3 || i == 6)
+ div.classList.add("top");
+ if (j == 3 || j == 6)
+ div.classList.add("left");
+ div.id = `${i}-${j}`;
+ grid.appendChild(div);
+ }
+ }
+ document.getElementById("wrap").appendChild(grid);
+}
+
+const fillGrid = () => {
+ let i, j;
+ let boxes = document.querySelectorAll(".box");
+ boxes.forEach((box) => {
+ i = box.id[0];
+ j = box.id[2];
+ ["pre", "filled", "text-yellow", "purple", "wrong"].forEach((Class) => {
+ if (box.classList.contains(Class))
+ box.classList.remove(Class);
+ });
+ if (board[i][j] != "0") {
+ box.classList.add("pre");
+ box.innerText = board[i][j];
+ if (mp[board[i][j]] != undefined)
+ mp[board[i][j]]++;
+ else
+ mp[board[i][j]] = 1;
+ } else {
+ box.innerText = "";
+ count++;
+ }
+ });
+
+ for (let it = 1; it < 10; it++) {
+ let numberBtn = document.getElementById(it);
+ numberBtn.className = "";
+ if (mp[it] == 9)
+ numberBtn.className = "complete";
+ }
+}
+
+
+function newGame(level) {
+ color_box = undefined;
+ clickFlag = -1;
+ currSelect = -1;
+ boardPosition = { left: 0, top: 0 };
+ let error = document.getElementById("error-count").innerText = 0;
+ for (var member in mp) delete mp[member];
+ count = 0;
+ prevBox = undefined;
+ document.getElementById("continue").classList.remove("hide");
+ let temp = generateSudoku(level);
+ board = temp.grid;
+ ans = temp.solution;
+ changeWrapper();
+ fillGrid();
+
+ startTimer();
+}
+
+function changeWrapper() {
+ let blurElement = document.getElementById("toggle-blur");
+ let levelWrapper = document.getElementById("wrapper");
+ toggleClass(blurElement, "hide");
+ toggleClass(levelWrapper, "after");
+ toggleClass(levelWrapper, "before");
+}
+
+window.onload = function () {
+ createGrid();
+ // This is for the switching of level wrapper on click of ".level"
+ document.querySelectorAll(".level").forEach((level) => {
+ level.addEventListener("click", () => {
+ if (level.id != "continue") {
+ let minute = document.getElementById("minute").innerText = '00';
+ let sec = document.getElementById("second").innerText = '00';
+ newGame(level.id);
+ }
+ else {
+ startTimer();
+ changeWrapper();
+ }
+ });
+ });
+
+ //newgame event listener
+ let levelWrapper = document.getElementById("wrapper");
+ let blurElement = document.getElementById("toggle-blur");
+ document.getElementById("new-game").addEventListener("click", () => {
+ if (Interval != undefined)
+ clearInterval(Interval);
+ changeWrapper();
+ });
+
+ let numbers = document.querySelectorAll("button");
+ numbers.forEach((number) => {
+ number.addEventListener("click", () => {
+ if (number.id != "moving-box" && number.classList != "level" && number.id != "new-game" && number.classList.contains("complete") == false) {
+ if (currSelect == number.id)
+ toggleEachNumber(currSelect, 0);
+ else if (currSelect != -1)
+ toggleEachNumber(currSelect, 0);
+ currSelect = number.id;
+ toggleEachNumber(currSelect, 1);
+ // moving the temporary box to number position
+ Move("moving-box", number.id, number.id);
+ if (clickFlag == 1)
+ toggleBG(prevBox, 0);
+ clickFlag = 0;
+ prevBox = undefined;
+ }
+ });
+ });
+
+ let boxes = document.querySelectorAll(".box");
+ boxes.forEach((box) => {
+ box.addEventListener("click", function (e) {
+ if (currSelect != -1 && mp[currSelect] < 9) {
+ if (box.classList.contains("wrong") == true) {
+ setTimeout(
+ (box) => {
+ box.innerText = "";
+ box.classList.remove("wrong");
+ },
+ 10,
+ box
+ );
+ }
+ if (box.innerText == "") {
+ let element = document.getElementById("moving-box");
+ toggleClass(element, "transition");
+ Move("moving-box", box.id, currSelect);
+ setTimeout(toggleClass, 500, element, "transition");
+ }
+ }
+ //
+ if (box.innerText == "" && clickFlag == 1 && prevBox != undefined) {
+ toggleBG(prevBox, 0);
+ clickFlag = -1;
+ }
+ if (box.innerText == "" && clickFlag == -1) {
+ toggleBG(box, 1);
+ prevBox = box;
+ clickFlag = 1;
+ }
+ //
+ });
+ });
+};
+
+// toggle between "transition"
+function toggleClass(element, className) {
+ element.classList.toggle(className);
+}
+// Return board-wrap coordinates
+function getBoardPosition() {
+ let boardPos = document.getElementById("wrap").getBoundingClientRect();
+ boardPosition.left = boardPos.left;
+ boardPosition.top = boardPos.top;
+}
+
+//to move the temporary button to any specific position by destination id
+function Move(sourceID, destID, text) {
+ getBoardPosition();
+ let source = document.getElementById(sourceID);
+ source.innerText = text;
+ let dest = document.getElementById(destID);
+ let destX = dest.getBoundingClientRect().x;
+ let destY = dest.getBoundingClientRect().y;
+ source.style.position = "absolute";
+ source.classList.remove("hidden");
+ if (dest.localName == "button") {
+ source.style.color = "black";
+ source.style.left = `${-boardPosition.left + destX - 3}px`;
+ source.style.top = `${-boardPosition.top + destY - 3}px`;
+ } else {
+ // may
+ source.style.left = `${-boardPosition.left + parseInt(destX)}px`;
+ source.style.top = `${-boardPosition.top + parseInt(destY)}px`;
+ source.style.color = "white";
+ dest.innerText = text;
+
+ if (isValid(dest) == false) {
+ let error = document.getElementById("error-count");
+ error.innerText = ++error.innerText;
+ dest.classList.add("wrong");
+ navigator.vibrate(50);
+ if (error.innerText == "1") {
+ setTimeout(
+ (msg) => {
+ alert(msg);
+ },
+ 1000,
+ "Click again on RED number to remove it from the Sudoku grid."
+ );
+ }
+ } else {
+ count--;
+ dest.classList.add("filled");
+ dest.classList.add("text-yellow");
+ if (mp[parseInt(dest.innerText)]) {
+ mp[parseInt(dest.innerText)]++;
+ } else {
+ mp[parseInt(dest.innerText)] = 1;
+ }
+ if (mp[parseInt(dest.innerText)] == 9) {
+ document.getElementById(dest.innerText).classList.add("complete");
+ }
+ }
+ if (count == 0) {
+ setTimeout(win, 2000);
+ }
+ setTimeout(Move, 600, "moving-box", text, text);
+ }
+}
+
+function isValid(box) {
+ let row = box.id[0];
+ let col = box.id[2];
+ return ans[row][col] == box.innerText;
+}
+
+
+function toggleBG(box, flag) {
+ let row = box.id[0];
+ let col = box.id[2];
+ let r = parseInt(row / 3) * 3;
+ let c = parseInt(col / 3) * 3;
+ for (let i = 0; i < 9; i++) {
+ let rowBox = document.getElementById(`${row}-${i}`);
+ let colBox = document.getElementById(`${i}-${col}`);
+ let DiagBox = document.getElementById(
+ `${r + parseInt(i / 3)}-${c + parseInt(i % 3)}`
+ );
+
+ if (flag) {
+ if (rowBox.classList.contains("pre") == false)
+ rowBox.classList.add("purple");
+ if (colBox.classList.contains("pre") == false)
+ colBox.classList.add("purple");
+ if (DiagBox.classList.contains("pre") == false)
+ DiagBox.classList.add("purple");
+ } else {
+ if (rowBox.classList.contains("pre") == false)
+ rowBox.classList.remove("purple");
+ if (colBox.classList.contains("pre") == false)
+ colBox.classList.remove("purple");
+ if (DiagBox.classList.contains("pre") == false)
+ DiagBox.classList.remove("purple");
+ }
+ }
+}
+// after completion of sudoku
+function win() {
+ location.reload();
+}
+
+function toggleEachNumber(num, flag) {
+ let numberBOx = document.getElementById(num).classList.toggle("clicked");
+ let boxes = document.querySelectorAll(".box");
+ boxes.forEach((box) => {
+ if (box.innerText == num) {
+ if (flag == true)
+ box.classList.add("text-yellow");
+ else
+ box.classList.remove("text-yellow");
+ }
+ });
+}
\ No newline at end of file
diff --git a/Web Development/Basic/Sudoku Game/styles.css b/Web Development/Basic/Sudoku Game/styles.css
new file mode 100644
index 000000000..df0374ac3
--- /dev/null
+++ b/Web Development/Basic/Sudoku Game/styles.css
@@ -0,0 +1,305 @@
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
+ font-weight: bold;
+ font-size: 1.1rem;
+ }
+ :root{
+ --text-yellow:#ffdb10;
+ --border-green:#2fff06;
+ }
+ body {
+ background-color: #031638;
+ mix-blend-mode: inherit;
+ background-position: unset;
+ overflow: hidden;
+ height: 100vh;
+ }
+ .numbers {
+ display: flex;
+ width: 350px;
+ justify-content: center;
+ margin-top: 450px;
+ color: black;
+ }
+ .numbers > * {
+ background-color: #3bff13;
+ width: 33px;
+ height: 33px;
+ margin: 3px;
+ border: none;
+ border-radius: 3px;
+ }
+ .numbers > *:not(#moving-box, .clicked, .complete) {
+ cursor: pointer !important;
+ box-shadow: 3px -4px 1px rgb(96, 177, 96) !important;
+ z-index: 999;
+ }
+
+ .numbers > *:not(#moving-box):hover {
+ background-color: #2b9e14;
+ }
+ .numbers > *:not(#moving-box):active {
+ transform: translateY(3px);
+ }
+ .sudoku-board {
+ display: grid;
+ grid-template-columns: repeat(9, 1fr);
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 350px;
+ height: 350px;
+ box-shadow: 1px 1px 15px 3px #6e76a7, -1px -1px 15px 3px #6e76a7;
+ border-radius: 2px;
+ border: 3px solid var(--border-green);
+ }
+ .box {
+ color: whitesmoke;
+ background-color: #091e42b6;
+ display: grid;
+ place-items: center;
+ outline: none;
+ cursor: pointer;
+ border-right: 1px solid #9bb39650;
+ border-bottom: 1px solid #9bb39650;
+ text-shadow: -1px 1px 5px #9bb396e1;
+ }
+ .box:hover {
+ background-color: rgba(119, 113, 150, 0.87);
+ border-radius: 1px;
+ text-shadow: -1px 1px 5px #1f201fe1;
+ }
+ .pre,
+ .pre:hover {
+ background-color: #020016;
+ color: whitesmoke;
+ text-shadow: -1px 1px 5px #9bb396e1;
+ }
+ .filled,
+ .filled:hover {
+ background-color: #6b007ed6;;
+ text-shadow: -1px 1px 3px #d9d9d9e1;
+ }
+
+ .wrong {
+ animation: shake;
+ animation-timing-function: ease-in-out;
+ animation-duration: 150ms;
+ animation-iteration-count: 3;
+ animation-fill-mode: forwards;
+ text-shadow: none;
+ }
+ @keyframes shake {
+ 0% {
+ transform: translateX(0);
+ }
+ 50% {
+ transform: translateX(-3px);
+ color: rgba(255, 0, 0, 0.767);
+ }
+ 75% {
+ transform: translateX(2px);
+ }
+ 100% {
+ transform: translateX(0);
+ color: rgba(255, 0, 0, 0.767);
+ }
+ }
+
+ .transition {
+ transition: 0.5s;
+ border: none;
+ z-index: 1;
+ }
+
+ .board-wrap {
+ z-index: 11;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+ #moving-box {
+ background-color: transparent;
+ color: whitesmoke;
+ z-index: 1;
+ }
+ .hidden {
+ display: none;
+ }
+
+ .left {
+ border-left: 2px solid var(--border-green);
+ }
+ .top {
+ border-top: 2px solid var(--border-green);
+ }
+ .purple {
+ background-color: rgb(39, 0, 39);
+ }
+
+ .win-card {
+ display: none;
+ background-color: rgba(252, 252, 252, 0.048);
+ width: 300px;
+ height: 170px;
+ position: absolute;
+ top: 44%;
+ left: calc(50% - 2px);
+ transform: translate(-50%, -50%);
+ backdrop-filter: blur(2px);
+ border-radius: 10px;
+ z-index: 999;
+ }
+
+ .win-card > * {
+ background-color: transparent;
+ }
+
+ #greeting-bg {
+ position: relative;
+ top: 32%;
+ left: 15px;
+ transform: translate(-50%, -50%);
+ display: inline;
+ font-size: 2rem;
+ color: black;
+ text-shadow: -1px -1px 4px rgb(47, 213, 255), 1px 1px 4px rgb(47, 213, 255);
+
+ font-family: "Permanent Marker", cursive;
+ }
+
+ .text-yellow,
+ .text-yellow:hover {
+ color: var(--text-yellow);
+ background-color: #00008b;
+ }
+
+ .clicked:not(.complete),
+ .clicked:hover:not(.complete) {
+ box-shadow: 4px 4px 2px #60b160;
+ transform: translatey(2px);
+ background-color: #2b9e14;
+ }
+
+ .error {
+ width: max-content;
+ margin: auto;
+ margin-top: 2rem;
+ color: var(--text-yellow);
+ text-align: center;
+ font-size: 10px;
+ }
+
+ #heading,#toggle-blur span {
+ font-size: 2rem;
+ color: #fff8a0;
+ text-shadow: 1px -4px 4px black;
+ margin-top: -1rem;
+ margin-bottom: 18px;
+ cursor: pointer;
+ }
+
+ .wrapper {
+ display: flex;
+ flex-direction: column;
+ width: calc(100vw - 400px);
+ min-width: 170px;
+ max-width: 400px;
+ background-color: rgb(253, 253, 253);
+ position: absolute;
+ bottom: 0px;
+ left: 50%;
+ transform: translate(-50%);
+ border: none;
+ border-radius: 5px;
+ z-index: 999;
+ box-sizing: border-box;
+ }
+
+ .wrapper :first-child {
+ border-radius: 5px 5px 0 0;
+ margin-top: 5px;
+ }
+
+ .wrapper :last-child {
+ padding-bottom: 10px;
+ border-radius: 0 0 5px 5px;
+ }
+
+ .wrapper > * {
+ background-color: white;
+ border: none;
+ cursor: pointer;
+ padding: 8px 8px;
+ border-bottom: 1px solid rgba(65, 62, 62, 0.589);
+ }
+
+ .wrapper :first-child {
+ border: none;
+ margin-bottom: 1.1rem;
+ }
+
+ .before {
+ bottom: -235px;
+ }
+
+ .before:hover,
+ .before:hover > * {
+ background-color: blue;
+ color: chartreuse;
+ }
+
+ .after {
+ bottom: 50%;
+ transform: translate(-50%, 50%);
+ transition: 500ms;
+ transition-timing-function: ease-in-out;
+ }
+
+ .after > *:hover,
+ .after:hover {
+ background-color: #031638;
+ width: 100%;
+ color: whitesmoke;
+ }
+
+ .after :first-child {
+ display: none;
+ }
+
+ .after :nth-child(2),
+ .after :nth-child(3) {
+ border-radius: 5px 5px 0 0;
+ }
+
+ .blur {
+ display: block;
+ width: 100vw;
+ height: 100vh;
+ position: absolute;
+ top: 0;
+ background-color: rgba(87, 81, 81, 0.329);
+ backdrop-filter: blur(5px);
+ z-index: 900;
+ }
+
+ #toggle-blur span{
+ margin: auto;
+ display: block;
+ width: max-content;
+ margin-top: 1.5rem;
+ }
+
+ .hide {
+ display: none;
+ }
+ .sub-heading {
+ display: flex;
+ width: 350px;
+ justify-content: space-around;
+ }
\ No newline at end of file
diff --git a/Web Development/Basic/Sudoku Game/sudokuGenerator.js b/Web Development/Basic/Sudoku Game/sudokuGenerator.js
new file mode 100644
index 000000000..c7d4c787c
--- /dev/null
+++ b/Web Development/Basic/Sudoku Game/sudokuGenerator.js
@@ -0,0 +1,103 @@
+let solution = Array(9);
+const levels = { easy: 25, medium: 45, hard: 60,insane:75};
+let solCount = 0;
+let grid;
+
+//create 9 x 9 empty array
+function createArray(){
+ for (let i = 0; i < 9; i++)
+ solution[i] = new Array(9).fill('0');
+}
+
+
+// Using Backtracking leetcode sudoku solver to generate full sudoku grid(Solution)
+const fillArray = (i, j) => {
+ for (; i < 9; i++) {
+ for (; j < 9; j++) {
+ if (solution[i][j] == '0') {
+ for (let k = parseInt(Math.random() * 9) + 1, ct = 0; ct < 9; k = (k == 9) ? 1 : k + 1) {
+ ct++;
+ if (isValid(i, j, k.toString(), solution)) {
+ solution[i][j] = k.toString();
+ if (fillArray(i, j))
+ return true;
+ solution[i][j] = '0';
+ }
+ }
+ return false;
+ }
+ }
+ j = 0;
+ }
+ return true;
+}
+
+// isValid checks that the placed number in board is violating sudoku rules or not
+const isValid = (i, j, k, board) => {
+ let row = parseInt(i / 3) * 3;
+ let col = parseInt(j / 3) * 3;
+ for (let it = 0; it < 9; it++) {
+ if (board[i][it] == k)
+ return false;
+ if (board[it][j] == k)
+ return false;
+ if (board[row + parseInt(it / 3)][col + parseInt(it % 3)] == k)
+ return false;
+ }
+ return true;
+}
+
+//removeCells after generating sudoku it removes some pre fetched cells number according to level
+function removeCells(k) {
+ grid = JSON.parse(JSON.stringify(solution));
+ let ct = 1;
+ let r = 40;
+ while (k && r) {
+ let row = parseInt(Math.random() * 9);
+ let col = parseInt(Math.random() * 9);
+ let removedNum = grid[row][col];
+ grid[row][col] = '0';
+ if (solve(0, 0, ct) == 1) {
+ k--;
+ ct++;
+ } else {
+ r--;
+ grid[row][col] = removedNum;
+ }
+ }
+}
+
+// solve -> after removing a cell number it counts number of solutions
+// if there are more than 1 solution than removed number will be placed again on it's original place
+// if there a only one solution than next random position cell will be removed
+const solve = (i, j, Count) => {
+ if (Count == 0) return 1;
+ let solCount = 0;
+ for (; i < 9; i++) {
+ for (; j < 9; j++) {
+ if (grid[i][j] == '0') {
+ for (let k = 1; k <= 9; k++) {
+ if (isValid(i, j, k.toString(), grid)) {
+ grid[i][j] = k.toString();
+ solCount += solve(i, j, Count - 1);
+ grid[i][j] = '0';
+ }
+ if (solCount > 1)
+ return solCount;
+ }
+ return solCount;
+ }
+ }
+ j = 0;
+ }
+ return solCount;
+}
+
+export const generateSudoku = (level) => {
+ solution = Array(9);
+ grid = undefined;
+ createArray();
+ fillArray(0, 0);
+ removeCells(levels[level]);
+ return { solution, grid };
+};
\ No newline at end of file