Modes actuels : deux joueurs locaux ou 1v1 à distance. Les descriptions d’annulation immédiate, de confirmation locale et de stockage dans le composant ci-dessous concernent le mode local. Le mode distant utilise un serveur et l’accord de l’adversaire ; voir la section dédiée en fin de fiche et le guide de déploiement (../DEPLOIEMENT_JEUX.md).
Fiche comparée aux sources, à l’interface et au catalogue le 26 octobre 2026. Voir l’audit commun des neuf activités (../JEUX.md#validation-documentaire). Les comptes de tests et recettes navigateur datés plus bas sont des vérifications historiques, pas un état de validation global actuel.
Accès et intégration
Disponible dans Jeux → Jeux de stratégie → L Game, à la route existante /rubriques/jeux-l-game. Le composant Svelte LGame.svelte est monté par src/pages/rubriques/[id].astro seulement pour cette rubrique et après le contrôle habituel du niveau du catalogue (public actuellement). Les autres blocs du composeur restent affichés après le jeu. Aucun nouvel identifiant de catalogue.
Règles et interface
Mode deux joueurs sur le même appareil. Plateau 4 × 4 ; un L de quatre cases par joueur, deux pions neutres. Sélectionner quatre cases puis valider le L. Rotations et réflexions admises, ancienne position interdite, anciennes cases réutilisables, collisions interdites. Ensuite, déplacer facultativement un seul pion neutre vers une case vide ; terminer le tour déclenche la détection de blocage adverse. Modifier la destination avant validation ne déplace pas plusieurs pions.
Sélection souris/toucher et clavier (Tab, flèches, Entrée, Espace), plateau sans coordonnées ni numéros visibles sur les pièces. Les coordonnées et les propriétaires restent annoncés aux lecteurs d’écran. Les cases sélectionnées sont en couleur pleine, y compris les cases réutilisées du L actuel ; seules ses cases non sélectionnées restent pâles. Annuler restaure le début du coup en cours, ou le début du dernier tour si aucun coup n’est commencé. Nouvelle partie demande confirmation dans la page. Le L du perdant est grisé et hachuré ; une partie nulle ne grise aucune pièce. Les règles sont toujours visibles. Le réglage de limite se trouve après les règles du jeu. La limite se règle avant la première sélection ; elle est verrouillée dès qu’une sélection, un coup en cours ou un historique existe ; Nouvelle partie permet de la modifier avant confirmation, tandis que Continuer restaure la limite en cours. Les boutons d’action prennent la couleur du joueur actif. La séparation sous le titre est supprimée pour les neuf pages interactives identifiées par isGame dans la route commune. La page porte la mention « Jeux de stratégie » et la description « Déplacez votre pièce afin de bloquer votre adversaire ! », sans bloc « À venir ».
Moteur et stockage
src/lib/l-game.mjs : moteur pur, 48 placements du L (8 orientations), état {pieces, neutrals, player, phase, winner, turn, maxTurns}, cases 0–15 en lecture par ligne. Phases l, neutral, over. Victoire évaluée uniquement après le déplacement facultatif du pion.
En mode local, partie et historique uniquement en mémoire du composant. Aucun localStorage, aucune API, aucun envoi des coups. Recharger ou quitter la page perd la partie ; indiqué dans l’interface. Aucune dépendance ajoutée. Pas d’IA ; le mode réseau est décrit ci-dessous. Pas de règle automatique de partie nulle par répétition. Limite configurable de 1 à 200 tours individuels au total, 20 par défaut, stockée dans maxTurns, évaluée après le déplacement facultatif du pion : le blocage adverse reste prioritaire ; sinon partie nulle. En fin de partie, turn reste le numéro du dernier tour joué, phase vaut over et winner vaut null pour une partie nulle.
Préparer un mode contre l’ordinateur (non implémenté)
Le moteur est séparé de l’interface et peut être importé sans Svelte ni DOM. Aucun adversaire automatique, algorithme de recherche, niveau de difficulté ou Worker de jeu n’existe actuellement. Les éléments ci-dessous sont des recommandations pour une future intervention, pas des fonctionnalités disponibles.
Contrat du moteur à réutiliser
| Export | Rôle et précaution |
|---|---|
| initialGame(maxTurns=20) | Crée une partie indépendante ; limite entière de 1 à 200. Le joueur 0 (bleu) commence. |
| placements | 48 placements géométriques immuables, toutes rotations et réflexions incluses. |
| legalMoves(state, player=state.player) | Renvoie les nouvelles positions légales du L seulement, pas les tours complets ni les déplacements de pions. Ne contrôle pas la phase : vérifier phase avant de lancer une recherche. |
| placementError(state, cells) | Message de refus ou chaîne vide pour un placement valide pendant la phase l. |
| moveL(state, cells) | Retourne un nouvel état en phase neutral, sans changer de joueur ; refuse un placement invalide. |
| finishTurn(state, neutralMove=null) | Termine le tour sans pion, ou avec {index:0 ou 1, to:case}. Bascule le joueur, puis teste victoire et limite. Refuse un appel hors phase neutral. |
Les cases sont numérotées de 0 à 15 par ligne. pieces contient deux tableaux de quatre cases ; neutrals contient deux cases. player et winner utilisent 0/1, tandis que l’interface affiche 1/2. winner=null signifie aussi bien « pas encore de vainqueur » que « match nul » : une nulle exige phase=over ET winner=null. Après une victoire, player désigne le joueur bloqué, winner son adversaire. turn commence à 1 ; il compte les tours individuels (pas les paires de tours) et ne dépasse pas le dernier tour joué à la fin de partie. MAX_TURNS est la valeur par défaut, pas la limite de chaque partie : utiliser state.maxTurns.
Les transitions ne modifient pas l’état reçu mais certaines listes peuvent être partagées entre états. Ne pas modifier leurs tableaux en place. Le moteur vérifie les actions, mais n’est pas un validateur complet d’états arbitraires importés.
Rechercher un tour complet
Pour chaque position donnée par legalMoves, appeler moveL, puis explorer finishTurn sans déplacement de pion ainsi que chaque déplacement d’un des deux pions vers chacune des cases vides après le déplacement du L. Le tour ne se termine qu’après cette seconde étape. Ne pas conclure à une victoire immédiatement après moveL : un pion déplacé ensuite peut rendre sa mobilité à l’adversaire. Garder la priorité de la victoire sur le match nul au dernier tour.
La limite de tours est une variante de ce portail. Une éventuelle stratégie ou table de positions pour le jeu sans limite ne doit pas être supposée correcte pour cette variante. Une recherche avec cache doit tenir compte du joueur au trait, du plateau et du nombre de tours restant ; de la phase aussi si elle mémorise des états intermédiaires. Les pions neutres sont interchangeables pour évaluer une position, mais une action rendue à finishTurn doit retrouver le bon index dans l’état courant.
Intégration à prévoir
- Préserver le mode deux joueurs ; décider avec le propriétaire du choix du camp, de qui commence et des niveaux de difficulté. Aucun de ces choix n’est encore arrêté.
- Isoler une recherche coûteuse dans un Web Worker, avec budget de calcul, annulation et identifiant de partie/requête. Ignorer tout résultat ancien après nouvelle partie, annulation, changement de mode ou démontage du composant.
- Bloquer les clics du joueur pendant le calcul et l’exécution du tour de l’ordinateur ; valider son résultat avec le moteur avant application. Ne pas déléguer les règles à un second moteur divergent.
- L’historique, turnStart et les sélections sont actuellement gérés dans LGame.svelte. Définir l’annulation en mode solo : un seul tour ou retour au dernier choix humain. Ne pas réutiliser automatiquement le comportement local sans cette décision.
- Conserver le calcul local et l’absence d’envoi des coups au serveur, sauf demande explicite contraire.
Vérifications à ajouter pour ce futur mode
Tester la légalité de chaque tour produit, une victoire immédiate, une défense obligatoire, les deux camps, le pion facultatif, le nul à différentes limites et la victoire au dernier tour. Tester aussi l’annulation pendant le calcul, le rejet des résultats périmés, la remise à zéro et la réactivité sur mobile. Toute difficulté ou performance annoncée devra être mesurée ; aucun niveau de jeu n’a été évalué à ce jour.
Validation
Tests : node –test tests/l-game.test.mjs (formes et symétries, collisions, ancienne position, séquence des phases, déplacement facultatif unique, victoire après le pion, immutabilité). Compléter par une partie au navigateur, annulation, nouvelle partie et contrôle à largeur réduite.
Règles : https://en.wikipedia.org/wiki/L_game et https://gamescrafters.berkeley.edu/games/software.php?game=lgame .
Vérifications effectuées le 26 octobre 2026
- Tests du moteur après ajout du réglage : 6 tests réussis (limites personnalisées, entrées invalides, nul au dernier tour et priorité de la victoire inclus). Suite complète lors de l’intégration initiale : 88 tests réussis.
- Compilation
npm run buildréussie. - Navigateur sur le serveur existant (port 4321) : déplacement valide des deux joueurs, symétrie du L, sélection avec flèche et Espace, tour avec un pion, tour sans pion, annulation du tour précédent, annulation du coup en cours, confirmation et remise à zéro.
- Affichage inspecté à environ 790 px de large. Le style prévoit une colonne sous 700 px ; l’affichage sur téléphone et les gestes sur écran tactile restent à vérifier sur appareil. Victoire avec L perdant hachuré et partie nulle après 20 tours vérifiées dans le navigateur. Nouvelle description, mention Jeux de stratégie, absence du bloc À venir et règles toujours visibles également vérifiées.
- Le catalogue a été actualisé après contrôle de l’absence de fichiers non déclarés ; aucune alerte de découverte. Le serveur existant n’a pas été redémarré.
Réglage personnalisé : 6 tests moteur réussis, compilation réussie. Vérification navigateur : limite fixée à 2, verrouillage au premier coup, compteur et règles adaptés, match nul au deuxième tour ; boutons bleu puis rouge et séparation sous le titre supprimée.
Mode distant — 27 octobre 2026
L’hôte choisit 1–200 tours (20 par défaut). Le L validé et la phase neutre restent sur le serveur : une reconnexion reprend cette phase. L’annulation consentie restaure le début du tour, pion compris, même si la phase neutre est encore en cours. Une sélection de cases non envoyée peut être effacée localement.
OnlineLobby.svelte gère création, invitation, présence et consentement ; OnlineSettings.svelte gère les options de l’hôte. L’invité ne peut pas les changer. Les API contrôlent la rubrique de ce jeu et réutilisent son moteur pur. Plateaux/historiques en mémoire serveur, clé de place dans sessionStorage (l-game-online-seat-v1). Recharger le même onglet retrouve le salon tant qu’il existe ; redémarrer le serveur le perd. Sélections préparatoires non envoyées non sauvegardées.
Annulation et nouvelle partie nécessitent l’accord adverse ; délai de demande d’une minute. Une coupure suspend le jeu et réserve la place cinq minutes par défaut. Ces délais et le plafond global sont décrits dans le contrat commun. La validation distante (tests de service, parties complètes, HTTP/SSE et scénario navigateur propre à ce jeu) est consignée dans cette fiche commune ; le tactile et l’hébergement public restent à valider. Les anciennes recettes datées ci-dessus restent un historique du mode local.
Revanche distante : le salon reste ouvert après victoire ou nul, jusqu’au départ ou à son expiration. Chaque nouvelle partie acceptée alterne le premier joueur (hôte, invité, hôte…), qui reçoit le joueur 1 et le bleu au départ. Les droits de l’hôte restent inchangés. Refus, retrait, expiration de demande, annulation de coup et reconnexion ne changent pas cet ordre. Voir les champs starterRole/playerIndex, délais et vérifications dans le contrat commun.