Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions projects/memory-game/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
***this is a simple memory gamee made using js only***
27 changes: 27 additions & 0 deletions projects/memory-game/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memory Game with JavaScript</title>
<link rel="stylesheet" href="style.css">
<script src="index.js" defer></script>
</head>
<body>
<div class="game">
<div class="controls">
<button>Start</button>
<button id="restart-btn" class="disabled">Restart</button>
<div class="stat">
<div class="move">0 moves</div>
<div class="timer">Time: 0 sec</div>
</div>
</div>
<div class="board-container">
<div class="board" data-dimension="4"></div>
<div class="win">You won!</div>
</div>
</div>
</body>
</html>
165 changes: 165 additions & 0 deletions projects/memory-game/index.js
Original file line number Diff line number Diff line change
@@ -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 => `
<div class="card">
<div class="card-front"></div>
<div class="card-back">${item}</div>
</div>
`).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 = `
<span class="win-text">
You won!<br />
with <span class="highlight">${state.totalFlips}</span> moves<br />
under <span class="highlight">${state.totalTime}</span> seconds
</span>
`;
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();
131 changes: 131 additions & 0 deletions projects/memory-game/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
Binary file added public/assets/127.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.