diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0186e40..2d07ec4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,13 @@ -## Describe your changes +## Describe your changes (Mandatory) -## Issue ticket number and link +## Issue ticket number and link (Mandatory) + +## Screenshots of your project, whatever you have added. (Mandatory) ## Checklist before requesting a review - [ ] I have performed a self-review of my code -- [ ] If it is a new project, I have added thorough tests. +- [ ] If it is a new project, I have done thorough tests. - [ ] Have you updated the README file of the repository and added the name of the project in it? -- [ ] Have you added a `README.md` file inside the directory of your project and explained it there properly? +- [ ] Have you added a `README.md` file inside the directory of your project and explained it there properly (with images)? +- [ ] Have you updated the `script.js` file so that the project is visible in the website? diff --git a/Hide-show-pass/.DS_Store b/Hide-show-pass/.DS_Store new file mode 100644 index 0000000..7ae5098 Binary files /dev/null and b/Hide-show-pass/.DS_Store differ diff --git a/Hide-show-pass/.vscode/settings.json b/Hide-show-pass/.vscode/settings.json new file mode 100644 index 0000000..3b66410 --- /dev/null +++ b/Hide-show-pass/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "git.ignoreLimitWarning": true +} \ No newline at end of file diff --git a/Hide-show-pass/Images/.DS_Store b/Hide-show-pass/Images/.DS_Store new file mode 100644 index 0000000..1d0a3cc Binary files /dev/null and b/Hide-show-pass/Images/.DS_Store differ diff --git a/Hide-show-pass/Images/open.png b/Hide-show-pass/Images/open.png new file mode 100644 index 0000000..1aed309 Binary files /dev/null and b/Hide-show-pass/Images/open.png differ diff --git a/Hide-show-pass/Images/shut.png b/Hide-show-pass/Images/shut.png new file mode 100644 index 0000000..d68b40d Binary files /dev/null and b/Hide-show-pass/Images/shut.png differ diff --git a/Hide-show-pass/README.md b/Hide-show-pass/README.md new file mode 100644 index 0000000..f4d6a75 --- /dev/null +++ b/Hide-show-pass/README.md @@ -0,0 +1,2 @@ +Hide/Show password +A project made using HTML, CSS and JS which can be integrated easily to your website for better security when entering password in public spaces.} \ No newline at end of file diff --git a/Hide-show-pass/index.html b/Hide-show-pass/index.html new file mode 100644 index 0000000..af9dcb9 --- /dev/null +++ b/Hide-show-pass/index.html @@ -0,0 +1,16 @@ + + + + + + Hide/Show pass + + + +
+ + error +
+ + + \ No newline at end of file diff --git a/Hide-show-pass/script.js b/Hide-show-pass/script.js new file mode 100644 index 0000000..89cc721 --- /dev/null +++ b/Hide-show-pass/script.js @@ -0,0 +1,13 @@ +let eyeicon = document.getElementById("eyeicon"); +let password = document.getElementById("password"); + +eyeicon.onclick = function(){ + if(password.type == "password"){ + password.type = "text"; + eyeicon.src = "./Images/open.png"; + } + else{ + password.type = "password"; + eyeicon.src = "./Images/shut.png"; + } +} \ No newline at end of file diff --git a/Hide-show-pass/style.css b/Hide-show-pass/style.css new file mode 100644 index 0000000..28d5af3 --- /dev/null +++ b/Hide-show-pass/style.css @@ -0,0 +1,40 @@ +*{ + margin: 0; + padding: 0; + font-family: 'Poppins', sans-serif; + box-sizing: border-box; +} + +body{ + background: #00008B; +} + +.input-box{ + background: #fff; + width: 90%; + max-width: 500px; + border-radius: 5px; + padding: 10px 20px; + margin: 300px auto; + display: flex; + align-items: center; +} + +.input-box input{ + width: 100%; + padding: 10px 0; + border: 0; + outline: 0; + font-size: 24px; + color: #555; +} + +.input-box img{ + width: 35px; + cursor: pointer; +} + +img{ + width: 35px; + cursor: pointer; +} \ No newline at end of file diff --git a/README.md b/README.md index 911f598..17959c6 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ - URL Shortener - Weather Appliation - Word Scramble +- Snake Game

🍰 Contribution Guidelines:

@@ -47,10 +48,15 @@ Open for contributions. Check this [file](https://github.com/shrey141102/Javascript-projects/blob/main/CONTRIBUTING.md) for steps to contribute. +Please read the `CONTRIBUTING.md` file carefully before submitting a PR. +Also, make sure your PR fulfills the required conditions present in the PR template. + Please update this README file by adding your project name. Also remember to add a README inside your project directory explaining what your project is. +Please avoid adding same projects again and again. (unless it has a very different approach/ui) +

💻 Built with

Built by people around the globe. 🌐🧑‍🤝‍🧑

@@ -60,5 +66,3 @@ Technologies used in the project: - Javascript - HTML - CSS - -please feel free to use any technology while building the project. It can be AI or Blockchain or anything. Just remeber that it should be able to work with and intergrate with the website. diff --git a/Snake_Game/Assets/food.png b/Snake_Game/Assets/food.png new file mode 100644 index 0000000..680bb05 Binary files /dev/null and b/Snake_Game/Assets/food.png differ diff --git a/Snake_Game/Assets/grass.jpg b/Snake_Game/Assets/grass.jpg new file mode 100644 index 0000000..c743b26 Binary files /dev/null and b/Snake_Game/Assets/grass.jpg differ diff --git a/Snake_Game/Assets/preview.jpg b/Snake_Game/Assets/preview.jpg new file mode 100644 index 0000000..badbdda Binary files /dev/null and b/Snake_Game/Assets/preview.jpg differ diff --git a/Snake_Game/Assets/snake.png b/Snake_Game/Assets/snake.png new file mode 100644 index 0000000..f957bc8 Binary files /dev/null and b/Snake_Game/Assets/snake.png differ diff --git a/Snake_Game/README.md b/Snake_Game/README.md new file mode 100644 index 0000000..8fe28b0 --- /dev/null +++ b/Snake_Game/README.md @@ -0,0 +1,2 @@ +# Snake-Game +Its a basics Javascript snake game using DOM Event diff --git a/Snake_Game/app.js b/Snake_Game/app.js new file mode 100644 index 0000000..f946c3f --- /dev/null +++ b/Snake_Game/app.js @@ -0,0 +1,33 @@ +let food =document.querySelector(".food"); +let snake=document.querySelector(".snake"); +let move=document.querySelector("input"); +let h1=document.querySelector("h1"); +let mh=0; +let mv=0; +let fh=0; +let fv=0; +let count =-1; +move.addEventListener("keydown",function(event){ + if(mv==fv&&mh==fh){ + fv=Math.floor(Math.random()*19)*30; + fh=Math.floor(Math.random()*29)*30; + food.style.marginTop=`${fv}px`; + food.style.marginLeft=`${fh}px`; + count++; + h1.innerText=`SCORE : ${count}`; + } + if(event.code=="ArrowUp"&&mv>0){ + mv-=30; + } + if(event.code=="ArrowDown"&&mv<560){ + mv+=30; + } + if(event.code=="ArrowLeft"&&mh>0){ + mh-=30; + } + if(event.code=="ArrowRight"&&mh<860){ + mh+=30; + } + snake.style.marginTop=`${mv}px`; + snake.style.marginLeft=`${mh}px`; +}); \ No newline at end of file diff --git a/Snake_Game/index.html b/Snake_Game/index.html new file mode 100644 index 0000000..5c26104 --- /dev/null +++ b/Snake_Game/index.html @@ -0,0 +1,23 @@ + + + + + + Snake Game + + + +
+ +
+
+
+
+
MOVE
+

+

SCORE : 0

+
+ + + + \ No newline at end of file diff --git a/Snake_Game/style.css b/Snake_Game/style.css new file mode 100644 index 0000000..b7a08bc --- /dev/null +++ b/Snake_Game/style.css @@ -0,0 +1,62 @@ +*{ + margin: 0px; + padding: 0px; +} +.playground{ + height:600px; + width: 900px; + background-image: url(Assets/grass.jpg); + background-size: cover; + position: absolute; + opacity: 0.8; +} + +.food{ + height: 50px; + width:70px; + background-image: url(Assets/food.png); + background-size: cover; + position: absolute; +} + +.snake{ + height: 60px; + width: 60px; + position: absolute; + background-image: url(Assets/snake.png); + background-size: cover; + position: absolute; +} +.score{ + + height: 300px; + width: 300px; + position: absolute; + margin-left: 903px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sudoku Game/.vscode/settings.json b/Sudoku Game/.vscode/settings.json new file mode 100644 index 0000000..6b665aa --- /dev/null +++ b/Sudoku Game/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} diff --git a/Sudoku Game/bozhin-karaivanov-yqcWOAHH1Rs-unsplash.jpg b/Sudoku Game/bozhin-karaivanov-yqcWOAHH1Rs-unsplash.jpg new file mode 100644 index 0000000..cca934b Binary files /dev/null and b/Sudoku Game/bozhin-karaivanov-yqcWOAHH1Rs-unsplash.jpg differ diff --git a/Sudoku Game/index.html b/Sudoku Game/index.html new file mode 100644 index 0000000..a48b4ec --- /dev/null +++ b/Sudoku Game/index.html @@ -0,0 +1,151 @@ + + + + + + + + + Play Free Sudoku online - solve web sudoku puzzles + + + + + + + +
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ Mistake + 0/3 + Hints: + 3/3 +
+
+ + +
+
+ + + + + + + + + +
+
+ + + + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/Sudoku Game/logo.png b/Sudoku Game/logo.png new file mode 100644 index 0000000..53ff503 Binary files /dev/null and b/Sudoku Game/logo.png differ diff --git a/Sudoku Game/main.js b/Sudoku Game/main.js new file mode 100644 index 0000000..bbd3d69 --- /dev/null +++ b/Sudoku Game/main.js @@ -0,0 +1,171 @@ +const gameBoard = document.getElementById("gameBoard"); +const squares = document.getElementsByClassName("square"); +const numbers = document.getElementsByClassName("number"); +const solveButton = document.getElementById("solveButton"); +const newGameButton = document.getElementById("newGameButton"); +const eraseButton = document.getElementById("eraseButton"); +const hintButton = document.getElementById("hintButton"); +const hints = document.getElementById("hint"); +const mistakeElement = document.getElementById("mistakes"); +let mistake =0; +let hintNumber =3; + +let level = difficulty.value; +let board = sudoku.generate(level,false); +let solvedString = sudoku.solve(board); +let sudokuString = board; +let sudokuBoard = stringToArray(sudokuString); +let sudokuSolved = stringToArray(solvedString); + +setupBoard(); +fillBoard(sudokuBoard); + + +function setupBoard() { + for (let i=0;isquare.classList.remove("active")); + this.classList.add("active"); +} + +function fillBoard(board) { + for (let i=0;isquare.classList.remove("active")); + showAlert(message,color); +} +eraseButton.addEventListener("click",function(){ + let activeSquare = document.querySelector(".active"); + if(activeSquare==null)return; + activeSquare.classList.remove("active"); + if(activeSquare.classList.contains("filled")) return; + activeSquare.innerHTML=""; +}); + +hintButton.addEventListener ("click",function(){ + if(hintNumber==0) { + showAlert("Oops! You've used all your hints."); + return; + } + let activeSquare = document.querySelector(".active"); + activeSquare.classList.remove("active"); + if(activeSquare.classList.contains("filled")) return; + let row = parseInt(activeSquare.id.charAt(0)); + let column = parseInt(activeSquare.id.charAt(1)); + activeSquare.innerHTML = sudokuSolved[row-1][column-1]; + activeSquare.classList.add("filled"); + activeSquare.classList.add("true"); + hintNumber--; + hints.innerHTML = hintNumber+"/3"; +}); +solveButton.addEventListener("click",function(){ + resetBoard(); + fillBoard(sudokuSolved); +}); +newGameButton.addEventListener("click",function(){ + resetBoard(); + level = difficulty.value; + board = sudoku.generate(level,false); + sudokuString = board; + solvedString = sudoku.solve(board); + sudokuBoard = stringToArray(sudokuString); + sudokuSolved = stringToArray(solvedString); + setupBoard(); + fillBoard(sudokuBoard); + mistake = 0; + mistakeElement.innerHTML = "0/3"; + hintNumber =3; + hints.innerHTML = "3/3"; +}); + +function resetBoard() { + for(let i=0;i units map + var SQUARE_PEERS_MAP = null; // Squares -> peers map + + var MIN_GIVENS = 17; // Minimum number of givens + var NR_SQUARES = 81; // Number of squares + + // Define difficulties by how many squares are given to the player in a new + // puzzle. + var DIFFICULTY = { + "easy": 62, + "medium": 53, + "hard": 44, + "very-hard": 35, + "insane": 26, + "inhuman": 17, + }; + + // Blank character and board representation + sudoku.BLANK_CHAR = '.'; + sudoku.BLANK_BOARD = "...................................................."+ + "............................."; + + // Init + // ------------------------------------------------------------------------- + function initialize(){ + /* Initialize the Sudoku library (invoked after library load) + */ + SQUARES = sudoku._cross(ROWS, COLS); + UNITS = sudoku._get_all_units(ROWS, COLS); + SQUARE_UNITS_MAP = sudoku._get_square_units_map(SQUARES, UNITS); + SQUARE_PEERS_MAP = sudoku._get_square_peers_map(SQUARES, + SQUARE_UNITS_MAP); + } + + // Generate + // ------------------------------------------------------------------------- + sudoku.generate = function(difficulty, unique){ + /* Generate a new Sudoku puzzle of a particular `difficulty`, e.g., + + // Generate an "easy" sudoku puzzle + sudoku.generate("easy"); + + + Difficulties are as follows, and represent the number of given squares: + + "easy": 61 + "medium": 52 + "hard": 43 + "very-hard": 34 + "insane": 25 + "inhuman": 17 + + + You may also enter a custom number of squares to be given, e.g., + + // Generate a new Sudoku puzzle with 60 given squares + sudoku.generate(60) + + + `difficulty` must be a number between 17 and 81 inclusive. If it's + outside of that range, `difficulty` will be set to the closest bound, + e.g., 0 -> 17, and 100 -> 81. + + + By default, the puzzles are unique, uless you set `unique` to false. + (Note: Puzzle uniqueness is not yet implemented, so puzzles are *not* + guaranteed to have unique solutions) + + TODO: Implement puzzle uniqueness + */ + + // If `difficulty` is a string or undefined, convert it to a number or + // default it to "easy" if undefined. + if(typeof difficulty === "string" || typeof difficulty === "undefined"){ + difficulty = DIFFICULTY[difficulty] || DIFFICULTY.easy; + } + + // Force difficulty between 17 and 81 inclusive + difficulty = sudoku._force_range(difficulty, NR_SQUARES + 1, + MIN_GIVENS); + + // Default unique to true + unique = unique || true; + + // Get a set of squares and all possible candidates for each square + var blank_board = ""; + for(var i = 0; i < NR_SQUARES; ++i){ + blank_board += '.'; + } + var candidates = sudoku._get_candidates_map(blank_board); + + // For each item in a shuffled list of squares + var shuffled_squares = sudoku._shuffle(SQUARES); + for(var si in shuffled_squares){ + var square = shuffled_squares[si]; + + // If an assignment of a random chioce causes a contradictoin, give + // up and try again + var rand_candidate_idx = + sudoku._rand_range(candidates[square].length); + var rand_candidate = candidates[square][rand_candidate_idx]; + if(!sudoku._assign(candidates, square, rand_candidate)){ + break; + } + + // Make a list of all single candidates + var single_candidates = []; + for(var si in SQUARES){ + var square = SQUARES[si]; + + if(candidates[square].length == 1){ + single_candidates.push(candidates[square]); + } + } + + // If we have at least difficulty, and the unique candidate count is + // at least 8, return the puzzle! + if(single_candidates.length >= difficulty && + sudoku._strip_dups(single_candidates).length >= 8){ + var board = ""; + var givens_idxs = []; + for(var i in SQUARES){ + var square = SQUARES[i]; + if(candidates[square].length == 1){ + board += candidates[square]; + givens_idxs.push(i); + } else { + board += sudoku.BLANK_CHAR; + } + } + + // If we have more than `difficulty` givens, remove some random + // givens until we're down to exactly `difficulty` + var nr_givens = givens_idxs.length; + if(nr_givens > difficulty){ + givens_idxs = sudoku._shuffle(givens_idxs); + for(var i = 0; i < nr_givens - difficulty; ++i){ + var target = parseInt(givens_idxs[i]); + board = board.substr(0, target) + sudoku.BLANK_CHAR + + board.substr(target + 1); + } + } + + // Double check board is solvable + // TODO: Make a standalone board checker. Solve is expensive. + if(sudoku.solve(board)){ + return board; + } + } + } + + // Give up and try a new puzzle + return sudoku.generate(difficulty); + }; + + // Solve + // ------------------------------------------------------------------------- + sudoku.solve = function(board, reverse){ + /* Solve a sudoku puzzle given a sudoku `board`, i.e., an 81-character + string of sudoku.DIGITS, 1-9, and spaces identified by '.', representing the + squares. There must be a minimum of 17 givens. If the given board has no + solutions, return false. + + Optionally set `reverse` to solve "backwards", i.e., rotate through the + possibilities in reverse. Useful for checking if there is more than one + solution. + */ + + // Assure a valid board + var report = sudoku.validate_board(board); + if(report !== true){ + throw report; + } + + // Check number of givens is at least MIN_GIVENS + var nr_givens = 0; + for(var i in board){ + if(board[i] !== sudoku.BLANK_CHAR && sudoku._in(board[i], sudoku.DIGITS)){ + ++nr_givens; + } + } + if(nr_givens < MIN_GIVENS){ + throw "Too few givens. Minimum givens is " + MIN_GIVENS; + } + + // Default reverse to false + reverse = reverse || false; + + var candidates = sudoku._get_candidates_map(board); + var result = sudoku._search(candidates, reverse); + + if(result){ + var solution = ""; + for(var square in result){ + solution += result[square]; + } + return solution; + } + return false; + }; + + sudoku.get_candidates = function(board){ + /* Return all possible candidatees for each square as a grid of + candidates, returnning `false` if a contradiction is encountered. + + Really just a wrapper for sudoku._get_candidates_map for programmer + consumption. + */ + + // Assure a valid board + var report = sudoku.validate_board(board); + if(report !== true){ + throw report; + } + + // Get a candidates map + var candidates_map = sudoku._get_candidates_map(board); + + // If there's an error, return false + if(!candidates_map){ + return false; + } + + // Transform candidates map into grid + var rows = []; + var cur_row = []; + var i = 0; + for(var square in candidates_map){ + var candidates = candidates_map[square]; + cur_row.push(candidates); + if(i % 9 == 8){ + rows.push(cur_row); + cur_row = []; + } + ++i; + } + return rows; + } + + sudoku._get_candidates_map = function(board){ + /* Get all possible candidates for each square as a map in the form + {square: sudoku.DIGITS} using recursive constraint propagation. Return `false` + if a contradiction is encountered + */ + + // Assure a valid board + var report = sudoku.validate_board(board); + if(report !== true){ + throw report; + } + + var candidate_map = {}; + var squares_values_map = sudoku._get_square_vals_map(board); + + // Start by assigning every digit as a candidate to every square + for(var si in SQUARES){ + candidate_map[SQUARES[si]] = sudoku.DIGITS; + } + + // For each non-blank square, assign its value in the candidate map and + // propigate. + for(var square in squares_values_map){ + var val = squares_values_map[square]; + + if(sudoku._in(val, sudoku.DIGITS)){ + var new_candidates = sudoku._assign(candidate_map, square, val); + + // Fail if we can't assign val to square + if(!new_candidates){ + return false; + } + } + } + + return candidate_map; + }; + + sudoku._search = function(candidates, reverse){ + /* Given a map of squares -> candiates, using depth-first search, + recursively try all possible values until a solution is found, or false + if no solution exists. + */ + + // Return if error in previous iteration + if(!candidates){ + return false; + } + + // Default reverse to false + reverse = reverse || false; + + // If only one candidate for every square, we've a solved puzzle! + // Return the candidates map. + var max_nr_candidates = 0; + var max_candidates_square = null; + for(var si in SQUARES){ + var square = SQUARES[si]; + + var nr_candidates = candidates[square].length; + + if(nr_candidates > max_nr_candidates){ + max_nr_candidates = nr_candidates; + max_candidates_square = square; + } + } + if(max_nr_candidates === 1){ + return candidates; + } + + // Choose the blank square with the fewest possibilities > 1 + var min_nr_candidates = 10; + var min_candidates_square = null; + for(si in SQUARES){ + var square = SQUARES[si]; + + var nr_candidates = candidates[square].length; + + if(nr_candidates < min_nr_candidates && nr_candidates > 1){ + min_nr_candidates = nr_candidates; + min_candidates_square = square; + } + } + + // Recursively search through each of the candidates of the square + // starting with the one with fewest candidates. + + // Rotate through the candidates forwards + var min_candidates = candidates[min_candidates_square]; + if(!reverse){ + for(var vi in min_candidates){ + var val = min_candidates[vi]; + + // TODO: Implement a non-rediculous deep copy function + var candidates_copy = JSON.parse(JSON.stringify(candidates)); + var candidates_next = sudoku._search( + sudoku._assign(candidates_copy, min_candidates_square, val) + ); + + if(candidates_next){ + return candidates_next; + } + } + + // Rotate through the candidates backwards + } else { + for(var vi = min_candidates.length - 1; vi >= 0; --vi){ + var val = min_candidates[vi]; + + // TODO: Implement a non-rediculous deep copy function + var candidates_copy = JSON.parse(JSON.stringify(candidates)); + var candidates_next = sudoku._search( + sudoku._assign(candidates_copy, min_candidates_square, val), + reverse + ); + + if(candidates_next){ + return candidates_next; + } + } + } + + // If we get through all combinations of the square with the fewest + // candidates without finding an answer, there isn't one. Return false. + return false; + }; + + sudoku._assign = function(candidates, square, val){ + /* Eliminate all values, *except* for `val`, from `candidates` at + `square` (candidates[square]), and propagate. Return the candidates map + when finished. If a contradiciton is found, return false. + + WARNING: This will modify the contents of `candidates` directly. + */ + + // Grab a list of canidates without 'val' + var other_vals = candidates[square].replace(val, ""); + + // Loop through all other values and eliminate them from the candidates + // at the current square, and propigate. If at any point we get a + // contradiction, return false. + for(var ovi in other_vals){ + var other_val = other_vals[ovi]; + + var candidates_next = + sudoku._eliminate(candidates, square, other_val); + + if(!candidates_next){ + //console.log("Contradiction found by _eliminate."); + return false; + } + } + + return candidates; + }; + + sudoku._eliminate = function(candidates, square, val){ + /* Eliminate `val` from `candidates` at `square`, (candidates[square]), + and propagate when values or places <= 2. Return updated candidates, + unless a contradiction is detected, in which case, return false. + + WARNING: This will modify the contents of `candidates` directly. + */ + + // If `val` has already been eliminated from candidates[square], return + // with candidates. + if(!sudoku._in(val, candidates[square])){ + return candidates; + } + + // Remove `val` from candidates[square] + candidates[square] = candidates[square].replace(val, ''); + + // If the square has only candidate left, eliminate that value from its + // peers + var nr_candidates = candidates[square].length; + if(nr_candidates === 1){ + var target_val = candidates[square]; + + for(var pi in SQUARE_PEERS_MAP[square]){ + var peer = SQUARE_PEERS_MAP[square][pi]; + + var candidates_new = + sudoku._eliminate(candidates, peer, target_val); + + if(!candidates_new){ + return false; + } + } + + // Otherwise, if the square has no candidates, we have a contradiction. + // Return false. + } if(nr_candidates === 0){ + return false; + } + + // If a unit is reduced to only one place for a value, then assign it + for(var ui in SQUARE_UNITS_MAP[square]){ + var unit = SQUARE_UNITS_MAP[square][ui]; + + var val_places = []; + for(var si in unit){ + var unit_square = unit[si]; + if(sudoku._in(val, candidates[unit_square])){ + val_places.push(unit_square); + } + } + + // If there's no place for this value, we have a contradition! + // return false + if(val_places.length === 0){ + return false; + + // Otherwise the value can only be in one place. Assign it there. + } else if(val_places.length === 1){ + var candidates_new = + sudoku._assign(candidates, val_places[0], val); + + if(!candidates_new){ + return false; + } + } + } + + return candidates; + }; + + + // Square relationships + // ------------------------------------------------------------------------- + // Squares, and their relationships with values, units, and peers. + + sudoku._get_square_vals_map = function(board){ + /* Return a map of squares -> values + */ + var squares_vals_map = {}; + + // Make sure `board` is a string of length 81 + if(board.length != SQUARES.length){ + throw "Board/squares length mismatch."; + + } else { + for(var i in SQUARES){ + squares_vals_map[SQUARES[i]] = board[i]; + } + } + + return squares_vals_map; + }; + + sudoku._get_square_units_map = function(squares, units){ + /* Return a map of `squares` and their associated units (row, col, box) + */ + var square_unit_map = {}; + + // For every square... + for(var si in squares){ + var cur_square = squares[si]; + + // Maintain a list of the current square's units + var cur_square_units = []; + + // Look through the units, and see if the current square is in it, + // and if so, add it to the list of of the square's units. + for(var ui in units){ + var cur_unit = units[ui]; + + if(cur_unit.indexOf(cur_square) !== -1){ + cur_square_units.push(cur_unit); + } + } + + // Save the current square and its units to the map + square_unit_map[cur_square] = cur_square_units; + } + + return square_unit_map; + }; + + sudoku._get_square_peers_map = function(squares, units_map){ + /* Return a map of `squares` and their associated peers, i.e., a set of + other squares in the square's unit. + */ + var square_peers_map = {}; + + // For every square... + for(var si in squares){ + var cur_square = squares[si]; + var cur_square_units = units_map[cur_square]; + + // Maintain list of the current square's peers + var cur_square_peers = []; + + // Look through the current square's units map... + for(var sui in cur_square_units){ + var cur_unit = cur_square_units[sui]; + + for(var ui in cur_unit){ + var cur_unit_square = cur_unit[ui]; + + if(cur_square_peers.indexOf(cur_unit_square) === -1 && + cur_unit_square !== cur_square){ + cur_square_peers.push(cur_unit_square); + } + } + } + + // Save the current square an its associated peers to the map + square_peers_map[cur_square] = cur_square_peers; + } + + return square_peers_map; + }; + + sudoku._get_all_units = function(rows, cols){ + /* Return a list of all units (rows, cols, boxes) + */ + var units = []; + + // Rows + for(var ri in rows){ + units.push(sudoku._cross(rows[ri], cols)); + } + + // Columns + for(var ci in cols){ + units.push(sudoku._cross(rows, cols[ci])); + } + + // Boxes + var row_squares = ["ABC", "DEF", "GHI"]; + var col_squares = ["123", "456", "789"]; + for(var rsi in row_squares){ + for(var csi in col_squares){ + units.push(sudoku._cross(row_squares[rsi], col_squares[csi])); + } + } + + return units; + }; + + + // Conversions + // ------------------------------------------------------------------------- + sudoku.board_string_to_grid = function(board_string){ + /* Convert a board string to a two-dimensional array + */ + var rows = []; + var cur_row = []; + for(var i in board_string){ + cur_row.push(board_string[i]); + if(i % 9 == 8){ + rows.push(cur_row); + cur_row = []; + } + } + return rows; + }; + + sudoku.board_grid_to_string = function(board_grid){ + /* Convert a board grid to a string + */ + var board_string = ""; + for(var r = 0; r < 9; ++r){ + for(var c = 0; c < 9; ++c){ + board_string += board_grid[r][c]; + } + } + return board_string; + }; + + + // Utility + // ------------------------------------------------------------------------- + + sudoku.print_board = function(board){ + /* Print a sudoku `board` to the console. + */ + + // Assure a valid board + var report = sudoku.validate_board(board); + if(report !== true){ + throw report; + } + + var V_PADDING = " "; // Insert after each square + var H_PADDING = '\n'; // Insert after each row + + var V_BOX_PADDING = " "; // Box vertical padding + var H_BOX_PADDING = '\n'; // Box horizontal padding + + var display_string = ""; + + for(var i in board){ + var square = board[i]; + + // Add the square and some padding + display_string += square + V_PADDING; + + // Vertical edge of a box, insert v. box padding + if(i % 3 === 2){ + display_string += V_BOX_PADDING; + } + + // End of a line, insert horiz. padding + if(i % 9 === 8){ + display_string += H_PADDING; + } + + // Horizontal edge of a box, insert h. box padding + if(i % 27 === 26){ + display_string += H_BOX_PADDING; + } + } + + console.log(display_string); + }; + + sudoku.validate_board = function(board){ + /* Return if the given `board` is valid or not. If it's valid, return + true. If it's not, return a string of the reason why it's not. + */ + + // Check for empty board + if(!board){ + return "Empty board"; + } + + // Invalid board length + if(board.length !== NR_SQUARES){ + return "Invalid board size. Board must be exactly " + NR_SQUARES + + " squares."; + } + + // Check for invalid characters + for(var i in board){ + if(!sudoku._in(board[i], sudoku.DIGITS) && board[i] !== sudoku.BLANK_CHAR){ + return "Invalid board character encountered at index " + i + + ": " + board[i]; + } + } + + // Otherwise, we're good. Return true. + return true; + }; + + sudoku._cross = function(a, b){ + /* Cross product of all elements in `a` and `b`, e.g., + sudoku._cross("abc", "123") -> + ["a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3"] + */ + var result = []; + for(var ai in a){ + for(var bi in b){ + result.push(a[ai] + b[bi]); + } + } + return result; + }; + + sudoku._in = function(v, seq){ + /* Return if a value `v` is in sequence `seq`. + */ + return seq.indexOf(v) !== -1; + }; + + sudoku._first_true = function(seq){ + /* Return the first element in `seq` that is true. If no element is + true, return false. + */ + for(var i in seq){ + if(seq[i]){ + return seq[i]; + } + } + return false; + }; + + sudoku._shuffle = function(seq){ + /* Return a shuffled version of `seq` + */ + + // Create an array of the same size as `seq` filled with false + var shuffled = []; + for(var i = 0; i < seq.length; ++i){ + shuffled.push(false); + } + + for(var i in seq){ + var ti = sudoku._rand_range(seq.length); + + while(shuffled[ti]){ + ti = (ti + 1) > (seq.length - 1) ? 0 : (ti + 1); + } + + shuffled[ti] = seq[i]; + } + + return shuffled; + }; + + sudoku._rand_range = function(max, min){ + /* Get a random integer in the range of `min` to `max` (non inclusive). + If `min` not defined, default to 0. If `max` not defined, throw an + error. + */ + min = min || 0; + if(max){ + return Math.floor(Math.random() * (max - min)) + min; + } else { + throw "Range undefined"; + } + }; + + sudoku._strip_dups = function(seq){ + /* Strip duplicate values from `seq` + */ + var seq_set = []; + var dup_map = {}; + for(var i in seq){ + var e = seq[i]; + if(!dup_map[e]){ + seq_set.push(e); + dup_map[e] = true; + } + } + return seq_set; + }; + + sudoku._force_range = function(nr, max, min){ + /* Force `nr` to be within the range from `min` to, but not including, + `max`. `min` is optional, and will default to 0. If `nr` is undefined, + treat it as zero. + */ + min = min || 0 + nr = nr || 0 + if(nr < min){ + return min; + } + if(nr > max){ + return max; + } + return nr + } + + // Initialize library after load + initialize(); + +// Pass whatever the root object is, lsike 'window' in browsers +})(this); \ No newline at end of file diff --git a/script.js b/script.js index 006fb90..85065b8 100644 --- a/script.js +++ b/script.js @@ -235,6 +235,20 @@ const projects = [ link: "./Word Scramble/index.html", image: "https://dictionary.cambridge.org/external/images/wordscramble-og-image.png" }, + { + title: "Snake Game", + discription: + "Its a basics Javascript snake game using DOM Event.", + link: "./Snake_Game/index.html", + image: "https://w7.pngwing.com/pngs/543/374/png-transparent-snake-2000-classic-nokia-game-slither-worm-snake-a-classic-snake-game-classic-game-snake-ii-snake-food-animals-grass-thumbnail.png" + }, + { + title: "Sudoku Game", + discription: + "Sudoku Game game made using HTML, CSS and JS", + link: "./Sudoku Game/index.html", + image: "./Sudoku Game/bozhin-karaivanov-yqcWOAHH1Rs-unsplash.jpg" + }, { title: "Background Color Changer", discription: