diff --git a/solution.md b/solution.md new file mode 100644 index 0000000..e69de29 diff --git a/tic-tac-toe/index.html b/tic-tac-toe/index.html new file mode 100644 index 0000000..0af5e5c --- /dev/null +++ b/tic-tac-toe/index.html @@ -0,0 +1,32 @@ + + + + + + Tic-Tac-Toe + + + +
+ Tic Tac Toe +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ +
+
+ + + \ No newline at end of file diff --git a/tic-tac-toe/script.js b/tic-tac-toe/script.js new file mode 100644 index 0000000..28521a7 --- /dev/null +++ b/tic-tac-toe/script.js @@ -0,0 +1,107 @@ +const cells = document.querySelectorAll(".box"); +const chance = document.querySelector("#player"); +const newButton = document.querySelector("#newGame"); + +let vict = 0; +let symbol; +let cellX = []; +let cellO = []; +let currentIndex = 0; // Keep track of keyboard navigation + +const winningPossibilities = [ + ['0', '1', '2'], + ['3', '4', '5'], + ['6', '7', '8'], + ['0', '3', '6'], + ['1', '4', '7'], + ['2', '5', '8'], + ['0', '4', '8'], + ['2', '4', '6'], +]; + +newButton.addEventListener("click", startGame); +document.addEventListener("keydown", handleKeyboardNavigation); + + +function startGame() { + newButton.blur(); + symbol = "O"; + cellO = []; + cellX = []; + vict = 0; + currentIndex = 0; + chance.innerHTML = `${symbol}'s turn`; + + cells.forEach(cell => { + cell.innerHTML = ""; + cell.classList.remove("highlight"); + cell.removeEventListener("click", instantiate); + cell.addEventListener("click", instantiate); + }); + + +} + +function changePlayer() { + symbol = symbol === "O" ? "X" : "O"; + chance.innerHTML = `${symbol}'s turn`; +} + +function winGame(playerCells, player) { + if (winningPossibilities.some(pattern => pattern.every(index => playerCells.includes(index)))) { + chance.innerHTML = `${player} has won the game!`; + vict = 1; + return; + } + if (cellX.length + cellO.length === 9) { + chance.innerHTML = "It's a draw!"; + vict = 1; + return; + } + changePlayer(); +} + +function instantiate(event) { + let cell = event.target; + if (cell.innerHTML !== "" || vict > 0) return; // Prevent overwriting or playing after a win + + let index = cell.getAttribute("data-index"); // Get the cell index + + cell.innerHTML = symbol; + if (symbol === "X") { + cellX.push(index); + cellX.sort(); + } else { + cellO.push(index); + cellO.sort(); + } + + winGame(symbol === "X" ? cellX : cellO, symbol); +} + +function handleKeyboardNavigation(event) { + if (vict > 0) return; // Stop if the game is over + + const rowSize = 3; + if (event.key === "ArrowRight") { + currentIndex = (currentIndex + 1) % cells.length; + } else if (event.key === "ArrowLeft") { + currentIndex = (currentIndex - 1 + cells.length) % cells.length; + } else if (event.key === "ArrowDown") { + currentIndex = (currentIndex + rowSize) % cells.length; + } else if (event.key === "ArrowUp") { + currentIndex = (currentIndex - rowSize + cells.length) % cells.length; + } else if (event.key === "Enter") { + instantiate({ target: cells[currentIndex] }); // Fix: Ensure Enter key works + } + + highlightCell(); +} + +function highlightCell() { + cells.forEach(cell => cell.classList.remove("highlight")); + cells[currentIndex].classList.add("highlight"); +} + + + diff --git a/tic-tac-toe/styles.css b/tic-tac-toe/styles.css new file mode 100644 index 0000000..12b79e5 --- /dev/null +++ b/tic-tac-toe/styles.css @@ -0,0 +1,50 @@ +#canva{ + width: 500px; + height: 500px; + border: solid 2px black; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr 1fr; + justify-self: center; +} + +.highlight{ + border: solid 2px black; + font-size: 80px; + text-align: center; + line-height: 160px; + background-color: rgb(4, 238, 238); +} + +.title{ + font-size: 40px; + letter-spacing: 8px; + margin: 40px 0px; + font-weight: bolder; + font-family: 'Times New Roman', Times, serif; + text-align: center; +} + +.bottom{ + justify-items: center; + margin-top: 60px; +} + +.box{ + border: solid 2px black; + font-size: 80px; + text-align: center; + line-height: 160px; +} + +#player{ + font-size: 40px;; +} + +button{ + margin-top: 20px; + width: 200px; + height: 50px; + font-size: 30px; + background-color: greenyellow; +} \ No newline at end of file diff --git a/typing-game-solution/.vscode/settings.json b/typing-game-solution/.vscode/settings.json new file mode 100644 index 0000000..6f3a291 --- /dev/null +++ b/typing-game-solution/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/typing-game-solution/index.html b/typing-game-solution/index.html new file mode 100644 index 0000000..0e388e3 --- /dev/null +++ b/typing-game-solution/index.html @@ -0,0 +1,22 @@ + + + Typing game + + + + + + +
+

