diff --git a/projects/memory-game/README.md b/projects/memory-game/README.md new file mode 100644 index 00000000..23223121 --- /dev/null +++ b/projects/memory-game/README.md @@ -0,0 +1 @@ +***this is a simple memory gamee made using js only*** \ No newline at end of file diff --git a/projects/memory-game/index.html b/projects/memory-game/index.html new file mode 100644 index 00000000..deb7e608 --- /dev/null +++ b/projects/memory-game/index.html @@ -0,0 +1,27 @@ + + + + + + + Memory Game with JavaScript + + + + +
+
+ + +
+
0 moves
+
Time: 0 sec
+
+
+
+
+
You won!
+
+
+ + \ No newline at end of file diff --git a/projects/memory-game/index.js b/projects/memory-game/index.js new file mode 100644 index 00000000..495dd557 --- /dev/null +++ b/projects/memory-game/index.js @@ -0,0 +1,165 @@ +const selectors = { + boardContainer: document.querySelector('.board-container'), + board: document.querySelector('.board'), + moves: document.querySelector('.move'), + timer: document.querySelector('.timer'), + start: document.querySelector('.controls button:first-of-type'), + restart: document.getElementById('restart-btn'), + win: document.querySelector('.win') +}; + +const state = { + gameStarted: false, + flippedCards: 0, + totalFlips: 0, + totalTime: 0, + loop: null +}; + + +const shuffle = array => { + const clonedArray = [...array]; + for (let i = clonedArray.length - 1; i > 0; i--) { + const randomIndex = Math.floor(Math.random() * (i + 1)); + [clonedArray[i], clonedArray[randomIndex]] = [clonedArray[randomIndex], clonedArray[i]]; + } + return clonedArray; +}; + + +const pickRandom = (array, items) => { + const clonedArray = [...array]; + const randomPicks = []; + for (let i = 0; i < items; i++) { + const randomIndex = Math.floor(Math.random() * clonedArray.length); + randomPicks.push(clonedArray.splice(randomIndex, 1)[0]); + } + return randomPicks; +}; + + +const generateGame = () => { + const dimensions = parseInt(selectors.board.getAttribute('data-dimension'), 10); + + if (dimensions % 2 !== 0) { + throw new Error("The dimension of the board must be an even number."); + } + + const emojis = ['🌹','đŸŒē','đŸĒˇ','💐','đŸĒģ','đŸŒģ','đŸŒŧ','đŸĨ€','🌷','🌸']; + const picks = pickRandom(emojis, (dimensions * dimensions) / 2); + const items = shuffle([...picks, ...picks]); + + const cards = items.map(item => ` +
+
+
${item}
+
+ `).join(''); + + selectors.board.innerHTML = cards; + selectors.board.style.gridTemplateColumns = `repeat(${dimensions}, auto)`; +}; + + +const startGame = () => { + state.gameStarted = true; + selectors.start.classList.add('disabled'); + selectors.restart.classList.remove('disabled'); + + state.loop = setInterval(() => { + state.totalTime++; + selectors.moves.innerText = `${state.totalFlips} moves`; + selectors.timer.innerText = `Time: ${state.totalTime} sec`; + }, 1000); +}; + + +const restartGame = () => { + + state.gameStarted = false; + state.flippedCards = 0; + state.totalFlips = 0; + state.totalTime = 0; + + clearInterval(state.loop); + + + selectors.start.classList.remove('disabled'); + selectors.restart.classList.add('disabled'); + selectors.moves.innerText = `0 moves`; + selectors.timer.innerText = `Time: 0 sec`; + + + generateGame(); +}; + + +const flipBackCards = () => { + document.querySelectorAll('.card:not(.matched)').forEach(card => { + card.classList.remove('flipped'); + }); + state.flippedCards = 0; +}; + + +const flipCard = card => { + if (!state.gameStarted) { + startGame(); + } + + if (!card.classList.contains('flipped') && state.flippedCards < 2) { + card.classList.add('flipped'); + state.flippedCards++; + state.totalFlips++; + } + + if (state.flippedCards === 2) { + const flippedCards = document.querySelectorAll('.card.flipped:not(.matched)'); + + if (flippedCards.length === 2) { + const [card1, card2] = flippedCards; + if (card1.querySelector('.card-back').innerText === card2.querySelector('.card-back').innerText) { + card1.classList.add('matched'); + card2.classList.add('matched'); + } + } + + setTimeout(() => { + flipBackCards(); + }, 1000); + } + + if (!document.querySelectorAll('.card:not(.flipped)').length) { + setTimeout(() => { + selectors.boardContainer.classList.add('flipped'); + selectors.win.innerHTML = ` + + You won!
+ with ${state.totalFlips} moves
+ under ${state.totalTime} seconds +
+ `; + clearInterval(state.loop); + }, 1000); + } +}; + + +const attachEventListeners = () => { + document.addEventListener('click', event => { + const target = event.target; + const card = target.closest('.card'); + + if (card && !card.classList.contains('flipped') && !card.classList.contains('matched')) { + flipCard(card); + } else if (target === selectors.start && !selectors.start.classList.contains('disabled')) { + startGame(); + } else if (target === selectors.restart && !selectors.restart.classList.contains('disabled')) { + restartGame(); + } + }); +}; + + +generateGame(); +attachEventListeners(); \ No newline at end of file diff --git a/projects/memory-game/style.css b/projects/memory-game/style.css new file mode 100644 index 00000000..bf7ae1de --- /dev/null +++ b/projects/memory-game/style.css @@ -0,0 +1,131 @@ +html { + width: 100%; + height: 100%; + background: linear-gradient(325deg, #03001e 0%,#7303c0 30%,#ec38bc 70%, #fdeff9 100%); + font-family: Arial, Helvetica, sans-serif; + overflow: hidden; +} +.game { + position: absolute; + top: 50%; + left: 70%; + transform: translate(-50%, -50%); +} +.controls { + display: flex; + gap: 20px; + margin-bottom: 20px; +} +button { + background: #282A3A; + color: #FFF; + border-radius: 5px; + padding: 10px 20px; + border: 0; + cursor: pointer; + font-family: Arial, Helvetica, sans-serif; + font-size: 18pt; + font-weight: bold; +} +.disabled { + color: #757575; +} + + + +#restart-btn { + background: #FF3E3E; + color: #FFF; + border-radius: 5px; + padding: 10px 20px; + border: 0; + cursor: pointer; + font-family: Arial, Helvetica, sans-serif; + font-size: 18pt; + font-weight: bold; +} + +#restart-btn.disabled { + color: #757575; + background: #FFB3B3; + cursor: not-allowed; +} +.stat { + color: #FFF; + font-size: 14pt; + font-weight: bold; +} +.board-container { + position: relative; +} +.board, +.win { + border-radius: 5px; + box-shadow: 0 25px 50px rgb(33 33 33 / 25%); + background: linear-gradient(135deg, #03001e 0%,#7303c0 0%,#ec38bc 50%, #fdeff9 100%); + transition: transform .6s cubic-bezier(0.4, 0.0, 0.2, 1); + backface-visibility: hidden; +} +.board { + padding: 20px; + display: grid; + grid-template-columns: repeat(4, auto); + grid-gap: 20px; +} +.board-container.flipped .board { + transform: rotateY(180deg) rotateZ(50deg); +} +.board-container.flipped .win { + transform: rotateY(0) rotateZ(0); +} +.card { + position: relative; + width: 100px; + height: 100px; + cursor: pointer; +} +.card-front, +.card-back { + position: absolute; + border-radius: 5px; + width: 100%; + height: 100%; + background: #282A3A; + transition: transform .6s cubic-bezier(0.4, 0.0, 0.2, 1); + backface-visibility: hidden; +} +.card-back { + transform: rotateY(180deg) rotateZ(50deg); + font-size: 28pt; + user-select: none; + text-align: center; + line-height: 100px; + background: #FDF8E6; +} +.card.flipped .card-front { + transform: rotateY(180deg) rotateZ(50deg); +} +.card.flipped .card-back { + transform: rotateY(0) rotateZ(0); +} +.win { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + background: #FDF8E6; + transform: rotateY(180deg) rotateZ(50deg); +} +.win-text { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 21pt; + color: #282A3A; +} +.highlight { + color: #7303c0; +} \ No newline at end of file diff --git a/public/assets/127.png b/public/assets/127.png new file mode 100644 index 00000000..f1aa9443 Binary files /dev/null and b/public/assets/127.png differ