warp12-react 0.1.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 +24 -0
- package/dist/adapters/game-to-trains.d.ts +12 -0
- package/dist/adapters/game-to-trains.d.ts.map +1 -0
- package/dist/adapters/table-focus.d.ts +35 -0
- package/dist/adapters/table-focus.d.ts.map +1 -0
- package/dist/adapters/trail-access.d.ts +14 -0
- package/dist/adapters/trail-access.d.ts.map +1 -0
- package/dist/coach/warp-coach.d.ts +14 -0
- package/dist/coach/warp-coach.d.ts.map +1 -0
- package/dist/hand/action-log.d.ts +20 -0
- package/dist/hand/action-log.d.ts.map +1 -0
- package/dist/hand/hand-layout.d.ts +30 -0
- package/dist/hand/hand-layout.d.ts.map +1 -0
- package/dist/hand/use-hand-layout.d.ts +14 -0
- package/dist/hand/use-hand-layout.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +457 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# warp12-react
|
|
2
|
+
|
|
3
|
+
React adapters for Warp 12 — `RoundState` to DoubleTwelve trains, tactical advisor, hand layout.
|
|
4
|
+
|
|
5
|
+
Published on npm as **`warp12-react`**.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install warp12-react warp12-engine doubletwelve react react-dom
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { gameStateToTrains, getCoachSuggestion, useHandLayout } from 'warp12-react';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Build
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
yarn build:react
|
|
23
|
+
yarn test:react
|
|
24
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Coordinate, PlacedCoordinate, RoundState } from '../../../engine/src/index.ts';
|
|
2
|
+
import { TrainData, DominoValue } from '../../../../vendor/DoubleTwelve/dist/index.js';
|
|
3
|
+
/** Hub arm reserved for the Neutral Zone (8-spoke layout). */
|
|
4
|
+
export declare const NEUTRAL_ZONE_SLOT = 7;
|
|
5
|
+
/** Map engine placement to domino halves with value1 toward the connecting end. */
|
|
6
|
+
export declare function placedToDomino(placed: PlacedCoordinate, connectValue?: number): DominoValue;
|
|
7
|
+
/** Walk a trail so each tile's value1 faces the hub or previous open end. */
|
|
8
|
+
export declare function tilesToDominoChain(tiles: readonly PlacedCoordinate[], hubValue: number): DominoValue[];
|
|
9
|
+
export declare function gameStateToTrains(round: RoundState, hubSlots?: number): TrainData[];
|
|
10
|
+
export declare function coordinatesEqual(a: Coordinate, b: Coordinate): boolean;
|
|
11
|
+
export declare function routeLabel(route: import('../../../engine/src/index.ts').ChartRoute, captainNames: Readonly<Record<string, string>>): string;
|
|
12
|
+
//# sourceMappingURL=game-to-trains.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"game-to-trains.d.ts","sourceRoot":"","sources":["../../src/adapters/game-to-trains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,mFAAmF;AACnF,wBAAgB,cAAc,CAC5B,MAAM,EAAE,gBAAgB,EACxB,YAAY,CAAC,EAAE,MAAM,GACpB,WAAW,CAiBb;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,gBAAgB,EAAE,EAClC,QAAQ,EAAE,MAAM,GACf,WAAW,EAAE,CAWf;AAiCD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EACjB,QAAQ,SAAI,GACX,SAAS,EAAE,CAkDb;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAEtE;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,eAAe,EAAE,UAAU,EACzC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAC7C,MAAM,CAgBR"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RoundState } from '../../../engine/src/index.ts';
|
|
2
|
+
export type ChartSite = {
|
|
3
|
+
kind: 'warp-trail';
|
|
4
|
+
captainId: string;
|
|
5
|
+
tileIndex: number;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'neutral-zone';
|
|
8
|
+
tileIndex: number;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'fracture-stabilizer';
|
|
11
|
+
trailPlayerId: string;
|
|
12
|
+
};
|
|
13
|
+
export interface TableFocusPoint {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
key: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TableFocusOptions {
|
|
19
|
+
round: RoundState;
|
|
20
|
+
site: ChartSite;
|
|
21
|
+
layoutStyle: 'offset' | 'linear';
|
|
22
|
+
centerX: number;
|
|
23
|
+
centerY: number;
|
|
24
|
+
hubRadius: number;
|
|
25
|
+
hubSlots: number;
|
|
26
|
+
}
|
|
27
|
+
/** Detect where a new coordinate was charted between two round snapshots. */
|
|
28
|
+
export declare function detectNewChart(previous: RoundState | null, next: RoundState): ChartSite | null;
|
|
29
|
+
export declare function computeTableFocusPoint(options: TableFocusOptions): TableFocusPoint | null;
|
|
30
|
+
/** Pan offset so content point sits at the viewport center at the given scale. */
|
|
31
|
+
export declare function panToCenterContentPoint(viewportWidth: number, viewportHeight: number, scale: number, contentX: number, contentY: number): {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=table-focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-focus.d.ts","sourceRoot":"","sources":["../../src/adapters/table-focus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAYhD,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,UAAU,GAAG,IAAI,EAC3B,IAAI,EAAE,UAAU,GACf,SAAS,GAAG,IAAI,CAwClB;AAyBD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,iBAAiB,GACzB,eAAe,GAAG,IAAI,CAoExB;AAED,kFAAkF;AAClF,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAK1B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RoundState } from '../../../engine/src/index.ts';
|
|
2
|
+
export type TrailAccessState = 'open' | 'shields' | 'neutral' | 'red-alert';
|
|
3
|
+
export interface TrailSpokeStatus {
|
|
4
|
+
readonly slot: number;
|
|
5
|
+
readonly captainId: string | null;
|
|
6
|
+
readonly label: string;
|
|
7
|
+
readonly state: TrailAccessState;
|
|
8
|
+
readonly connectValue: number;
|
|
9
|
+
}
|
|
10
|
+
/** Whether other captains may chart on this warp trail. */
|
|
11
|
+
export declare function isWarpTrailOpenToOthers(round: RoundState, captainId: string): boolean;
|
|
12
|
+
export declare function buildTrailSpokeStatuses(round: RoundState, names: Readonly<Record<string, string>>, hubSlots: number): TrailSpokeStatus[];
|
|
13
|
+
export declare function openTrailCaptainNames(statuses: readonly TrailSpokeStatus[]): string[];
|
|
14
|
+
//# sourceMappingURL=trail-access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trail-access.d.ts","sourceRoot":"","sources":["../../src/adapters/trail-access.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAIvB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAET;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACvC,QAAQ,EAAE,MAAM,GACf,gBAAgB,EAAE,CAmDpB;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,MAAM,EAAE,CAIV"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ChartRoute, GameAction, GameState, PlayerId, WarpAiAction } from '../../../engine/src/index.ts';
|
|
2
|
+
export interface CoachSuggestion {
|
|
3
|
+
readonly action: WarpAiAction;
|
|
4
|
+
readonly gameAction: GameAction;
|
|
5
|
+
readonly reasons: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function getCoachSuggestion(state: GameState, playerId: PlayerId): CoachSuggestion | null;
|
|
8
|
+
export declare function formatCoachSuggestion(action: WarpAiAction, names: Readonly<Record<string, string>>): string;
|
|
9
|
+
export declare function coachChartMove(action: WarpAiAction): {
|
|
10
|
+
coordinate: import('../../../engine/src/index.ts').Coordinate;
|
|
11
|
+
route: ChartRoute;
|
|
12
|
+
} | null;
|
|
13
|
+
export declare function coachActionKind(action: WarpAiAction): WarpAiAction['kind'];
|
|
14
|
+
//# sourceMappingURL=warp-coach.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warp-coach.d.ts","sourceRoot":"","sources":["../../src/coach/warp-coach.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,QAAQ,GACjB,eAAe,GAAG,IAAI,CAkBxB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACtC,MAAM,CAqBR;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG;IACpD,UAAU,EAAE,OAAO,eAAe,EAAE,UAAU,CAAC;IAC/C,KAAK,EAAE,UAAU,CAAC;CACnB,GAAG,IAAI,CAKP;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,CAE1E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { GameAction } from '../../../engine/src/index.ts';
|
|
2
|
+
export type ActionLogSource = 'human' | 'ai' | 'auto';
|
|
3
|
+
export interface ActionLogEntry {
|
|
4
|
+
at: string;
|
|
5
|
+
playerId: string;
|
|
6
|
+
action: GameAction;
|
|
7
|
+
ok: boolean | null;
|
|
8
|
+
violation?: string;
|
|
9
|
+
source: ActionLogSource;
|
|
10
|
+
}
|
|
11
|
+
export interface ActionLog {
|
|
12
|
+
append(entry: Omit<ActionLogEntry, 'at'> & {
|
|
13
|
+
at?: string;
|
|
14
|
+
}): void;
|
|
15
|
+
snapshot(): readonly ActionLogEntry[];
|
|
16
|
+
clear(): void;
|
|
17
|
+
}
|
|
18
|
+
export declare function playerIdForAction(action: GameAction): string;
|
|
19
|
+
export declare function createActionLog(): ActionLog;
|
|
20
|
+
//# sourceMappingURL=action-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-log.d.ts","sourceRoot":"","sources":["../../src/hand/action-log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClE,QAAQ,IAAI,SAAS,cAAc,EAAE,CAAC;IACtC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAK5D;AAED,wBAAgB,eAAe,IAAI,SAAS,CAiB3C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Coordinate } from '../../../engine/src/index.ts';
|
|
2
|
+
export type HandSortMode = 'custom' | 'pips-desc' | 'pips-asc' | 'low-first' | 'doubles-first' | 'best-train';
|
|
3
|
+
export declare function coordinateKey(coordinate: Coordinate): string;
|
|
4
|
+
export declare function pipValue(coordinate: Coordinate): number;
|
|
5
|
+
/** Keep the player's custom order; append newly drawn tiles at the end. */
|
|
6
|
+
export declare function mergeHandOrder(previousOrder: readonly string[], hand: readonly Coordinate[]): string[];
|
|
7
|
+
export declare function sortHand(hand: readonly Coordinate[], mode: HandSortMode): string[];
|
|
8
|
+
/** Order and orient the hand as the longest chain from the given open end. */
|
|
9
|
+
export declare function bestTrainLayout(hand: readonly Coordinate[], connectValue: number): StoredHandLayout;
|
|
10
|
+
export declare function reorderHand(order: readonly string[], fromKey: string, toKey: string): string[];
|
|
11
|
+
export declare function orderHand(hand: readonly Coordinate[], order: readonly string[]): Coordinate[];
|
|
12
|
+
export declare function handLayoutStorageKey(gameId: string, playerId: string): string;
|
|
13
|
+
export interface StoredHandLayout {
|
|
14
|
+
order: string[];
|
|
15
|
+
flipped?: Record<string, boolean>;
|
|
16
|
+
}
|
|
17
|
+
export declare function mergeFlippedKeys(previous: Readonly<Record<string, boolean>>, hand: readonly Coordinate[]): Record<string, boolean>;
|
|
18
|
+
export declare function toggleFlippedKey(flipped: Readonly<Record<string, boolean>>, key: string): Record<string, boolean>;
|
|
19
|
+
export declare function isCoordinateFlipped(flipped: Readonly<Record<string, boolean>>, key: string): boolean;
|
|
20
|
+
export declare function displayCoordinateValues(coordinate: Coordinate, flipped: boolean): {
|
|
21
|
+
top: number;
|
|
22
|
+
bottom: number;
|
|
23
|
+
};
|
|
24
|
+
export declare function readStoredHandLayout(gameId: string, playerId: string): StoredHandLayout | null;
|
|
25
|
+
export declare function writeStoredHandLayout(gameId: string, playerId: string, layout: StoredHandLayout): void;
|
|
26
|
+
/** @deprecated Use readStoredHandLayout */
|
|
27
|
+
export declare function readStoredHandOrder(gameId: string, playerId: string): string[] | null;
|
|
28
|
+
/** @deprecated Use writeStoredHandLayout */
|
|
29
|
+
export declare function writeStoredHandOrder(gameId: string, playerId: string, order: readonly string[]): void;
|
|
30
|
+
//# sourceMappingURL=hand-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hand-layout.d.ts","sourceRoot":"","sources":["../../src/hand/hand-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,WAAW,GACX,UAAU,GACV,WAAW,GACX,eAAe,GACf,YAAY,CAAC;AAEjB,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAE5D;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAEvD;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAC5B,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,IAAI,EAAE,SAAS,UAAU,EAAE,GAC1B,MAAM,EAAE,CAUV;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CA8ClF;AA8FD,8EAA8E;AAC9E,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,YAAY,EAAE,MAAM,GACnB,gBAAgB,CA+BlB;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAWV;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,UAAU,EAAE,CAKd;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7E;AAKD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3C,IAAI,EAAE,SAAS,UAAU,EAAE,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC1C,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC1C,GAAG,EAAE,MAAM,GACV,OAAO,CAET;AAED,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,GACf;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAIjC;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,gBAAgB,GAAG,IAAI,CAuBzB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,gBAAgB,GACvB,IAAI,CASN;AAED,2CAA2C;AAC3C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,MAAM,EAAE,GAAG,IAAI,CAEjB;AAED,4CAA4C;AAC5C,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,IAAI,CAEN"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Coordinate } from '../../../engine/src/index.ts';
|
|
2
|
+
import { HandSortMode } from './hand-layout.js';
|
|
3
|
+
export declare function useHandLayout(gameId: string, playerId: string, hand: readonly Coordinate[]): {
|
|
4
|
+
orderedHand: Coordinate[];
|
|
5
|
+
applySort: (mode: HandSortMode, connectValue?: number) => void;
|
|
6
|
+
toggleFlip: (key: string) => void;
|
|
7
|
+
isFlipped: (key: string) => boolean;
|
|
8
|
+
onDragStart: (key: string, event: React.DragEvent<HTMLButtonElement>) => void;
|
|
9
|
+
onDragEnd: () => void;
|
|
10
|
+
onDragOver: (event: React.DragEvent) => void;
|
|
11
|
+
onDrop: (targetKey: string) => void;
|
|
12
|
+
shouldIgnoreClick: () => boolean;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=use-hand-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-hand-layout.d.ts","sourceRoot":"","sources":["../../src/hand/use-hand-layout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAYL,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAe1B,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,SAAS,UAAU,EAAE;;sBAkClB,YAAY,iBAAiB,MAAM;sBAYP,MAAM;qBAKnC,MAAM;uBAKN,MAAM,SAAS,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC;;wBAiBlB,KAAK,CAAC,SAAS;wBAKf,MAAM;;EAoB9C"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './adapters/game-to-trains.js';
|
|
2
|
+
export * from './adapters/trail-access.js';
|
|
3
|
+
export * from './adapters/table-focus.js';
|
|
4
|
+
export * from './coach/warp-coach.js';
|
|
5
|
+
export * from './hand/hand-layout.js';
|
|
6
|
+
export * from './hand/use-hand-layout.js';
|
|
7
|
+
export * from './hand/action-log.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { createWarpAiPlayer as e, explainWarpAiAction as t, getWarpSkillProfile as n, neutralZoneOpenValue as r, observe as i, toGameAction as a, trailOpenValue as o, trailsOpenToOthers as s } from "warp12-engine";
|
|
2
|
+
import { computeTrainTree as c, flattenSegments as l, hubTrainStartDistance as u } from "doubletwelve";
|
|
3
|
+
import { useCallback as d, useEffect as f, useMemo as p, useRef as m, useState as h } from "react";
|
|
4
|
+
//#region libs/react/src/adapters/game-to-trains.ts
|
|
5
|
+
var g = 7;
|
|
6
|
+
function _(e, t) {
|
|
7
|
+
let { coordinate: n } = e;
|
|
8
|
+
if (t !== void 0) {
|
|
9
|
+
if (n.low === t) return {
|
|
10
|
+
value1: n.low,
|
|
11
|
+
value2: n.high
|
|
12
|
+
};
|
|
13
|
+
if (n.high === t) return {
|
|
14
|
+
value1: n.high,
|
|
15
|
+
value2: n.low
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
let { openValue: r } = e;
|
|
19
|
+
return {
|
|
20
|
+
value1: n.low === r ? n.high : n.low,
|
|
21
|
+
value2: r
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function v(e, t) {
|
|
25
|
+
let n = t, r = [];
|
|
26
|
+
for (let t of e) {
|
|
27
|
+
let e = _(t, n);
|
|
28
|
+
r.push(e), n = t.openValue;
|
|
29
|
+
}
|
|
30
|
+
return r;
|
|
31
|
+
}
|
|
32
|
+
function y(e, t) {
|
|
33
|
+
let n = e.table.subspaceFracture;
|
|
34
|
+
if (!n || n.stabilizers.length === 0) return;
|
|
35
|
+
let r = e.table.warpTrails[t].tiles.findIndex((e) => e.index === n.anchor.index);
|
|
36
|
+
if (r === -1) return;
|
|
37
|
+
let i = n.stabilizers.slice(0, 2).map((e) => ({ dominoes: [_(e, n.requiredValue)] }));
|
|
38
|
+
if (i.length !== 0) return { [r]: i };
|
|
39
|
+
}
|
|
40
|
+
function b(e, t = 8) {
|
|
41
|
+
let n = [], r = e.spacedockValue, i = new Map(e.turnOrder.map((e, t) => [e, t]));
|
|
42
|
+
for (let t of e.turnOrder) {
|
|
43
|
+
let a = i.get(t), o = e.table.warpTrails[t], c = v(o.tiles, r), l = e.table.subspaceFracture;
|
|
44
|
+
if (l && l.stabilizers.length >= 3 && e.turnOrder.find((t) => e.table.warpTrails[t].tiles.some((e) => e.index === l.anchor.index)) === t) {
|
|
45
|
+
let e = l.anchor.index, t = l.stabilizers[2], n = c.slice(0, e + 1), r = _(t, l.requiredValue), i = v(o.tiles.slice(e + 1), t.openValue);
|
|
46
|
+
c = [
|
|
47
|
+
...n,
|
|
48
|
+
r,
|
|
49
|
+
...i
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
n.push({
|
|
53
|
+
playerId: a,
|
|
54
|
+
isPublic: s(e, t),
|
|
55
|
+
dominoes: c,
|
|
56
|
+
feet: y(e, t)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return (e.table.neutralZone.tiles.length > 0 || t > e.turnOrder.length) && n.push({
|
|
60
|
+
playerId: 7,
|
|
61
|
+
isPublic: !0,
|
|
62
|
+
dominoes: v(e.table.neutralZone.tiles, r)
|
|
63
|
+
}), n;
|
|
64
|
+
}
|
|
65
|
+
function ee(e, t) {
|
|
66
|
+
return e.low === t.low && e.high === t.high;
|
|
67
|
+
}
|
|
68
|
+
function x(e, t) {
|
|
69
|
+
switch (e.kind) {
|
|
70
|
+
case "warp-trail": return `Warp trail · ${t[e.playerId] ?? e.playerId}`;
|
|
71
|
+
case "neutral-zone": return "Neutral zone";
|
|
72
|
+
case "fracture-stabilizer": return "Stabilize fracture";
|
|
73
|
+
case "red-alert-cover": {
|
|
74
|
+
if (e.neutralZone) return "Cover red alert · Neutral zone";
|
|
75
|
+
let n = e.trailPlayerId ?? "fleet";
|
|
76
|
+
return `Cover red alert · ${t[n] ?? n}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region libs/react/src/adapters/trail-access.ts
|
|
82
|
+
function S(e, t) {
|
|
83
|
+
return s(e, t);
|
|
84
|
+
}
|
|
85
|
+
function te(e, t, n) {
|
|
86
|
+
let i = new Map(e.turnOrder.map((e, t) => [e, t])), a = [];
|
|
87
|
+
for (let s = 0; s < n; s += 1) {
|
|
88
|
+
if (s === 7) {
|
|
89
|
+
a.push({
|
|
90
|
+
slot: s,
|
|
91
|
+
captainId: null,
|
|
92
|
+
label: "Neutral",
|
|
93
|
+
state: "neutral",
|
|
94
|
+
connectValue: r(e.table.neutralZone, e.spacedockValue)
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
let n = e.turnOrder.find((e) => i.get(e) === s);
|
|
99
|
+
if (!n) continue;
|
|
100
|
+
let c = e.table.warpTrails[n], l = o(c, e.spacedockValue), u = e.table.redAlert?.active && e.table.redAlert.trailPlayerId === n, d = "shields";
|
|
101
|
+
u ? d = "red-alert" : S(e, n) && (d = "open"), a.push({
|
|
102
|
+
slot: s,
|
|
103
|
+
captainId: n,
|
|
104
|
+
label: t[n] ?? n,
|
|
105
|
+
state: d,
|
|
106
|
+
connectValue: l
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return a;
|
|
110
|
+
}
|
|
111
|
+
function C(e) {
|
|
112
|
+
return e.filter((e) => e.state === "open" && e.captainId).map((e) => e.label);
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region libs/react/src/adapters/table-focus.ts
|
|
116
|
+
var w = 60;
|
|
117
|
+
function T(e, t) {
|
|
118
|
+
if (!e || e.roundNumber !== t.roundNumber) return null;
|
|
119
|
+
let n = e.table.subspaceFracture, r = t.table.subspaceFracture;
|
|
120
|
+
if (r && (n?.stabilizers.length ?? 0) < r.stabilizers.length) {
|
|
121
|
+
for (let e of t.turnOrder) if (t.table.warpTrails[e].tiles.some((e) => e.index === r.anchor.index)) return {
|
|
122
|
+
kind: "fracture-stabilizer",
|
|
123
|
+
trailPlayerId: e
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
let i = e.table.neutralZone.tiles.length, a = t.table.neutralZone.tiles.length;
|
|
127
|
+
if (a > i) return {
|
|
128
|
+
kind: "neutral-zone",
|
|
129
|
+
tileIndex: a - 1
|
|
130
|
+
};
|
|
131
|
+
for (let n of t.turnOrder) {
|
|
132
|
+
let r = e.table.warpTrails[n]?.tiles.length ?? 0, i = t.table.warpTrails[n]?.tiles.length ?? 0;
|
|
133
|
+
if (i > r) return {
|
|
134
|
+
kind: "warp-trail",
|
|
135
|
+
captainId: n,
|
|
136
|
+
tileIndex: i - 1
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
function E(e, t, n, r, i, a) {
|
|
142
|
+
let o = e * 360 / t, s = o * Math.PI / 180, c = u(t, i, w, a);
|
|
143
|
+
return {
|
|
144
|
+
startX: n + c * Math.cos(s),
|
|
145
|
+
startY: r + c * Math.sin(s),
|
|
146
|
+
angle: o
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function D(e) {
|
|
150
|
+
let t = b(e.round, e.hubSlots), { site: n, layoutStyle: r, centerX: i, centerY: a, hubRadius: o, hubSlots: s } = e, u, d;
|
|
151
|
+
switch (n.kind) {
|
|
152
|
+
case "warp-trail":
|
|
153
|
+
u = e.round.turnOrder.indexOf(n.captainId), d = n.tileIndex;
|
|
154
|
+
break;
|
|
155
|
+
case "neutral-zone":
|
|
156
|
+
u = 7, d = n.tileIndex;
|
|
157
|
+
break;
|
|
158
|
+
case "fracture-stabilizer":
|
|
159
|
+
u = e.round.turnOrder.indexOf(n.trailPlayerId), d = null;
|
|
160
|
+
break;
|
|
161
|
+
default: return null;
|
|
162
|
+
}
|
|
163
|
+
if (u < 0) return null;
|
|
164
|
+
let f = t.find((e) => e.playerId === u);
|
|
165
|
+
if (!f) return null;
|
|
166
|
+
let p = E(u, s, i, a, o, r), m = l(c({
|
|
167
|
+
startX: p.startX,
|
|
168
|
+
startY: p.startY,
|
|
169
|
+
angle: p.angle,
|
|
170
|
+
branch: {
|
|
171
|
+
dominoes: f.dominoes,
|
|
172
|
+
feet: f.feet
|
|
173
|
+
},
|
|
174
|
+
layoutStyle: r
|
|
175
|
+
})), h = d != null && d >= 0 ? m[d] ?? m.at(-1) : m.at(-1);
|
|
176
|
+
if (!h) return null;
|
|
177
|
+
let g = n.kind === "warp-trail" ? `warp:${n.captainId}:${n.tileIndex}` : n.kind === "neutral-zone" ? `neutral:${n.tileIndex}` : `fracture:${n.trailPlayerId}:${e.round.table.subspaceFracture?.stabilizers.length ?? 0}`;
|
|
178
|
+
return {
|
|
179
|
+
x: h.x,
|
|
180
|
+
y: h.y,
|
|
181
|
+
key: g
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function O(e, t, n, r, i) {
|
|
185
|
+
return {
|
|
186
|
+
x: e / 2 - r * n,
|
|
187
|
+
y: t / 2 - i * n
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region libs/react/src/coach/warp-coach.ts
|
|
192
|
+
function k(r, o) {
|
|
193
|
+
let s = i(r, o);
|
|
194
|
+
if (!s) return null;
|
|
195
|
+
let c = e({
|
|
196
|
+
skill: n("advanced", r.objective),
|
|
197
|
+
objective: r.objective,
|
|
198
|
+
lookahead: {
|
|
199
|
+
depth: 2,
|
|
200
|
+
determinizations: 6,
|
|
201
|
+
maxBranch: 6
|
|
202
|
+
}
|
|
203
|
+
}).decide(s);
|
|
204
|
+
return {
|
|
205
|
+
action: c,
|
|
206
|
+
gameAction: a(c, o),
|
|
207
|
+
reasons: t(r, o, c)
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function A(e, t) {
|
|
211
|
+
switch (e.kind) {
|
|
212
|
+
case "chart": {
|
|
213
|
+
let { low: n, high: r } = e.move.coordinate;
|
|
214
|
+
return `Chart ${n}-${r} · ${x(e.move.route, t)}`;
|
|
215
|
+
}
|
|
216
|
+
case "draw": return "Draw from Uncharted Sectors";
|
|
217
|
+
case "deploy-beacon": return "Deploy Distress Beacon (shields down)";
|
|
218
|
+
case "pass-red-alert": return "Pass Red Alert to the next captain";
|
|
219
|
+
case "pass-turn": return "Pass turn (voluntary shields down)";
|
|
220
|
+
case "declare-treaty": return "Drop to impulse · Neutral Zone win";
|
|
221
|
+
case "invoke-q-flash": return `Invoke Q-Flash · ${e.effect.replaceAll("-", " ")}`;
|
|
222
|
+
case "resolve-q-gamble": return `Keep gamble tile ${e.keepIndex + 1}`;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function j(e) {
|
|
226
|
+
return e.kind === "chart" ? e.move : null;
|
|
227
|
+
}
|
|
228
|
+
function M(e) {
|
|
229
|
+
return e.kind;
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region libs/react/src/hand/hand-layout.ts
|
|
233
|
+
function N(e) {
|
|
234
|
+
return `${e.low}-${e.high}`;
|
|
235
|
+
}
|
|
236
|
+
function P(e) {
|
|
237
|
+
return e.low + e.high;
|
|
238
|
+
}
|
|
239
|
+
function F(e, t) {
|
|
240
|
+
let n = new Set(t.map(N)), r = e.filter((e) => n.has(e));
|
|
241
|
+
for (let e of t) {
|
|
242
|
+
let t = N(e);
|
|
243
|
+
r.includes(t) || r.push(t);
|
|
244
|
+
}
|
|
245
|
+
return r;
|
|
246
|
+
}
|
|
247
|
+
function I(e, t) {
|
|
248
|
+
let n = e.map((e) => ({
|
|
249
|
+
key: N(e),
|
|
250
|
+
coordinate: e
|
|
251
|
+
}));
|
|
252
|
+
switch (t) {
|
|
253
|
+
case "pips-desc":
|
|
254
|
+
n.sort((e, t) => P(t.coordinate) - P(e.coordinate) || e.coordinate.low - t.coordinate.low || e.coordinate.high - t.coordinate.high);
|
|
255
|
+
break;
|
|
256
|
+
case "pips-asc":
|
|
257
|
+
n.sort((e, t) => P(e.coordinate) - P(t.coordinate) || e.coordinate.low - t.coordinate.low || e.coordinate.high - t.coordinate.high);
|
|
258
|
+
break;
|
|
259
|
+
case "low-first":
|
|
260
|
+
n.sort((e, t) => e.coordinate.low - t.coordinate.low || e.coordinate.high - t.coordinate.high);
|
|
261
|
+
break;
|
|
262
|
+
case "doubles-first":
|
|
263
|
+
n.sort((e, t) => (e.coordinate.low === e.coordinate.high ? 0 : 1) - (t.coordinate.low === t.coordinate.high ? 0 : 1) || P(t.coordinate) - P(e.coordinate) || e.coordinate.low - t.coordinate.low);
|
|
264
|
+
break;
|
|
265
|
+
default: break;
|
|
266
|
+
}
|
|
267
|
+
return n.map((e) => e.key);
|
|
268
|
+
}
|
|
269
|
+
function L(e, t) {
|
|
270
|
+
return e.low === t || e.high === t;
|
|
271
|
+
}
|
|
272
|
+
function R(e, t) {
|
|
273
|
+
return e.low === t ? e.high : e.low;
|
|
274
|
+
}
|
|
275
|
+
function z(e, t) {
|
|
276
|
+
return e.low === t ? !1 : e.high === t;
|
|
277
|
+
}
|
|
278
|
+
function B(e, t, n) {
|
|
279
|
+
if (e.length !== t.length) return e.length - t.length;
|
|
280
|
+
let r = (e) => e.reduce((e, t) => e + P(n.get(t.key) ?? {
|
|
281
|
+
low: 0,
|
|
282
|
+
high: 0
|
|
283
|
+
}), 0), i = r(e) - r(t);
|
|
284
|
+
return i === 0 ? e.map((e) => e.key).join(",").localeCompare(t.map((e) => e.key).join(",")) : i;
|
|
285
|
+
}
|
|
286
|
+
function V(e, t) {
|
|
287
|
+
let n = e.map((e) => ({
|
|
288
|
+
key: N(e),
|
|
289
|
+
coordinate: e
|
|
290
|
+
})), r = new Map(n.map((e) => [e.key, e.coordinate])), i = n.length, a = [], o = (e, t, s) => {
|
|
291
|
+
if (B(s, a, r) > 0 && (a = s.slice()), !(s.length + (i - s.length) <= a.length)) for (let r = 0; r < i; r += 1) {
|
|
292
|
+
if (t[r]) continue;
|
|
293
|
+
let { key: i, coordinate: a } = n[r];
|
|
294
|
+
L(a, e) && (t[r] = !0, s.push({
|
|
295
|
+
key: i,
|
|
296
|
+
connectOn: e
|
|
297
|
+
}), o(R(a, e), t, s), s.pop(), t[r] = !1);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
return o(t, Array.from({ length: i }, () => !1), []), a;
|
|
301
|
+
}
|
|
302
|
+
function H(e, t) {
|
|
303
|
+
let n = e.map((e) => ({
|
|
304
|
+
key: N(e),
|
|
305
|
+
coordinate: e
|
|
306
|
+
})), r = new Map(n.map((e) => [e.key, e.coordinate])), i = V(e, t), a = new Set(i.map((e) => e.key)), o = {};
|
|
307
|
+
for (let e of i) {
|
|
308
|
+
let t = r.get(e.key);
|
|
309
|
+
t && z(t, e.connectOn) && (o[e.key] = !0);
|
|
310
|
+
}
|
|
311
|
+
let s = n.filter((e) => !a.has(e.key)).sort((e, t) => P(t.coordinate) - P(e.coordinate) || e.coordinate.low - t.coordinate.low || e.coordinate.high - t.coordinate.high).map((e) => e.key);
|
|
312
|
+
return {
|
|
313
|
+
order: [...i.map((e) => e.key), ...s],
|
|
314
|
+
flipped: q(o, e)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function U(e, t, n) {
|
|
318
|
+
if (t === n) return [...e];
|
|
319
|
+
let r = e.filter((e) => e !== t), i = r.indexOf(n);
|
|
320
|
+
return i === -1 ? [...e] : (r.splice(i, 0, t), r);
|
|
321
|
+
}
|
|
322
|
+
function W(e, t) {
|
|
323
|
+
let n = new Map(e.map((e) => [N(e), e]));
|
|
324
|
+
return t.map((e) => n.get(e)).filter((e) => e !== void 0);
|
|
325
|
+
}
|
|
326
|
+
function G(e, t) {
|
|
327
|
+
return `warp12-hand-layout:${e}:${t}`;
|
|
328
|
+
}
|
|
329
|
+
var K = (e, t) => `warp12-hand-order:${e}:${t}`;
|
|
330
|
+
function q(e, t) {
|
|
331
|
+
let n = new Set(t.map(N)), r = {};
|
|
332
|
+
for (let [t, i] of Object.entries(e)) n.has(t) && i && (r[t] = !0);
|
|
333
|
+
return r;
|
|
334
|
+
}
|
|
335
|
+
function J(e, t) {
|
|
336
|
+
if (e[t]) {
|
|
337
|
+
let n = { ...e };
|
|
338
|
+
return delete n[t], n;
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
...e,
|
|
342
|
+
[t]: !0
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function Y(e, t) {
|
|
346
|
+
return e[t] ?? !1;
|
|
347
|
+
}
|
|
348
|
+
function X(e, t) {
|
|
349
|
+
return t ? {
|
|
350
|
+
top: e.high,
|
|
351
|
+
bottom: e.low
|
|
352
|
+
} : {
|
|
353
|
+
top: e.low,
|
|
354
|
+
bottom: e.high
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function Z(e, t) {
|
|
358
|
+
try {
|
|
359
|
+
let n = localStorage.getItem(G(e, t)) ?? localStorage.getItem(K(e, t));
|
|
360
|
+
if (!n) return null;
|
|
361
|
+
let r = JSON.parse(n);
|
|
362
|
+
return Array.isArray(r) && r.every((e) => typeof e == "string") ? { order: r } : r && typeof r == "object" && "order" in r && Array.isArray(r.order) && r.order.every((e) => typeof e == "string") ? r : null;
|
|
363
|
+
} catch {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function Q(e, t, n) {
|
|
368
|
+
try {
|
|
369
|
+
localStorage.setItem(G(e, t), JSON.stringify(n));
|
|
370
|
+
} catch {}
|
|
371
|
+
}
|
|
372
|
+
function ne(e, t) {
|
|
373
|
+
return Z(e, t)?.order ?? null;
|
|
374
|
+
}
|
|
375
|
+
function re(e, t, n) {
|
|
376
|
+
Q(e, t, { order: [...n] });
|
|
377
|
+
}
|
|
378
|
+
//#endregion
|
|
379
|
+
//#region libs/react/src/hand/use-hand-layout.ts
|
|
380
|
+
var ie = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7", $ = null;
|
|
381
|
+
function ae() {
|
|
382
|
+
return $ || ($ = new Image(), $.src = ie), $;
|
|
383
|
+
}
|
|
384
|
+
function oe(e, t, n) {
|
|
385
|
+
let r = p(() => n.map(N).sort().join("|"), [n]), [i, a] = h(() => F(Z(e, t)?.order ?? n.map(N), n)), [o, s] = h(() => q(Z(e, t)?.flipped ?? {}, n)), c = m(null), l = m(!1);
|
|
386
|
+
return f(() => {
|
|
387
|
+
a((e) => F(e, n)), s((e) => q(e, n));
|
|
388
|
+
}, [
|
|
389
|
+
e,
|
|
390
|
+
t,
|
|
391
|
+
r
|
|
392
|
+
]), f(() => {
|
|
393
|
+
Q(e, t, {
|
|
394
|
+
order: i,
|
|
395
|
+
flipped: o
|
|
396
|
+
});
|
|
397
|
+
}, [
|
|
398
|
+
e,
|
|
399
|
+
t,
|
|
400
|
+
i,
|
|
401
|
+
o
|
|
402
|
+
]), {
|
|
403
|
+
orderedHand: p(() => W(n, i), [n, i]),
|
|
404
|
+
applySort: d((e, t) => {
|
|
405
|
+
if (e === "best-train" && t !== void 0) {
|
|
406
|
+
let e = H(n, t);
|
|
407
|
+
a(e.order), s(e.flipped ?? {});
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
a(I(n, e));
|
|
411
|
+
}, [n]),
|
|
412
|
+
toggleFlip: d((e) => {
|
|
413
|
+
s((t) => J(t, e));
|
|
414
|
+
}, []),
|
|
415
|
+
isFlipped: d((e) => Y(o, e), [o]),
|
|
416
|
+
onDragStart: d((e, t) => {
|
|
417
|
+
c.current = e, l.current = !0, t.dataTransfer.effectAllowed = "move", t.dataTransfer.setData("text/plain", e), t.dataTransfer.setDragImage(ae(), 0, 0);
|
|
418
|
+
}, []),
|
|
419
|
+
onDragEnd: d(() => {
|
|
420
|
+
c.current = null, window.setTimeout(() => {
|
|
421
|
+
l.current = !1;
|
|
422
|
+
}, 0);
|
|
423
|
+
}, []),
|
|
424
|
+
onDragOver: d((e) => {
|
|
425
|
+
e.preventDefault(), e.dataTransfer.dropEffect = "move";
|
|
426
|
+
}, []),
|
|
427
|
+
onDrop: d((e) => {
|
|
428
|
+
let t = c.current;
|
|
429
|
+
t && (a((n) => U(n, t, e)), c.current = null);
|
|
430
|
+
}, []),
|
|
431
|
+
shouldIgnoreClick: d(() => l.current, [])
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region libs/react/src/hand/action-log.ts
|
|
436
|
+
function se(e) {
|
|
437
|
+
return e.type === "END_ROUND" ? e.winnerId ?? "" : e.playerId;
|
|
438
|
+
}
|
|
439
|
+
function ce() {
|
|
440
|
+
let e = [];
|
|
441
|
+
return {
|
|
442
|
+
append(t) {
|
|
443
|
+
e.push({
|
|
444
|
+
...t,
|
|
445
|
+
at: t.at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
446
|
+
});
|
|
447
|
+
},
|
|
448
|
+
snapshot() {
|
|
449
|
+
return [...e];
|
|
450
|
+
},
|
|
451
|
+
clear() {
|
|
452
|
+
e.length = 0;
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
//#endregion
|
|
457
|
+
export { g as NEUTRAL_ZONE_SLOT, H as bestTrainLayout, te as buildTrailSpokeStatuses, M as coachActionKind, j as coachChartMove, D as computeTableFocusPoint, N as coordinateKey, ee as coordinatesEqual, ce as createActionLog, T as detectNewChart, X as displayCoordinateValues, A as formatCoachSuggestion, b as gameStateToTrains, k as getCoachSuggestion, G as handLayoutStorageKey, Y as isCoordinateFlipped, S as isWarpTrailOpenToOthers, q as mergeFlippedKeys, F as mergeHandOrder, C as openTrailCaptainNames, W as orderHand, O as panToCenterContentPoint, P as pipValue, _ as placedToDomino, se as playerIdForAction, Z as readStoredHandLayout, ne as readStoredHandOrder, U as reorderHand, x as routeLabel, I as sortHand, v as tilesToDominoChain, J as toggleFlippedKey, oe as useHandLayout, Q as writeStoredHandLayout, re as writeStoredHandOrder };
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "warp12-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React adapters for Warp 12 — state to trains, coach, hand layout",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Jessica Mulein",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
".": {
|
|
15
|
+
"@warp12/source": "./src/index.ts",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"warp12",
|
|
27
|
+
"react",
|
|
28
|
+
"mexican-train",
|
|
29
|
+
"dominoes",
|
|
30
|
+
"game"
|
|
31
|
+
],
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/Digital-Defiance/Warp12.git",
|
|
35
|
+
"directory": "libs/react"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public",
|
|
39
|
+
"registry": "https://registry.npmjs.org/"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"prepublishOnly": "cd ../.. && yarn build:react && yarn test:react"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"doubletwelve": ">=0.3.0",
|
|
46
|
+
"react": ">=18.0.0",
|
|
47
|
+
"warp12-engine": ">=0.1.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"doubletwelve": "workspace:*",
|
|
51
|
+
"react": "^19.0.0",
|
|
52
|
+
"warp12-engine": "workspace:*"
|
|
53
|
+
}
|
|
54
|
+
}
|