Règles du jeu¶
Règles telles qu'implémentées
Cette page décrit le comportement du code (orapa-core pour la géométrie, orapa-server/src/logic.rs pour le déroulé de partie), pas le livret officiel. Les formes des pièces de base sont une reconstruction (voir Pièces).
Plateau et points de tir¶
- Grille 10 × 8 (
griddansdata/pieces.json). Repère :xde 0 à 9 vers la droite,yde 0 à 7 vers le bas, case(0,0)en haut à gauche. - 36 points de tir sur le pourtour, générés par
orapa_core::beam::entry_points(et répliqués côté client dansweb/src/lib/points.ts).
1 2 3 4 5 6 7 8 9 10
A · · · · · · · · · · 11
B · · · · · · · · · · 12
C · · · · · · · · · · 13
D · · · · · · · · · · 14
E · · · · · · · · · · 15
F · · · · · · · · · · 16
G · · · · · · · · · · 17
H · · · · · · · · · · 18
I J K L M N O P Q R
| Côté | Identifiants | Ordre | L'onde entre en allant vers… |
|---|---|---|---|
| Gauche | A–H |
haut → bas (y = 0…7) |
la droite |
| Bas | I–R |
gauche → droite (x = 0…9) |
le haut |
| Haut | 1–10 |
gauche → droite (x = 0…9) |
le bas |
| Droite | 11–18 |
haut → bas (y = 0…7) |
la gauche |
Un point sert à la fois d'entrée et de sortie : une onde qui quitte la grille est annoncée au point situé à cet endroit du bord.
Pièces¶
Cases et demi-cases¶
Une pièce est une liste de cases relatives {x, y, kind} :
kind |
Contenu | Côtés pleins (« cathètes ») | Hypoténuse |
|---|---|---|---|
square |
case pleine | les 4 | — |
tri_nw (◤) |
moitié de case côté coin nord-ouest | nord, ouest | diagonale / |
tri_ne (◥) |
moitié côté coin nord-est | nord, est | diagonale \ |
tri_se (◢) |
moitié côté coin sud-est | sud, est | diagonale / |
tri_sw (◣) |
moitié côté coin sud-ouest | sud, ouest | diagonale \ |
Catalogue (data/pieces.json)¶
Formes de base (orientation 0), avec la notation de la démo CLI (· = vide dans la boîte englobante) :
Rouge Jaune Bleu / Blanc (grand triangle) Blanc (losange) / Diamant Corps noir
◥■◣ ■◤ ◥■■◤ ◢◣ ■■
◤· ·◥◤· ◥◤
id |
Nom | Couleur | Forme | Aire (cases) | Orientations | Extension |
|---|---|---|---|---|---|---|
red |
Rouge | rouge | parallélogramme | 2 | 4 | — |
yellow |
Jaune | jaune | triangle rectangle isocèle (cathètes de 2) | 2 | 4 | — |
blue |
Bleu | bleu | grand triangle (hypoténuse de 4) | 4 | 4 | — |
white1 |
Blanc (grand triangle) | blanc | identique à blue |
4 | 4 | — |
white2 |
Blanc (losange) | blanc | losange de 4 demi-cases | 2 | 1 | — |
diamond |
Diamant | aucune (special: transparent) |
losange | 2 | 1 | diamond |
black |
Corps noir | aucune (special: absorb) |
rectangle 1×2 | 2 | 2 | black |
- Partie de base :
red,yellow,blue,white1,white2(5 pièces). Les options de lobby ajoutentdiamondet/oublack(6 ou 7 pièces). - Orientations : le moteur les génère à partir de la forme de base (4 rotations de 90°, plus leurs miroirs), puis supprime les doublons. On ne les liste jamais à la main.
- Dans l'interface, le bouton Pivoter (ou la touche R) fait défiler toutes les orientations, miroirs compris. Les flèches déplacent la pièce sélectionnée, Del ou Backspace la retire.
Formes reconstruites
Le livret officiel n'était pas disponible pendant le développement (README, « Limites connues »). Pour corriger une forme, on modifie uniquement le tableau cells de la pièce dans data/pieces.json, puis on lance cargo test -p orapa-core (voir Développement).
Contraintes de placement¶
Le moteur (orapa_core::validate_placement) renvoie toutes les violations, pas seulement la première. Il est appelé en direct dans le navigateur (WASM) pendant le placement, puis par le serveur à la réception de SetPlacement.
Violation (kind) |
Règle |
|---|---|
OutOfBounds |
Une case de la pièce sort de la grille. |
Overlap |
Deux pièces occupent la même case, même partiellement : une case ne contient qu'une seule demi-case ou case pleine. |
EdgeContact |
Deux cases voisines (horizontalement ou verticalement) de pièces différentes, dont les deux côtés en vis-à-vis sont pleins (côté d'un carré ou cathète). Un contact coin à coin, ou contre une hypoténuse, est autorisé. |
Unreachable |
Aucune des 36 ondes ne touche la pièce (calculé en tirant réellement les 36 ondes sur le placement). |
WhiteSymmetry |
Les cases occupées par les deux gemmes blanches forment un ensemble identique à son image par symétrie d'axe vertical (x ↦ 9 − x) ou horizontal (y ↦ 7 − y) du plateau. Activée par rules.white_symmetry_forbidden: true. |
Symétrie des blanches
La comparaison porte sur les coordonnées des cases, pas sur l'orientation des triangles. Comme les deux blanches n'ont pas la même forme, la violation ne survient que si chacune est symétrique par rapport au même axe central (par exemple grand triangle pointe en bas et losange, tous deux centrés sur x = 4,5).
Le bouton Placement aléatoire valide demande au serveur un tirage qui respecte toutes les contraintes (tirage avec rejet, orapa_core::random_valid_placement).
Actions pendant la partie¶
À son tour, un joueur fait une action sur la grille adverse :
| Action | Résultat renvoyé | Passe le tour |
|---|---|---|
| Envoyer une onde depuis un point du bord | point de sortie et couleur, ou Absorbed (signal absorbé), ou Lost (onde perdue) |
oui |
Sonder une case (x, y) |
empty (vide), couleur de la gemme, ou occupied_no_color (Diamant ou Corps noir). Une demi-case compte comme occupée. |
oui |
| Proposer une solution (grille d'hypothèses complète) | juste / fausse | oui, sauf si la partie se termine |
- Les résultats de toutes les actions (des deux joueurs) sont visibles dans l'historique.
- Côté client, un point déjà tiré ne peut pas être retiré : un clic dessus met son trajet en évidence. Le serveur, lui, accepte de retirer depuis le même point.
- Une proposition est comparée case par case au plateau secret (type de case, couleur, propriété spéciale), pas pièce par pièce. Deux placements qui donnent exactement le même plateau sont équivalents.
Trajet d'une onde¶
Modèle « centre de case » (crates/orapa-core/src/beam.rs) : l'onde avance de centre de case en centre de case, et entre ou sort par le milieu des côtés. Elle ne passe jamais par un sommet de la grille, donc les cas « coin exact » et « onde qui longe une arête » sont impossibles par construction.
À chaque case atteinte :
- Case vide : l'onde continue tout droit.
- Case occupée : la pièce compte comme touchée et sa couleur (si elle en a une) est ajoutée au mélange. Ensuite :
- Corps noir : l'onde est absorbée (
Absorbed), sans point de sortie ni couleur. - Carré, ou triangle touché par une cathète : demi-tour.
- Triangle touché côté hypoténuse (l'onde entre par la moitié vide) : déviation à 90°.
- Corps noir : l'onde est absorbée (
- Sortie de grille : résultat
Exit { point, color }. - État
(case, direction)déjà vu : boucle fermée, résultatLost. Un nombre maximal de pas (4 × largeur × hauteur + 1) sert de filet de sécurité.
| Triangle | L'onde arrive en allant vers… | Elle repart vers… |
|---|---|---|
tri_nw ◤ |
la gauche / le haut | le bas / la droite |
tri_se ◢ |
la droite / le bas | le haut / la gauche |
tri_ne ◥ |
la droite / le haut | le bas / la gauche |
tri_sw ◣ |
la gauche / le bas | le haut / la droite |
Bon à savoir
- Une couleur compte même si l'onde ne fait que rebondir sur la pièce.
- Le Diamant se comporte géométriquement comme n'importe quelle demi-case (rebond ou déviation) mais n'ajoute aucune couleur.
- Les trajets sont réversibles : tirer depuis le point de sortie ramène au point d'entrée avec la même couleur (test
beam_paths_are_reversible). - Un carré renvoie l'onde sur elle-même : si rien d'autre n'est touché, elle ressort par son point d'entrée.
Mélange des couleurs¶
Fonction orapa_core::mix_colors : chaque couleur de gemme touchée compte une seule fois, quel que soit l'ordre.
| Gemmes touchées | Résultat | Valeur JSON |
|---|---|---|
| aucune | Transparent | transparent |
| Rouge | Rouge | red |
| Bleu | Bleu | blue |
| Jaune | Jaune | yellow |
| Blanc | Blanc | white |
| Rouge + Bleu | Violet | purple |
| Rouge + Jaune | Orange | orange |
| Bleu + Jaune | Vert | green |
| Rouge + Blanc | Rose | pink |
| Bleu + Blanc | Bleu ciel | sky_blue |
| Jaune + Blanc | Citron | lemon |
| Rouge + Bleu + Jaune | Noir | black |
| Rouge + Bleu + Blanc | Violet clair | light_purple |
| Bleu + Jaune + Blanc | Vert clair | light_green |
| Rouge + Jaune + Blanc | Orange clair | light_orange |
| Rouge + Bleu + Jaune + Blanc | Gris | gray |
Note
Le résultat Noir (rouge + bleu + jaune) est une sortie normale avec un point de sortie. Il ne faut pas le confondre avec Signal absorbé (Corps noir), qui n'a ni sortie ni couleur.
Tours, vies et fin de partie¶
- Premier joueur : tiré au hasard quand les deux joueurs sont prêts. Le tour alterne ensuite après chaque action.
- Vies : 1 par défaut (règle officielle selon le code), ou 2 en option de lobby. Affichées sous forme de ♦.
- Limite de temps par tour (option : aucune, 30 s, 60 s, 120 s) : à l'expiration, une entrée
Timeoutest ajoutée à l'historique et le tour passe. Duel uniquement.
| Situation | Issue |
|---|---|
| Proposition juste du joueur qui n'a pas commencé | Victoire immédiate |
| Proposition juste du premier joueur | Mort subite : l'adversaire a un dernier tour pour égaliser |
| Mort subite, puis proposition juste | Égalité |
| Mort subite, puis proposition fausse | Victoire du premier joueur |
| Proposition fausse, il reste des vies | −1 vie, le tour passe |
| Proposition fausse, plus de vie | Élimination, l'adversaire gagne |
Mort subite : comportement actuel du code
Seule une proposition clôt la mort subite. Si l'adversaire envoie une onde ou sonde une case (ou si son temps expire), la main revient au premier joueur et la partie continue en mode mort subite. La proposition suivante, quel que soit son auteur, termine la partie selon le tableau ci-dessus : juste = égalité, fausse = victoire du premier joueur.
Mode solo (entraînement)¶
- Le serveur tire une disposition aléatoire valide (avec les extensions choisies). La partie démarre directement en phase de jeu, sans placement ni alternance de tours ni minuteur.
- Les vies s'appliquent : une proposition juste gagne. Si les vies tombent à 0, la partie se termine sans vainqueur (
winner: null). - Le bouton Voir la solution affiche la disposition sans terminer la partie (refusé par le serveur en duel).
Affichage d'une défaite en solo
ResultScreen interprète winner: null comme une égalité : une défaite en solo s'affiche donc « Égalité ! ».
Mode aide¶
- Option de lobby Mode aide (vérifie tes hypothèses), cochée par défaut dans le client.
- Pendant la partie, le joueur construit sa grille d'hypothèses (même éditeur que pour le placement). Le bouton Vérifier la cohérence rejoue localement, en WebAssembly, toutes ses ondes et ses sondages contre cette grille, puis liste les indices contredits (
onde C,sondage (3,4)…). - Ne consomme pas de tour. Aucune donnée secrète adverse n'est utilisée : seul l'historique public sert à la vérification.
Réactions¶
En duel, trois réactions rapides sont diffusées aux deux joueurs : « Bien joué ! » (gg), « Aïe ! » (oops), « Je réfléchis… » (think).