Aller au contenu
← 1001 Widgets
N° 011 · ●●○

Morpion

Un morpion à deux joueurs, avec la ligne gagnante mise en valeur et le score qui se garde. Le bon exercice pour apprendre à décrire un jeu par son état.

HTMLJS
Ce qu'on apprend
  • Représenter un plateau avec un tableau de 9 cases
  • Tester les 8 lignes gagnantes
  • Bloquer le plateau quand la partie est finie
Pourquoi ce langage

Pourquoi un morpion ? Neuf cases, deux joueurs, huit façons de gagner. C'est le plus petit jeu complet qu'on puisse coder : un plateau, des tours, une condition de victoire, une fin de partie.

On représente le plateau par un tableau de neuf cases, et on teste les huit lignes gagnantes après chaque coup.

Pourquoi en JavaScript simple ? Toute la logique tient dans un tableau. C'est la base de la variante imbattable, qui ajoute une IA.

Comment ça marche
  1. LE HTML

    <div id="plateau"></div>
    <p id="statut" aria-live="polite"></p>
    <button id="rejouer">Rejouer</button>
  2. L'ÉTAT

    Neuf cases vides, le joueur qui commence, et la fin de partie.

    let cases = Array(9).fill(null);
    let joueur = 'X';
    let fini = false;
  3. LES LIGNES GAGNANTES

    Trois lignes, trois colonnes, deux diagonales.

    const LIGNES = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]];
    function gagnant() {
      for (const [a, b, c] of LIGNES) {
        if (cases[a] && cases[a] === cases[b] && cases[a] === cases[c]) return cases[a];
      }
      return cases.every(Boolean) ? 'nul' : null;
    }
  4. AFFICHER

    Neuf boutons, désactivés quand la case est prise ou la partie finie.

    function afficher() {
      document.getElementById('plateau').innerHTML = cases.map((v, i) =>
        `<button data-i="${i}" ${v || fini ? 'disabled' : ''} aria-label="Case ${i + 1}">${v || ''}</button>`
      ).join('');
      const g = gagnant();
      document.getElementById('statut').textContent =
        g === 'nul' ? 'Match nul.' : g ? `${g} gagne.` : `Au tour de ${joueur}.`;
    }
  5. JOUER

    document.getElementById('plateau').addEventListener('click', e => {
      const i = e.target.dataset.i;
      if (i === undefined || cases[i] || fini) return;
      cases[i] = joueur;
      fini = Boolean(gagnant());
      joueur = joueur === 'X' ? 'O' : 'X';
      afficher();
    });
    document.getElementById('rejouer').addEventListener('click', () => {
      cases = Array(9).fill(null);
      joueur = 'X';
      fini = false;
      afficher();
    });
    afficher();
Pièges

PIÈGE 1 : Tester la victoire à la main

Piège

Mauvais : une longue suite de if pour chaque ligne. Une faute de frappe, et une diagonale ne compte plus.

Fix

Correct : un tableau des huit lignes et une seule boucle.

PIÈGE 2 : Jouer après la fin

Piège

Mauvais : oublier de bloquer le plateau. On peut encore cliquer après la victoire.

Fix

Correct : une variable fini, et des boutons désactivés.

PIÈGE 3 : Des div cliquables

Piège

Mauvais : des <div> avec un onclick. Impossible de jouer au clavier.

Fix

Correct : des <button>, un aria-label par case, et le statut dans une zone aria-live.

PERSONNALISER
  • Surligner la ligne gagnante : renvoyez la ligne dans gagnant() et ajoutez une classe aux trois cases (c'est ce que fait la démo).
  • Un score qui survit à « Rejouer » : trois compteurs, X, O et nuls.
  • Vos symboles : remplacez X et O par deux kanji, ou deux emoji.
OPTIMISATION
  • Le joueur courant se déduit du nombre de cases remplies : une variable de moins à garder synchronisée.
  • Pour une IA, l'algorithme minimax explore toutes les suites possibles : c'est la variante « Morpion imbattable ».
VERS REACT

cases dans un useState, et le gagnant calculé pendant le rendu, jamais stocké.

Un historique des coups permet un bouton « Annuler » en une ligne.

Variantes
Commentaires
0/1000

Chargement des commentaires…