<div id="app"></div>
.play-area__row {
display: flex;
}
.play-area__card {
display: inline-block;
outline: 1px solid black;
min-height: 20px;
min-width: 20px;
text-align: center;
padding: 5px;
color: lightblue;
background: lightblue;
margin: 5px;
}
.play-area__card--removed {
background: unset;
outline: unset;
}
.play-area__card--shown {
color: black;
}
/*
* https://frontendeval.com/questions/memory-game
*
* Create a card-matching memory game
*/
const App = () => {
return (
<React.Fragment>
<p>Memory game</p>
<MemoryGame size={4} />
</React.Fragment>
);
};
const createGame = (size) => {
const cardCount = size * size;
const cardValues = new Array();
for (let i = 1; i <= cardCount / 2; i++) {
cardValues.push(i);
cardValues.push(i);
}
const game = new Array();
for (let i = 0; i < size; i++) {
game.push(new Array(size));
}
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
const rand = Math.round(Math.random() * cardValues.length);
if (cardValues[rand] !== undefined) {
const [num] = cardValues.splice(rand, 1);
game[i][j] = num;
} else {
j--;
}
}
}
// const sum = game.reduce(
// (totalSum, row) => totalSum + row.reduce((rowSum, n) => rowSum + n, 0),
// 0
// );
// const expectedSum = (cardCount / 2) * (1 + cardCount / 2);
// const isOkay = sum === expectedSum;
// console.log("isOkay", isOkay);
return game;
};
function MemoryGame({ size }) {
const [game, setGame] = React.useState(() => createGame(size));
const isInProgress = game.some((row) => row.some((item) => !!item));
return (
<div>
{(isInProgress && (
<MemoryGamePlayArea game={game} setGame={setGame} />
)) || <button onClick={() => setGame(createGame(size))}>Reset</button>}
</div>
);
}
function MemoryGamePlayArea({ game, setGame }) {
const [firstCard, setFirstCard] = React.useState();
const [secondCard, setSecondCard] = React.useState();
const [disabled, setDisabled] = React.useState(false);
const onCardClick = (i2, j2) => {
if (!firstCard) setFirstCard([i2, j2]);
else {
setSecondCard([i2, j2]);
setDisabled(true);
setTimeout(() => {
setDisabled(false);
const [i1, j1] = firstCard;
const num1 = game[i1][j1];
const num2 = game[i2][j2];
if (num1 === num2) {
game[i1][j1] = null;
game[i2][j2] = null;
setGame(JSON.parse(JSON.stringify(game)));
}
setFirstCard();
setSecondCard();
}, 300);
}
};
return (
<section className="play-area">
{game.map((row, i) => (
<div className="play-area__row" key={i}>
{row.map((num, j) => (
<Card
num={num}
key={"" + i + j + num}
onClick={disabled ? null : () => onCardClick(i, j)}
show={
(firstCard && firstCard[0] === i && firstCard[1] === j) ||
(secondCard && secondCard[0] === i && secondCard[1] === j)
}
/>
))}
</div>
))}
</section>
);
}
function Card({ num, onClick, show }) {
let className = show
? "play-area__card--shown"
: !num
? "play-area__card--removed"
: "";
return (
<span className={`play-area__card ${className}`} onClick={onClick}>
{num}
</span>
);
}
ReactDOM.render(<App />, document.getElementById("app"));
View Compiled
This Pen doesn't use any external CSS resources.