Skip to content

Commit 4fab191

Browse files
committed
Merge branch 'dev' into staging
2 parents 557dd89 + 1a02773 commit 4fab191

27 files changed

Lines changed: 5876 additions & 213 deletions

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Changelog
2+
3+
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
4+
5+
Le format est basé sur Keep a Changelog et ce projet adhère au Semantic Versioning.
6+
7+
## [Unreleased]
8+
9+
---
10+
11+
## [0.1.0] - 2026-04-07
12+
13+
### Added
14+
15+
* Initialisation du backend avec Express
16+
* Ajout de Socket.IO pour la communication temps réel
17+
* Création d’une route de test (`GET /`)
18+
* Initialisation du frontend avec Next.js
19+
* Installation et configuration de Tailwind CSS
20+
* Intégration de MongoDB avec Mongoose
21+
* Mise en place des variables d’environnement (`.env`)
22+
* Création de l’architecture du projet (`frontend/`, `backend/`)
23+
* Ajout des fichiers `.gitignore`
24+
* Configuration du serveur pour utiliser les ES Modules
25+
* Gestion des erreurs de connexion MongoDB

docs/mvp/gameplay.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# MVP — Gameplay
2+
3+
## Fonctionnalités implémentées
4+
5+
- Lancer de dés aléatoire (2×d6) — tour par tour
6+
- Détection automatique des Doubles (d1 === d2)
7+
- Calcul du Lucky (distance minimale) et du Looser (distance maximale)
8+
- Gestion des égalités avec prolongations (Lucky et Looser indépendants)
9+
- Bonus de gorgées cumulé à chaque prolongation (+1 par prolongation)
10+
- Règles spéciales suspendues pendant les prolongations
11+
- Affichage des gorgées uniquement quand Lucky et Looser sont désignés
12+
- Enchaînement des tours (mémoire du Lucky pour l'annonce suivante)
13+
14+
---
15+
16+
## Fichiers concernés
17+
18+
| Fichier | Rôle |
19+
|---|---|
20+
| `frontend/src/app/components/GameScreen.tsx` | Moteur de jeu complet |
21+
22+
---
23+
24+
## Phases d'un tour
25+
26+
```
27+
Annonce → Lancer → Résultats
28+
↓ (égalité)
29+
Prolongation(s)
30+
↓ (résolu)
31+
Résultats (gorgées)
32+
```
33+
34+
### Phase Annonce
35+
36+
- **Tour 1** : annonce automatique = 12 ("le plus"), pas de saisie
37+
- **Tours suivants** : le Lucky saisit un nombre entre 2 et 12
38+
- Rappel affiché : "le moins" pour 2, "le plus" pour 12
39+
- Validation : entier dans `[2, 12]` obligatoire
40+
41+
### Phase Lancer
42+
43+
- Les joueurs lancent **un par un** dans l'ordre de la liste
44+
- Chaque lancer :
45+
- Animation 700 ms (🎲🎲 bounce)
46+
- Génération `d1 = rollD6()`, `d2 = rollD6()`
47+
- `score = d1 + d2`
48+
- `isDouble = d1 === d2`
49+
- Le résultat (faces + score) s'affiche immédiatement dans la liste
50+
- Badges **Double** et **Marchand** affichés en temps réel si les règles sont actives
51+
- Quand tous ont lancé → bouton "Voir les résultats"
52+
53+
### Phase Résultats
54+
55+
- Classement par distance croissante à l'annonce
56+
- `distance = |score - annonce|`
57+
- **Lucky** : distance minimale → fond jaune + 🏆
58+
- **Looser** : distance maximale → fond rouge + 💀
59+
- Si égalité Lucky **et** Looser → le Lucky est résolu en premier
60+
- Section "Gorgées" affichée uniquement quand les deux sont désignés
61+
- Bouton "Nouveau tour" disponible uniquement quand tout est résolu
62+
63+
---
64+
65+
## Calcul des gorgées
66+
67+
### Lucky
68+
69+
| Situation | Gorgées de base | + Prolongations |
70+
|---|---|---|
71+
| Score différent de l'annonce | 1 | +1 par prolongation Lucky |
72+
| Score exact (distance = 0) | 2 | +1 par prolongation Lucky |
73+
74+
### Looser
75+
76+
| Situation | Gorgées de base | + Prolongations |
77+
|---|---|---|
78+
| Toujours | 1 | +1 par prolongation Looser |
79+
80+
### Double *(si règle activée)*
81+
82+
| Valeur du dé | Gorgées |
83+
|---|---|
84+
| 1 (score 2) | 1 gorgée **ou** fait relancer un joueur au choix |
85+
| 2 à 6 | Autant de gorgées que la valeur du dé |
86+
87+
### Marchand de sable *(si règle activée)*
88+
89+
- Score de 3 (1+2) → immunité totale ce tour
90+
91+
---
92+
93+
## Gestion des égalités (prolongations)
94+
95+
### Principe
96+
97+
Une prolongation est déclenchée si plusieurs joueurs partagent la même distance minimale (Lucky) ou maximale (Looser).
98+
99+
- Lucky et Looser sont résolus **indépendamment**
100+
- Les prolongations Lucky et Looser ont chacune leur propre compteur
101+
- Les règles spéciales (Double, Marchand) sont **suspendues** pendant les prolongations
102+
103+
### Flux
104+
105+
```
106+
Égalité détectée sur le Lucky ou le Looser
107+
→ bouton "Lancer la prolongation" affiché
108+
→ Phase Prolongation :
109+
- Seuls les joueurs à égalité relancent (tour par tour)
110+
- Même annonce que le tour principal
111+
- Enjeu affiché = 1 + numéro de prolongation
112+
- Bouton "Résoudre la prolongation"
113+
→ nouvelle égalité → même joueurs relancent encore
114+
→ désignation → retour aux Résultats avec Lucky/Looser mis à jour
115+
```
116+
117+
### Calcul de l'enjeu en prolongation
118+
119+
```
120+
enjeu = gorgées_de_base + numéro_de_prolongation
121+
122+
Exemple :
123+
- Prolongation 1 Lucky → Lucky distribue 1 + 1 = 2 gorgées
124+
- Prolongation 2 Lucky → Lucky distribue 1 + 2 = 3 gorgées
125+
- Score exact + Prolongation 1 → Lucky distribue 2 + 1 = 3 gorgées
126+
```
127+
128+
### Version hard *(non implémentée)*
129+
130+
Les gorgées sont **doublées** à chaque prolongation au lieu d'être incrémentées.
131+
132+
```
133+
enjeu = gorgées_de_base × 2^numéro_de_prolongation
134+
```
135+
136+
---
137+
138+
## Logique métier
139+
140+
### Génération d'un dé
141+
142+
```ts
143+
function rollD6(): number {
144+
return Math.ceil(Math.random() * 6); // 1 à 6 inclus
145+
}
146+
```
147+
148+
### Calcul Lucky / Looser
149+
150+
```ts
151+
distance = Math.abs(score - announcement)
152+
153+
Luckyjoueurs avec distance === Math.min(...distances)
154+
Looserjoueurs avec distance === Math.max(...distances)
155+
156+
// Égalité : length > 1 → prolongation
157+
```
158+
159+
### Résolution d'une prolongation
160+
161+
```ts
162+
// Lucky : re-calcul du min parmi les joueurs à égalité
163+
// Si toujours égalité → même liste relance, compteur incrémenté
164+
// Si désigné → result.luckyPlayers = [winner]
165+
166+
// Idem pour Looser avec le max
167+
```
168+
169+
### État géré dans GameScreen
170+
171+
| Variable | Type | Rôle |
172+
|---|---|---|
173+
| `round` | `number` | Numéro du tour en cours |
174+
| `phase` | `'announce' \| 'roll' \| 'results' \| 'prolongation'` | Phase active |
175+
| `announcement` | `number` | Score cible du tour |
176+
| `luckyPlayer` | `Player \| null` | Lucky du tour précédent (pour l'annonce) |
177+
| `rolledDice` | `DiceRoll[]` | Lancers du tour principal |
178+
| `rollerIndex` | `number` | Index du joueur courant en phase lancer |
179+
| `result` | `RoundResult \| null` | Résultat calculé du tour |
180+
| `luckyProlongations` | `number` | Nombre de prolongations Lucky résolues |
181+
| `looserProlongations` | `number` | Nombre de prolongations Looser résolues |
182+
| `prolongation` | `ProlongationState \| null` | État de la prolongation en cours |
183+
184+
---
185+
186+
## Choix techniques
187+
188+
**Tour par tour pour le lancer**
189+
Sur un seul appareil, chaque joueur prend le téléphone à son tour. Ça reproduit la prise en main physique et évite la saisie manuelle des scores.
190+
191+
**Prolongations Lucky et Looser indépendantes**
192+
Les deux peuvent se produire dans le même tour (ex. 3 joueurs à distance 2, 2 joueurs à distance 5). Chacune a son propre compteur et son propre flux de relance.
193+
194+
**Règles spéciales suspendues en prolongation**
195+
Pendant une prolongation, l'enjeu est uniquement les gorgées du pot. Les Doubles ou Marchands générés en prolongation ne sont pas comptabilisés — conformément aux règles du jeu.
196+
197+
**Affichage des gorgées bloqué tant qu'une égalité subsiste**
198+
La section "Gorgées" et le bouton "Nouveau tour" n'apparaissent qu'une fois Lucky et Looser désignés. Cela évite d'afficher un résultat partiel et incomplet.
199+
200+
**Mémoire du Lucky entre les tours**
201+
`luckyPlayer` est mis à jour en fin de tour. En cas d'égalité non résolue (ne devrait pas arriver), il reste `null` et l'affichage de l'annonce est générique ("Le Lucky").

docs/mvp/parties.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Gestion des parties
2+
3+
## Fonctionnalités implémentées
4+
5+
- Configuration des règles optionnelles avant la partie
6+
- Déroulement d'une partie en 3 phases : Annonce → Lancer → Résultats
7+
- Génération aléatoire de 2 dés par joueur (tour par tour)
8+
- Détection automatique des Doubles
9+
- Calcul automatique du Lucky et du Looser
10+
- Gestion des égalités (signal de prolongation)
11+
- Application des règles actives (Double, Marchand de sable)
12+
- Enchaînement des tours avec mémoire du Lucky précédent
13+
- Pages informatives : Règles du jeu, À propos
14+
15+
---
16+
17+
## Architecture
18+
19+
```
20+
page.tsx
21+
└── SingleDeviceLobby.tsx ← configuration joueurs + règles
22+
└── GameScreen.tsx ← moteur de jeu (3 phases)
23+
└── RulesPage.tsx ← explication des règles du jeu
24+
└── AboutPage.tsx ← guide d'utilisation de l'app
25+
```
26+
27+
---
28+
29+
## Fichiers créés / modifiés
30+
31+
| Fichier | Rôle |
32+
|---|---|
33+
| `frontend/src/app/page.tsx` | Ajout des boutons "Règles du jeu" et "À propos" |
34+
| `frontend/src/app/components/SingleDeviceLobby.tsx` | Config des règles optionnelles + lancement |
35+
| `frontend/src/app/components/GameScreen.tsx` | Moteur de jeu complet (annonce / lancer / résultats) |
36+
| `frontend/src/app/components/RulesPage.tsx` | Page des règles du jeu (jouable avec ou sans app) |
37+
| `frontend/src/app/components/AboutPage.tsx` | Page "À propos" — guide d'utilisation de l'app |
38+
39+
---
40+
41+
## Règles
42+
43+
### Règles toujours actives
44+
45+
Ces règles font partie du cœur du jeu et ne sont pas configurables.
46+
47+
| Règle | Description |
48+
|---|---|
49+
| **Lucky** | Le joueur le plus proche de l'annonce distribue 1 gorgée (2 si score exact) |
50+
| **Looser** | Le joueur le plus éloigné de l'annonce boit 1 gorgée |
51+
| **L'Annonce** | Règle orale — le Lucky doit dire "le moins" pour 2 et "le plus" pour 12. Non implémentable automatiquement. |
52+
53+
### Règles optionnelles (configurables)
54+
55+
Cochées par défaut, désactivables dans le lobby avant de lancer la partie.
56+
57+
| Règle | Implémentée | Description |
58+
|---|---|---|
59+
| **Double** || Deux dés identiques → le joueur distribue autant de gorgées que la valeur du dé |
60+
| **Marchand de sable** || Score de 3 (1+2) → immunité totale ce tour |
61+
62+
### Règles à venir (désactivées)
63+
64+
| Règle | Description |
65+
|---|---|
66+
| **Jeton** | Score de 7 → boit 1 gorgée |
67+
| **Jackpot** | Trois joueurs à 7 → règle Jeton suspendue, pot à distribuer |
68+
| **Légende** | Score de 11 (5+6) → joueurs avec dé à 5 ou 6 boivent |
69+
| **Démon** | Trois joueurs à 6 → pot à distribuer |
70+
| **Mode hard** | Variantes avec pénalités multipliées |
71+
72+
---
73+
74+
## Flux — Déroulement d'une partie
75+
76+
```
77+
SingleDeviceLobby
78+
→ saisie des joueurs (min. 2)
79+
→ configuration des règles optionnelles
80+
→ clic "Lancer la partie"
81+
→ GameScreen
82+
83+
GameScreen — Phase Annonce
84+
Tour 1 : annonce automatique = 12 ("le plus")
85+
Tours suivants : le Lucky saisit un nombre entre 2 et 12
86+
→ clic "Commencer le tour" / "Confirmer l'annonce"
87+
88+
GameScreen — Phase Lancer (tour par tour)
89+
Pour chaque joueur dans l'ordre :
90+
→ affichage du nom du joueur courant
91+
→ clic "Lancer les dés"
92+
→ animation 700ms
93+
→ génération 2×d6 aléatoires
94+
→ calcul : score = d1 + d2, isDouble = (d1 === d2)
95+
→ affichage des faces de dés + score
96+
→ joueur suivant…
97+
Quand tous ont lancé :
98+
→ bouton "Voir les résultats"
99+
100+
GameScreen — Phase Résultats
101+
→ classement par distance à l'annonce (croissant)
102+
→ Lucky : distance minimale (fond jaune + 🏆)
103+
→ Looser : distance maximale (fond rouge + 💀)
104+
→ en cas d'égalité : message "prolongation !"
105+
→ section "Gorgées" avec les messages des règles actives
106+
→ bouton "Nouveau tour" → retour Phase Annonce (Lucky = winner du tour)
107+
→ bouton "Fin de partie" → retour au lobby
108+
```
109+
110+
---
111+
112+
## Logique métier
113+
114+
### Génération des dés
115+
116+
```ts
117+
function rollD6(): number {
118+
return Math.ceil(Math.random() * 6); // 1 à 6
119+
}
120+
// score = d1 + d2 (2 à 12)
121+
// isDouble = d1 === d2
122+
```
123+
124+
### Calcul Lucky / Looser
125+
126+
```ts
127+
distance = Math.abs(score - announcement)
128+
129+
Luckydistance minimale parmi tous les joueurs
130+
Looserdistance maximale parmi tous les joueurs
131+
132+
// Égalité : plusieurs joueurs partagent le min ou le max
133+
// → message de prolongation, aucun Lucky/Looser désigné
134+
```
135+
136+
### Distribution des gorgées (Lucky)
137+
138+
| Situation | Gorgées distribuées |
139+
|---|---|
140+
| Score différent de l'annonce | 1 |
141+
| Score exact (distance = 0) | 2 |
142+
143+
### Double
144+
145+
```ts
146+
diceValue = d1 // = d2 car identiques
147+
drinks = diceValue
148+
149+
// Cas spécial Double 1 (score 2) :
150+
// distribue 1 gorgée OU fait relancer un joueur au choix
151+
```
152+
153+
---
154+
155+
## Choix techniques
156+
157+
**Tour par tour pour le lancer**
158+
Sur un seul appareil, les joueurs lancent l'un après l'autre. Cela évite la saisie manuelle des scores et reproduit le côté "prise en main physique du téléphone" du jeu réel.
159+
160+
**Détection automatique des Doubles**
161+
Puisque les dés sont générés numériquement, la détection `d1 === d2` est fiable et immédiate — plus besoin de case à cocher manuelle.
162+
163+
**L'Annonce non implémentée**
164+
L'annonce est une règle orale (pénalité si on oublie "le moins" ou "le plus"). L'application ne peut pas détecter si le joueur l'a dit ou non. Un rappel visuel est affiché, la règle reste à appliquer de bonne foi par les joueurs.
165+
166+
**Mémoire du Lucky entre les tours**
167+
Le Lucky du tour précédent (`luckyPlayer`) est conservé en état pour pré-remplir l'affichage de la phase d'annonce au tour suivant. En cas d'égalité, `luckyPlayer` est `null` et l'affichage est générique.
168+
169+
**Règles toujours actives vs optionnelles**
170+
Lucky et Looser sont le cœur du jeu — ils ne peuvent pas être désactivés. Double et Marchand de sable enrichissent les tours mais ne changent pas la mécanique de base, d'où leur caractère optionnel.

0 commit comments

Comments
 (0)