diff --git a/Data/levels/level_01.json b/Data/levels/level_01.json index 5ea92bb..a0adec0 100644 --- a/Data/levels/level_01.json +++ b/Data/levels/level_01.json @@ -5,13 +5,14 @@ "width": 4, "height": 4, "productions": [ - { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood", "interval": 2 } + { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood" } ], "demands": [ - { "col": 3, "row": 0, "name": "Depot Royal", "cargo": "wood", "amount": 3, "deadline": 30 } + { "col": 3, "row": 0, "name": "Depot Royal", "cargo": "wood", "amount": 3, "deadline": 30 } ], "walls": [], "stock": [ - { "kind": "rook", "count": 3 } + { "kind": "pawn", "count": 4 }, + { "kind": "rook", "count": 2 } ] } diff --git a/Data/levels/level_02.json b/Data/levels/level_02.json index 0b8de0d..657f80e 100644 --- a/Data/levels/level_02.json +++ b/Data/levels/level_02.json @@ -5,7 +5,7 @@ "width": 6, "height": 6, "productions": [ - { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood", "interval": 2 } + { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood" } ], "demands": [ { "col": 5, "row": 0, "name": "Depot Royal", "cargo": "wood", "amount": 2, "deadline": 30 }, @@ -13,6 +13,7 @@ ], "walls": [], "stock": [ + { "kind": "pawn", "count": 6 }, { "kind": "rook", "count": 4 }, { "kind": "bishop", "count": 1 } ] diff --git a/Data/levels/level_03.json b/Data/levels/level_03.json index 7842138..9696ea8 100644 --- a/Data/levels/level_03.json +++ b/Data/levels/level_03.json @@ -5,8 +5,8 @@ "width": 6, "height": 6, "productions": [ - { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood", "interval": 2 }, - { "col": 5, "row": 0, "name": "Carriere", "cargo": "stone", "interval": 2 } + { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood" }, + { "col": 5, "row": 0, "name": "Carriere", "cargo": "stone" } ], "demands": [ { "col": 5, "row": 5, "name": "Depot Royal", "cargo": "wood", "amount": 2, "deadline": 40 }, @@ -20,7 +20,8 @@ { "col": 4, "row": 4 } ], "stock": [ - { "kind": "rook", "count": 4 }, + { "kind": "pawn", "count": 6 }, + { "kind": "rook", "count": 6 }, { "kind": "bishop", "count": 1 }, { "kind": "knight", "count": 2 } ] diff --git a/Data/levels/level_04.json b/Data/levels/level_04.json new file mode 100644 index 0000000..c124503 --- /dev/null +++ b/Data/levels/level_04.json @@ -0,0 +1,27 @@ +{ + "id": 4, + "name": "Le Carrefour", + "description": "Deux productions, deux demandes, et un carrefour au centre.", + "width": 8, + "height": 8, + "productions": [ + { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood" }, + { "col": 7, "row": 7, "name": "Carriere", "cargo": "stone" } + ], + "demands": [ + { "col": 7, "row": 0, "name": "Depot Royal", "cargo": "wood", "amount": 3, "deadline": 40 }, + { "col": 0, "row": 7, "name": "Forge", "cargo": "stone", "amount": 3, "deadline": 40 } + ], + "walls": [ + { "col": 3, "row": 3 }, + { "col": 4, "row": 4 }, + { "col": 3, "row": 4 }, + { "col": 4, "row": 3 } + ], + "stock": [ + { "kind": "pawn", "count": 8 }, + { "kind": "rook", "count": 4 }, + { "kind": "bishop", "count": 2 }, + { "kind": "knight", "count": 2 } + ] +} diff --git a/Data/levels/level_05.json b/Data/levels/level_05.json new file mode 100644 index 0000000..39aa675 --- /dev/null +++ b/Data/levels/level_05.json @@ -0,0 +1,35 @@ +{ + "id": 5, + "name": "Le Labyrinthe", + "description": "Un couloir etroit serpente a travers les murs. Seuls les cavaliers peuvent prendre des raccourcis.", + "width": 8, + "height": 6, + "productions": [ + { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood" }, + { "col": 0, "row": 5, "name": "Carriere", "cargo": "stone" } + ], + "demands": [ + { "col": 7, "row": 5, "name": "Depot Royal", "cargo": "wood", "amount": 3, "deadline": 50 }, + { "col": 7, "row": 0, "name": "Forge", "cargo": "stone", "amount": 3, "deadline": 50 } + ], + "walls": [ + { "col": 2, "row": 0 }, + { "col": 2, "row": 1 }, + { "col": 2, "row": 2 }, + { "col": 2, "row": 3 }, + { "col": 4, "row": 2 }, + { "col": 4, "row": 3 }, + { "col": 4, "row": 4 }, + { "col": 4, "row": 5 }, + { "col": 6, "row": 0 }, + { "col": 6, "row": 1 }, + { "col": 6, "row": 2 }, + { "col": 6, "row": 3 } + ], + "stock": [ + { "kind": "pawn", "count": 10 }, + { "kind": "rook", "count": 4 }, + { "kind": "bishop", "count": 2 }, + { "kind": "knight", "count": 3 } + ] +} diff --git a/Data/levels/level_06.json b/Data/levels/level_06.json new file mode 100644 index 0000000..9f9b435 --- /dev/null +++ b/Data/levels/level_06.json @@ -0,0 +1,35 @@ +{ + "id": 6, + "name": "Trois Royaumes", + "description": "Trois productions, trois demandes. Gerez un reseau complet sans interferences.", + "width": 10, + "height": 8, + "productions": [ + { "col": 0, "row": 0, "name": "Scierie", "cargo": "wood" }, + { "col": 0, "row": 7, "name": "Carriere", "cargo": "stone" }, + { "col": 9, "row": 3, "name": "Scierie Est", "cargo": "wood" } + ], + "demands": [ + { "col": 9, "row": 0, "name": "Depot Royal", "cargo": "wood", "amount": 3, "deadline": 50 }, + { "col": 9, "row": 7, "name": "Forge", "cargo": "stone", "amount": 3, "deadline": 50 }, + { "col": 4, "row": 7, "name": "Chantier", "cargo": "wood", "amount": 3, "deadline": 50 } + ], + "walls": [ + { "col": 3, "row": 2 }, + { "col": 3, "row": 3 }, + { "col": 3, "row": 4 }, + { "col": 3, "row": 5 }, + { "col": 6, "row": 2 }, + { "col": 6, "row": 3 }, + { "col": 6, "row": 4 }, + { "col": 6, "row": 5 }, + { "col": 4, "row": 3 }, + { "col": 5, "row": 3 } + ], + "stock": [ + { "kind": "pawn", "count": 14 }, + { "kind": "rook", "count": 6 }, + { "kind": "bishop", "count": 3 }, + { "kind": "knight", "count": 4 } + ] +} diff --git a/PLAN.md b/PLAN.md index 2132778..6c19033 100644 --- a/PLAN.md +++ b/PLAN.md @@ -20,25 +20,13 @@ - GDD stock corrections: Level 2 = 6R+1B, Level 3 = 10R+2K - 60 tests passing including 2 new CargoFilter tests -## Phase 3: Surplus stock and puzzle difficulty tuning +## Phase 3: Pion, surplus stock, levels 4-6 (DONE) -**Goal**: Levels give more pieces than the minimum, creating genuine puzzle space. - -- With forward-preferring transfers working, longer chains are viable. -- Design levels where the player has choice: multiple valid solutions with different - efficiency scores (PiecesUsed, TurnsTaken, CellsOccupied). -- Add scoring/star system based on Metrics. -- Levels 4-6: increasing board size (8x8, 10x10), more complex wall layouts, multiple - productions and demands. - -## Phase 4: New piece — Pion (Pawn) - -**Goal**: Add a one-directional piece for asymmetric relay constraints. - -- Pion moves forward only (one direction, range 1). -- Cheap to place (low piece cost if scoring is added). -- Creates interesting constraints: must plan direction of cargo flow. -- Test levels specifically designed around Pion usage. +- Pion: orthogonal range 1, status 1 (lowest), cheap relay maillon +- Surplus stock on all levels (more pieces than minimum solution) +- Levels 4-6: Le Carrefour (8x8), Le Labyrinthe (8x6), Trois Royaumes (10x8) +- Production interval removed: all productions fire every turn +- GDD updated with Pion, 6 levels ## Phase 5: Network levels and Dame (Queen) diff --git a/Scripts/Main.cs b/Scripts/Main.cs index 05bfedb..99b0b36 100644 --- a/Scripts/Main.cs +++ b/Scripts/Main.cs @@ -44,7 +44,7 @@ public partial class Main : Node2D private bool _running; private bool _panning; - private static readonly string[] LevelFiles = ["level_01.json", "level_02.json", "level_03.json"]; + private static readonly string[] LevelFiles = ["level_01.json", "level_02.json", "level_03.json", "level_04.json", "level_05.json", "level_06.json"]; private const float SidePanelWidth = 280f; private const float ControlBarHeight = 48f; diff --git a/Scripts/Pieces/PieceView.cs b/Scripts/Pieces/PieceView.cs index ad55f97..1bd6525 100644 --- a/Scripts/Pieces/PieceView.cs +++ b/Scripts/Pieces/PieceView.cs @@ -15,6 +15,7 @@ public partial class PieceView : Node2D public Coords StartCell { get; private set; } public Coords EndCell { get; private set; } + private static readonly Color PawnColor = new("#7AB54A"); private static readonly Color RookColor = new("#4A7AB5"); private static readonly Color BishopColor = new("#B54A8E"); private static readonly Color KnightColor = new("#B5824A"); @@ -32,6 +33,7 @@ public partial class PieceView : Node2D var color = kind switch { + PieceKind.Pawn => PawnColor, PieceKind.Rook => RookColor, PieceKind.Bishop => BishopColor, PieceKind.Knight => KnightColor, @@ -57,6 +59,7 @@ public partial class PieceView : Node2D { Text = kind switch { + PieceKind.Pawn => "P", PieceKind.Rook => "T", PieceKind.Bishop => "F", PieceKind.Knight => "C", diff --git a/Scripts/UI/PieceStockPanel.cs b/Scripts/UI/PieceStockPanel.cs index 639d058..1cd87c1 100644 --- a/Scripts/UI/PieceStockPanel.cs +++ b/Scripts/UI/PieceStockPanel.cs @@ -93,6 +93,7 @@ public partial class PieceStockPanel : VBoxContainer private static string GetPieceName(PieceKind kind) => kind switch { + PieceKind.Pawn => "Pion", PieceKind.Rook => "Tour II", PieceKind.Bishop => "Fou II", PieceKind.Knight => "Cavalier", diff --git a/chessistics-engine/Loading/LevelLoader.cs b/chessistics-engine/Loading/LevelLoader.cs index 6a15e09..b1aff21 100644 --- a/chessistics-engine/Loading/LevelLoader.cs +++ b/chessistics-engine/Loading/LevelLoader.cs @@ -52,6 +52,7 @@ public static class LevelLoader private static PieceKind ParseKind(string kind) => kind.ToLowerInvariant() switch { + "pawn" => PieceKind.Pawn, "rook" => PieceKind.Rook, "bishop" => PieceKind.Bishop, "knight" => PieceKind.Knight, diff --git a/chessistics-engine/Model/PieceKind.cs b/chessistics-engine/Model/PieceKind.cs index 1af2fec..c507773 100644 --- a/chessistics-engine/Model/PieceKind.cs +++ b/chessistics-engine/Model/PieceKind.cs @@ -2,6 +2,7 @@ namespace Chessistics.Engine.Model; public enum PieceKind { + Pawn, Rook, Bishop, Knight diff --git a/chessistics-engine/Model/PieceRules.cs b/chessistics-engine/Model/PieceRules.cs index 7611e16..ea0c19c 100644 --- a/chessistics-engine/Model/PieceRules.cs +++ b/chessistics-engine/Model/PieceRules.cs @@ -4,6 +4,7 @@ public static class PieceRules { public static int GetSocialStatus(PieceKind kind) => kind switch { + PieceKind.Pawn => 1, PieceKind.Rook => 5, PieceKind.Bishop => 3, PieceKind.Knight => 3, @@ -12,6 +13,7 @@ public static class PieceRules public static int GetMaxRange(PieceKind kind) => kind switch { + PieceKind.Pawn => 1, PieceKind.Rook => 2, PieceKind.Bishop => 2, PieceKind.Knight => 0, // Knight uses L-shape, not range diff --git a/chessistics-engine/Rules/MoveValidator.cs b/chessistics-engine/Rules/MoveValidator.cs index 53920bb..fd5805d 100644 --- a/chessistics-engine/Rules/MoveValidator.cs +++ b/chessistics-engine/Rules/MoveValidator.cs @@ -19,6 +19,7 @@ public static class MoveValidator return kind switch { + PieceKind.Pawn => GetSlidingMoves(start, OrthogonalDirs, 1, board), PieceKind.Rook => GetSlidingMoves(start, OrthogonalDirs, 2, board), PieceKind.Bishop => GetSlidingMoves(start, DiagonalDirs, 2, board), PieceKind.Knight => GetKnightMoves(start, board), diff --git a/docs/GDD_prototype.md b/docs/GDD_prototype.md index 1c55e8a..d47080f 100644 --- a/docs/GDD_prototype.md +++ b/docs/GDD_prototype.md @@ -85,9 +85,22 @@ C'est tout. Pas de programmation, pas de route multi-etapes. La piece fait l'all ### 3.2 Pieces disponibles dans le prototype -3 types. Chaque piece a un **niveau** (I, II, III…) qui determine sa puissance relative au sein d'un meme type. Dans le prototype, toutes les pieces sont de niveau fixe — le systeme de niveaux sera exploite dans les versions futures. +4 types. Chaque piece a un **niveau** (I, II, III…) qui determine sa puissance relative au sein d'un meme type. Dans le prototype, toutes les pieces sont de niveau fixe — le systeme de niveaux sera exploite dans les versions futures. -3 types : +4 types : + +#### Pion + +``` + X + X [Pion] X + X +``` + +- Se deplace de **1 case** en ligne droite (horizontal ou vertical) +- Ne peut pas traverser les murs ni les autres pieces +- Statut social : **1** (le plus bas — recoit et donne en dernier) +- Piece la moins chere, utile pour combler les maillons courts #### Tour (niveau II) @@ -178,6 +191,7 @@ Hierarchie de statut social (proto) : Tour 5 Fou 3 Cavalier 3 + Pion 1 ``` **Departage par direction** (en y-up, sens horaire) : @@ -421,7 +435,7 @@ Le joueur peut arreter la simulation a tout moment, reorganiser, et relancer. --- -## 8. Les 3 niveaux du prototype +## 8. Les 6 niveaux du prototype ### Niveau 1 — "Premier Convoi" @@ -574,6 +588,86 @@ Le Cavalier saute le mur en L. Il peut connecter les deux cotes du plateau la ou --- +### Niveau 4 — "Le Carrefour" + +**Intention** : premier plateau 8x8, deux cargaisons en diagonale, un bloc de murs au centre force le contournement. + +``` + 8 . . . . . . . . + 7 [D2] . . . . . . . Forge — 3 Pierre en 40 coups + 6 . . . . . . . . + 5 . . . ## . . . . + 4 . . . ## . . . . + 3 . . . . . . . . + 2 . . . . . . . . + 1 [S1] . . . . . . [D1] Depot Royal — 3 Bois en 40 coups + + a b c d e f g h + [S2] Carriere (h8) +``` + +- Plateau : **8x8** +- S1 = Scierie (a1, Bois), S2 = Carriere (h8, Pierre) +- D1 = Depot Royal (h1, 3 Bois/40c), D2 = Forge (a8, 3 Pierre/40c) +- Murs : bloc 2x2 au centre (d4, e5, d5, e4) +- Stock : 8 Pions, 4 Tours, 2 Fous, 2 Cavaliers + +**L'enjeu** : les routes Bois (a1→h1) et Pierre (h8→a8) se croisent en diagonale. Le bloc central empeche la ligne droite. Le joueur decouvre le Pion comme maillon economique. + +--- + +### Niveau 5 — "Le Labyrinthe" + +**Intention** : des murs verticaux creent des couloirs etroits. Les Cavaliers sont essentiels pour enjamber les obstacles. + +``` + 6 [S2] . # . # . # . Carriere (a6) + 5 . . # . # . # . + 4 . . # . # . . [D1] Depot Royal — 3 Bois en 50 coups + 3 . . # . . . # . + 2 . . . . # . # . + 1 [S1] . . . # . . [D2] Forge — 3 Pierre en 50 coups + + a b c d e f g h +``` + +- Plateau : **8x6** +- S1 = Scierie (a1, Bois), S2 = Carriere (a6, Pierre) +- D1 = Depot Royal (h6, 3 Bois/50c), D2 = Forge (h1, 3 Pierre/50c) +- Murs : 3 colonnes partielles formant un labyrinthe +- Stock : 10 Pions, 4 Tours, 2 Fous, 3 Cavaliers + +**L'enjeu** : les murs fragmentent le plateau en couloirs. Seul le Cavalier saute par-dessus. Le joueur doit combiner Pions (relais courts dans les couloirs) et Cavaliers (ponts entre couloirs). + +--- + +### Niveau 6 — "Trois Royaumes" + +**Intention** : reseau a 3 productions et 3 demandes, plateau 10x8. Le joueur gere un vrai reseau logistique. + +``` + 8 [S2] . . # . . # . . [D2] Forge — 3 Pierre en 50 coups + 7 . . . # . . # . . . + 6 . . . # ## . # . . . + 5 . . . . . . . . . . + 4 . . . # ## . # . . [S3] Scierie Est (j4, Bois) + 3 . . . # . . # . . . + 2 . . . . . . . . . . + 1 [S1] . . . [D3] . . . . [D1] Depot Royal — 3 Bois en 50 coups + + a b c d e f g h i j +``` + +- Plateau : **10x8** +- S1 = Scierie (a1, Bois), S2 = Carriere (a8, Pierre), S3 = Scierie Est (j4, Bois) +- D1 = Depot Royal (j1, 3 Bois/50c), D2 = Forge (j8, 3 Pierre/50c), D3 = Chantier (e8, 3 Bois/50c) +- Murs : deux colonnes avec pont horizontal +- Stock : 14 Pions, 6 Tours, 3 Fous, 4 Cavaliers + +**L'enjeu** : le joueur doit decider comment repartir les productions entre les demandes. S1 et S3 produisent du Bois mais sont loin l'une de l'autre. Les murs creent trois "royaumes" et le joueur doit construire un reseau d'interconnexion. + +--- + ## 9. Direction artistique (prototype) Le prototype vise la lisibilite.