@pompidup/kingdomino-engine 3.5.1 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,15 +42,19 @@ while (isGameWithNextAction(game)) {
42
42
  const { nextLord, nextAction } = game.nextAction;
43
43
 
44
44
  if (nextAction === "pickDomino") {
45
- const domino = game.currentDominoes.find((d) => !d.picked);
46
- if (domino) {
47
- game = engine.chooseDomino({ game, lordId: nextLord, dominoPick: domino.domino.number });
48
- }
45
+ const [dominoPick] = engine.getValidDominoPicks({ game });
46
+ game = engine.chooseDomino({ game, lordId: nextLord, dominoPick });
49
47
  } else if (nextAction === "placeDomino") {
50
48
  const lord = game.lords.find((l) => l.id === nextLord);
51
49
  const player = game.players.find((p) => p.id === lord?.playerId);
52
50
  if (lord?.dominoPicked && player) {
53
- const placements = engine.getValidPlacements({ kingdom: player.kingdom, domino: lord.dominoPicked });
51
+ // maxKingdomSize: 5, or 7 for a 7x7 kingdom (The Mighty Duel, Neolithic,
52
+ // QueenDomino and AgeOfGiants-QueenDomino at 2 players)
53
+ const placements = engine.getValidPlacements({
54
+ kingdom: player.kingdom,
55
+ domino: lord.dominoPicked,
56
+ maxKingdomSize: game.rules.basic.maxKingdomSize,
57
+ });
54
58
  if (placements.length > 0) {
55
59
  game = engine.placeDomino({ game, lordId: nextLord, position: placements[0].position, rotation: placements[0].rotation });
56
60
  } else {
@@ -71,12 +75,12 @@ console.log(results.result);
71
75
  | Mode | Description |
72
76
  |------|-------------|
73
77
  | **Classic** | Original Kingdomino rules. 1-4 players, 5x5 kingdom, terrain-based scoring. |
74
- | **QueenDomino** | Full Queendomino expansion with buildings, coins, knights, the Queen and the Dragon. |
78
+ | **QueenDomino** | Full Queendomino expansion with buildings, coins, knights, the Queen and the Dragon. 2-4 players (7x7 kingdom with the 48 dominoes at 2 players). |
75
79
  | **KingdominoOrigins-Discovery** | Origins expansion — volcanoes, fire tokens, fire-based scoring. |
76
80
  | **KingdominoOrigins-Totem** | Origins — Discovery + wooden resources + totem majority tiles. |
77
81
  | **KingdominoOrigins-Tribe** | Origins — Discovery + resources + cave board + cavemen recruitment. |
78
82
  | **AgeOfGiants** | Age of Giants extension — giants, quest tiles, 5-player support, 12 new dominos on Classic. |
79
- | **AgeOfGiants-QueenDomino** | Age of Giants combined with QueenDomino. |
83
+ | **AgeOfGiants-QueenDomino** | Age of Giants combined with QueenDomino (7x7 kingdom with the 60 dominoes at 2 players). |
80
84
 
81
85
  ```typescript
82
86
  let game = engine.createGame({ mode: "Classic" });
@@ -92,11 +96,12 @@ See [Game Modes](docs/game-modes.md) for rules, player counts, and extra rules d
92
96
  The QueenDomino mode adds significant new mechanics to the base game:
93
97
 
94
98
  - **Construction squares** on some domino tiles where buildings can be placed
95
- - **Coins** (7 starting) used to purchase buildings or use the Dragon
96
- - **Knights** (max 3) placed on dominos to collect tax from construction squares
97
- - **Buildings** (18 types) purchased from the Builders Board, granting crowns, towers, and end-game bonuses
98
- - **The Queen** goes to the player with the most towers, granting +1 crown to the best territory
99
- - **The Dragon** burns a building tile from the Builders Board
99
+ - **Coins** (7 starting) used to purchase buildings or bribe the Dragon; 1 point per 3 unused coins at the end of the game
100
+ - **Knights** (1 at the start, more from building bonuses) placed on the domino just placed, up to 2 per turn, collecting 1 coin per square of the territory
101
+ - **Buildings** purchased from the 6-spot Builders Board (spots costing 5 to 0 coins), granting crowns, towers, and end-game bonuses
102
+ - **The Queen** hosted by the player who reaches the most towers (even on a tie): -1 coin on her host's constructions, +1 crown on their largest territory at the end
103
+ - **The Dragon** burns a building tile from the Builders Board for 1 coin
104
+ - **2 players**: 7x7 kingdoms with all 48 dominoes (official rule)
100
105
 
101
106
  The turn flow is extended with optional actions after placing a domino:
102
107
 
@@ -147,10 +152,13 @@ if (nextAction === "placeGiant") {
147
152
  game = engine.placeGiant({ game, lordId: nextLord, position });
148
153
  }
149
154
  if (nextAction === "sendGiant") {
150
- game = engine.sendGiant({ game, lordId: nextLord, giantIndex, targetPlayerId, targetCrownPosition });
155
+ // The targeted opponent chooses the crown the giant covers
156
+ game = engine.sendGiant({ game, lordId: nextLord, giantIndex, targetPlayerId });
151
157
  }
152
158
  ```
153
159
 
160
+ After `sendGiant`, a single free crown of the opponent is covered automatically. With several free crowns, `game.ageOfGiants.pendingGiant` is set and the game waits for a `placeGiant` played by a lord of the **targeted** player (`getValidGiantPositions` lists its crowns). `targetCrownPosition` is still accepted for backward compatibility.
161
+
154
162
  See [Age of Giants Guide](docs/age-of-giants.md) for the complete rules and mechanics.
155
163
 
156
164
  ## Extra Rules
@@ -159,13 +167,16 @@ See [Age of Giants Guide](docs/age-of-giants.md) for the complete rules and mech
159
167
  |------|-------------|-------------|
160
168
  | **The Middle Kingdom** | +10 points if castle is centered | — |
161
169
  | **Harmony** | +5 points if no dominos were discarded | — |
162
- | **The Mighty Duel** | All 48 dominos, 7x7 kingdom | 2 players only |
170
+ | **The Mighty Duel** | All 48 dominos, 7x7 kingdom | 2 players only (QueenDomino already plays 7x7 at 2 players: accepted, without further effect) |
163
171
  | **Dynasty** | Play 3 games, highest total wins | — |
164
172
 
173
+ Origins has its own equivalents: **Empire of Fire**, **Homo Habilis**, **Neolithic** (2 players, 7x7, and the first pick of each line takes the dominoes 1 & 4 or 2 & 3 — see [Origins Guide](docs/origins.md#neolithic-2-players)) and **Dynasty**.
174
+
165
175
  ```typescript
166
176
  game = engine.addExtraRules({ game, extraRules: ["The middle Kingdom", "Harmony"] });
167
177
 
168
- // Dynasty: aggregate results from multiple games
178
+ // Dynasty: aggregate results from multiple games (grouped by player id: pass
179
+ // the same stable ids to addPlayers in every game, e.g. { id: "alice", name: "Alice" })
169
180
  const dynastyResults = engine.getDynastyResults({ games: [game1, game2, game3] });
170
181
  ```
171
182
 
@@ -202,6 +213,8 @@ const engine = createGameEngine({
202
213
  | `calculateScore` | Calculate score for any kingdom |
203
214
  | `getValidPlacements` | Find all valid placements for a domino |
204
215
  | `canPlaceDomino` | Check if any placement exists |
216
+ | `getValidDominoPicks` | Dominoes the lord to play may pick (Neolithic reservations included) |
217
+ | `calculatePlayerScore` | Mode-aware live (or final) score of one player, with its breakdown |
205
218
  | `serialize` / `deserialize` | Save and restore game state |
206
219
  | `getDynastyResults` | Aggregate scores from multiple games |
207
220
 
@@ -211,7 +224,7 @@ const engine = createGameEngine({
211
224
  |--------|-------------|
212
225
  | `placeKnight` | Place a knight and collect tax |
213
226
  | `constructBuilding` | Buy and place a building |
214
- | `useDragon` | Destroy a building tile from the board |
227
+ | `useDragon` | Destroy a building tile from the board (1 coin) |
215
228
  | `skipOptionalAction` | Skip the current optional action |
216
229
 
217
230
  ### Origins Methods
@@ -228,14 +241,18 @@ const engine = createGameEngine({
228
241
  | `placeGiant` | Place a giant on a crown in your kingdom |
229
242
  | `sendGiant` | Send a giant to an opponent's kingdom |
230
243
 
244
+ ### Valid targets
245
+
246
+ `getValidFireTokenPositions`, `getValidKnightPositions`, `getValidBuildingPositions`, `getAffordableBuildings`, `getValidDragonTargets`, `getValidCavemanPlacements`, `getValidGiantPositions`, `getValidGiantTargets` and `canSkipOptionalAction` list what the extension actions accept, with the same checks as the actions (see [Valid targets](docs/api-reference.md#valid-targets-for-extension-actions)).
247
+
231
248
  See [API Reference](docs/api-reference.md) for complete method signatures, types, and error codes.
232
249
 
233
250
  ## Additional Features
234
251
 
235
- - **Bot / AI**: 4 built-in strategies (`randomStrategy`, `greedyStrategy`, `advancedStrategy`, `expertStrategy`) with `playBotTurn()` helper
252
+ - **Bot / AI**: 4 built-in strategies (`randomStrategy`, `greedyStrategy`, `advancedStrategy`, `expertStrategy`) with `playBotTurn()` helper; mode-aware (they evaluate with the mode-aware score and play the Queendomino, Origins and Age of Giants actions — see [Bot Strategies](docs/api-reference.md#bot-strategies))
236
253
  - **Mixed games**: Human and bot players in the same game via `bot: { strategyName }` on player input
237
254
  - **Undo / Redo**: Snapshot-based history with `createGameHistory()`, `pushState()`, `undo()`, `redo()`
238
- - **Action Log**: Immutable log via `wrapWithActionLog(engine)` for replay with `replayActions()`
255
+ - **Action Log**: Immutable log via `wrapWithActionLog(engine)` for replay with `replayActions()`; format v2 records the seed and the game, player and lord ids, so a replay gives a strictly identical state (v1 logs remain replayable)
239
256
  - **Events**: Callbacks via `EngineConfig.events` (`onDominoPlaced`, `onGameEnd`, etc.)
240
257
  - **Debug Mode**: `wrapWithDebug(engine)` with 3 verbosity levels
241
258
  - **Seeded games**: Deterministic shuffle via `createGame({ mode, seed: "my-seed" })`