@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 +35 -18
- package/dist/index.d.ts +1454 -677
- package/dist/index.js +4370 -2514
- package/dist/index.js.map +1 -1
- package/dist/index.universal.js +4370 -2514
- package/dist/wasm-bridge.js +4018 -2249
- package/package.json +1 -9
package/dist/index.d.ts
CHANGED
|
@@ -73,6 +73,13 @@ type RevealsDomino = {
|
|
|
73
73
|
lordId: string | null;
|
|
74
74
|
/** Display position in the revealed set (for UI ordering) */
|
|
75
75
|
position: number;
|
|
76
|
+
/**
|
|
77
|
+
* Id of the player this domino is reserved for (Kingdomino Origins
|
|
78
|
+
* "Neolithic" rule): set on the whole line by its first pick, the pair
|
|
79
|
+
* 1 & 4 or 2 & 3 going to that lord's player and the two other dominoes to
|
|
80
|
+
* the opponent. Only lords of this player can pick it. Absent otherwise.
|
|
81
|
+
*/
|
|
82
|
+
reservedFor?: string;
|
|
76
83
|
};
|
|
77
84
|
|
|
78
85
|
/**
|
|
@@ -157,6 +164,17 @@ type QuestTile = {
|
|
|
157
164
|
/** Target terrain type (only for localTrade and kingdomBorders quests) */
|
|
158
165
|
terrain?: Ground;
|
|
159
166
|
};
|
|
167
|
+
/**
|
|
168
|
+
* A giant sent with `sendGiant` that the targeted opponent must now place on
|
|
169
|
+
* one of their own crowns (official rule: the opponent chooses the crown).
|
|
170
|
+
* While it is set, `nextAction` is `placeGiant` for a lord of the target.
|
|
171
|
+
*/
|
|
172
|
+
type PendingGiant = {
|
|
173
|
+
/** Lord who sent the giant; their turn resumes once the giant is placed */
|
|
174
|
+
fromLordId: string;
|
|
175
|
+
/** Player who received the giant and must choose the crown */
|
|
176
|
+
targetPlayerId: string;
|
|
177
|
+
};
|
|
160
178
|
/**
|
|
161
179
|
* Complete Age of Giants-specific game state.
|
|
162
180
|
* Stored as an optional field on Game and only present in AoG modes.
|
|
@@ -166,6 +184,8 @@ type AgeOfGiantsState = {
|
|
|
166
184
|
giantPool: number;
|
|
167
185
|
/** The 2 quest tiles drawn for this game */
|
|
168
186
|
questTiles: QuestTile[];
|
|
187
|
+
/** Giant sent to an opponent, waiting for that opponent to choose a crown */
|
|
188
|
+
pendingGiant?: PendingGiant;
|
|
169
189
|
};
|
|
170
190
|
|
|
171
191
|
/**
|
|
@@ -322,8 +342,28 @@ type WarriorTile = {
|
|
|
322
342
|
/** Combat power (1, 2, or 3) */
|
|
323
343
|
power: number;
|
|
324
344
|
};
|
|
325
|
-
/**
|
|
345
|
+
/**
|
|
346
|
+
* Discriminant values of `CavemanTile["kind"]`.
|
|
347
|
+
*/
|
|
348
|
+
declare const cavemanKinds: {
|
|
349
|
+
readonly hunterGatherer: "hunterGatherer";
|
|
350
|
+
readonly warrior: "warrior";
|
|
351
|
+
};
|
|
352
|
+
type CavemanKind = ObjectValues<typeof cavemanKinds>;
|
|
353
|
+
/** Discriminated union of all caveman tile types (discriminant: `kind`). */
|
|
326
354
|
type CavemanTile = HunterGathererTile | WarriorTile;
|
|
355
|
+
/**
|
|
356
|
+
* Type guard to check if a caveman tile is a hunter-gatherer.
|
|
357
|
+
* @param caveman - The caveman tile to check
|
|
358
|
+
* @returns True if the tile is a `HunterGathererTile`
|
|
359
|
+
*/
|
|
360
|
+
declare const isHunterGathererTile: (caveman: CavemanTile) => caveman is HunterGathererTile;
|
|
361
|
+
/**
|
|
362
|
+
* Type guard to check if a caveman tile is a warrior.
|
|
363
|
+
* @param caveman - The caveman tile to check
|
|
364
|
+
* @returns True if the tile is a `WarriorTile`
|
|
365
|
+
*/
|
|
366
|
+
declare const isWarriorTile: (caveman: CavemanTile) => caveman is WarriorTile;
|
|
327
367
|
/**
|
|
328
368
|
* A caveman tile placed on a player's kingdom.
|
|
329
369
|
*/
|
|
@@ -391,7 +431,12 @@ type BuildingTile = {
|
|
|
391
431
|
id: number;
|
|
392
432
|
/** Display name */
|
|
393
433
|
name: string;
|
|
394
|
-
/**
|
|
434
|
+
/**
|
|
435
|
+
* Intrinsic cost of the tile. On a Builders Board with `slotCosts` (every
|
|
436
|
+
* game started since the official 6-spot board), the price is carried by
|
|
437
|
+
* the spot the tile occupies instead (see `BuildersBoard.slotCosts`); this
|
|
438
|
+
* value is only used by boards without `slotCosts` (older saved games).
|
|
439
|
+
*/
|
|
395
440
|
cost: number;
|
|
396
441
|
/** Immediate bonus when constructed (optional) */
|
|
397
442
|
immediateBonus?: ImmediateBonus;
|
|
@@ -408,12 +453,26 @@ type BuildingTile = {
|
|
|
408
453
|
type BuildingSlot = BuildingTile | null;
|
|
409
454
|
/**
|
|
410
455
|
* The Builders Board holding available building tiles for purchase.
|
|
456
|
+
*
|
|
457
|
+
* Official board: 6 spots whose construction cost is printed below them
|
|
458
|
+
* (5, 4, 3, 2, 1 and 0 coins, from the draw pile to the cheapest spot). At
|
|
459
|
+
* each new round the remaining tiles slide to the cheapest spots and the
|
|
460
|
+
* empty spots are filled from the draw pile.
|
|
411
461
|
*/
|
|
412
462
|
type BuildersBoard = {
|
|
413
|
-
/**
|
|
463
|
+
/**
|
|
464
|
+
* Visible building tiles available for purchase, one per spot (6 spots; 4 in
|
|
465
|
+
* games started before the official board). `null` is an empty spot.
|
|
466
|
+
*/
|
|
414
467
|
slots: BuildingSlot[];
|
|
415
468
|
/** Remaining building tiles in the draw pile */
|
|
416
469
|
drawPile: BuildingTile[];
|
|
470
|
+
/**
|
|
471
|
+
* Construction cost of each spot, aligned with `slots` (`[5, 4, 3, 2, 1, 0]`).
|
|
472
|
+
* Absent in games started before the official board: the price is then the
|
|
473
|
+
* tile's own `cost`.
|
|
474
|
+
*/
|
|
475
|
+
slotCosts?: number[];
|
|
417
476
|
};
|
|
418
477
|
/**
|
|
419
478
|
* A building that has been placed on a player's kingdom.
|
|
@@ -454,6 +513,11 @@ type Player = {
|
|
|
454
513
|
towers?: number;
|
|
455
514
|
/** Knights placed on the kingdom (Queendomino) */
|
|
456
515
|
knights?: Knight[];
|
|
516
|
+
/**
|
|
517
|
+
* Extra knights granted by building immediate bonuses (Queendomino).
|
|
518
|
+
* Each one raises the player's knight limit above the base maximum.
|
|
519
|
+
*/
|
|
520
|
+
bonusKnights?: number;
|
|
457
521
|
/** Buildings placed on the kingdom (Queendomino) */
|
|
458
522
|
buildings?: PlacedBuilding[];
|
|
459
523
|
/** Fire tokens placed on the kingdom (Origins) */
|
|
@@ -519,6 +583,12 @@ type QueenDominoState = {
|
|
|
519
583
|
dragonAvailable: boolean;
|
|
520
584
|
/** Whether the Dragon has been used this round (resets each round) */
|
|
521
585
|
dragonUsedThisRound: boolean;
|
|
586
|
+
/**
|
|
587
|
+
* Kingdom positions of the two squares of the domino the current lord has
|
|
588
|
+
* just placed. Knights may only be placed on these squares. Empty when the
|
|
589
|
+
* lord discarded their domino.
|
|
590
|
+
*/
|
|
591
|
+
lastPlacedPositions?: Position[];
|
|
522
592
|
};
|
|
523
593
|
|
|
524
594
|
/**
|
|
@@ -559,6 +629,12 @@ type Rules = {
|
|
|
559
629
|
basic: Record<number, BasicRules>;
|
|
560
630
|
/** Age of Giants basic rules indexed by player count (2-5) */
|
|
561
631
|
aogBasic?: Record<number, BasicRules>;
|
|
632
|
+
/**
|
|
633
|
+
* Basic rules specific to one game mode, indexed by mode name then player
|
|
634
|
+
* count. They take precedence over `basic` / `aogBasic` for that mode and
|
|
635
|
+
* player count (e.g. Queendomino at 2 players: 7x7 kingdom, 48 dominoes).
|
|
636
|
+
*/
|
|
637
|
+
modeBasic?: Record<string, Record<number, BasicRules>>;
|
|
562
638
|
/** Available extra rules */
|
|
563
639
|
extraRules: ExtraRule[];
|
|
564
640
|
};
|
|
@@ -573,742 +649,1228 @@ type SelectedRules = {
|
|
|
573
649
|
};
|
|
574
650
|
|
|
575
651
|
/**
|
|
576
|
-
*
|
|
577
|
-
*
|
|
652
|
+
* Error codes for domain-level errors.
|
|
653
|
+
* These codes can be used for i18n and programmatic error handling.
|
|
578
654
|
*/
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
655
|
+
declare const ErrorCode: {
|
|
656
|
+
readonly INVALID_STEP: "INVALID_STEP";
|
|
657
|
+
readonly STEP_EXECUTION_FAILED: "STEP_EXECUTION_FAILED";
|
|
658
|
+
readonly ACTION_EXECUTION_FAILED: "ACTION_EXECUTION_FAILED";
|
|
659
|
+
readonly LORD_NOT_FOUND: "LORD_NOT_FOUND";
|
|
660
|
+
readonly PLAYER_NOT_FOUND: "PLAYER_NOT_FOUND";
|
|
661
|
+
readonly DOMINO_NOT_FOUND: "DOMINO_NOT_FOUND";
|
|
662
|
+
readonly MODE_NOT_FOUND: "MODE_NOT_FOUND";
|
|
663
|
+
readonly INVALID_PLAYER_COUNT: "INVALID_PLAYER_COUNT";
|
|
664
|
+
readonly INVALID_PLAYER_NAME: "INVALID_PLAYER_NAME";
|
|
665
|
+
readonly EXTRA_RULE_NOT_AVAILABLE: "EXTRA_RULE_NOT_AVAILABLE";
|
|
666
|
+
readonly INVALID_PLACEMENT: "INVALID_PLACEMENT";
|
|
667
|
+
readonly PLACEMENT_NOT_EMPTY: "PLACEMENT_NOT_EMPTY";
|
|
668
|
+
readonly PLACEMENT_NOT_ADJACENT: "PLACEMENT_NOT_ADJACENT";
|
|
669
|
+
readonly PLACEMENT_INVALID_TERRAIN: "PLACEMENT_INVALID_TERRAIN";
|
|
670
|
+
readonly PLACEMENT_OUT_OF_BOUNDS: "PLACEMENT_OUT_OF_BOUNDS";
|
|
671
|
+
readonly PLACEMENT_EXCEEDS_KINGDOM_SIZE: "PLACEMENT_EXCEEDS_KINGDOM_SIZE";
|
|
672
|
+
readonly NOT_YOUR_TURN: "NOT_YOUR_TURN";
|
|
673
|
+
readonly CANNOT_PICK: "CANNOT_PICK";
|
|
674
|
+
readonly CANNOT_PLACE: "CANNOT_PLACE";
|
|
675
|
+
readonly DOMINO_ALREADY_PICKED: "DOMINO_ALREADY_PICKED";
|
|
676
|
+
readonly DOMINO_RESERVED: "DOMINO_RESERVED";
|
|
677
|
+
readonly UNDO_UNAVAILABLE: "UNDO_UNAVAILABLE";
|
|
678
|
+
readonly REDO_UNAVAILABLE: "REDO_UNAVAILABLE";
|
|
679
|
+
readonly CANNOT_PLACE_KNIGHT: "CANNOT_PLACE_KNIGHT";
|
|
680
|
+
readonly MAX_KNIGHTS_REACHED: "MAX_KNIGHTS_REACHED";
|
|
681
|
+
readonly KNIGHT_TERRITORY_OCCUPIED: "KNIGHT_TERRITORY_OCCUPIED";
|
|
682
|
+
readonly CANNOT_AFFORD_BUILDING: "CANNOT_AFFORD_BUILDING";
|
|
683
|
+
readonly NO_CONSTRUCTION_SQUARE: "NO_CONSTRUCTION_SQUARE";
|
|
684
|
+
readonly DRAGON_UNAVAILABLE: "DRAGON_UNAVAILABLE";
|
|
685
|
+
readonly QUEEN_HOLDER_CANNOT_USE_DRAGON: "QUEEN_HOLDER_CANNOT_USE_DRAGON";
|
|
686
|
+
readonly BUILDING_NOT_FOUND: "BUILDING_NOT_FOUND";
|
|
687
|
+
readonly INVALID_OPTIONAL_ACTION: "INVALID_OPTIONAL_ACTION";
|
|
688
|
+
readonly GIANT_POOL_EMPTY: "GIANT_POOL_EMPTY";
|
|
689
|
+
readonly GIANT_NOT_FOUND: "GIANT_NOT_FOUND";
|
|
690
|
+
readonly INVALID_GIANT_PLACEMENT: "INVALID_GIANT_PLACEMENT";
|
|
691
|
+
readonly NOT_AOG_MODE: "NOT_AOG_MODE";
|
|
692
|
+
readonly FIRE_TOKEN_POOL_EMPTY: "FIRE_TOKEN_POOL_EMPTY";
|
|
693
|
+
readonly FIRE_TOKEN_INVALID_POSITION: "FIRE_TOKEN_INVALID_POSITION";
|
|
694
|
+
readonly NO_PENDING_FIRE_TOKEN: "NO_PENDING_FIRE_TOKEN";
|
|
695
|
+
readonly CANNOT_RECRUIT_CAVEMAN: "CANNOT_RECRUIT_CAVEMAN";
|
|
696
|
+
readonly INSUFFICIENT_RESOURCES: "INSUFFICIENT_RESOURCES";
|
|
697
|
+
readonly INVALID_CAVEMAN_PLACEMENT: "INVALID_CAVEMAN_PLACEMENT";
|
|
698
|
+
readonly CAVEMAN_NOT_FOUND: "CAVEMAN_NOT_FOUND";
|
|
699
|
+
readonly NOT_TRIBE_MODE: "NOT_TRIBE_MODE";
|
|
700
|
+
readonly INVALID_PLAYER_ID: "INVALID_PLAYER_ID";
|
|
606
701
|
};
|
|
702
|
+
type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
607
703
|
/**
|
|
608
|
-
*
|
|
704
|
+
* Structured domain error with code and context.
|
|
609
705
|
*/
|
|
610
|
-
|
|
611
|
-
/**
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
|
|
615
|
-
/**
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
readonly result: "result";
|
|
619
|
-
};
|
|
620
|
-
/** Union type of all possible game steps */
|
|
621
|
-
type GameSteps = ObjectValues<typeof gameSteps>;
|
|
706
|
+
interface DomainError {
|
|
707
|
+
/** Error code for programmatic handling */
|
|
708
|
+
code: ErrorCodeType;
|
|
709
|
+
/** Human-readable error message */
|
|
710
|
+
message: string;
|
|
711
|
+
/** Optional context data for debugging */
|
|
712
|
+
context?: Record<string, unknown>;
|
|
713
|
+
}
|
|
622
714
|
/**
|
|
623
|
-
*
|
|
624
|
-
* Used during active gameplay.
|
|
715
|
+
* Creates a domain error object.
|
|
625
716
|
*/
|
|
626
|
-
|
|
627
|
-
/** Discriminator for action type */
|
|
628
|
-
type: "action";
|
|
629
|
-
/** ID of the lord who must perform the action */
|
|
630
|
-
nextLord: string;
|
|
631
|
-
/** The action the lord must perform */
|
|
632
|
-
nextAction: PlayerActions;
|
|
633
|
-
};
|
|
717
|
+
declare const createDomainError: (code: ErrorCodeType, message: string, context?: Record<string, unknown>) => DomainError;
|
|
634
718
|
/**
|
|
635
|
-
*
|
|
636
|
-
* Used during setup and game end.
|
|
719
|
+
* Base class for domain errors thrown by handlers.
|
|
637
720
|
*/
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
};
|
|
644
|
-
/** Game state where a player action is required */
|
|
645
|
-
type GameWithNextAction = Game & {
|
|
646
|
-
nextAction: NextAction;
|
|
647
|
-
};
|
|
648
|
-
/** Game state where a phase transition is occurring */
|
|
649
|
-
type GameWithNextStep = Game & {
|
|
650
|
-
nextAction: NextStep;
|
|
651
|
-
};
|
|
652
|
-
/** Union of all possible game states */
|
|
653
|
-
type GameState = GameWithNextAction | GameWithNextStep;
|
|
654
|
-
/** Result wrapper for game state operations */
|
|
655
|
-
type GameStateResult = Result<GameState>;
|
|
721
|
+
declare class DomainException extends Error {
|
|
722
|
+
readonly code: ErrorCodeType;
|
|
723
|
+
readonly context?: Record<string, unknown>;
|
|
724
|
+
constructor(error: DomainError);
|
|
725
|
+
}
|
|
656
726
|
/**
|
|
657
|
-
*
|
|
658
|
-
* @param game - The game state to check
|
|
659
|
-
* @returns True if the game is waiting for a player action
|
|
727
|
+
* Error thrown when the game is in an invalid step for the requested action.
|
|
660
728
|
*/
|
|
661
|
-
declare
|
|
729
|
+
declare class InvalidStepError extends DomainException {
|
|
730
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
731
|
+
}
|
|
662
732
|
/**
|
|
663
|
-
*
|
|
664
|
-
* @param game - The game state to check
|
|
665
|
-
* @returns True if the game is transitioning between phases
|
|
733
|
+
* Error thrown when a step execution fails.
|
|
666
734
|
*/
|
|
667
|
-
declare
|
|
735
|
+
declare class StepExecutionError extends DomainException {
|
|
736
|
+
constructor(message: string, code?: ErrorCodeType, context?: Record<string, unknown>);
|
|
737
|
+
}
|
|
668
738
|
/**
|
|
669
|
-
*
|
|
739
|
+
* Error thrown when an action execution fails.
|
|
670
740
|
*/
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
/** Size of the largest contiguous property */
|
|
675
|
-
maxPropertiesSize: number;
|
|
676
|
-
/** Total number of crowns in the kingdom */
|
|
677
|
-
totalCrowns: number;
|
|
678
|
-
};
|
|
741
|
+
declare class ActionExecutionError extends DomainException {
|
|
742
|
+
constructor(message: string, code?: ErrorCodeType, context?: Record<string, unknown>);
|
|
743
|
+
}
|
|
679
744
|
/**
|
|
680
|
-
*
|
|
745
|
+
* Error thrown when a required entity is not found.
|
|
681
746
|
*/
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
/** Player's display name */
|
|
686
|
-
playerName: string;
|
|
687
|
-
/** Detailed score breakdown */
|
|
688
|
-
details: Score;
|
|
689
|
-
};
|
|
747
|
+
declare class NotFoundError extends DomainException {
|
|
748
|
+
constructor(message: string, code?: ErrorCodeType, context?: Record<string, unknown>);
|
|
749
|
+
}
|
|
690
750
|
/**
|
|
691
|
-
*
|
|
751
|
+
* Error thrown when validation fails.
|
|
692
752
|
*/
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
};
|
|
697
|
-
/** Game state with final results calculated */
|
|
698
|
-
type GameWithResults = Game & {
|
|
699
|
-
result: FinalResult[];
|
|
700
|
-
};
|
|
701
|
-
|
|
702
|
-
type AddExtraRulesCommand = {
|
|
703
|
-
game: GameState;
|
|
704
|
-
extraRules: string[];
|
|
705
|
-
};
|
|
706
|
-
|
|
753
|
+
declare class ValidationError extends DomainException {
|
|
754
|
+
constructor(message: string, code: ErrorCodeType, context?: Record<string, unknown>);
|
|
755
|
+
}
|
|
707
756
|
/**
|
|
708
|
-
*
|
|
757
|
+
* Error thrown when undo is requested but no previous state exists.
|
|
709
758
|
*/
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
strategyName: string;
|
|
714
|
-
};
|
|
715
|
-
};
|
|
716
|
-
type AddPlayersCommand = {
|
|
717
|
-
game: GameState;
|
|
718
|
-
players: PlayerInput[];
|
|
719
|
-
};
|
|
720
|
-
|
|
721
|
-
type CalculateScoreCommand = {
|
|
722
|
-
kingdom: Kingdom;
|
|
723
|
-
};
|
|
724
|
-
|
|
759
|
+
declare class UndoError extends DomainException {
|
|
760
|
+
constructor(message?: string, context?: Record<string, unknown>);
|
|
761
|
+
}
|
|
725
762
|
/**
|
|
726
|
-
*
|
|
727
|
-
* - "error": The state is corrupted and cannot be used safely.
|
|
728
|
-
* - "warning": The state is suspicious but may still work.
|
|
763
|
+
* Error thrown when redo is requested but no future state exists.
|
|
729
764
|
*/
|
|
730
|
-
|
|
765
|
+
declare class RedoError extends DomainException {
|
|
766
|
+
constructor(message?: string, context?: Record<string, unknown>);
|
|
767
|
+
}
|
|
768
|
+
|
|
731
769
|
/**
|
|
732
|
-
*
|
|
770
|
+
* Translation keys for internationalization support.
|
|
771
|
+
* Use these keys instead of hardcoded strings for translatable content.
|
|
733
772
|
*/
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
773
|
+
declare const TranslationKey: {
|
|
774
|
+
readonly ERROR_INVALID_STEP: "error.invalidStep";
|
|
775
|
+
readonly ERROR_STEP_EXECUTION_FAILED: "error.stepExecutionFailed";
|
|
776
|
+
readonly ERROR_ACTION_EXECUTION_FAILED: "error.actionExecutionFailed";
|
|
777
|
+
readonly ERROR_LORD_NOT_FOUND: "error.lordNotFound";
|
|
778
|
+
readonly ERROR_PLAYER_NOT_FOUND: "error.playerNotFound";
|
|
779
|
+
readonly ERROR_DOMINO_NOT_FOUND: "error.dominoNotFound";
|
|
780
|
+
readonly ERROR_MODE_NOT_FOUND: "error.modeNotFound";
|
|
781
|
+
readonly ERROR_INVALID_PLACEMENT: "error.invalidPlacement";
|
|
782
|
+
readonly ERROR_PLACEMENT_NOT_EMPTY: "error.placementNotEmpty";
|
|
783
|
+
readonly ERROR_PLACEMENT_NOT_ADJACENT: "error.placementNotAdjacent";
|
|
784
|
+
readonly ERROR_PLACEMENT_INVALID_TERRAIN: "error.placementInvalidTerrain";
|
|
785
|
+
readonly ERROR_PLACEMENT_OUT_OF_BOUNDS: "error.placementOutOfBounds";
|
|
786
|
+
readonly ERROR_PLACEMENT_EXCEEDS_KINGDOM_SIZE: "error.placementExceedsKingdomSize";
|
|
787
|
+
readonly ERROR_NOT_YOUR_TURN: "error.notYourTurn";
|
|
788
|
+
readonly ERROR_CANNOT_PICK: "error.cannotPick";
|
|
789
|
+
readonly ERROR_CANNOT_PLACE: "error.cannotPlace";
|
|
790
|
+
readonly ERROR_DOMINO_ALREADY_PICKED: "error.dominoAlreadyPicked";
|
|
791
|
+
readonly ERROR_DOMINO_RESERVED: "error.dominoReserved";
|
|
792
|
+
readonly ERROR_INVALID_PLAYER_COUNT: "error.invalidPlayerCount";
|
|
793
|
+
readonly ERROR_INVALID_PLAYER_NAME: "error.invalidPlayerName";
|
|
794
|
+
readonly ERROR_EXTRA_RULE_NOT_AVAILABLE: "error.extraRuleNotAvailable";
|
|
795
|
+
readonly ERROR_UNDO_UNAVAILABLE: "error.undoUnavailable";
|
|
796
|
+
readonly ERROR_REDO_UNAVAILABLE: "error.redoUnavailable";
|
|
797
|
+
readonly MODE_CLASSIC: "mode.classic";
|
|
798
|
+
readonly MODE_QUEENDOMINO: "mode.queenDomino";
|
|
799
|
+
readonly MODE_ORIGINS_DISCOVERY: "mode.originsDiscovery";
|
|
800
|
+
readonly MODE_ORIGINS_TOTEM: "mode.originsTotem";
|
|
801
|
+
readonly MODE_ORIGINS_TRIBE: "mode.originsTribe";
|
|
802
|
+
readonly MODE_AGE_OF_GIANTS: "mode.ageOfGiants";
|
|
803
|
+
readonly MODE_AGE_OF_GIANTS_QUEENDOMINO: "mode.ageOfGiantsQueenDomino";
|
|
804
|
+
readonly RULE_MIDDLE_KINGDOM: "rule.middleKingdom";
|
|
805
|
+
readonly RULE_HARMONY: "rule.harmony";
|
|
806
|
+
readonly RULE_MIGHTY_DUEL: "rule.mightyDuel";
|
|
807
|
+
readonly RULE_DYNASTY: "rule.dynasty";
|
|
808
|
+
readonly RULE_EMPIRE_OF_FIRE: "rule.empireOfFire";
|
|
809
|
+
readonly RULE_HOMO_HABILIS: "rule.homoHabilis";
|
|
810
|
+
readonly RULE_NEOLITHIC: "rule.neolithic";
|
|
811
|
+
readonly GROUND_CASTLE: "ground.castle";
|
|
812
|
+
readonly GROUND_WHEAT: "ground.wheat";
|
|
813
|
+
readonly GROUND_FOREST: "ground.forest";
|
|
814
|
+
readonly GROUND_SEA: "ground.sea";
|
|
815
|
+
readonly GROUND_PLAIN: "ground.plain";
|
|
816
|
+
readonly GROUND_SWAMP: "ground.swamp";
|
|
817
|
+
readonly GROUND_MINE: "ground.mine";
|
|
818
|
+
readonly GROUND_GRASSLAND: "ground.grassland";
|
|
819
|
+
readonly GROUND_LAKE: "ground.lake";
|
|
820
|
+
readonly GROUND_JUNGLE: "ground.jungle";
|
|
821
|
+
readonly GROUND_QUARRY: "ground.quarry";
|
|
822
|
+
readonly GROUND_DESERT: "ground.desert";
|
|
823
|
+
readonly GROUND_VOLCANO: "ground.volcano";
|
|
824
|
+
readonly RESOURCE_MAMMOTH: "resource.mammoth";
|
|
825
|
+
readonly RESOURCE_FISH: "resource.fish";
|
|
826
|
+
readonly RESOURCE_MUSHROOM: "resource.mushroom";
|
|
827
|
+
readonly RESOURCE_FLINT: "resource.flint";
|
|
828
|
+
readonly CAVEMAN_HUNTER_GATHERER: "caveman.hunterGatherer";
|
|
829
|
+
readonly CAVEMAN_WARRIOR: "caveman.warrior";
|
|
830
|
+
readonly CAVEMAN_MAMMOTH_HUNTER: "caveman.mammothHunter";
|
|
831
|
+
readonly CAVEMAN_FISHERMAN: "caveman.fisherman";
|
|
832
|
+
readonly CAVEMAN_MUSHROOM_PICKER: "caveman.mushroomPicker";
|
|
833
|
+
readonly CAVEMAN_FLINT_COLLECTOR: "caveman.flintCollector";
|
|
834
|
+
readonly CAVEMAN_TRAPPER: "caveman.trapper";
|
|
835
|
+
readonly CAVEMAN_GATHERER: "caveman.gatherer";
|
|
836
|
+
readonly CAVEMAN_FIRE_LADY: "caveman.fireLady";
|
|
837
|
+
readonly CAVEMAN_WARRIOR_SMALL: "caveman.warriorSmall";
|
|
838
|
+
readonly CAVEMAN_WARRIOR_AMAZON: "caveman.warriorAmazon";
|
|
839
|
+
readonly CAVEMAN_WARRIOR_OAFISH: "caveman.warriorOafish";
|
|
840
|
+
readonly PHASE_ADD_PLAYERS: "phase.addPlayers";
|
|
841
|
+
readonly PHASE_OPTIONS: "phase.options";
|
|
842
|
+
readonly PHASE_START: "phase.start";
|
|
843
|
+
readonly PHASE_RESULT: "phase.result";
|
|
844
|
+
readonly ACTION_PICK_DOMINO: "action.pickDomino";
|
|
845
|
+
readonly ACTION_PLACE_DOMINO: "action.placeDomino";
|
|
846
|
+
readonly ACTION_PASS: "action.pass";
|
|
847
|
+
readonly ACTION_PLACE_KNIGHT: "action.placeKnight";
|
|
848
|
+
readonly ACTION_CONSTRUCT_BUILDING: "action.constructBuilding";
|
|
849
|
+
readonly ACTION_USE_DRAGON: "action.useDragon";
|
|
850
|
+
readonly ACTION_SKIP_OPTIONAL_ACTION: "action.skipOptionalAction";
|
|
851
|
+
readonly ACTION_PLACE_GIANT: "action.placeGiant";
|
|
852
|
+
readonly ACTION_SEND_GIANT: "action.sendGiant";
|
|
853
|
+
readonly ACTION_PLACE_FIRE_TOKEN: "action.placeFireToken";
|
|
854
|
+
readonly ACTION_RECRUIT_CAVEMAN: "action.recruitCaveman";
|
|
855
|
+
readonly ERROR_CANNOT_PLACE_KNIGHT: "error.cannotPlaceKnight";
|
|
856
|
+
readonly ERROR_MAX_KNIGHTS_REACHED: "error.maxKnightsReached";
|
|
857
|
+
readonly ERROR_KNIGHT_TERRITORY_OCCUPIED: "error.knightTerritoryOccupied";
|
|
858
|
+
readonly ERROR_CANNOT_AFFORD_BUILDING: "error.cannotAffordBuilding";
|
|
859
|
+
readonly ERROR_NO_CONSTRUCTION_SQUARE: "error.noConstructionSquare";
|
|
860
|
+
readonly ERROR_DRAGON_UNAVAILABLE: "error.dragonUnavailable";
|
|
861
|
+
readonly ERROR_QUEEN_HOLDER_CANNOT_USE_DRAGON: "error.queenHolderCannotUseDragon";
|
|
862
|
+
readonly ERROR_BUILDING_NOT_FOUND: "error.buildingNotFound";
|
|
863
|
+
readonly ERROR_INVALID_OPTIONAL_ACTION: "error.invalidOptionalAction";
|
|
864
|
+
readonly ERROR_GIANT_POOL_EMPTY: "error.giantPoolEmpty";
|
|
865
|
+
readonly ERROR_GIANT_NOT_FOUND: "error.giantNotFound";
|
|
866
|
+
readonly ERROR_INVALID_GIANT_PLACEMENT: "error.invalidGiantPlacement";
|
|
867
|
+
readonly ERROR_NOT_AOG_MODE: "error.notAogMode";
|
|
868
|
+
readonly ERROR_FIRE_TOKEN_POOL_EMPTY: "error.fireTokenPoolEmpty";
|
|
869
|
+
readonly ERROR_FIRE_TOKEN_INVALID_POSITION: "error.fireTokenInvalidPosition";
|
|
870
|
+
readonly ERROR_NO_PENDING_FIRE_TOKEN: "error.noPendingFireToken";
|
|
871
|
+
readonly ERROR_CANNOT_RECRUIT_CAVEMAN: "error.cannotRecruitCaveman";
|
|
872
|
+
readonly ERROR_INSUFFICIENT_RESOURCES: "error.insufficientResources";
|
|
873
|
+
readonly ERROR_INVALID_CAVEMAN_PLACEMENT: "error.invalidCavemanPlacement";
|
|
874
|
+
readonly ERROR_CAVEMAN_NOT_FOUND: "error.cavemanNotFound";
|
|
875
|
+
readonly ERROR_NOT_TRIBE_MODE: "error.notTribeMode";
|
|
876
|
+
readonly ERROR_INVALID_PLAYER_ID: "error.invalidPlayerId";
|
|
877
|
+
readonly SCORE_QUEEN: "score.queen";
|
|
878
|
+
readonly SCORE_BUILDING: "score.building";
|
|
879
|
+
readonly SCORE_WEALTH: "score.wealth";
|
|
880
|
+
readonly SCORE_TOTEM_MAMMOTH: "score.totemMammoth";
|
|
881
|
+
readonly SCORE_TOTEM_FISH: "score.totemFish";
|
|
882
|
+
readonly SCORE_TOTEM_MUSHROOM: "score.totemMushroom";
|
|
883
|
+
readonly SCORE_TOTEM_FLINT: "score.totemFlint";
|
|
884
|
+
readonly SCORE_RESOURCES: "score.resources";
|
|
885
|
+
readonly SCORE_WARRIORS: "score.warriors";
|
|
886
|
+
readonly SCORE_FIRE: "score.fire";
|
|
887
|
+
readonly QUEST_LOCAL_TRADE: "quest.localTrade";
|
|
888
|
+
readonly QUEST_KINGDOM_BORDERS: "quest.kingdomBorders";
|
|
889
|
+
readonly QUEST_HARMONY: "quest.harmony";
|
|
890
|
+
readonly QUEST_MIDDLE_KINGDOM: "quest.middleKingdom";
|
|
891
|
+
readonly QUEST_LOST_CORNER: "quest.lostCorner";
|
|
892
|
+
readonly QUEST_MEGALOMANIA: "quest.megalomania";
|
|
893
|
+
readonly QUEST_AUSTERE_KING: "quest.austereKing";
|
|
743
894
|
};
|
|
744
|
-
|
|
895
|
+
type TranslationKeyType = (typeof TranslationKey)[keyof typeof TranslationKey];
|
|
745
896
|
/**
|
|
746
|
-
*
|
|
897
|
+
* Default English translations.
|
|
898
|
+
* Also available as `englishTranslations` / `translations.en`.
|
|
747
899
|
*/
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
/** The domino to check placement for */
|
|
752
|
-
domino: Domino;
|
|
753
|
-
/** Maximum kingdom size (default: 5, use 7 for Mighty Duel) */
|
|
754
|
-
maxKingdomSize?: number;
|
|
755
|
-
};
|
|
756
|
-
|
|
757
|
-
type ChooseDominoCommand = {
|
|
758
|
-
game: GameState;
|
|
759
|
-
dominoPick: number;
|
|
760
|
-
lordId: string;
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
type ConstructBuildingCommand = {
|
|
764
|
-
game: GameWithNextAction;
|
|
765
|
-
lordId: string;
|
|
766
|
-
buildingId: number;
|
|
767
|
-
position: Position;
|
|
768
|
-
};
|
|
769
|
-
|
|
770
|
-
type CreateGameCommand = {
|
|
771
|
-
mode: string;
|
|
772
|
-
seed?: string;
|
|
773
|
-
};
|
|
774
|
-
|
|
775
|
-
type DiscardDominoCommand = {
|
|
776
|
-
game: GameState;
|
|
777
|
-
lordId: string;
|
|
778
|
-
};
|
|
779
|
-
|
|
780
|
-
type GetDynastyResultCommand = {
|
|
781
|
-
games: GameWithResults[];
|
|
782
|
-
};
|
|
783
|
-
|
|
784
|
-
type GetExtraRulesCommand = {
|
|
785
|
-
mode: GameMode["name"];
|
|
786
|
-
players: number;
|
|
787
|
-
};
|
|
788
|
-
|
|
789
|
-
type GetModesCommand = Record<string, never>;
|
|
790
|
-
|
|
791
|
-
type GetResultCommand = {
|
|
792
|
-
game: GameState;
|
|
793
|
-
};
|
|
794
|
-
|
|
900
|
+
declare const defaultTranslations: Record<TranslationKeyType, string>;
|
|
901
|
+
/** English translations (alias of `defaultTranslations`). */
|
|
902
|
+
declare const englishTranslations: Record<TranslationKeyType, string>;
|
|
795
903
|
/**
|
|
796
|
-
*
|
|
904
|
+
* French translations.
|
|
797
905
|
*/
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
/** Maximum kingdom size (default: 5, use 7 for Mighty Duel) */
|
|
804
|
-
maxKingdomSize?: number;
|
|
805
|
-
};
|
|
806
|
-
|
|
807
|
-
type PlaceDominoCommand = {
|
|
808
|
-
game: GameState;
|
|
809
|
-
lordId: string;
|
|
810
|
-
position: Position;
|
|
811
|
-
rotation: Rotation;
|
|
812
|
-
};
|
|
813
|
-
|
|
814
|
-
type PlaceFireTokenCommand = {
|
|
815
|
-
game: GameWithNextAction;
|
|
816
|
-
lordId: string;
|
|
817
|
-
position: Position;
|
|
818
|
-
};
|
|
819
|
-
|
|
820
|
-
type PlaceGiantCommand = {
|
|
821
|
-
game: GameWithNextAction;
|
|
822
|
-
lordId: string;
|
|
823
|
-
position: Position;
|
|
824
|
-
};
|
|
825
|
-
|
|
826
|
-
type PlaceKnightCommand = {
|
|
827
|
-
game: GameWithNextAction;
|
|
828
|
-
lordId: string;
|
|
829
|
-
position: Position;
|
|
830
|
-
};
|
|
831
|
-
|
|
832
|
-
type RecruitCavemanCommand = {
|
|
833
|
-
game: GameWithNextAction;
|
|
834
|
-
lordId: string;
|
|
835
|
-
/** ID of the caveman tile to recruit */
|
|
836
|
-
cavemanId: number;
|
|
837
|
-
/** Position on the kingdom to place the caveman */
|
|
838
|
-
position: Position;
|
|
839
|
-
/** Positions of resources to spend as payment */
|
|
840
|
-
resourcePositions: Position[];
|
|
841
|
-
};
|
|
842
|
-
|
|
843
|
-
type SendGiantCommand = {
|
|
844
|
-
game: GameWithNextAction;
|
|
845
|
-
lordId: string;
|
|
846
|
-
/** Index of the giant to send from the current player's giants array */
|
|
847
|
-
giantIndex: number;
|
|
848
|
-
/** ID of the opponent player to receive the giant */
|
|
849
|
-
targetPlayerId: string;
|
|
850
|
-
/** Position on the opponent's kingdom where the giant will cover a crown */
|
|
851
|
-
targetCrownPosition: Position;
|
|
852
|
-
};
|
|
853
|
-
|
|
906
|
+
declare const frenchTranslations: Record<TranslationKeyType, string>;
|
|
907
|
+
/** Locales shipped with the engine. */
|
|
908
|
+
declare const supportedLocales: readonly ["en", "fr"];
|
|
909
|
+
/** A locale shipped with the engine. */
|
|
910
|
+
type SupportedLocale = (typeof supportedLocales)[number];
|
|
854
911
|
/**
|
|
855
|
-
*
|
|
912
|
+
* Built-in translation dictionaries, indexed by locale.
|
|
913
|
+
* Every dictionary contains every `TranslationKey`.
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```typescript
|
|
917
|
+
* const translator = createTranslator(localeTranslations.fr);
|
|
918
|
+
* ```
|
|
856
919
|
*/
|
|
857
|
-
|
|
858
|
-
/** The game state to serialize */
|
|
859
|
-
game: GameState;
|
|
860
|
-
};
|
|
920
|
+
declare const localeTranslations: Record<SupportedLocale, Record<TranslationKeyType, string>>;
|
|
861
921
|
/**
|
|
862
|
-
*
|
|
922
|
+
* Maps every terrain type (`Ground`) to its translation key.
|
|
863
923
|
*/
|
|
864
|
-
|
|
865
|
-
/** The JSON string to deserialize */
|
|
866
|
-
json: string;
|
|
867
|
-
};
|
|
868
|
-
|
|
869
|
-
type SkipOptionalActionCommand = {
|
|
870
|
-
game: GameWithNextAction;
|
|
871
|
-
lordId: string;
|
|
872
|
-
};
|
|
873
|
-
|
|
874
|
-
type StartGameCommand = {
|
|
875
|
-
game: GameState;
|
|
876
|
-
};
|
|
877
|
-
|
|
878
|
-
type UseDragonCommand = {
|
|
879
|
-
game: GameWithNextAction;
|
|
880
|
-
lordId: string;
|
|
881
|
-
buildingId: number;
|
|
882
|
-
};
|
|
883
|
-
|
|
884
|
-
type DynastyResult = {
|
|
885
|
-
playerId: string;
|
|
886
|
-
playerName: string;
|
|
887
|
-
totalPoints: number;
|
|
888
|
-
gamesPoints: number[];
|
|
889
|
-
position: number;
|
|
890
|
-
};
|
|
891
|
-
|
|
924
|
+
declare const groundToTranslationKey: Record<Ground, TranslationKeyType>;
|
|
892
925
|
/**
|
|
893
|
-
*
|
|
926
|
+
* Maps every player action (`PlayerActions`) to its translation key.
|
|
894
927
|
*/
|
|
895
|
-
|
|
896
|
-
position: Position;
|
|
897
|
-
rotation: Rotation;
|
|
898
|
-
};
|
|
899
|
-
|
|
928
|
+
declare const playerActionToTranslationKey: Record<PlayerActions, TranslationKeyType>;
|
|
900
929
|
/**
|
|
901
|
-
*
|
|
902
|
-
*
|
|
903
|
-
* This interface provides all methods needed to manage a complete game lifecycle,
|
|
904
|
-
* from creation to scoring. Each method follows a command pattern and returns
|
|
905
|
-
* an updated game state.
|
|
906
|
-
*
|
|
907
|
-
* @example
|
|
908
|
-
* ```typescript
|
|
909
|
-
* import { createGameEngine, isGameWithNextAction } from '@pompidup/kingdomino-engine';
|
|
910
|
-
*
|
|
911
|
-
* const engine = createGameEngine({});
|
|
912
|
-
* let game = engine.createGame({ mode: 'Classic' });
|
|
913
|
-
* game = engine.addPlayers({ game, players: ['Alice', 'Bob'] });
|
|
914
|
-
* game = engine.startGame({ game });
|
|
915
|
-
*
|
|
916
|
-
* while (isGameWithNextAction(game)) {
|
|
917
|
-
* // Handle player actions...
|
|
918
|
-
* }
|
|
919
|
-
*
|
|
920
|
-
* const results = engine.getResults({ game });
|
|
921
|
-
* ```
|
|
930
|
+
* Maps every Origins resource type to its translation key.
|
|
922
931
|
*/
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
* @returns Game state with first player action required
|
|
961
|
-
*/
|
|
962
|
-
startGame: (command: StartGameCommand) => GameWithNextAction;
|
|
963
|
-
/**
|
|
964
|
-
* Allows a lord to choose a domino from the currently revealed set.
|
|
965
|
-
* The chosen domino is reserved for that lord to place later.
|
|
966
|
-
* @param command - Contains game state, lord ID, and domino number to pick
|
|
967
|
-
* @returns Updated game state with next action
|
|
968
|
-
*/
|
|
969
|
-
chooseDomino: (command: ChooseDominoCommand) => GameWithNextAction;
|
|
970
|
-
/**
|
|
971
|
-
* Places a domino on the lord's kingdom at the specified position and rotation.
|
|
972
|
-
* The domino must be adjacent to an existing tile and match terrain types.
|
|
973
|
-
* @param command - Contains game state, lord ID, position {x, y}, and rotation (0, 90, 180, 270)
|
|
974
|
-
* @returns Updated game state (may transition to 'result' step if game ends)
|
|
975
|
-
* @throws Error if placement is invalid
|
|
976
|
-
*/
|
|
977
|
-
placeDomino: (command: PlaceDominoCommand) => GameState;
|
|
978
|
-
/**
|
|
979
|
-
* Discards a domino when no valid placement exists.
|
|
980
|
-
* The lord forfeits placing the domino this turn.
|
|
981
|
-
* @param command - Contains game state and lord ID
|
|
982
|
-
* @returns Updated game state with next action
|
|
983
|
-
*/
|
|
984
|
-
discardDomino: (command: DiscardDominoCommand) => GameState;
|
|
985
|
-
/**
|
|
986
|
-
* Calculates and returns final results after the game ends.
|
|
987
|
-
* Applies extra rule bonuses and ranks players.
|
|
988
|
-
* @param command - Contains the final game state
|
|
989
|
-
* @returns Game state with complete results including positions
|
|
990
|
-
*/
|
|
991
|
-
getResults: (command: GetResultCommand) => GameWithResults;
|
|
992
|
-
/**
|
|
993
|
-
* Calculates the score for a single kingdom.
|
|
994
|
-
* Useful for showing live scores during gameplay.
|
|
995
|
-
* @param command - Contains the kingdom grid to score
|
|
996
|
-
* @returns Score with points, largest property size, and total crowns
|
|
997
|
-
*/
|
|
998
|
-
calculateScore: (command: CalculateScoreCommand) => Score;
|
|
999
|
-
/**
|
|
1000
|
-
* Finds all valid placements for a domino on a kingdom.
|
|
1001
|
-
* Useful for AI players or showing available moves to human players.
|
|
1002
|
-
* @param command - Contains kingdom and domino to check
|
|
1003
|
-
* @returns Array of valid position/rotation combinations
|
|
1004
|
-
*/
|
|
1005
|
-
getValidPlacements: (command: GetValidPlacementsCommand) => ValidPlacement[];
|
|
1006
|
-
/**
|
|
1007
|
-
* Checks if a domino can be placed anywhere on a kingdom.
|
|
1008
|
-
* Quick check before deciding to discard.
|
|
1009
|
-
* @param command - Contains kingdom and domino to check
|
|
1010
|
-
* @returns True if at least one valid placement exists
|
|
1011
|
-
*/
|
|
1012
|
-
canPlaceDomino: (command: CanPlaceDominoCommand) => boolean;
|
|
1013
|
-
/**
|
|
1014
|
-
* Serializes the game state to a JSON string for persistence.
|
|
1015
|
-
* @param command - Contains the game state to serialize
|
|
1016
|
-
* @returns JSON string representation of the game
|
|
1017
|
-
*/
|
|
1018
|
-
serialize: (command: SerializeGameCommand) => string;
|
|
1019
|
-
/**
|
|
1020
|
-
* Deserializes a JSON string back to a game state.
|
|
1021
|
-
* @param command - Contains the JSON string to parse
|
|
1022
|
-
* @returns The restored game state
|
|
1023
|
-
* @throws Error if the JSON is invalid or incompatible
|
|
1024
|
-
*/
|
|
1025
|
-
deserialize: (command: DeserializeGameCommand) => GameState;
|
|
1026
|
-
/**
|
|
1027
|
-
* Calculates dynasty results from multiple completed games.
|
|
1028
|
-
* Sum total points across games, highest total wins.
|
|
1029
|
-
* @param command - Contains array of completed games with results
|
|
1030
|
-
* @returns Ranked dynasty results per player
|
|
1031
|
-
*/
|
|
1032
|
-
getDynastyResults: (command: GetDynastyResultCommand) => DynastyResult[];
|
|
1033
|
-
/**
|
|
1034
|
-
* Places a giant on a crown in the lord's kingdom (Age of Giants).
|
|
1035
|
-
* Mandatory after placing a giant domino (A-F). The giant covers the crown for scoring.
|
|
1036
|
-
* @param command - Contains game state, lord ID, and crown position
|
|
1037
|
-
* @returns Updated game state with next action
|
|
1038
|
-
*/
|
|
1039
|
-
placeGiant: (command: PlaceGiantCommand) => GameState;
|
|
1040
|
-
/**
|
|
1041
|
-
* Sends a giant from the lord's kingdom to an opponent's kingdom (Age of Giants).
|
|
1042
|
-
* Optional after placing a footprint domino (49-54). The opponent chooses which crown is covered.
|
|
1043
|
-
* @param command - Contains game state, lord ID, giant index, target player ID, and target crown position
|
|
1044
|
-
* @returns Updated game state with next action
|
|
1045
|
-
*/
|
|
1046
|
-
sendGiant: (command: SendGiantCommand) => GameState;
|
|
932
|
+
declare const resourceToTranslationKey: Record<ResourceType, TranslationKeyType>;
|
|
933
|
+
/**
|
|
934
|
+
* Maps every caveman tile kind (`CavemanKind`) to its translation key.
|
|
935
|
+
*/
|
|
936
|
+
declare const cavemanKindToTranslationKey: Record<CavemanKind, TranslationKeyType>;
|
|
937
|
+
/**
|
|
938
|
+
* Maps every hunter-gatherer type to its translation key.
|
|
939
|
+
*/
|
|
940
|
+
declare const hunterGathererKindToTranslationKey: Record<HunterGathererKind, TranslationKeyType>;
|
|
941
|
+
/**
|
|
942
|
+
* Maps every warrior type to its translation key.
|
|
943
|
+
*/
|
|
944
|
+
declare const warriorTypeToTranslationKey: Record<WarriorType, TranslationKeyType>;
|
|
945
|
+
/**
|
|
946
|
+
* Maps game mode names (`GameMode["name"]`, as returned by `getModes`)
|
|
947
|
+
* to their translation key.
|
|
948
|
+
*/
|
|
949
|
+
declare const modeNameToTranslationKey: Readonly<Record<string, TranslationKeyType>>;
|
|
950
|
+
/**
|
|
951
|
+
* Maps extra rule names (`ExtraRule["name"]`, as returned by `getExtraRules`)
|
|
952
|
+
* to their translation key.
|
|
953
|
+
*/
|
|
954
|
+
declare const extraRuleNameToTranslationKey: Readonly<Record<string, TranslationKeyType>>;
|
|
955
|
+
/**
|
|
956
|
+
* Maps ErrorCode values to their corresponding TranslationKey values.
|
|
957
|
+
* Used by handlers to translate error codes into localized messages.
|
|
958
|
+
*/
|
|
959
|
+
declare const errorCodeToTranslationKey: Record<ErrorCodeType, TranslationKeyType>;
|
|
960
|
+
/**
|
|
961
|
+
* Translates an error code to a localized message.
|
|
962
|
+
* Convenience function combining errorCodeToTranslationKey lookup and translation.
|
|
963
|
+
*/
|
|
964
|
+
declare const translateErrorCode: (translator: Translator, code: ErrorCodeType, params?: Record<string, string | number>) => string;
|
|
965
|
+
/**
|
|
966
|
+
* Translator interface for custom translations.
|
|
967
|
+
*/
|
|
968
|
+
interface Translator {
|
|
1047
969
|
/**
|
|
1048
|
-
*
|
|
1049
|
-
* @param
|
|
1050
|
-
* @
|
|
970
|
+
* Translate a key to the current language.
|
|
971
|
+
* @param key - The translation key
|
|
972
|
+
* @param params - Optional parameters for interpolation
|
|
973
|
+
* @returns The translated string
|
|
1051
974
|
*/
|
|
1052
|
-
|
|
975
|
+
t(key: TranslationKeyType, params?: Record<string, string | number>): string;
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Creates a translator with the provided translations.
|
|
979
|
+
* Falls back to default English translations for missing keys.
|
|
980
|
+
*
|
|
981
|
+
* @param translations - Custom translations to use
|
|
982
|
+
* @returns A translator instance
|
|
983
|
+
*/
|
|
984
|
+
declare const createTranslator: (translations?: Partial<Record<TranslationKeyType, string>>) => Translator;
|
|
985
|
+
/**
|
|
986
|
+
* Default translator using English translations.
|
|
987
|
+
*/
|
|
988
|
+
declare const defaultTranslator: Translator;
|
|
989
|
+
/**
|
|
990
|
+
* Maps every Age of Giants quest type to the translation key of its name
|
|
991
|
+
* (used as `label` of `quest` score bonuses).
|
|
992
|
+
*/
|
|
993
|
+
declare const questTypeToTranslationKey: Record<QuestType, TranslationKeyType>;
|
|
994
|
+
/**
|
|
995
|
+
* Maps every Origins totem (by resource type) to the translation key of its
|
|
996
|
+
* name (used as `label` of `totem` score bonuses).
|
|
997
|
+
*/
|
|
998
|
+
declare const totemToTranslationKey: Record<ResourceType, TranslationKeyType>;
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* One scored territory (a group of orthogonally connected squares of the
|
|
1002
|
+
* same terrain) of a kingdom. The castle is never part of a territory.
|
|
1003
|
+
*/
|
|
1004
|
+
type ScoreTerritory = {
|
|
1005
|
+
/** Terrain shared by every square of the territory */
|
|
1006
|
+
terrain: Ground;
|
|
1007
|
+
/** Squares of the territory, sorted by row then column */
|
|
1008
|
+
cells: Position[];
|
|
1053
1009
|
/**
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
* @returns Updated game state with next action
|
|
1010
|
+
* Crowns counted for scoring (Origins: fire symbols). Crowns covered by an
|
|
1011
|
+
* Age of Giants giant are not counted.
|
|
1057
1012
|
*/
|
|
1058
|
-
|
|
1013
|
+
crowns: number;
|
|
1014
|
+
/** Crowns of the territory covered by giants (not counted in `crowns`) */
|
|
1015
|
+
coveredCrowns: number;
|
|
1016
|
+
/** Points scored by the territory: `cells.length * crowns` */
|
|
1017
|
+
points: number;
|
|
1018
|
+
};
|
|
1019
|
+
/**
|
|
1020
|
+
* Kinds of bonus that can appear in a score breakdown.
|
|
1021
|
+
*/
|
|
1022
|
+
declare const scoreBonusTypes: {
|
|
1023
|
+
/** "The middle Kingdom" optional rule: castle in the middle (+10) */
|
|
1024
|
+
readonly middleKingdom: "middleKingdom";
|
|
1025
|
+
/** "Empire of Fire" optional rule (Origins): hut in the middle (+10) */
|
|
1026
|
+
readonly empireOfFire: "empireOfFire";
|
|
1027
|
+
/** "Harmony" optional rule: complete kingdom, no discarded domino (+5) */
|
|
1028
|
+
readonly harmony: "harmony";
|
|
1029
|
+
/** "Homo Habilis" optional rule (Origins): complete territory (+5) */
|
|
1030
|
+
readonly homoHabilis: "homoHabilis";
|
|
1031
|
+
/** Queendomino: the Queen counts as an extra crown on the largest territory */
|
|
1032
|
+
readonly queen: "queen";
|
|
1033
|
+
/** Queendomino: end-game scoring of one constructed building */
|
|
1034
|
+
readonly building: "building";
|
|
1035
|
+
/** Queendomino: Wealth, 1 point per 3 unused coins */
|
|
1036
|
+
readonly wealth: "wealth";
|
|
1037
|
+
/** Age of Giants: one quest tile */
|
|
1038
|
+
readonly quest: "quest";
|
|
1039
|
+
/** Origins Totem: one totem held by the player */
|
|
1040
|
+
readonly totem: "totem";
|
|
1041
|
+
/** Origins Totem: 1 point per wooden resource left in the kingdom */
|
|
1042
|
+
readonly resources: "resources";
|
|
1043
|
+
/** Origins Tribe: one hunter-gatherer */
|
|
1044
|
+
readonly hunterGatherer: "hunterGatherer";
|
|
1045
|
+
/** Origins Tribe: every warrior group */
|
|
1046
|
+
readonly warriors: "warriors";
|
|
1047
|
+
/** Origins: fire tokens placed in the kingdom's territories */
|
|
1048
|
+
readonly fire: "fire";
|
|
1049
|
+
};
|
|
1050
|
+
/** Union of every bonus kind */
|
|
1051
|
+
type ScoreBonusType = ObjectValues<typeof scoreBonusTypes>;
|
|
1052
|
+
/**
|
|
1053
|
+
* One bonus of a score breakdown.
|
|
1054
|
+
*/
|
|
1055
|
+
type ScoreBonus = {
|
|
1056
|
+
/** Kind of bonus */
|
|
1057
|
+
type: ScoreBonusType;
|
|
1059
1058
|
/**
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
* @returns Updated game state with next action
|
|
1059
|
+
* Translation key of the bonus name (see `TranslationKey`). Translate it
|
|
1060
|
+
* with `translator.t(bonus.label, bonus.labelParams)`.
|
|
1063
1061
|
*/
|
|
1064
|
-
|
|
1062
|
+
label: TranslationKeyType;
|
|
1063
|
+
/** Interpolation parameters of the label (e.g. the building name) */
|
|
1064
|
+
labelParams?: Record<string, string | number>;
|
|
1065
|
+
/** Points granted by the bonus (may be 0 when its condition is not met) */
|
|
1066
|
+
points: number;
|
|
1065
1067
|
/**
|
|
1066
|
-
*
|
|
1067
|
-
*
|
|
1068
|
-
*
|
|
1068
|
+
* `true` while the game is in progress: the bonus is evaluated on the
|
|
1069
|
+
* current state and may still change (or disappear) before the end of the
|
|
1070
|
+
* game. `false` once the game is over.
|
|
1069
1071
|
*/
|
|
1070
|
-
|
|
1072
|
+
provisional: boolean;
|
|
1073
|
+
/** Building id (`building` bonuses) */
|
|
1074
|
+
buildingId?: number;
|
|
1075
|
+
/** Quest tile id (`quest` bonuses) */
|
|
1076
|
+
questId?: number;
|
|
1077
|
+
/** Quest type (`quest` bonuses) */
|
|
1078
|
+
questType?: QuestType;
|
|
1079
|
+
/** Target terrain of the quest (Local Trade, Kingdom Borders) */
|
|
1080
|
+
terrain?: Ground;
|
|
1081
|
+
/** Resource of the totem (`totem` bonuses) */
|
|
1082
|
+
resource?: ResourceType;
|
|
1083
|
+
/** Caveman tile id (`hunterGatherer` bonuses) */
|
|
1084
|
+
cavemanId?: number;
|
|
1085
|
+
/** Kingdom position the bonus relates to (building, hunter-gatherer) */
|
|
1086
|
+
position?: Position;
|
|
1087
|
+
};
|
|
1088
|
+
/**
|
|
1089
|
+
* Detailed score of one kingdom.
|
|
1090
|
+
* Invariant: `total === territoryPoints + bonusPoints`, where
|
|
1091
|
+
* `territoryPoints` is the sum of the territory points and `bonusPoints`
|
|
1092
|
+
* the sum of the bonus points.
|
|
1093
|
+
*/
|
|
1094
|
+
type ScoreBreakdown = {
|
|
1095
|
+
/** Every scored territory of the kingdom */
|
|
1096
|
+
territories: ScoreTerritory[];
|
|
1097
|
+
/** Every bonus applying to the player in the current game mode */
|
|
1098
|
+
bonuses: ScoreBonus[];
|
|
1099
|
+
/** Sum of the territory points */
|
|
1100
|
+
territoryPoints: number;
|
|
1101
|
+
/** Sum of the bonus points */
|
|
1102
|
+
bonusPoints: number;
|
|
1103
|
+
/** Total score: `territoryPoints + bonusPoints` */
|
|
1104
|
+
total: number;
|
|
1105
|
+
};
|
|
1106
|
+
/**
|
|
1107
|
+
* Mode-aware score of one player, as returned by `calculatePlayerScore`.
|
|
1108
|
+
*/
|
|
1109
|
+
type PlayerScore = {
|
|
1110
|
+
/** Player's unique identifier */
|
|
1111
|
+
playerId: string;
|
|
1112
|
+
/** Player's display name */
|
|
1113
|
+
playerName: string;
|
|
1114
|
+
/** Total score (same as `breakdown.total`) */
|
|
1115
|
+
points: number;
|
|
1116
|
+
/** Size of the largest territory (tie-breaker) */
|
|
1117
|
+
maxPropertiesSize: number;
|
|
1118
|
+
/** Total crowns counted in the kingdom */
|
|
1119
|
+
totalCrowns: number;
|
|
1071
1120
|
/**
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1121
|
+
* `true` when the game is over: the score is the final score, identical
|
|
1122
|
+
* to the one returned by `getResults`. `false` during the game: the score
|
|
1123
|
+
* is a live estimate of the current state (end-of-game-only bonuses such
|
|
1124
|
+
* as Harmony are not included yet).
|
|
1075
1125
|
*/
|
|
1076
|
-
|
|
1126
|
+
final: boolean;
|
|
1127
|
+
/** Detailed score */
|
|
1128
|
+
breakdown: ScoreBreakdown;
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* Represents the complete state of a Kingdomino game.
|
|
1133
|
+
* This is the main aggregate containing all game data.
|
|
1134
|
+
*/
|
|
1135
|
+
type Game = {
|
|
1136
|
+
/** Unique identifier for the game */
|
|
1137
|
+
id: string;
|
|
1138
|
+
/** Remaining dominoes in the draw pile */
|
|
1139
|
+
dominoes: Domino[];
|
|
1140
|
+
/** Currently revealed dominoes available for picking */
|
|
1141
|
+
currentDominoes: RevealsDomino[];
|
|
1142
|
+
/** Players participating in the game with their kingdoms */
|
|
1143
|
+
players: Player[];
|
|
1144
|
+
/** Lords (player tokens) used for turn order and domino selection */
|
|
1145
|
+
lords: Lord[];
|
|
1146
|
+
/** Current turn number (1-based) */
|
|
1147
|
+
turn: number;
|
|
1148
|
+
/** Next required action or game step */
|
|
1149
|
+
nextAction: NextAction | NextStep;
|
|
1150
|
+
/** Active rules for this game */
|
|
1151
|
+
rules: SelectedRules;
|
|
1152
|
+
/** Game mode being played */
|
|
1153
|
+
mode: GameMode;
|
|
1154
|
+
/** Optional seed for deterministic shuffle (replays, sharing) */
|
|
1155
|
+
seed?: string;
|
|
1156
|
+
/** Queendomino-specific state (only present in QueenDomino mode) */
|
|
1157
|
+
queendomino?: QueenDominoState;
|
|
1158
|
+
/** Origins-specific state (only present in KingdominoOrigins modes) */
|
|
1159
|
+
origins?: OriginsState;
|
|
1160
|
+
/** Age of Giants-specific state (only present in AgeOfGiants modes) */
|
|
1161
|
+
ageOfGiants?: AgeOfGiantsState;
|
|
1162
|
+
};
|
|
1163
|
+
/**
|
|
1164
|
+
* Available game steps representing phases of game setup and completion.
|
|
1165
|
+
*/
|
|
1166
|
+
declare const gameSteps: {
|
|
1167
|
+
/** Waiting for players to be added */
|
|
1168
|
+
readonly addPlayers: "addPlayers";
|
|
1169
|
+
/** Optional rules selection phase */
|
|
1170
|
+
readonly options: "options";
|
|
1171
|
+
/** Ready to start the game */
|
|
1172
|
+
readonly start: "start";
|
|
1173
|
+
/** Game has ended, results available */
|
|
1174
|
+
readonly result: "result";
|
|
1175
|
+
};
|
|
1176
|
+
/** Union type of all possible game steps */
|
|
1177
|
+
type GameSteps = ObjectValues<typeof gameSteps>;
|
|
1178
|
+
/**
|
|
1179
|
+
* Represents a player action that needs to be performed.
|
|
1180
|
+
* Used during active gameplay.
|
|
1181
|
+
*/
|
|
1182
|
+
type NextAction = {
|
|
1183
|
+
/** Discriminator for action type */
|
|
1184
|
+
type: "action";
|
|
1185
|
+
/** ID of the lord who must perform the action */
|
|
1186
|
+
nextLord: string;
|
|
1187
|
+
/** The action the lord must perform */
|
|
1188
|
+
nextAction: PlayerActions;
|
|
1189
|
+
};
|
|
1190
|
+
/**
|
|
1191
|
+
* Represents a game phase transition.
|
|
1192
|
+
* Used during setup and game end.
|
|
1193
|
+
*/
|
|
1194
|
+
type NextStep = {
|
|
1195
|
+
/** Discriminator for step type */
|
|
1196
|
+
type: "step";
|
|
1197
|
+
/** The current game step/phase */
|
|
1198
|
+
step: GameSteps;
|
|
1199
|
+
};
|
|
1200
|
+
/** Game state where a player action is required */
|
|
1201
|
+
type GameWithNextAction = Game & {
|
|
1202
|
+
nextAction: NextAction;
|
|
1203
|
+
};
|
|
1204
|
+
/** Game state where a phase transition is occurring */
|
|
1205
|
+
type GameWithNextStep = Game & {
|
|
1206
|
+
nextAction: NextStep;
|
|
1207
|
+
};
|
|
1208
|
+
/** Union of all possible game states */
|
|
1209
|
+
type GameState = GameWithNextAction | GameWithNextStep;
|
|
1210
|
+
/** Result wrapper for game state operations */
|
|
1211
|
+
type GameStateResult = Result<GameState>;
|
|
1212
|
+
/**
|
|
1213
|
+
* Type guard to check if the game requires a player action.
|
|
1214
|
+
* @param game - The game state to check
|
|
1215
|
+
* @returns True if the game is waiting for a player action
|
|
1216
|
+
*/
|
|
1217
|
+
declare const isGameWithNextAction: (game: GameWithNextAction | GameWithNextStep) => game is GameWithNextAction;
|
|
1218
|
+
/**
|
|
1219
|
+
* Type guard to check if the game is in a phase transition.
|
|
1220
|
+
* @param game - The game state to check
|
|
1221
|
+
* @returns True if the game is transitioning between phases
|
|
1222
|
+
*/
|
|
1223
|
+
declare const isGameWithNextStep: (game: GameWithNextAction | GameWithNextStep) => game is GameWithNextStep;
|
|
1224
|
+
/**
|
|
1225
|
+
* Represents the score calculation for a kingdom.
|
|
1226
|
+
*/
|
|
1227
|
+
type Score = {
|
|
1228
|
+
/** Total points earned */
|
|
1229
|
+
points: number;
|
|
1230
|
+
/** Size of the largest contiguous property */
|
|
1231
|
+
maxPropertiesSize: number;
|
|
1232
|
+
/** Total number of crowns in the kingdom */
|
|
1233
|
+
totalCrowns: number;
|
|
1234
|
+
};
|
|
1235
|
+
/**
|
|
1236
|
+
* Score result for a specific player.
|
|
1237
|
+
*/
|
|
1238
|
+
type ScoreResult = {
|
|
1239
|
+
/** Player's unique identifier */
|
|
1240
|
+
playerId: string;
|
|
1241
|
+
/** Player's display name */
|
|
1242
|
+
playerName: string;
|
|
1243
|
+
/** Detailed score breakdown */
|
|
1244
|
+
details: Score;
|
|
1077
1245
|
/**
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1246
|
+
* Territory-by-territory and bonus-by-bonus score, computed by the same
|
|
1247
|
+
* function as `calculatePlayerScore` (`breakdown.total === details.points`).
|
|
1248
|
+
* Always set by `getResults`.
|
|
1081
1249
|
*/
|
|
1082
|
-
|
|
1250
|
+
breakdown?: ScoreBreakdown;
|
|
1083
1251
|
};
|
|
1084
|
-
|
|
1085
1252
|
/**
|
|
1086
|
-
*
|
|
1087
|
-
* These codes can be used for i18n and programmatic error handling.
|
|
1253
|
+
* Final result including ranking position.
|
|
1088
1254
|
*/
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
readonly MODE_NOT_FOUND: "MODE_NOT_FOUND";
|
|
1097
|
-
readonly INVALID_PLAYER_COUNT: "INVALID_PLAYER_COUNT";
|
|
1098
|
-
readonly INVALID_PLAYER_NAME: "INVALID_PLAYER_NAME";
|
|
1099
|
-
readonly INVALID_PLACEMENT: "INVALID_PLACEMENT";
|
|
1100
|
-
readonly PLACEMENT_NOT_EMPTY: "PLACEMENT_NOT_EMPTY";
|
|
1101
|
-
readonly PLACEMENT_NOT_ADJACENT: "PLACEMENT_NOT_ADJACENT";
|
|
1102
|
-
readonly PLACEMENT_INVALID_TERRAIN: "PLACEMENT_INVALID_TERRAIN";
|
|
1103
|
-
readonly PLACEMENT_OUT_OF_BOUNDS: "PLACEMENT_OUT_OF_BOUNDS";
|
|
1104
|
-
readonly PLACEMENT_EXCEEDS_KINGDOM_SIZE: "PLACEMENT_EXCEEDS_KINGDOM_SIZE";
|
|
1105
|
-
readonly NOT_YOUR_TURN: "NOT_YOUR_TURN";
|
|
1106
|
-
readonly CANNOT_PICK: "CANNOT_PICK";
|
|
1107
|
-
readonly CANNOT_PLACE: "CANNOT_PLACE";
|
|
1108
|
-
readonly DOMINO_ALREADY_PICKED: "DOMINO_ALREADY_PICKED";
|
|
1109
|
-
readonly UNDO_UNAVAILABLE: "UNDO_UNAVAILABLE";
|
|
1110
|
-
readonly REDO_UNAVAILABLE: "REDO_UNAVAILABLE";
|
|
1111
|
-
readonly CANNOT_PLACE_KNIGHT: "CANNOT_PLACE_KNIGHT";
|
|
1112
|
-
readonly MAX_KNIGHTS_REACHED: "MAX_KNIGHTS_REACHED";
|
|
1113
|
-
readonly KNIGHT_TERRITORY_OCCUPIED: "KNIGHT_TERRITORY_OCCUPIED";
|
|
1114
|
-
readonly CANNOT_AFFORD_BUILDING: "CANNOT_AFFORD_BUILDING";
|
|
1115
|
-
readonly NO_CONSTRUCTION_SQUARE: "NO_CONSTRUCTION_SQUARE";
|
|
1116
|
-
readonly DRAGON_UNAVAILABLE: "DRAGON_UNAVAILABLE";
|
|
1117
|
-
readonly QUEEN_HOLDER_CANNOT_USE_DRAGON: "QUEEN_HOLDER_CANNOT_USE_DRAGON";
|
|
1118
|
-
readonly BUILDING_NOT_FOUND: "BUILDING_NOT_FOUND";
|
|
1119
|
-
readonly INVALID_OPTIONAL_ACTION: "INVALID_OPTIONAL_ACTION";
|
|
1120
|
-
readonly GIANT_POOL_EMPTY: "GIANT_POOL_EMPTY";
|
|
1121
|
-
readonly GIANT_NOT_FOUND: "GIANT_NOT_FOUND";
|
|
1122
|
-
readonly INVALID_GIANT_PLACEMENT: "INVALID_GIANT_PLACEMENT";
|
|
1123
|
-
readonly NOT_AOG_MODE: "NOT_AOG_MODE";
|
|
1124
|
-
readonly FIRE_TOKEN_POOL_EMPTY: "FIRE_TOKEN_POOL_EMPTY";
|
|
1125
|
-
readonly FIRE_TOKEN_INVALID_POSITION: "FIRE_TOKEN_INVALID_POSITION";
|
|
1126
|
-
readonly NO_PENDING_FIRE_TOKEN: "NO_PENDING_FIRE_TOKEN";
|
|
1127
|
-
readonly CANNOT_RECRUIT_CAVEMAN: "CANNOT_RECRUIT_CAVEMAN";
|
|
1128
|
-
readonly INSUFFICIENT_RESOURCES: "INSUFFICIENT_RESOURCES";
|
|
1129
|
-
readonly INVALID_CAVEMAN_PLACEMENT: "INVALID_CAVEMAN_PLACEMENT";
|
|
1130
|
-
readonly CAVEMAN_NOT_FOUND: "CAVEMAN_NOT_FOUND";
|
|
1131
|
-
readonly NOT_TRIBE_MODE: "NOT_TRIBE_MODE";
|
|
1255
|
+
type FinalResult = ScoreResult & {
|
|
1256
|
+
/** Player's final position (1 = winner) */
|
|
1257
|
+
position: number;
|
|
1258
|
+
};
|
|
1259
|
+
/** Game state with final results calculated */
|
|
1260
|
+
type GameWithResults = Game & {
|
|
1261
|
+
result: FinalResult[];
|
|
1132
1262
|
};
|
|
1133
|
-
type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
1134
1263
|
/**
|
|
1135
|
-
*
|
|
1264
|
+
* Type guard to check if final results have been computed for the game
|
|
1265
|
+
* (i.e. the state returned by `getResults`).
|
|
1266
|
+
* @param game - The game state to check
|
|
1267
|
+
* @returns True if the game carries a `result` array
|
|
1136
1268
|
*/
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
}
|
|
1269
|
+
declare const isGameWithResults: (game: Game | GameWithResults) => game is GameWithResults;
|
|
1270
|
+
|
|
1271
|
+
type AddExtraRulesCommand = {
|
|
1272
|
+
game: GameState;
|
|
1273
|
+
extraRules: string[];
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1145
1276
|
/**
|
|
1146
|
-
*
|
|
1277
|
+
* Input for a single player: either a name string (human) or an object with
|
|
1278
|
+
* an optional stable `id` and an optional bot config.
|
|
1279
|
+
*
|
|
1280
|
+
* Pass a stable `id` (e.g. your own user/account id) when the same person plays
|
|
1281
|
+
* several games, such as a Dynasty: ids are otherwise regenerated by every
|
|
1282
|
+
* `addPlayers` call. Ids must be non-empty and unique within one call.
|
|
1147
1283
|
*/
|
|
1148
|
-
|
|
1284
|
+
type PlayerInput = string | {
|
|
1285
|
+
id?: string;
|
|
1286
|
+
name: string;
|
|
1287
|
+
bot?: {
|
|
1288
|
+
strategyName: string;
|
|
1289
|
+
};
|
|
1290
|
+
};
|
|
1291
|
+
type AddPlayersCommand = {
|
|
1292
|
+
game: GameState;
|
|
1293
|
+
players: PlayerInput[];
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1296
|
+
type CalculatePlayerScoreCommand = {
|
|
1297
|
+
/**
|
|
1298
|
+
* Game state, at any stage: in progress (live score) or over (final
|
|
1299
|
+
* score, also accepts the state returned by `getResults`).
|
|
1300
|
+
*/
|
|
1301
|
+
game: Game;
|
|
1302
|
+
/** Id of the player to score */
|
|
1303
|
+
playerId: string;
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1306
|
+
type CalculateScoreCommand = {
|
|
1307
|
+
kingdom: Kingdom;
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1149
1310
|
/**
|
|
1150
|
-
*
|
|
1311
|
+
* Severity level for a validation issue.
|
|
1312
|
+
* - "error": The state is corrupted and cannot be used safely.
|
|
1313
|
+
* - "warning": The state is suspicious but may still work.
|
|
1151
1314
|
*/
|
|
1152
|
-
|
|
1153
|
-
readonly code: ErrorCodeType;
|
|
1154
|
-
readonly context?: Record<string, unknown>;
|
|
1155
|
-
constructor(error: DomainError);
|
|
1156
|
-
}
|
|
1315
|
+
type ValidationSeverity = "error" | "warning";
|
|
1157
1316
|
/**
|
|
1158
|
-
*
|
|
1317
|
+
* Describes a single validation issue found in a game state.
|
|
1159
1318
|
*/
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1319
|
+
type ValidationIssue = {
|
|
1320
|
+
/** JSON-path-like location of the issue (e.g. "players[0].kingdom") */
|
|
1321
|
+
path: string;
|
|
1322
|
+
/** Machine-readable code identifying the kind of issue */
|
|
1323
|
+
code: string;
|
|
1324
|
+
/** Human-readable description of the issue */
|
|
1325
|
+
message: string;
|
|
1326
|
+
/** Severity level */
|
|
1327
|
+
severity: ValidationSeverity;
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1163
1330
|
/**
|
|
1164
|
-
*
|
|
1331
|
+
* Command to check if a domino can be placed anywhere on a kingdom.
|
|
1165
1332
|
*/
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1333
|
+
type CanPlaceDominoCommand = {
|
|
1334
|
+
/** The kingdom grid to check */
|
|
1335
|
+
kingdom: Kingdom;
|
|
1336
|
+
/** The domino to check placement for */
|
|
1337
|
+
domino: Domino;
|
|
1338
|
+
/** Maximum kingdom size (default: 5, use 7 for Mighty Duel) */
|
|
1339
|
+
maxKingdomSize?: number;
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1342
|
+
type ChooseDominoCommand = {
|
|
1343
|
+
game: GameState;
|
|
1344
|
+
dominoPick: number;
|
|
1345
|
+
lordId: string;
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1348
|
+
type ConstructBuildingCommand = {
|
|
1349
|
+
game: GameWithNextAction;
|
|
1350
|
+
lordId: string;
|
|
1351
|
+
buildingId: number;
|
|
1352
|
+
position: Position;
|
|
1353
|
+
};
|
|
1354
|
+
|
|
1355
|
+
type CreateGameCommand = {
|
|
1356
|
+
mode: string;
|
|
1357
|
+
seed?: string;
|
|
1358
|
+
};
|
|
1359
|
+
|
|
1360
|
+
type DiscardDominoCommand = {
|
|
1361
|
+
game: GameState;
|
|
1362
|
+
lordId: string;
|
|
1363
|
+
};
|
|
1364
|
+
|
|
1365
|
+
/**
|
|
1366
|
+
* How Dynasty results group a player across games.
|
|
1367
|
+
* - `"playerId"` (default): by `playerId`. Pass stable ids to `addPlayers`
|
|
1368
|
+
* (`players: [{ id, name }]`) so the same person keeps one id across games.
|
|
1369
|
+
* - `"playerName"`: by player name, for games whose players were added
|
|
1370
|
+
* without stable ids (ids are regenerated by every `addPlayers` call).
|
|
1371
|
+
*/
|
|
1372
|
+
type DynastyGroupBy = "playerId" | "playerName";
|
|
1373
|
+
type GetDynastyResultCommand = {
|
|
1374
|
+
games: GameWithResults[];
|
|
1375
|
+
/** Grouping key across games. Defaults to `"playerId"`. */
|
|
1376
|
+
groupBy?: DynastyGroupBy;
|
|
1377
|
+
};
|
|
1378
|
+
|
|
1379
|
+
type GetExtraRulesCommand = {
|
|
1380
|
+
mode: GameMode["name"];
|
|
1381
|
+
players: number;
|
|
1382
|
+
};
|
|
1383
|
+
|
|
1384
|
+
type GetModesCommand = Record<string, never>;
|
|
1385
|
+
|
|
1386
|
+
type GetResultCommand = {
|
|
1387
|
+
game: GameState;
|
|
1388
|
+
};
|
|
1389
|
+
|
|
1169
1390
|
/**
|
|
1170
|
-
*
|
|
1391
|
+
* Command to query the valid targets of the current extension action
|
|
1392
|
+
* (Queendomino, Origins, Age of Giants).
|
|
1393
|
+
*
|
|
1394
|
+
* Any game state is accepted: the query answers empty (`[]`, or `false` for
|
|
1395
|
+
* `canSkipOptionalAction`) when the action is not the one the game waits for,
|
|
1396
|
+
* when it does not exist in the game mode, or when `lordId` is not the lord
|
|
1397
|
+
* that must play.
|
|
1171
1398
|
*/
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1399
|
+
type GetValidActionTargetsCommand = {
|
|
1400
|
+
/** The current game state */
|
|
1401
|
+
game: GameState;
|
|
1402
|
+
/** Lord to check. Defaults to the lord that must play (`game.nextAction.nextLord`) */
|
|
1403
|
+
lordId?: string;
|
|
1404
|
+
};
|
|
1405
|
+
/** Command for `getValidFireTokenPositions` (Origins `placeFireToken`). */
|
|
1406
|
+
type GetValidFireTokenPositionsCommand = GetValidActionTargetsCommand;
|
|
1407
|
+
/** Command for `getValidKnightPositions` (Queendomino `placeKnight`). */
|
|
1408
|
+
type GetValidKnightPositionsCommand = GetValidActionTargetsCommand;
|
|
1409
|
+
/** Command for `getValidBuildingPositions` (Queendomino `constructBuilding`). */
|
|
1410
|
+
type GetValidBuildingPositionsCommand = GetValidActionTargetsCommand;
|
|
1411
|
+
/** Command for `getAffordableBuildings` (Queendomino `constructBuilding`). */
|
|
1412
|
+
type GetAffordableBuildingsCommand = GetValidActionTargetsCommand;
|
|
1413
|
+
/** Command for `getValidDragonTargets` (Queendomino `useDragon`). */
|
|
1414
|
+
type GetValidDragonTargetsCommand = GetValidActionTargetsCommand;
|
|
1415
|
+
/** Command for `getValidCavemanPlacements` (Origins Tribe `recruitCaveman`). */
|
|
1416
|
+
type GetValidCavemanPlacementsCommand = GetValidActionTargetsCommand;
|
|
1417
|
+
/** Command for `getValidGiantPositions` (Age of Giants `placeGiant`). */
|
|
1418
|
+
type GetValidGiantPositionsCommand = GetValidActionTargetsCommand;
|
|
1419
|
+
/** Command for `getValidGiantTargets` (Age of Giants `sendGiant`). */
|
|
1420
|
+
type GetValidGiantTargetsCommand = GetValidActionTargetsCommand;
|
|
1421
|
+
/** Command for `canSkipOptionalAction` (`skipOptionalAction`). */
|
|
1422
|
+
type CanSkipOptionalActionCommand = GetValidActionTargetsCommand;
|
|
1423
|
+
|
|
1424
|
+
/**
|
|
1425
|
+
* Command for `getValidDominoPicks` (`chooseDomino`): any game state and an
|
|
1426
|
+
* optional lord (default: the lord that must play).
|
|
1427
|
+
*/
|
|
1428
|
+
type GetValidDominoPicksCommand = GetValidActionTargetsCommand;
|
|
1429
|
+
|
|
1175
1430
|
/**
|
|
1176
|
-
*
|
|
1431
|
+
* Command to get all valid placements for a domino on a kingdom.
|
|
1177
1432
|
*/
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1433
|
+
type GetValidPlacementsCommand = {
|
|
1434
|
+
/** The kingdom grid to check placements on */
|
|
1435
|
+
kingdom: Kingdom;
|
|
1436
|
+
/** The domino to find placements for */
|
|
1437
|
+
domino: Domino;
|
|
1438
|
+
/** Maximum kingdom size (default: 5, use 7 for Mighty Duel) */
|
|
1439
|
+
maxKingdomSize?: number;
|
|
1440
|
+
};
|
|
1441
|
+
|
|
1442
|
+
type PlaceDominoCommand = {
|
|
1443
|
+
game: GameState;
|
|
1444
|
+
lordId: string;
|
|
1445
|
+
position: Position;
|
|
1446
|
+
rotation: Rotation;
|
|
1447
|
+
};
|
|
1448
|
+
|
|
1449
|
+
type PlaceFireTokenCommand = {
|
|
1450
|
+
game: GameWithNextAction;
|
|
1451
|
+
lordId: string;
|
|
1452
|
+
position: Position;
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
type PlaceGiantCommand = {
|
|
1456
|
+
game: GameWithNextAction;
|
|
1457
|
+
lordId: string;
|
|
1458
|
+
position: Position;
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
type PlaceKnightCommand = {
|
|
1462
|
+
game: GameWithNextAction;
|
|
1463
|
+
lordId: string;
|
|
1464
|
+
position: Position;
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
type RecruitCavemanCommand = {
|
|
1468
|
+
game: GameWithNextAction;
|
|
1469
|
+
lordId: string;
|
|
1470
|
+
/** ID of the caveman tile to recruit */
|
|
1471
|
+
cavemanId: number;
|
|
1472
|
+
/** Position on the kingdom to place the caveman */
|
|
1473
|
+
position: Position;
|
|
1474
|
+
/** Positions of resources to spend as payment */
|
|
1475
|
+
resourcePositions: Position[];
|
|
1476
|
+
};
|
|
1477
|
+
|
|
1478
|
+
type SendGiantCommand = {
|
|
1479
|
+
game: GameWithNextAction;
|
|
1480
|
+
lordId: string;
|
|
1481
|
+
/** Index of the giant to send from the current player's giants array */
|
|
1482
|
+
giantIndex: number;
|
|
1483
|
+
/** ID of the opponent player to receive the giant */
|
|
1484
|
+
targetPlayerId: string;
|
|
1485
|
+
/**
|
|
1486
|
+
* Crown of the opponent's kingdom the giant will cover. Per the official
|
|
1487
|
+
* rules the targeted opponent chooses it: omit it and the engine places the
|
|
1488
|
+
* giant automatically when the opponent has a single free crown, or asks
|
|
1489
|
+
* the opponent with a `placeGiant` action otherwise. When provided, it must
|
|
1490
|
+
* be the crown chosen by the opponent.
|
|
1491
|
+
*/
|
|
1492
|
+
targetCrownPosition?: Position;
|
|
1493
|
+
};
|
|
1494
|
+
|
|
1181
1495
|
/**
|
|
1182
|
-
*
|
|
1496
|
+
* Command to serialize a game state to JSON.
|
|
1183
1497
|
*/
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1498
|
+
type SerializeGameCommand = {
|
|
1499
|
+
/** The game state to serialize */
|
|
1500
|
+
game: GameState;
|
|
1501
|
+
};
|
|
1187
1502
|
/**
|
|
1188
|
-
*
|
|
1503
|
+
* Command to deserialize a game state from JSON.
|
|
1189
1504
|
*/
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1505
|
+
type DeserializeGameCommand = {
|
|
1506
|
+
/** The JSON string to deserialize */
|
|
1507
|
+
json: string;
|
|
1508
|
+
};
|
|
1509
|
+
|
|
1510
|
+
type SkipOptionalActionCommand = {
|
|
1511
|
+
game: GameWithNextAction;
|
|
1512
|
+
lordId: string;
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
type StartGameCommand = {
|
|
1516
|
+
game: GameState;
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1519
|
+
type UseDragonCommand = {
|
|
1520
|
+
game: GameWithNextAction;
|
|
1521
|
+
lordId: string;
|
|
1522
|
+
buildingId: number;
|
|
1523
|
+
};
|
|
1524
|
+
|
|
1525
|
+
type DynastyResult = {
|
|
1526
|
+
/**
|
|
1527
|
+
* Player id. With `groupBy: "playerName"`, the id the player had in the
|
|
1528
|
+
* first game where that name appears.
|
|
1529
|
+
*/
|
|
1530
|
+
playerId: string;
|
|
1531
|
+
playerName: string;
|
|
1532
|
+
totalPoints: number;
|
|
1533
|
+
gamesPoints: number[];
|
|
1534
|
+
position: number;
|
|
1535
|
+
};
|
|
1536
|
+
|
|
1537
|
+
type ShuffleMethod = <T>(array: T[]) => T[];
|
|
1538
|
+
|
|
1193
1539
|
/**
|
|
1194
|
-
*
|
|
1540
|
+
* Price of recruiting one caveman of the cave board.
|
|
1195
1541
|
*/
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1542
|
+
type RecruitmentCost = {
|
|
1543
|
+
/** Where the caveman is taken from */
|
|
1544
|
+
source: "visible" | "drawPile";
|
|
1545
|
+
/** Number of resources to spend */
|
|
1546
|
+
resourceCount: number;
|
|
1547
|
+
/** Number of different resource types among the spent resources */
|
|
1548
|
+
differentTypes: number;
|
|
1549
|
+
};
|
|
1199
1550
|
|
|
1200
1551
|
/**
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1552
|
+
* A caveman of the cave board that can be recruited now, with every valid way
|
|
1553
|
+
* to pay for it (Origins Tribe).
|
|
1203
1554
|
*/
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
readonly ERROR_MODE_NOT_FOUND: "error.modeNotFound";
|
|
1212
|
-
readonly ERROR_INVALID_PLACEMENT: "error.invalidPlacement";
|
|
1213
|
-
readonly ERROR_PLACEMENT_NOT_EMPTY: "error.placementNotEmpty";
|
|
1214
|
-
readonly ERROR_PLACEMENT_NOT_ADJACENT: "error.placementNotAdjacent";
|
|
1215
|
-
readonly ERROR_PLACEMENT_INVALID_TERRAIN: "error.placementInvalidTerrain";
|
|
1216
|
-
readonly ERROR_PLACEMENT_OUT_OF_BOUNDS: "error.placementOutOfBounds";
|
|
1217
|
-
readonly ERROR_PLACEMENT_EXCEEDS_KINGDOM_SIZE: "error.placementExceedsKingdomSize";
|
|
1218
|
-
readonly ERROR_NOT_YOUR_TURN: "error.notYourTurn";
|
|
1219
|
-
readonly ERROR_CANNOT_PICK: "error.cannotPick";
|
|
1220
|
-
readonly ERROR_CANNOT_PLACE: "error.cannotPlace";
|
|
1221
|
-
readonly ERROR_DOMINO_ALREADY_PICKED: "error.dominoAlreadyPicked";
|
|
1222
|
-
readonly ERROR_INVALID_PLAYER_COUNT: "error.invalidPlayerCount";
|
|
1223
|
-
readonly ERROR_INVALID_PLAYER_NAME: "error.invalidPlayerName";
|
|
1224
|
-
readonly ERROR_UNDO_UNAVAILABLE: "error.undoUnavailable";
|
|
1225
|
-
readonly ERROR_REDO_UNAVAILABLE: "error.redoUnavailable";
|
|
1226
|
-
readonly MODE_CLASSIC: "mode.classic";
|
|
1227
|
-
readonly RULE_MIDDLE_KINGDOM: "rule.middleKingdom";
|
|
1228
|
-
readonly RULE_HARMONY: "rule.harmony";
|
|
1229
|
-
readonly GROUND_CASTLE: "ground.castle";
|
|
1230
|
-
readonly GROUND_WHEAT: "ground.wheat";
|
|
1231
|
-
readonly GROUND_FOREST: "ground.forest";
|
|
1232
|
-
readonly GROUND_SEA: "ground.sea";
|
|
1233
|
-
readonly GROUND_PLAIN: "ground.plain";
|
|
1234
|
-
readonly GROUND_SWAMP: "ground.swamp";
|
|
1235
|
-
readonly GROUND_MINE: "ground.mine";
|
|
1236
|
-
readonly PHASE_ADD_PLAYERS: "phase.addPlayers";
|
|
1237
|
-
readonly PHASE_OPTIONS: "phase.options";
|
|
1238
|
-
readonly PHASE_START: "phase.start";
|
|
1239
|
-
readonly PHASE_RESULT: "phase.result";
|
|
1240
|
-
readonly ACTION_PICK_DOMINO: "action.pickDomino";
|
|
1241
|
-
readonly ACTION_PLACE_DOMINO: "action.placeDomino";
|
|
1242
|
-
readonly ACTION_PASS: "action.pass";
|
|
1243
|
-
readonly ERROR_CANNOT_PLACE_KNIGHT: "error.cannotPlaceKnight";
|
|
1244
|
-
readonly ERROR_MAX_KNIGHTS_REACHED: "error.maxKnightsReached";
|
|
1245
|
-
readonly ERROR_KNIGHT_TERRITORY_OCCUPIED: "error.knightTerritoryOccupied";
|
|
1246
|
-
readonly ERROR_CANNOT_AFFORD_BUILDING: "error.cannotAffordBuilding";
|
|
1247
|
-
readonly ERROR_NO_CONSTRUCTION_SQUARE: "error.noConstructionSquare";
|
|
1248
|
-
readonly ERROR_DRAGON_UNAVAILABLE: "error.dragonUnavailable";
|
|
1249
|
-
readonly ERROR_QUEEN_HOLDER_CANNOT_USE_DRAGON: "error.queenHolderCannotUseDragon";
|
|
1250
|
-
readonly ERROR_BUILDING_NOT_FOUND: "error.buildingNotFound";
|
|
1251
|
-
readonly ERROR_INVALID_OPTIONAL_ACTION: "error.invalidOptionalAction";
|
|
1252
|
-
readonly ERROR_GIANT_POOL_EMPTY: "error.giantPoolEmpty";
|
|
1253
|
-
readonly ERROR_GIANT_NOT_FOUND: "error.giantNotFound";
|
|
1254
|
-
readonly ERROR_INVALID_GIANT_PLACEMENT: "error.invalidGiantPlacement";
|
|
1255
|
-
readonly ERROR_NOT_AOG_MODE: "error.notAogMode";
|
|
1256
|
-
readonly ERROR_FIRE_TOKEN_POOL_EMPTY: "error.fireTokenPoolEmpty";
|
|
1257
|
-
readonly ERROR_FIRE_TOKEN_INVALID_POSITION: "error.fireTokenInvalidPosition";
|
|
1258
|
-
readonly ERROR_NO_PENDING_FIRE_TOKEN: "error.noPendingFireToken";
|
|
1259
|
-
readonly ERROR_CANNOT_RECRUIT_CAVEMAN: "error.cannotRecruitCaveman";
|
|
1260
|
-
readonly ERROR_INSUFFICIENT_RESOURCES: "error.insufficientResources";
|
|
1261
|
-
readonly ERROR_INVALID_CAVEMAN_PLACEMENT: "error.invalidCavemanPlacement";
|
|
1262
|
-
readonly ERROR_CAVEMAN_NOT_FOUND: "error.cavemanNotFound";
|
|
1263
|
-
readonly ERROR_NOT_TRIBE_MODE: "error.notTribeMode";
|
|
1555
|
+
type CavemanRecruitmentOption = {
|
|
1556
|
+
/** Caveman to pass as `cavemanId` to `recruitCaveman` */
|
|
1557
|
+
cavemanId: number;
|
|
1558
|
+
/** Visible caveman (2 different resources) or draw pile (4 different) */
|
|
1559
|
+
source: RecruitmentCost["source"];
|
|
1560
|
+
/** Every valid `resourcePositions` payment for this caveman */
|
|
1561
|
+
resourceCombinations: Position[][];
|
|
1264
1562
|
};
|
|
1265
|
-
type TranslationKeyType = (typeof TranslationKey)[keyof typeof TranslationKey];
|
|
1266
1563
|
/**
|
|
1267
|
-
*
|
|
1564
|
+
* Valid `recruitCaveman` arguments: any option, any of its resource
|
|
1565
|
+
* combinations and any position can be combined. Both lists are empty when
|
|
1566
|
+
* no recruitment is possible.
|
|
1268
1567
|
*/
|
|
1269
|
-
|
|
1568
|
+
type ValidCavemanPlacements = {
|
|
1569
|
+
/** Recruitable cavemen with their valid payments */
|
|
1570
|
+
options: CavemanRecruitmentOption[];
|
|
1571
|
+
/** Squares where the recruited caveman can be placed */
|
|
1572
|
+
positions: Position[];
|
|
1573
|
+
};
|
|
1270
1574
|
/**
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1575
|
+
* Valid `sendGiant` arguments: any giant index can be sent to any target
|
|
1576
|
+
* player. Both lists are empty when no giant can be sent. The crown covered is
|
|
1577
|
+
* chosen by the targeted opponent (see `getValidGiantPositions`).
|
|
1273
1578
|
*/
|
|
1274
|
-
|
|
1579
|
+
type ValidGiantTargets = {
|
|
1580
|
+
/** Indexes in the sender's `giants` array that can be sent */
|
|
1581
|
+
giantIndexes: number[];
|
|
1582
|
+
/** Opponents that can receive a giant */
|
|
1583
|
+
targetPlayerIds: string[];
|
|
1584
|
+
};
|
|
1585
|
+
/** Signature shared by the valid-target queries. */
|
|
1586
|
+
type ValidActionTargetsUseCase<T> = (game: GameState, lordId?: string) => T;
|
|
1587
|
+
|
|
1275
1588
|
/**
|
|
1276
|
-
*
|
|
1277
|
-
* Convenience function combining errorCodeToTranslationKey lookup and translation.
|
|
1589
|
+
* Represents a valid placement position with rotation.
|
|
1278
1590
|
*/
|
|
1279
|
-
|
|
1591
|
+
type ValidPlacement = {
|
|
1592
|
+
position: Position;
|
|
1593
|
+
rotation: Rotation;
|
|
1594
|
+
};
|
|
1595
|
+
|
|
1280
1596
|
/**
|
|
1281
|
-
*
|
|
1597
|
+
* The main interface for interacting with the Kingdomino game engine.
|
|
1598
|
+
*
|
|
1599
|
+
* This interface provides all methods needed to manage a complete game lifecycle,
|
|
1600
|
+
* from creation to scoring. Each method follows a command pattern and returns
|
|
1601
|
+
* an updated game state.
|
|
1602
|
+
*
|
|
1603
|
+
* @example
|
|
1604
|
+
* ```typescript
|
|
1605
|
+
* import { createGameEngine, isGameWithNextAction } from '@pompidup/kingdomino-engine';
|
|
1606
|
+
*
|
|
1607
|
+
* const engine = createGameEngine({});
|
|
1608
|
+
* let game = engine.createGame({ mode: 'Classic' });
|
|
1609
|
+
* game = engine.addPlayers({ game, players: ['Alice', 'Bob'] });
|
|
1610
|
+
* game = engine.startGame({ game });
|
|
1611
|
+
*
|
|
1612
|
+
* while (isGameWithNextAction(game)) {
|
|
1613
|
+
* // Handle player actions...
|
|
1614
|
+
* }
|
|
1615
|
+
*
|
|
1616
|
+
* const results = engine.getResults({ game });
|
|
1617
|
+
* ```
|
|
1282
1618
|
*/
|
|
1283
|
-
|
|
1619
|
+
type GameEngine = {
|
|
1620
|
+
/**
|
|
1621
|
+
* Retrieves all available game modes.
|
|
1622
|
+
* @param command - Empty command object
|
|
1623
|
+
* @returns Array of available game modes (e.g., 'Classic')
|
|
1624
|
+
*/
|
|
1625
|
+
getModes: (command: GetModesCommand) => GameMode[];
|
|
1626
|
+
/**
|
|
1627
|
+
* Retrieves available extra rules for a specific mode and player count.
|
|
1628
|
+
* @param command - Contains mode name and number of players
|
|
1629
|
+
* @returns Array of applicable extra rules
|
|
1630
|
+
*/
|
|
1631
|
+
getExtraRules: (command: GetExtraRulesCommand) => ExtraRule[];
|
|
1632
|
+
/**
|
|
1633
|
+
* Creates a new game instance with the specified mode.
|
|
1634
|
+
* This is the first step in setting up a game.
|
|
1635
|
+
* @param command - Contains the game mode name
|
|
1636
|
+
* @returns Game state with next step 'addPlayers'
|
|
1637
|
+
*/
|
|
1638
|
+
createGame: (command: CreateGameCommand) => GameWithNextStep;
|
|
1639
|
+
/**
|
|
1640
|
+
* Adds players to the game and initializes their kingdoms.
|
|
1641
|
+
* Each player receives an empty kingdom with a castle at the center.
|
|
1642
|
+
* @param command - Contains game state and array of player names (1-4 players)
|
|
1643
|
+
* @returns Game state with next step 'options' or 'start'
|
|
1644
|
+
* @throws Error if player count is invalid or names are too short
|
|
1645
|
+
*/
|
|
1646
|
+
addPlayers: (command: AddPlayersCommand) => GameWithNextStep;
|
|
1284
1647
|
/**
|
|
1285
|
-
*
|
|
1286
|
-
* @param
|
|
1287
|
-
* @
|
|
1288
|
-
* @returns The translated string
|
|
1648
|
+
* Adds optional extra rules to modify gameplay.
|
|
1649
|
+
* @param command - Contains game state and array of extra rule names
|
|
1650
|
+
* @returns Game state with next step 'start'
|
|
1289
1651
|
*/
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1652
|
+
addExtraRules: (command: AddExtraRulesCommand) => GameWithNextStep;
|
|
1653
|
+
/**
|
|
1654
|
+
* Starts the game, initializing lords, shuffling dominoes, and revealing the first set.
|
|
1655
|
+
* @param command - Contains the game state
|
|
1656
|
+
* @returns Game state with first player action required
|
|
1657
|
+
*/
|
|
1658
|
+
startGame: (command: StartGameCommand) => GameWithNextAction;
|
|
1659
|
+
/**
|
|
1660
|
+
* Allows a lord to choose a domino from the currently revealed set.
|
|
1661
|
+
* The chosen domino is reserved for that lord to place later.
|
|
1662
|
+
* @param command - Contains game state, lord ID, and domino number to pick
|
|
1663
|
+
* @returns Updated game state with next action
|
|
1664
|
+
*/
|
|
1665
|
+
chooseDomino: (command: ChooseDominoCommand) => GameWithNextAction;
|
|
1666
|
+
/**
|
|
1667
|
+
* Places a domino on the lord's kingdom at the specified position and rotation.
|
|
1668
|
+
* The domino must be adjacent to an existing tile and match terrain types.
|
|
1669
|
+
* @param command - Contains game state, lord ID, position {x, y}, and rotation (0, 90, 180, 270)
|
|
1670
|
+
* @returns Updated game state (may transition to 'result' step if game ends)
|
|
1671
|
+
* @throws Error if placement is invalid
|
|
1672
|
+
*/
|
|
1673
|
+
placeDomino: (command: PlaceDominoCommand) => GameState;
|
|
1674
|
+
/**
|
|
1675
|
+
* Discards a domino when no valid placement exists.
|
|
1676
|
+
* The lord forfeits placing the domino this turn.
|
|
1677
|
+
* @param command - Contains game state and lord ID
|
|
1678
|
+
* @returns Updated game state with next action
|
|
1679
|
+
*/
|
|
1680
|
+
discardDomino: (command: DiscardDominoCommand) => GameState;
|
|
1681
|
+
/**
|
|
1682
|
+
* Calculates and returns final results after the game ends.
|
|
1683
|
+
* Applies extra rule bonuses and ranks players.
|
|
1684
|
+
* @param command - Contains the final game state
|
|
1685
|
+
* @returns Game state with complete results including positions
|
|
1686
|
+
*/
|
|
1687
|
+
getResults: (command: GetResultCommand) => GameWithResults;
|
|
1688
|
+
/**
|
|
1689
|
+
* Calculates the score for a single kingdom.
|
|
1690
|
+
* Useful for showing live scores during gameplay.
|
|
1691
|
+
* @param command - Contains the kingdom grid to score
|
|
1692
|
+
* @returns Score with points, largest property size, and total crowns
|
|
1693
|
+
*/
|
|
1694
|
+
calculateScore: (command: CalculateScoreCommand) => Score;
|
|
1695
|
+
/**
|
|
1696
|
+
* Finds all valid placements for a domino on a kingdom.
|
|
1697
|
+
* Useful for AI players or showing available moves to human players.
|
|
1698
|
+
* @param command - Contains kingdom and domino to check
|
|
1699
|
+
* @returns Array of valid position/rotation combinations
|
|
1700
|
+
*/
|
|
1701
|
+
getValidPlacements: (command: GetValidPlacementsCommand) => ValidPlacement[];
|
|
1702
|
+
/**
|
|
1703
|
+
* Checks if a domino can be placed anywhere on a kingdom.
|
|
1704
|
+
* Quick check before deciding to discard.
|
|
1705
|
+
* @param command - Contains kingdom and domino to check
|
|
1706
|
+
* @returns True if at least one valid placement exists
|
|
1707
|
+
*/
|
|
1708
|
+
canPlaceDomino: (command: CanPlaceDominoCommand) => boolean;
|
|
1709
|
+
/**
|
|
1710
|
+
* Numbers of the revealed dominoes `chooseDomino` accepts for the lord
|
|
1711
|
+
* (default: the lord to play): the dominoes not picked yet and, with the
|
|
1712
|
+
* Origins "Neolithic" rule, not reserved for the other player (the first
|
|
1713
|
+
* pick of each line takes the pair 1 & 4 or 2 & 3 for the lord's player).
|
|
1714
|
+
* @param command - Contains game state and optional lord ID
|
|
1715
|
+
* @returns Domino numbers, or [] when the game does not wait for this lord to pick
|
|
1716
|
+
*/
|
|
1717
|
+
getValidDominoPicks: (command: GetValidDominoPicksCommand) => number[];
|
|
1718
|
+
/**
|
|
1719
|
+
* Serializes the game state to a JSON string for persistence.
|
|
1720
|
+
* @param command - Contains the game state to serialize
|
|
1721
|
+
* @returns JSON string representation of the game
|
|
1722
|
+
*/
|
|
1723
|
+
serialize: (command: SerializeGameCommand) => string;
|
|
1724
|
+
/**
|
|
1725
|
+
* Deserializes a JSON string back to a game state.
|
|
1726
|
+
* @param command - Contains the JSON string to parse
|
|
1727
|
+
* @returns The restored game state
|
|
1728
|
+
* @throws Error if the JSON is invalid or incompatible
|
|
1729
|
+
*/
|
|
1730
|
+
deserialize: (command: DeserializeGameCommand) => GameState;
|
|
1731
|
+
/**
|
|
1732
|
+
* Calculates dynasty results from multiple completed games.
|
|
1733
|
+
* Sum total points across games, highest total wins.
|
|
1734
|
+
* @param command - Contains array of completed games with results
|
|
1735
|
+
* @returns Ranked dynasty results per player
|
|
1736
|
+
*/
|
|
1737
|
+
getDynastyResults: (command: GetDynastyResultCommand) => DynastyResult[];
|
|
1738
|
+
/**
|
|
1739
|
+
* Places a giant on a crown in the lord's kingdom (Age of Giants).
|
|
1740
|
+
* Mandatory after placing a giant domino (A-F). The giant covers the crown for scoring.
|
|
1741
|
+
* @param command - Contains game state, lord ID, and crown position
|
|
1742
|
+
* @returns Updated game state with next action
|
|
1743
|
+
*/
|
|
1744
|
+
placeGiant: (command: PlaceGiantCommand) => GameState;
|
|
1745
|
+
/**
|
|
1746
|
+
* Sends a giant from the lord's kingdom to an opponent's kingdom (Age of Giants).
|
|
1747
|
+
* Optional after placing a footprint domino (49-54). The opponent chooses which crown is covered.
|
|
1748
|
+
* @param command - Contains game state, lord ID, giant index, target player ID, and target crown position
|
|
1749
|
+
* @returns Updated game state with next action
|
|
1750
|
+
*/
|
|
1751
|
+
sendGiant: (command: SendGiantCommand) => GameState;
|
|
1752
|
+
/**
|
|
1753
|
+
* Places a knight on the lord's kingdom at the specified position (Queendomino).
|
|
1754
|
+
* @param command - Contains game state, lord ID, and position
|
|
1755
|
+
* @returns Updated game state with next action
|
|
1756
|
+
*/
|
|
1757
|
+
placeKnight: (command: PlaceKnightCommand) => GameState;
|
|
1758
|
+
/**
|
|
1759
|
+
* Constructs a building on the lord's kingdom (Queendomino).
|
|
1760
|
+
* @param command - Contains game state, lord ID, building ID, and position
|
|
1761
|
+
* @returns Updated game state with next action
|
|
1762
|
+
*/
|
|
1763
|
+
constructBuilding: (command: ConstructBuildingCommand) => GameState;
|
|
1764
|
+
/**
|
|
1765
|
+
* Uses the dragon to destroy a building on the builders board (Queendomino).
|
|
1766
|
+
* @param command - Contains game state, lord ID, and building ID
|
|
1767
|
+
* @returns Updated game state with next action
|
|
1768
|
+
*/
|
|
1769
|
+
useDragon: (command: UseDragonCommand) => GameState;
|
|
1770
|
+
/**
|
|
1771
|
+
* Places a fire token on the lord's kingdom after placing a volcano domino (Origins).
|
|
1772
|
+
* @param command - Contains game state, lord ID, and target position
|
|
1773
|
+
* @returns Updated game state with next action
|
|
1774
|
+
*/
|
|
1775
|
+
placeFireToken: (command: PlaceFireTokenCommand) => GameState;
|
|
1776
|
+
/**
|
|
1777
|
+
* Recruits a caveman from the cave board and places it on the lord's kingdom (Origins).
|
|
1778
|
+
* @param command - Contains game state, lord ID, caveman ID, position, and resource positions to spend
|
|
1779
|
+
* @returns Updated game state with next action
|
|
1780
|
+
*/
|
|
1781
|
+
recruitCaveman: (command: RecruitCavemanCommand) => GameState;
|
|
1782
|
+
/**
|
|
1783
|
+
* Skips the current optional action (Queendomino/Origins).
|
|
1784
|
+
* @param command - Contains game state and lord ID
|
|
1785
|
+
* @returns Updated game state with next action
|
|
1786
|
+
*/
|
|
1787
|
+
skipOptionalAction: (command: SkipOptionalActionCommand) => GameState;
|
|
1788
|
+
/**
|
|
1789
|
+
* Squares where `placeFireToken` accepts the pending fire token (Origins).
|
|
1790
|
+
* @param command - Contains game state and optional lord ID
|
|
1791
|
+
* @returns Valid positions, or [] when no fire token is pending for the lord
|
|
1792
|
+
*/
|
|
1793
|
+
getValidFireTokenPositions: (command: GetValidFireTokenPositionsCommand) => Position[];
|
|
1794
|
+
/**
|
|
1795
|
+
* Squares where `placeKnight` accepts a knight: squares of the domino just
|
|
1796
|
+
* placed holding no knight yet, while the player still has a knight
|
|
1797
|
+
* available (Queendomino).
|
|
1798
|
+
* @param command - Contains game state and optional lord ID
|
|
1799
|
+
* @returns Valid positions, or [] when placeKnight is not the current action
|
|
1800
|
+
*/
|
|
1801
|
+
getValidKnightPositions: (command: GetValidKnightPositionsCommand) => Position[];
|
|
1802
|
+
/**
|
|
1803
|
+
* Construction squares where `constructBuilding` succeeds with any building
|
|
1804
|
+
* of `getAffordableBuildings` (Queendomino).
|
|
1805
|
+
* @param command - Contains game state and optional lord ID
|
|
1806
|
+
* @returns Valid positions, or [] when no construction is possible
|
|
1807
|
+
*/
|
|
1808
|
+
getValidBuildingPositions: (command: GetValidBuildingPositionsCommand) => Position[];
|
|
1809
|
+
/**
|
|
1810
|
+
* Buildings of the Builders Board the lord can pay for, buildable on any
|
|
1811
|
+
* square of `getValidBuildingPositions` (Queendomino).
|
|
1812
|
+
* @param command - Contains game state and optional lord ID
|
|
1813
|
+
* @returns Buildings to pass to constructBuilding, or [] when none applies
|
|
1814
|
+
*/
|
|
1815
|
+
getAffordableBuildings: (command: GetAffordableBuildingsCommand) => BuildingTile[];
|
|
1816
|
+
/**
|
|
1817
|
+
* Buildings of the Builders Board that `useDragon` accepts to burn
|
|
1818
|
+
* (Queendomino): every building of the board when the Dragon is still in
|
|
1819
|
+
* its cave this round, the lord does not host the Queen and can pay its
|
|
1820
|
+
* 1 coin.
|
|
1821
|
+
* @param command - Contains game state and optional lord ID
|
|
1822
|
+
* @returns Buildings to pass to useDragon, or [] when the Dragon cannot be used
|
|
1823
|
+
*/
|
|
1824
|
+
getValidDragonTargets: (command: GetValidDragonTargetsCommand) => BuildingTile[];
|
|
1825
|
+
/**
|
|
1826
|
+
* Valid `recruitCaveman` arguments: recruitable cavemen with every valid
|
|
1827
|
+
* resource payment, and the squares for the caveman (Origins Tribe).
|
|
1828
|
+
* @param command - Contains game state and optional lord ID
|
|
1829
|
+
* @returns Options and positions (any combination is valid), both empty when none applies
|
|
1830
|
+
*/
|
|
1831
|
+
getValidCavemanPlacements: (command: GetValidCavemanPlacementsCommand) => ValidCavemanPlacements;
|
|
1832
|
+
/**
|
|
1833
|
+
* Crowns where `placeGiant` accepts the giant (Age of Giants), including a
|
|
1834
|
+
* giant sent by an opponent: the targeted player's own crowns.
|
|
1835
|
+
* @param command - Contains game state and optional lord ID
|
|
1836
|
+
* @returns Valid crown positions, or [] when placeGiant is not the current action
|
|
1837
|
+
*/
|
|
1838
|
+
getValidGiantPositions: (command: GetValidGiantPositionsCommand) => Position[];
|
|
1839
|
+
/**
|
|
1840
|
+
* Valid `sendGiant` arguments: the lord's giants that can be sent and the
|
|
1841
|
+
* opponents that can receive one (Age of Giants). The opponent chooses the crown.
|
|
1842
|
+
* @param command - Contains game state and optional lord ID
|
|
1843
|
+
* @returns Giant indexes and target player IDs (any pair is valid), both empty when none applies
|
|
1844
|
+
*/
|
|
1845
|
+
getValidGiantTargets: (command: GetValidGiantTargetsCommand) => ValidGiantTargets;
|
|
1846
|
+
/**
|
|
1847
|
+
* Whether `skipOptionalAction` can skip the current action for the lord
|
|
1848
|
+
* (false for placeGiant, which is mandatory).
|
|
1849
|
+
* @param command - Contains game state and optional lord ID
|
|
1850
|
+
* @returns True if the current action can be skipped
|
|
1851
|
+
*/
|
|
1852
|
+
canSkipOptionalAction: (command: CanSkipOptionalActionCommand) => boolean;
|
|
1853
|
+
/**
|
|
1854
|
+
* Calculates the mode-aware score of one player, with its breakdown
|
|
1855
|
+
* (territories and every bonus of the game mode: Queen, buildings, fire
|
|
1856
|
+
* tokens, resources, totems, cavemen, quests, optional rules...).
|
|
1857
|
+
*
|
|
1858
|
+
* During the game the score is live (`final: false`): it reflects the
|
|
1859
|
+
* current state and end-of-game-only bonuses (Harmony, Homo Habilis,
|
|
1860
|
+
* Harmony quest) are not included yet. Once the game is over it is final
|
|
1861
|
+
* and identical to the score returned by `getResults`.
|
|
1862
|
+
* @param command - Contains the game state (any stage) and the player id
|
|
1863
|
+
* @returns The player's score with its breakdown
|
|
1864
|
+
* @throws NotFoundError if the player is not in the game
|
|
1865
|
+
*/
|
|
1866
|
+
calculatePlayerScore: (command: CalculatePlayerScoreCommand) => PlayerScore;
|
|
1867
|
+
};
|
|
1304
1868
|
|
|
1305
1869
|
type Logger = Readonly<{
|
|
1306
1870
|
info: (message: string) => void;
|
|
1307
1871
|
error: (message: string) => void;
|
|
1308
1872
|
}>;
|
|
1309
1873
|
|
|
1310
|
-
type ShuffleMethod = <T>(array: T[]) => T[];
|
|
1311
|
-
|
|
1312
1874
|
type UuidMethod = () => string;
|
|
1313
1875
|
|
|
1314
1876
|
/**
|
|
@@ -1419,6 +1981,19 @@ type GameEventCallbacks = {
|
|
|
1419
1981
|
lordId: string;
|
|
1420
1982
|
dominoNumber: number;
|
|
1421
1983
|
}) => void;
|
|
1984
|
+
/**
|
|
1985
|
+
* Called after the first pick of a line chose the Neolithic pair (Origins,
|
|
1986
|
+
* 2 players): `dominoNumbers` (pair 1 & 4 or 2 & 3) are reserved for the
|
|
1987
|
+
* picking lord's player, `opponentDominoNumbers` for the other player.
|
|
1988
|
+
* Emitted after `onDominoPicked`.
|
|
1989
|
+
*/
|
|
1990
|
+
onNeolithicPairChosen?: (event: {
|
|
1991
|
+
game: GameState;
|
|
1992
|
+
lordId: string;
|
|
1993
|
+
playerId: string;
|
|
1994
|
+
dominoNumbers: number[];
|
|
1995
|
+
opponentDominoNumbers: number[];
|
|
1996
|
+
}) => void;
|
|
1422
1997
|
/** Called after a lord places a domino on their kingdom */
|
|
1423
1998
|
onDominoPlaced?: (event: {
|
|
1424
1999
|
game: GameState;
|
|
@@ -1439,7 +2014,7 @@ type GameEventCallbacks = {
|
|
|
1439
2014
|
game: GameState;
|
|
1440
2015
|
turn: number;
|
|
1441
2016
|
}) => void;
|
|
1442
|
-
/** Called when the game reaches the result phase */
|
|
2017
|
+
/** Called once when the game reaches the result phase, whatever the action that ended it */
|
|
1443
2018
|
onGameEnd?: (event: {
|
|
1444
2019
|
game: GameState;
|
|
1445
2020
|
}) => void;
|
|
@@ -1482,14 +2057,31 @@ type GameEventCallbacks = {
|
|
|
1482
2057
|
lordId: string;
|
|
1483
2058
|
targetPlayerId: string;
|
|
1484
2059
|
}) => void;
|
|
2060
|
+
/** Called after extra rules are added to the game (setup) */
|
|
2061
|
+
onExtraRulesAdded?: (event: {
|
|
2062
|
+
game: GameWithNextStep;
|
|
2063
|
+
extraRules: string[];
|
|
2064
|
+
}) => void;
|
|
2065
|
+
/** Called after a lord skips an optional action (QueenDomino, Origins, Age of Giants) */
|
|
2066
|
+
onOptionalActionSkipped?: (event: {
|
|
2067
|
+
game: GameState;
|
|
2068
|
+
lordId: string;
|
|
2069
|
+
/** The optional action that was skipped (e.g. `"placeKnight"`, `"sendGiant"`) */
|
|
2070
|
+
skippedAction: PlayerActions;
|
|
2071
|
+
}) => void;
|
|
1485
2072
|
};
|
|
1486
2073
|
/**
|
|
1487
2074
|
* Wraps a GameEngine to emit event callbacks after each state-changing method.
|
|
1488
2075
|
* Read-only methods (getModes, calculateScore, etc.) are passed through unchanged.
|
|
1489
2076
|
*
|
|
1490
|
-
* Derived events
|
|
1491
|
-
*
|
|
1492
|
-
* - `
|
|
2077
|
+
* Derived events are detected centrally, by comparing the game state before
|
|
2078
|
+
* and after every gameplay method (whatever the method that caused it):
|
|
2079
|
+
* - `onTurnEnd` + `onTurnStart`: emitted when the turn number changes
|
|
2080
|
+
* - `onGameEnd`: emitted exactly once, when the game transitions to the
|
|
2081
|
+
* "result" step (placeDomino, discardDomino, skipOptionalAction,
|
|
2082
|
+
* placeFireToken, recruitCaveman, useDragon, placeGiant, sendGiant…)
|
|
2083
|
+
*
|
|
2084
|
+
* The action-specific event is always emitted before the derived ones.
|
|
1493
2085
|
*
|
|
1494
2086
|
* @param engine - The base game engine to wrap
|
|
1495
2087
|
* @param callbacks - Optional event callbacks
|
|
@@ -1561,6 +2153,88 @@ type RuleRepository = {
|
|
|
1561
2153
|
getAllExtra: () => ExtraRule[];
|
|
1562
2154
|
};
|
|
1563
2155
|
|
|
2156
|
+
/**
|
|
2157
|
+
* Mode-aware evaluation and extension-action decisions of the built-in bots
|
|
2158
|
+
* (Queendomino, Kingdomino Origins, Age of Giants).
|
|
2159
|
+
*
|
|
2160
|
+
* Every decision follows the same recipe, without re-implementing any rule:
|
|
2161
|
+
* 1. enumerate the valid targets of the action (`getValidActionTargets`, whose
|
|
2162
|
+
* targets are guaranteed to be accepted by the action), plus "skip" when
|
|
2163
|
+
* `canSkipOptionalAction` allows it;
|
|
2164
|
+
* 2. simulate each target with the pure use case of the action;
|
|
2165
|
+
* 3. evaluate the resulting state with the mode-aware live score
|
|
2166
|
+
* (`computePlayerScore`) of the deciding player, plus a small value for the
|
|
2167
|
+
* assets the score does not count yet (coins, knights left, Tribe
|
|
2168
|
+
* resources), optionally minus the score of the best opponent;
|
|
2169
|
+
* 4. keep the best target (the first one on ties, "skip" coming first).
|
|
2170
|
+
*/
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* Common part of the context given to a bot strategy for an extension action.
|
|
2174
|
+
*/
|
|
2175
|
+
type ExtensionContext = {
|
|
2176
|
+
game: GameWithNextAction;
|
|
2177
|
+
/** Lord whose action it is (`game.nextAction.nextLord`) */
|
|
2178
|
+
lordId: string;
|
|
2179
|
+
/**
|
|
2180
|
+
* Player who decides: the owner of the lord. For a giant sent by an
|
|
2181
|
+
* opponent (`ageOfGiants.pendingGiant`), the targeted player.
|
|
2182
|
+
*/
|
|
2183
|
+
playerId: string;
|
|
2184
|
+
/** Whether returning `null` (skipping the action) is allowed */
|
|
2185
|
+
canSkip: boolean;
|
|
2186
|
+
};
|
|
2187
|
+
/** `placeKnight` (Queendomino): squares where a knight can go. */
|
|
2188
|
+
type KnightContext = ExtensionContext & {
|
|
2189
|
+
validPositions: Position[];
|
|
2190
|
+
};
|
|
2191
|
+
/** `constructBuilding` (Queendomino): any building on any square. */
|
|
2192
|
+
type BuildingContext = ExtensionContext & {
|
|
2193
|
+
validPositions: Position[];
|
|
2194
|
+
affordableBuildings: BuildingTile[];
|
|
2195
|
+
};
|
|
2196
|
+
/** A building to construct and its construction square. */
|
|
2197
|
+
type BuildingChoice = {
|
|
2198
|
+
buildingId: number;
|
|
2199
|
+
position: Position;
|
|
2200
|
+
};
|
|
2201
|
+
/** `useDragon` (Queendomino): buildings of the board the dragon can burn. */
|
|
2202
|
+
type DragonContext = ExtensionContext & {
|
|
2203
|
+
targetBuildings: BuildingTile[];
|
|
2204
|
+
};
|
|
2205
|
+
/** `placeFireToken` (Origins): squares where the pending token can go. */
|
|
2206
|
+
type FireTokenContext = ExtensionContext & {
|
|
2207
|
+
validPositions: Position[];
|
|
2208
|
+
};
|
|
2209
|
+
/** `recruitCaveman` (Origins Tribe): recruitable cavemen and squares. */
|
|
2210
|
+
type CavemanContext = ExtensionContext & {
|
|
2211
|
+
recruitment: ValidCavemanPlacements;
|
|
2212
|
+
};
|
|
2213
|
+
/** A caveman to recruit, where to place it and how to pay for it. */
|
|
2214
|
+
type CavemanChoice = {
|
|
2215
|
+
cavemanId: number;
|
|
2216
|
+
position: Position;
|
|
2217
|
+
resourcePositions: Position[];
|
|
2218
|
+
};
|
|
2219
|
+
/**
|
|
2220
|
+
* `placeGiant` (Age of Giants, mandatory): crowns of the deciding player's
|
|
2221
|
+
* kingdom the giant can cover.
|
|
2222
|
+
*/
|
|
2223
|
+
type GiantPositionContext = ExtensionContext & {
|
|
2224
|
+
validPositions: Position[];
|
|
2225
|
+
/** True when the giant was sent by an opponent (`pendingGiant`) */
|
|
2226
|
+
sentByOpponent: boolean;
|
|
2227
|
+
};
|
|
2228
|
+
/** `sendGiant` (Age of Giants): giants that can be sent and their targets. */
|
|
2229
|
+
type SendGiantContext = ExtensionContext & {
|
|
2230
|
+
targets: ValidGiantTargets;
|
|
2231
|
+
};
|
|
2232
|
+
/** A giant to send and the opponent receiving it. */
|
|
2233
|
+
type SendGiantChoice = {
|
|
2234
|
+
giantIndex: number;
|
|
2235
|
+
targetPlayerId: string;
|
|
2236
|
+
};
|
|
2237
|
+
|
|
1564
2238
|
/**
|
|
1565
2239
|
* Context provided to a bot strategy when choosing a domino to pick.
|
|
1566
2240
|
*/
|
|
@@ -1580,38 +2254,72 @@ type PlaceContext = {
|
|
|
1580
2254
|
validPlacements: ValidPlacement[];
|
|
1581
2255
|
};
|
|
1582
2256
|
/**
|
|
1583
|
-
* A bot strategy that decides which domino to pick and where to place it
|
|
1584
|
-
*
|
|
2257
|
+
* A bot strategy that decides which domino to pick and where to place it,
|
|
2258
|
+
* and optionally how to play the extension actions (Queendomino, Origins,
|
|
2259
|
+
* Age of Giants). Strategies are stateless — all information comes from the
|
|
2260
|
+
* context.
|
|
2261
|
+
*
|
|
2262
|
+
* Every extension method is optional: when a strategy does not define one,
|
|
2263
|
+
* `playBotTurn` uses the choice of `greedyStrategy` (best immediate
|
|
2264
|
+
* mode-aware score). An extension method is only called when the action has
|
|
2265
|
+
* at least one valid target, and every target of its context is accepted by
|
|
2266
|
+
* the action. Returning `null` skips the action (for the mandatory
|
|
2267
|
+
* `placeGiant`, `null` falls back to the greedy choice).
|
|
1585
2268
|
*/
|
|
1586
2269
|
type BotStrategy = {
|
|
1587
2270
|
chooseDomino: (context: PickContext) => number;
|
|
1588
2271
|
choosePlacement: (context: PlaceContext) => ValidPlacement | null;
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
2272
|
+
/** `placeKnight` (Queendomino): a square, or null to skip */
|
|
2273
|
+
chooseKnightPosition?: (context: KnightContext) => Position | null;
|
|
2274
|
+
/** `constructBuilding` (Queendomino): a building and square, or null */
|
|
2275
|
+
chooseBuilding?: (context: BuildingContext) => BuildingChoice | null;
|
|
2276
|
+
/** `useDragon` (Queendomino): id of the building to burn, or null */
|
|
2277
|
+
chooseDragonTarget?: (context: DragonContext) => number | null;
|
|
2278
|
+
/** `placeFireToken` (Origins): a square, or null to skip */
|
|
2279
|
+
chooseFireTokenPosition?: (context: FireTokenContext) => Position | null;
|
|
2280
|
+
/** `recruitCaveman` (Origins Tribe): a recruitment, or null to skip */
|
|
2281
|
+
chooseCavemanRecruitment?: (context: CavemanContext) => CavemanChoice | null;
|
|
2282
|
+
/** `placeGiant` (Age of Giants, mandatory): the crown to cover */
|
|
2283
|
+
chooseGiantPosition?: (context: GiantPositionContext) => Position | null;
|
|
2284
|
+
/** `sendGiant` (Age of Giants): a giant and its target, or null to skip */
|
|
2285
|
+
chooseGiantToSend?: (context: SendGiantContext) => SendGiantChoice | null;
|
|
2286
|
+
};
|
|
2287
|
+
/** The extension-action methods of a strategy. */
|
|
2288
|
+
type BotExtensionChoices = Required<Omit<BotStrategy, "chooseDomino" | "choosePlacement">>;
|
|
2289
|
+
/**
|
|
2290
|
+
* Bot strategy that makes random choices, seeded by the game seed and the
|
|
2291
|
+
* decision point (the same game replayed with the same seed gets the same
|
|
2292
|
+
* decisions). Picks a random available domino, places it at a random valid
|
|
2293
|
+
* position, and plays every extension action on a random valid target, or
|
|
2294
|
+
* skips it ("skip" being one more option when the action is optional).
|
|
1593
2295
|
*/
|
|
1594
2296
|
declare const randomStrategy: BotStrategy;
|
|
1595
2297
|
/**
|
|
1596
|
-
* Bot strategy that maximizes the immediate score.
|
|
1597
|
-
* Evaluates every valid placement and picks the one yielding the highest
|
|
1598
|
-
*
|
|
2298
|
+
* Bot strategy that maximizes the immediate mode-aware score.
|
|
2299
|
+
* Evaluates every valid placement and picks the one yielding the highest
|
|
2300
|
+
* score (territories plus every bonus of the mode). When picking a domino,
|
|
2301
|
+
* simulates the best placement for each option. Extension actions: the
|
|
2302
|
+
* target with the best own score (taxes, buildings, fire tokens, cavemen,
|
|
2303
|
+
* least costly crown for a giant), or skip when nothing improves it.
|
|
1599
2304
|
*/
|
|
1600
|
-
declare const greedyStrategy: BotStrategy;
|
|
2305
|
+
declare const greedyStrategy: BotStrategy & BotExtensionChoices;
|
|
1601
2306
|
/**
|
|
1602
2307
|
* Bot strategy with 1-turn lookahead.
|
|
1603
|
-
* When making decisions, considers not just the immediate score
|
|
1604
|
-
* the best possible score achievable in the next turn by peeking at
|
|
1605
|
-
* the upcoming domino batch from the draw pile.
|
|
2308
|
+
* When making decisions, considers not just the immediate mode-aware score
|
|
2309
|
+
* but also the best possible score achievable in the next turn by peeking at
|
|
2310
|
+
* the upcoming domino batch from the draw pile. Extension actions: the target
|
|
2311
|
+
* with the best own score minus half the best opponent's score (e.g. sending
|
|
2312
|
+
* a giant to the leader, taking a Totem majority from them).
|
|
1606
2313
|
*/
|
|
1607
|
-
declare const advancedStrategy: BotStrategy;
|
|
2314
|
+
declare const advancedStrategy: BotStrategy & BotExtensionChoices;
|
|
1608
2315
|
/**
|
|
1609
2316
|
* Bot strategy that searches the game tree with beam-search pruning.
|
|
1610
|
-
* Explores
|
|
1611
|
-
*
|
|
1612
|
-
*
|
|
2317
|
+
* Explores the next turns, but limits the number of placements evaluated per
|
|
2318
|
+
* domino to the top candidates (by greedy mode-aware score). Since kingdoms
|
|
2319
|
+
* are independent, the domino search is a solo optimization. Extension
|
|
2320
|
+
* actions: the target that maximizes the lead over the best opponent.
|
|
1613
2321
|
*/
|
|
1614
|
-
declare const expertStrategy: BotStrategy;
|
|
2322
|
+
declare const expertStrategy: BotStrategy & BotExtensionChoices;
|
|
1615
2323
|
/**
|
|
1616
2324
|
* Executes a single bot turn using the given strategy and engine.
|
|
1617
2325
|
* Reads the current game state to determine the required action,
|
|
@@ -1653,28 +2361,52 @@ declare const getStrategy: (name: string, custom?: Record<string, BotStrategy>)
|
|
|
1653
2361
|
*/
|
|
1654
2362
|
declare const getStrategyNames: () => string[];
|
|
1655
2363
|
|
|
2364
|
+
type CalculatePlayerScoreUseCase = (game: Game, playerId: string) => Result<PlayerScore>;
|
|
2365
|
+
|
|
1656
2366
|
type ConstructBuildingUseCase = (game: GameWithNextAction, lordId: string, buildingId: number, position: Position) => GameStateResult;
|
|
1657
2367
|
|
|
2368
|
+
/**
|
|
2369
|
+
* Current action log format version.
|
|
2370
|
+
*
|
|
2371
|
+
* - `1` (or no `version` field): legacy logs. `createGame` may omit the seed,
|
|
2372
|
+
* player ids and lord ids are not recorded, so a replay regenerates them.
|
|
2373
|
+
* - `2`: the effective seed, the game id, the player ids and the lord ids are
|
|
2374
|
+
* recorded, so a replay reproduces a strictly identical game state.
|
|
2375
|
+
*
|
|
2376
|
+
* Version 1 logs remain replayable.
|
|
2377
|
+
*/
|
|
2378
|
+
declare const ACTION_LOG_VERSION = 2;
|
|
1658
2379
|
/**
|
|
1659
2380
|
* The types of state-changing actions that can be recorded.
|
|
1660
2381
|
*/
|
|
1661
|
-
type ActionType = "createGame" | "addPlayers" | "addExtraRules" | "startGame" | "chooseDomino" | "placeDomino" | "discardDomino" | "placeGiant" | "sendGiant";
|
|
2382
|
+
type ActionType = "createGame" | "addPlayers" | "addExtraRules" | "startGame" | "chooseDomino" | "placeDomino" | "discardDomino" | "placeGiant" | "sendGiant" | "placeKnight" | "constructBuilding" | "useDragon" | "placeFireToken" | "recruitCaveman" | "skipOptionalAction";
|
|
1662
2383
|
/**
|
|
1663
2384
|
* Payload types for each action, containing only the command parameters
|
|
1664
|
-
* (excluding the game state, which is too large to store)
|
|
2385
|
+
* (excluding the game state, which is too large to store), plus the ids the
|
|
2386
|
+
* engine generated so that a replay reproduces them.
|
|
1665
2387
|
*/
|
|
1666
2388
|
type ActionPayloadMap = {
|
|
1667
2389
|
createGame: {
|
|
1668
2390
|
mode: string;
|
|
2391
|
+
/** Effective seed of the game (generated by the engine when the caller gave none) */
|
|
1669
2392
|
seed?: string;
|
|
2393
|
+
/** Id the engine generated for the game (restored on replay) */
|
|
2394
|
+
gameId?: string;
|
|
1670
2395
|
};
|
|
2396
|
+
/**
|
|
2397
|
+
* Players as `{ id, name, bot? }` objects carrying the ids the engine
|
|
2398
|
+
* assigned (legacy logs may contain plain names).
|
|
2399
|
+
*/
|
|
1671
2400
|
addPlayers: {
|
|
1672
2401
|
players: PlayerInput[];
|
|
1673
2402
|
};
|
|
1674
2403
|
addExtraRules: {
|
|
1675
2404
|
extraRules: string[];
|
|
1676
2405
|
};
|
|
1677
|
-
startGame:
|
|
2406
|
+
startGame: {
|
|
2407
|
+
/** Ids of the lords, in `game.lords` order (restored on replay) */
|
|
2408
|
+
lordIds?: string[];
|
|
2409
|
+
};
|
|
1678
2410
|
chooseDomino: {
|
|
1679
2411
|
lordId: string;
|
|
1680
2412
|
dominoPick: number;
|
|
@@ -1687,6 +2419,10 @@ type ActionPayloadMap = {
|
|
|
1687
2419
|
discardDomino: {
|
|
1688
2420
|
lordId: string;
|
|
1689
2421
|
};
|
|
2422
|
+
/**
|
|
2423
|
+
* `lordId` is the lord that played the action: the current lord, or a lord
|
|
2424
|
+
* of the targeted player when it places a giant sent by an opponent.
|
|
2425
|
+
*/
|
|
1690
2426
|
placeGiant: {
|
|
1691
2427
|
lordId: string;
|
|
1692
2428
|
position: Position;
|
|
@@ -1695,7 +2431,33 @@ type ActionPayloadMap = {
|
|
|
1695
2431
|
lordId: string;
|
|
1696
2432
|
giantIndex: number;
|
|
1697
2433
|
targetPlayerId: string;
|
|
1698
|
-
targetCrownPosition
|
|
2434
|
+
targetCrownPosition?: Position;
|
|
2435
|
+
};
|
|
2436
|
+
placeKnight: {
|
|
2437
|
+
lordId: string;
|
|
2438
|
+
position: Position;
|
|
2439
|
+
};
|
|
2440
|
+
constructBuilding: {
|
|
2441
|
+
lordId: string;
|
|
2442
|
+
buildingId: number;
|
|
2443
|
+
position: Position;
|
|
2444
|
+
};
|
|
2445
|
+
useDragon: {
|
|
2446
|
+
lordId: string;
|
|
2447
|
+
buildingId: number;
|
|
2448
|
+
};
|
|
2449
|
+
placeFireToken: {
|
|
2450
|
+
lordId: string;
|
|
2451
|
+
position: Position;
|
|
2452
|
+
};
|
|
2453
|
+
recruitCaveman: {
|
|
2454
|
+
lordId: string;
|
|
2455
|
+
cavemanId: number;
|
|
2456
|
+
position: Position;
|
|
2457
|
+
resourcePositions: Position[];
|
|
2458
|
+
};
|
|
2459
|
+
skipOptionalAction: {
|
|
2460
|
+
lordId: string;
|
|
1699
2461
|
};
|
|
1700
2462
|
};
|
|
1701
2463
|
/**
|
|
@@ -1716,6 +2478,8 @@ type ActionEntry<T extends ActionType = ActionType> = {
|
|
|
1716
2478
|
/**
|
|
1717
2479
|
* An immutable log of all actions performed during a game.
|
|
1718
2480
|
* Can be used to replay a game or analyze player decisions.
|
|
2481
|
+
* It is plain JSON: persist it with `JSON.stringify` and read it back with
|
|
2482
|
+
* `JSON.parse`.
|
|
1719
2483
|
*
|
|
1720
2484
|
* @example
|
|
1721
2485
|
* ```typescript
|
|
@@ -1728,6 +2492,8 @@ type ActionEntry<T extends ActionType = ActionType> = {
|
|
|
1728
2492
|
* ```
|
|
1729
2493
|
*/
|
|
1730
2494
|
type GameActionLog = {
|
|
2495
|
+
/** Format version (see `ACTION_LOG_VERSION`); absent in legacy logs (version 1) */
|
|
2496
|
+
version?: number;
|
|
1731
2497
|
/** The game ID this log belongs to */
|
|
1732
2498
|
gameId: string;
|
|
1733
2499
|
/** Immutable array of recorded actions */
|
|
@@ -1774,12 +2540,18 @@ declare const wrapWithActionLog: (engine: GameEngine) => {
|
|
|
1774
2540
|
};
|
|
1775
2541
|
/**
|
|
1776
2542
|
* Replays all actions from a log on a fresh engine to reconstruct the final game state.
|
|
1777
|
-
* The engine should use the same configuration (especially shuffleMethod) as the original game
|
|
1778
|
-
* to guarantee deterministic results when a seed is present.
|
|
1779
2543
|
*
|
|
1780
|
-
*
|
|
2544
|
+
* Version 2 logs (see `ACTION_LOG_VERSION`) record the effective seed and every
|
|
2545
|
+
* generated id (game, players, lords), so the replayed state is strictly
|
|
2546
|
+
* identical to the original one, whatever the replay engine's `uuidMethod`
|
|
2547
|
+
* and `shuffleMethod`. Legacy logs (version 1) are still replayed; their ids
|
|
2548
|
+
* are regenerated, and when they lack a seed the replay engine should use the
|
|
2549
|
+
* same configuration (especially shuffleMethod) as the original game.
|
|
2550
|
+
*
|
|
2551
|
+
* @param engine - A game engine instance
|
|
1781
2552
|
* @param log - The action log to replay
|
|
1782
2553
|
* @returns The final game state after replaying all actions
|
|
2554
|
+
* @throws Error if the log is empty, does not start with createGame, or has an unsupported version
|
|
1783
2555
|
*/
|
|
1784
2556
|
declare const replayActions: (engine: GameEngine, log: GameActionLog) => GameState;
|
|
1785
2557
|
|
|
@@ -1870,7 +2642,7 @@ type PlaceKnightUseCase = (game: GameWithNextAction, lordId: string, position: P
|
|
|
1870
2642
|
|
|
1871
2643
|
type RecruitCavemanUseCase = (game: GameWithNextAction, lordId: string, cavemanId: number, position: Position, resourcePositions: Position[]) => GameStateResult;
|
|
1872
2644
|
|
|
1873
|
-
type SendGiantUseCase = (game: GameWithNextAction, lordId: string, giantIndex: number, targetPlayerId: string, targetCrownPosition
|
|
2645
|
+
type SendGiantUseCase = (game: GameWithNextAction, lordId: string, giantIndex: number, targetPlayerId: string, targetCrownPosition?: Position) => GameStateResult;
|
|
1874
2646
|
|
|
1875
2647
|
/**
|
|
1876
2648
|
* Serializes a game state to a JSON string.
|
|
@@ -1918,6 +2690,11 @@ declare const createSavePoint: (game: GameState) => GameSavePoint;
|
|
|
1918
2690
|
declare const restoreFromSavePoint: (savePoint: GameSavePoint) => Result<GameState>;
|
|
1919
2691
|
|
|
1920
2692
|
type SkipOptionalActionUseCase = (game: GameWithNextAction, lordId: string) => GameStateResult;
|
|
2693
|
+
/**
|
|
2694
|
+
* Whether `action` is an optional action that `skipOptionalAction` accepts.
|
|
2695
|
+
* `placeDomino`, `pickDomino`, `pass` and `placeGiant` cannot be skipped.
|
|
2696
|
+
*/
|
|
2697
|
+
declare const isSkippableAction: (action: PlayerActions) => boolean;
|
|
1921
2698
|
|
|
1922
2699
|
type UseDragonUseCase = (game: GameWithNextAction, lordId: string, buildingId: number) => GameStateResult;
|
|
1923
2700
|
|
|
@@ -1946,4 +2723,4 @@ type UseDragonUseCase = (game: GameWithNextAction, lordId: string, buildingId: n
|
|
|
1946
2723
|
*/
|
|
1947
2724
|
declare const createGameEngine: (config: Partial<EngineConfig>) => GameEngine;
|
|
1948
2725
|
|
|
1949
|
-
export { type ActionEntry, ActionExecutionError, type ActionPayloadMap, type ActionType, type AddExtraRulesCommand, type AddPlayersCommand, type AgeOfGiantsState, type BasicRules, type BotStrategy, type BuildersBoard, type BuildingSlot, type BuildingTile, type BuildingsRepository, type CalculateScoreCommand, type CanPlaceDominoCommand, type CaveBoard, type CavemanTile, type CavemenRepository, type ChooseDominoCommand, type ConstructBuildingCommand, type ConstructBuildingUseCase, type CreateGameCommand, type Crown, type DebugLogEntry, type DebugLogLevel, type DebugLogger, type DebugOptions, type DeserializeGameCommand, type DiscardDominoCommand, type DomainError, DomainException, type Domino, type DominoesRepository, type DynastyResult, type EmptyGround, type EmptyTile, type EndGameScoring, type EndGameScoringType, type EngineConfig, ErrorCode, type ErrorCodeType, type ExtraRule, type FinalResult, type FireTokenPool, GRIDSIZE, GROUND, type Game, type GameActionLog, type GameEngine, type GameEventCallbacks, type GameHistory, type GameMode, type GameSavePoint, type GameState, type GameStateResult, type GameStateSummary, type GameSteps, type GameWithNextAction, type GameWithNextStep, type GameWithResults, type GetDynastyResultCommand, type GetExtraRulesCommand, type GetModesCommand, type GetResultCommand, type GetValidPlacementsCommand, type Ground, type HunterGathererKind, type HunterGathererTile, type ImmediateBonus, type ImmediateBonusType, InvalidStepError, type Kingdom, type Knight, type Logger, type Lord, MAX_KINGDOM_SIZE, type ModeRepository, type NextAction, type NextStep, NotFoundError, type ObjectValues, type OriginsState, type OriginsSubMode, type PendingFireToken, type PickContext, type PlaceContext, type PlaceDominoCommand, type PlaceFireTokenCommand, type PlaceFireTokenUseCase, type PlaceGiantCommand, type PlaceGiantUseCase, type PlaceKnightCommand, type PlaceKnightUseCase, type PlacedBuilding, type PlacedCaveman, type PlacedFireToken, type PlacedGiant, type Player, type PlayerActions, type PlayerInput, type PlayerPayload, type Players, type PlayersPayload, type Position, type QueenDominoState, type QuestTile, type QuestTilesRepository, type QuestType, type RecruitCavemanCommand, type RecruitCavemanUseCase, RedoError, type Resource, type ResourceType, type RevealsDomino, type Rotation, type RuleRepository, type Rules, type Score, type ScoreResult, type SelectedRules, type SendGiantCommand, type SendGiantUseCase, type SerializeGameCommand, type ShuffleMethod, type SkipOptionalActionCommand, type SkipOptionalActionUseCase, type StartGameCommand, StepExecutionError, type StrategyName, type Tile, type TotemBonus, type TotemState, TranslationKey, type TranslationKeyType, type Translator, UndoError, type UseDragonCommand, type UseDragonUseCase, type UuidMethod, type ValidPlacement, ValidationError, type ValidationIssue, type ValidationSeverity, WARRIOR_POWER, type WarriorTile, type WarriorType, advancedStrategy, appendAction, canRedo, canUndo, clearHistory, createActionLog, createDomainError, createGameEngine, createGameHistory, createSavePoint, createTranslator, defaultTranslations, defaultTranslator, deserializeGame, errorCodeToTranslationKey, expertStrategy, gameSteps, getActions, getActionsByTurn, getActionsByType, getHistorySize, getStrategy, getStrategyNames, greedyStrategy, hunterGathererKinds, isBotTurn, isGameWithNextAction, isGameWithNextStep, originsSubModes, playBotTurn, playBotTurns, playerActions, pushState, questTypes, randomStrategy, redo, replayActions, resourceTypes, restoreFromSavePoint, serializeGame, summarizeGameState, translateErrorCode, undo, validateGameState, warriorTypes, wrapWithActionLog, wrapWithDebug, wrapWithEvents };
|
|
2726
|
+
export { ACTION_LOG_VERSION, type ActionEntry, ActionExecutionError, type ActionPayloadMap, type ActionType, type AddExtraRulesCommand, type AddPlayersCommand, type AgeOfGiantsState, type BasicRules, type BotExtensionChoices, type BotStrategy, type BuildersBoard, type BuildingChoice, type BuildingContext, type BuildingSlot, type BuildingTile, type BuildingsRepository, type CalculatePlayerScoreCommand, type CalculatePlayerScoreUseCase, type CalculateScoreCommand, type CanPlaceDominoCommand, type CanSkipOptionalActionCommand, type CaveBoard, type CavemanChoice, type CavemanContext, type CavemanKind, type CavemanRecruitmentOption, type CavemanTile, type CavemenRepository, type ChooseDominoCommand, type ConstructBuildingCommand, type ConstructBuildingUseCase, type CreateGameCommand, type Crown, type DebugLogEntry, type DebugLogLevel, type DebugLogger, type DebugOptions, type DeserializeGameCommand, type DiscardDominoCommand, type DomainError, DomainException, type Domino, type DominoesRepository, type DragonContext, type DynastyGroupBy, type DynastyResult, type EmptyGround, type EmptyTile, type EndGameScoring, type EndGameScoringType, type EngineConfig, ErrorCode, type ErrorCodeType, type ExtensionContext, type ExtraRule, type FinalResult, type FireTokenContext, type FireTokenPool, GRIDSIZE, GROUND, type Game, type GameActionLog, type GameEngine, type GameEventCallbacks, type GameHistory, type GameMode, type GameSavePoint, type GameState, type GameStateResult, type GameStateSummary, type GameSteps, type GameWithNextAction, type GameWithNextStep, type GameWithResults, type GetAffordableBuildingsCommand, type GetDynastyResultCommand, type GetExtraRulesCommand, type GetModesCommand, type GetResultCommand, type GetValidActionTargetsCommand, type GetValidBuildingPositionsCommand, type GetValidCavemanPlacementsCommand, type GetValidDominoPicksCommand, type GetValidDragonTargetsCommand, type GetValidFireTokenPositionsCommand, type GetValidGiantPositionsCommand, type GetValidGiantTargetsCommand, type GetValidKnightPositionsCommand, type GetValidPlacementsCommand, type GiantPositionContext, type Ground, type HunterGathererKind, type HunterGathererTile, type ImmediateBonus, type ImmediateBonusType, InvalidStepError, type Kingdom, type Knight, type KnightContext, type Logger, type Lord, MAX_KINGDOM_SIZE, type ModeRepository, type NextAction, type NextStep, NotFoundError, type ObjectValues, type OriginsState, type OriginsSubMode, type PendingFireToken, type PendingGiant, type PickContext, type PlaceContext, type PlaceDominoCommand, type PlaceFireTokenCommand, type PlaceFireTokenUseCase, type PlaceGiantCommand, type PlaceGiantUseCase, type PlaceKnightCommand, type PlaceKnightUseCase, type PlacedBuilding, type PlacedCaveman, type PlacedFireToken, type PlacedGiant, type Player, type PlayerActions, type PlayerInput, type PlayerPayload, type PlayerScore, type Players, type PlayersPayload, type Position, type QueenDominoState, type QuestTile, type QuestTilesRepository, type QuestType, type RecruitCavemanCommand, type RecruitCavemanUseCase, RedoError, type Resource, type ResourceType, type RevealsDomino, type Rotation, type RuleRepository, type Rules, type Score, type ScoreBonus, type ScoreBonusType, type ScoreBreakdown, type ScoreResult, type ScoreTerritory, type SelectedRules, type SendGiantChoice, type SendGiantCommand, type SendGiantContext, type SendGiantUseCase, type SerializeGameCommand, type ShuffleMethod, type SkipOptionalActionCommand, type SkipOptionalActionUseCase, type StartGameCommand, StepExecutionError, type StrategyName, type SupportedLocale, type Tile, type TotemBonus, type TotemState, TranslationKey, type TranslationKeyType, type Translator, UndoError, type UseDragonCommand, type UseDragonUseCase, type UuidMethod, type ValidActionTargetsUseCase, type ValidCavemanPlacements, type ValidGiantTargets, type ValidPlacement, ValidationError, type ValidationIssue, type ValidationSeverity, WARRIOR_POWER, type WarriorTile, type WarriorType, advancedStrategy, appendAction, canRedo, canUndo, cavemanKindToTranslationKey, cavemanKinds, clearHistory, createActionLog, createDomainError, createGameEngine, createGameHistory, createSavePoint, createTranslator, defaultTranslations, defaultTranslator, deserializeGame, englishTranslations, errorCodeToTranslationKey, expertStrategy, extraRuleNameToTranslationKey, frenchTranslations, gameSteps, getActions, getActionsByTurn, getActionsByType, getHistorySize, getStrategy, getStrategyNames, greedyStrategy, groundToTranslationKey, hunterGathererKindToTranslationKey, hunterGathererKinds, isBotTurn, isGameWithNextAction, isGameWithNextStep, isGameWithResults, isHunterGathererTile, isSkippableAction, isWarriorTile, localeTranslations, modeNameToTranslationKey, originsSubModes, playBotTurn, playBotTurns, playerActionToTranslationKey, playerActions, pushState, questTypeToTranslationKey, questTypes, randomStrategy, redo, replayActions, resourceToTranslationKey, resourceTypes, restoreFromSavePoint, scoreBonusTypes, serializeGame, summarizeGameState, supportedLocales, totemToTranslationKey, translateErrorCode, undo, validateGameState, warriorTypeToTranslationKey, warriorTypes, wrapWithActionLog, wrapWithDebug, wrapWithEvents };
|