Skip to the solution
HardMachine Coding14 min read

Build a Memory (flip-card) Game

379 views

The problem

Question presented to candidate: "Build a memory card game. Show a 4 by 4 grid of face-down cards holding 8 pairs. The player flips two cards; if they match they stay face up, if not they flip back after a short delay. Count moves, detect the win and add a New game button. You have about 45 minutes."

Requirements:

  • 16 cards (8 pairs), shuffled fairly, face down at the start.
  • Clicking a card turns it face up. After the second card: a match stays up, a mismatch flips back after about 800 ms.
  • While a mismatched pair is showing, further clicks are ignored (no third card).
  • A move counter (one move per pair of flips), a pairs counter and a win message.
  • New game reshuffles and resets everything, even in the middle of a flip-back delay.

What a strong answer should cover:

  • Game rules as pure functions (createGame, flip, hideUnmatched) separate from the UI, with the shuffle's randomness injected (a seeded RNG) so it can be tested.
  • A correct Fisher-Yates shuffle, and why sort(() => Math.random() - 0.5) is biased.
  • The lock: deriving "two unmatched cards are open" from state instead of a separate boolean that can drift.
  • The flip-back timer: started from state, cancelled on reset and unmount (effect cleanup), safe under React StrictMode.
  • Accessibility: cards are real buttons, the label says face down or the symbol, a live region announces the result.

Clarifying questions expected:

  • "How long should a mismatch stay visible, and can the player click during it?"
  • "Should the grid size or number of pairs be configurable?"
  • "Do you want a timer or a best score, or just moves?"

Code / implementation expected: Yes. A working game in the framework of your choice, with the rules in plain functions and a short explanation of the timer cleanup.

  • React
  • Game
  • Timers

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

14 min read ยท 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useEffect, useState } from "react";
import Card from "./src/components/Card";
import { createGame, flip, hideUnmatched, isLocked, isWon } from "./src/utils/memory";

const FLIP_BACK_MS = 800;

export default function App() {
  const [game, setGame] = useState(() => createGame(1));
  const locked = isLocked(game);
  const won = isWon(game);

  // The flip-back timer is derived from state: it exists only while two
  // unmatched cards are face up, and the cleanup cancels it on reset/unmount.
  useEffect(() => {
    if (!locked) return;
    const id = setTimeout(() => setGame(hideUnmatched), FLIP_BACK_MS);
    return () => clearTimeout(id);
  }, [locked]);

  return (
    <main className="memory">
      <h1>Memory</h1>
      <div className="bar">
        <span data-testid="moves">
          Moves: {game.moves} ยท Pairs: {game.matched.length / 2}/
          {game.deck.length / 2}
        </span>
        <button
          type="button"
          onClick={() => setGame((g) => createGame(g.seed + 1))}
        >
          New game
        </button>
      </div>
      <div className="grid" role="group" aria-label="Cards" aria-busy={locked}>
        {game.deck.map((symbol, i) => (
          <Card
            key={game.seed + "-" + i}
            index={i}
            symbol={symbol}
            faceUp={game.open.includes(i) || game.matched.includes(i)}
            matched={game.matched.includes(i)}
            onFlip={(idx) => setGame((g) => flip(g, idx))}
          />
        ))}
      </div>
      <p className="status" role="status" data-testid="status">
        {won
          ? "You won in " + game.moves + " moves!"
          : locked
            ? "No match. Flipping back..."
            : ""}
      </p>
    </main>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 97 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

Build Minesweeper

Continue