Typing game !

+

Practice your typing skills with a quote from Sherlock Holmes. Click **start** to begin!

+

+

+
+
+ + +
+ + + \ No newline at end of file diff --git a/typing-game-solution/script.js b/typing-game-solution/script.js new file mode 100644 index 0000000..fd55fa7 --- /dev/null +++ b/typing-game-solution/script.js @@ -0,0 +1,97 @@ +// inside script.js +// all of our quotes +const quotes = [ + 'When you have eliminated the impossible, whatever remains, however improbable, must be the truth.', + 'There is nothing more deceptive than an obvious fact.', + 'I ought to know by this time that when a fact appears to be opposed to a long train of deductions it invariably proves to be capable of bearing some other interpretation.', + 'I never make exceptions. An exception disproves the rule.', + 'What one man can invent another can discover.', + 'Nothing clears up a case so much as stating it to another person.', + 'Education never ends, Watson. It is a series of lessons, with the greatest for the last.', + 'Mediocrity knows nothing higher than itself; but talent instantly recognizes genius.', + 'What you do in this world is a matter of no consequence. The question is what can you make people believe you have done.', + 'Crime is common. Logic is rare. Therefore it is upon the logic rather than upon the crime that you should dwell.', +]; +// store the list of words and the index of the word the player is currently typing +let words = []; +let wordIndex = 0; +// the starting time +let startTime = Date.now(); +// page elements +const quoteElement = document.getElementById('quote'); +const messageElement = document.getElementById('message'); +const typedValueElement = document.getElementById('typed-value'); + +// at the end of script.js +document.getElementById('start').addEventListener('click', () => { + // get a quote + typedValueElement.disabled=false; + const quoteIndex = Math.floor(Math.random() * quotes.length); + const quote = quotes[quoteIndex]; + // Put the quote into an array of words + words = quote.split(' '); + // reset the word index for tracking + wordIndex = 0; + + // UI updates + // Create an array of span elements so we can set a class + const spanWords = words.map(function(word) { return `${word} `}); + // Convert into string and set as innerHTML on quote display + quoteElement.innerHTML = spanWords.join(''); + // Highlight the first word + quoteElement.childNodes[0].className = 'highlight'; + // Clear any prior messages + messageElement.innerText = ''; + + // Setup the textbox + // Clear the textbox + typedValueElement.value = ''; + // set focus + typedValueElement.focus(); + // set the event handler + + // Start the timer + startTime = new Date().getTime(); + }); + + // at the end of script.js +typedValueElement.addEventListener('input', getInput); + + + +function getInput(){ + // Get the current word + const currentWord = words[wordIndex]; + // get the current value + const typedValue = typedValueElement.value; + + if (typedValue === currentWord && wordIndex === words.length - 1) { + // end of sentence + // Display success + const elapsedTime = new Date().getTime() - startTime; + const message = `CONGRATULATIONS! You finished in ${elapsedTime / 1000} seconds.`; + messageElement.innerText = message; + typedValueElement.removeEventListener('input',getInput); + typedValueElement.disabled=true; + } else if (typedValue.endsWith(' ') && typedValue.trim() === currentWord) { + // end of word + // clear the typedValueElement for the new word + typedValueElement.value = ''; + // move to the next word + wordIndex++; + // reset the class name for all elements in quote + for (const wordElement of quoteElement.childNodes) { + wordElement.className = ''; + } + // highlight the new word + quoteElement.childNodes[wordIndex].className = 'highlight'; + } else if (currentWord.startsWith(typedValue)) { + // currently correct + // highlight the next word + typedValueElement.className=''; + typedValueElement.disabled=false; + } else { + // error state + typedValueElement.className = 'error'; + } +} \ No newline at end of file diff --git a/typing-game-solution/style.css b/typing-game-solution/style.css new file mode 100644 index 0000000..a366906 --- /dev/null +++ b/typing-game-solution/style.css @@ -0,0 +1,62 @@ +.highlight { + background-color: rgb(7, 182, 235); + } + +.error { + background-color: lightcoral; + border: red; + width: 220px; + height: 45px; + font-size: 25px; + font-weight: bolder; + } + +body{ + background-color: rgb(12, 2, 2); +} + +h1{ + font-family: 'Fondamento',serif; + font-size: 80px; + color: blueviolet; + text-align: center; + } + +p{ + font-family: 'Fondamento',serif; + font-size: 40px; + color: yellow; + text-align: center; +} + +input { + width: 220px; + height: 45px; + font-size: 25px; + font-weight: bolder; +} + +input:disabled { + width: 0px; + height: 0px; + background-color: rgb(12, 2, 2); +} + +input:focus{ + outline: none; + border: none; +} + +button{ + height: 45px; + margin-left: 30px; + border-color: white; + width: 70px; + font-size: 20px; + font-weight: bolder; +} + +.typing{ + margin-top: 90px; + margin-left: 40%; +} \ No newline at end of file