Aller au contenu
← 1001 Widgets
N° 025 · ●●●

Échiquier

Un échiquier à deux joueurs qui n'accepte que les coups légaux : roque, prise en passant, promotion, échec et mat. Le bon exercice pour transformer des règles en code.

JS
Ce qu'on apprend
  • Représenter un plateau dans un tableau de 64 cases
  • Générer les coups puis retirer ceux qui laissent le roi en échec
  • Vérifier son code avec le test perft
Pourquoi ce langage

Pourquoi un échiquier ? Parce que les échecs sont le meilleur entraînement à la logique : des règles simples à dire, et pleines d'exceptions à coder. Le roque, la prise en passant et la promotion piègent tout le monde au premier essai.

La méthode : on génère tous les déplacements possibles de chaque pièce, puis on joue chacun dans une copie du plateau et on garde seulement ceux qui ne laissent pas son propre roi en échec. Plus de coups possibles ? C'est mat ou pat.

Pourquoi en JavaScript simple ? Un tableau, des directions, une fonction qui joue un coup sur une copie. Pour vérifier, on compte les positions possibles après trois coups : 8 902 depuis le départ, ni plus ni moins.

Comment ça marche
  1. LE PLATEAU

    64 cases, index = rangée * 8 + colonne. Majuscules pour les blancs, minuscules pour les noirs.

    const etat = { b: [...'rnbqkbnr', ...'pppppppp', ...Array(32).fill(null), ...'PPPPPPPP', ...'RNBQKBNR'],
                   tour: 'w', roque: 'KQkq', ep: -1 };
  2. LES DIRECTIONS

    const FOU = [[-1, -1], [-1, 1], [1, -1], [1, 1]];
    const TOUR = [[-1, 0], [1, 0], [0, -1], [0, 1]];
    const CAVALIER = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]];
  3. LES PIÈCES QUI GLISSENT

    On avance dans une direction jusqu'à un bord ou une pièce. On peut prendre une pièce adverse.

    function glisser(etat, i, directions, coups) {
      for (const [dr, dc] of directions) {
        let r = (i >> 3) + dr, c = (i & 7) + dc;
        while (r >= 0 && r < 8 && c >= 0 && c < 8) {
          const j = r * 8 + c, piece = etat.b[j];
          if (piece && camp(piece) === etat.tour) break;
          coups.push({ de: i, a: j });
          if (piece) break;
          r += dr; c += dc;
        }
      }
    }
  4. JOUER SUR UNE COPIE

    On ne modifie jamais l'état en place : c'est ce qui permet de tester un coup.

    function jouer(etat, coup) {
      const b = etat.b.slice();
      b[coup.a] = coup.promo || b[coup.de];
      b[coup.de] = null;
      return { ...etat, b, tour: etat.tour === 'w' ? 'b' : 'w' };
    }
  5. GARDER LES COUPS LÉGAUX

    Un coup est légal s'il ne laisse pas son propre roi attaqué. pseudoLegaux rassemble les coups de toutes les pièces, enEchec cherche une pièce adverse qui vise le roi.

    const legaux = etat => pseudoLegaux(etat).filter(c => !enEchec(jouer(etat, c), etat.tour));
  6. TESTER AVEC PERFT

    On compte les positions atteignables : 20, 400, 8 902. Un seul écart trahit un bug.

    const perft = (etat, n) => n === 0 ? 1 : legaux(etat).reduce((t, c) => t + perft(jouer(etat, c), n - 1), 0);
Pièges

PIÈGE 1 : Oublier l'échec à la découverte

Piège

Mauvais : vérifier seulement que la pièce jouée ne se met pas en danger. Un fou qui bouge peut ouvrir une ligne vers son propre roi.

Fix

Correct : jouer chaque coup sur une copie et vérifier si le roi est attaqué après.

PIÈGE 2 : Roquer à travers un échec

Piège

Mauvais : autoriser le roque dès que les cases sont vides. Le roi ne doit ni partir, ni passer, ni arriver sur une case attaquée.

Fix

Correct : tester les trois cases du trajet du roi avant d'ajouter le coup.

PIÈGE 3 : Garder les droits de roque pour toujours

Piège

Mauvais : ne retirer le droit de roque que quand le roi bouge. Une tour prise dans son coin doit aussi l'annuler.

Fix

Correct : retirer le droit quand une tour quitte son coin, ou quand quelque chose arrive sur ce coin.

PERSONNALISER
  • Un choix de pièce à la promotion : la démo promeut toujours en dame, un petit menu suffit pour les autres.
  • La notation des coups joués, comme e4 ou Cf3, dans une liste à côté du plateau.
  • Une pendule pour chaque joueur, avec la logique du Pomodoro.
OPTIMISATION
  • Pour une IA, la représentation en 64 cases devient lente : les moteurs utilisent des bitboards, un nombre de 64 bits par type de pièce.
  • Calculez les coups légaux une seule fois par position, et réutilisez-les pour l'affichage et la fin de partie.
VERS REACT

La position vit dans un useState, chaque coup en crée une nouvelle : l'historique et le bouton Annuler deviennent faciles.

Les coups légaux se calculent avec useMemo à partir de la position.

Les règles restent dans un fichier JavaScript pur, sans React, testable avec perft.

Commentaires
0/1000

Chargement des commentaires…