@slugbugblue/trax 1.1.0 → 1.2.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/RELEASE.v1.2.0.md +10 -0
- package/benchmark/benchmarks.json +25 -0
- package/benchmark/engine.bench.js +228 -0
- package/gl-sast-report.json +1 -0
- package/package.json +15 -19
- package/src/engine.d.ts +456 -0
- package/src/engine.js +527 -312
- package/src/version.js +1 -1
- package/CHANGELOG.md +0 -237
- package/CONTRIBUTING.md +0 -113
- package/docs/engine.md +0 -432
- package/src/types.d.ts +0 -84
package/src/engine.d.ts
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/** A digital representation of a Trax game. */
|
|
2
|
+
export class Trax {
|
|
3
|
+
/** @readonly */
|
|
4
|
+
static readonly version: '1.2.0'
|
|
5
|
+
/**
|
|
6
|
+
@readonly
|
|
7
|
+
@type {Record<TraxVariant, string>}
|
|
8
|
+
*/
|
|
9
|
+
static readonly names: Record<TraxVariant, string>
|
|
10
|
+
/** @readonly */
|
|
11
|
+
static readonly variants: Set<string>
|
|
12
|
+
/**
|
|
13
|
+
Create an x,y Point object with special functions.
|
|
14
|
+
@param {number|PointLike} x - either the x value, or an object with x,y keys
|
|
15
|
+
@param {number} [y] - if x is a number, y must be provided as well
|
|
16
|
+
@returns {Point} a new Point object
|
|
17
|
+
*/
|
|
18
|
+
static point: (x: number | PointLike, y?: number) => Point
|
|
19
|
+
/**
|
|
20
|
+
Given a player number, get the color.
|
|
21
|
+
@param {number} playerNumber - the player number, 1 or 2
|
|
22
|
+
@returns {Color} the color of that player, w or b
|
|
23
|
+
*/
|
|
24
|
+
static colorOf: (playerNumber: number) => Color
|
|
25
|
+
/**
|
|
26
|
+
Given a color, get the player number.
|
|
27
|
+
@param {string} color - the color, w or b
|
|
28
|
+
@returns {number} the player number, 1 or 2
|
|
29
|
+
*/
|
|
30
|
+
static playerNumber: (color: string) => number
|
|
31
|
+
/**
|
|
32
|
+
Given a color, get the other color.
|
|
33
|
+
@param {string} color - the color, w or b
|
|
34
|
+
@returns {Color} the other color, b or w
|
|
35
|
+
*/
|
|
36
|
+
static other: (color: string) => Color
|
|
37
|
+
/**
|
|
38
|
+
Encode a numeric column number into the Trax notation column letter.
|
|
39
|
+
@param {number} col - the column number, with 0 just to the left of the tiles
|
|
40
|
+
@returns {string} the encoded column letter
|
|
41
|
+
*/
|
|
42
|
+
static encodeCol: (col: number) => string
|
|
43
|
+
/**
|
|
44
|
+
Decode a Trax notation column letter back to a number.
|
|
45
|
+
@param {string} col - the Trax column letter
|
|
46
|
+
@returns {number} the column number
|
|
47
|
+
*/
|
|
48
|
+
static decodeCol: (col: string) => number
|
|
49
|
+
/**
|
|
50
|
+
Create a new Trax game
|
|
51
|
+
@param {TraxVariant} [rules='trax'] - the variant to play
|
|
52
|
+
@param {string|string[]} [moves=''] - the initial moves to pre-play
|
|
53
|
+
@param {string} [id='trax'] - an id used to differentiate tiles from multiple games
|
|
54
|
+
*/
|
|
55
|
+
constructor(rules?: TraxVariant, moves?: string | string[], id?: string)
|
|
56
|
+
id: string
|
|
57
|
+
rules: TraxVariant
|
|
58
|
+
turn: number
|
|
59
|
+
over: boolean
|
|
60
|
+
left: number
|
|
61
|
+
right: number
|
|
62
|
+
top: number
|
|
63
|
+
bottom: number
|
|
64
|
+
count: number
|
|
65
|
+
/** @type {string[]} */
|
|
66
|
+
moves: string[]
|
|
67
|
+
/** @type {Map<TileId, Point>} */
|
|
68
|
+
frontier: Map<TileId, Point>
|
|
69
|
+
/** @type {Record<TileId, Tile>} */
|
|
70
|
+
tiles: Record<TileId, Tile>
|
|
71
|
+
/** @type {TileId[]} */
|
|
72
|
+
path: TileId[]
|
|
73
|
+
invalid: boolean
|
|
74
|
+
/**
|
|
75
|
+
Save the current game data to a variable.
|
|
76
|
+
@returns {SaveState} an opaque save state object
|
|
77
|
+
@see restore for restoring the state
|
|
78
|
+
*/
|
|
79
|
+
save(): SaveState
|
|
80
|
+
/**
|
|
81
|
+
Restore a previously saved position.
|
|
82
|
+
@param {SaveState} saved - the previously saved state
|
|
83
|
+
@see save for saving the state
|
|
84
|
+
*/
|
|
85
|
+
restore(saved: SaveState): void
|
|
86
|
+
/**
|
|
87
|
+
Lightweight checkpoint for internal rollback. Valid only for ancestor restores.
|
|
88
|
+
Callers must be in a non-over, valid game state — rewind() restores those
|
|
89
|
+
fields to those fixed values rather than saving and restoring them.
|
|
90
|
+
@returns {Checkpoint} a lightweight snapshot of mutable board dimensions
|
|
91
|
+
@typedef {{ move: number, count: number, turn: number, left: number, right: number, top: number, bottom: number }} Checkpoint
|
|
92
|
+
*/
|
|
93
|
+
checkpoint(): {
|
|
94
|
+
move: number
|
|
95
|
+
count: number
|
|
96
|
+
turn: number
|
|
97
|
+
left: number
|
|
98
|
+
right: number
|
|
99
|
+
top: number
|
|
100
|
+
bottom: number
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
Rewind to a checkpoint. Only valid for ancestor restores.
|
|
104
|
+
@param {Checkpoint} cp - the checkpoint to rewind to
|
|
105
|
+
*/
|
|
106
|
+
rewind(cp: {
|
|
107
|
+
move: number
|
|
108
|
+
count: number
|
|
109
|
+
turn: number
|
|
110
|
+
left: number
|
|
111
|
+
right: number
|
|
112
|
+
top: number
|
|
113
|
+
bottom: number
|
|
114
|
+
}): void
|
|
115
|
+
/** The name of this variant. */
|
|
116
|
+
get name(): string
|
|
117
|
+
/** The move number of the last-played move. */
|
|
118
|
+
get move(): number
|
|
119
|
+
/** The color of the current player, w or b. */
|
|
120
|
+
get color(): Color
|
|
121
|
+
/** True if the game is over. */
|
|
122
|
+
get gameOver(): boolean
|
|
123
|
+
/** 1 or 2 for a win, 0 for a tie, false if the game is still in progress. */
|
|
124
|
+
get winner(): number | false
|
|
125
|
+
/**
|
|
126
|
+
Provides the tile ID for the tile at the given location.
|
|
127
|
+
@param {PointLike} loc - the location
|
|
128
|
+
@returns {TileId} a string key encoding this game's id and the location
|
|
129
|
+
*/
|
|
130
|
+
tileId(loc: PointLike): TileId
|
|
131
|
+
/**
|
|
132
|
+
Add a tile to the board. Note that no validity checking is done here,
|
|
133
|
+
except that invalid tiles are not actually placed on the board, so this
|
|
134
|
+
should only be called externally.
|
|
135
|
+
@param {TileType} type - letter 'a'-'f' for valid tiles, 'x' for invalid
|
|
136
|
+
@param {Point} loc - the location
|
|
137
|
+
@returns {Tile} the tile placed on the board
|
|
138
|
+
*/
|
|
139
|
+
addTile(type: TileType, loc: Point): Tile
|
|
140
|
+
/**
|
|
141
|
+
The type of tile at the given location.
|
|
142
|
+
@param {PointLike} loc - the location the tile is in
|
|
143
|
+
@returns {ValidTiles|undefined} the type of tile, or undefined if no tile
|
|
144
|
+
*/
|
|
145
|
+
tileAt(loc: PointLike): ValidTiles | undefined
|
|
146
|
+
validTile(type: string, loc: Point): type is ValidTiles
|
|
147
|
+
/**
|
|
148
|
+
Get a list of possible tiles that can be played in this location.
|
|
149
|
+
@param {Point} loc - the location to check
|
|
150
|
+
@param {string | boolean} [s=false] - if provided, a direction modifier, '/', '\\', or '+'
|
|
151
|
+
@returns {TileType[]} the list of valid tile types for this location
|
|
152
|
+
*/
|
|
153
|
+
possibleTiles(loc: Point, s?: string | boolean): TileType[]
|
|
154
|
+
get height(): number
|
|
155
|
+
get width(): number
|
|
156
|
+
/**
|
|
157
|
+
Determine if a location is valid to play in.
|
|
158
|
+
@param {Point} loc - the location to check
|
|
159
|
+
@returns {boolean} true if a tile can be placed here
|
|
160
|
+
*/
|
|
161
|
+
validLocation(loc: Point): boolean
|
|
162
|
+
/**
|
|
163
|
+
Find all possible locations to play in. Note that these are not
|
|
164
|
+
necessarily valid locations, just empty ones that border existing tiles.
|
|
165
|
+
@returns {Point[]} all frontier locations
|
|
166
|
+
*/
|
|
167
|
+
possibleLocations(): Point[]
|
|
168
|
+
/**
|
|
169
|
+
Find all possible moves as a list of notations,
|
|
170
|
+
ie: ['@1+', '@1/', '@1\\', ...]
|
|
171
|
+
|
|
172
|
+
Note that moves are not guaranteed to be valid.
|
|
173
|
+
@returns {string[]} all valid move notations from the current position
|
|
174
|
+
*/
|
|
175
|
+
possibleMoves(): string[]
|
|
176
|
+
/**
|
|
177
|
+
Called after a move was just played, to determine the forced moves.
|
|
178
|
+
@param {Point} loc - the location just played at
|
|
179
|
+
@returns {Tile[]} a list of tiles that should be added as part of the move
|
|
180
|
+
*/
|
|
181
|
+
forcedMoves(loc: Point): Tile[]
|
|
182
|
+
/**
|
|
183
|
+
Determine the notation for a move. Note that this must be determined
|
|
184
|
+
BEFORE the move is placed on the board.
|
|
185
|
+
@param {ValidTiles} type - the tile placed on the board
|
|
186
|
+
@param {Point} loc - the location the tile is placed
|
|
187
|
+
@returns {string} the notation of the move
|
|
188
|
+
*/
|
|
189
|
+
notate(type: ValidTiles, loc: Point): string
|
|
190
|
+
/**
|
|
191
|
+
Turn a move notation into a tile type and location.
|
|
192
|
+
@param {string} notation - a notation for a single move to be played at
|
|
193
|
+
the current board position
|
|
194
|
+
@returns {RawMove} the tile type and location of the move
|
|
195
|
+
*/
|
|
196
|
+
decodeNotation(notation: string): RawMove
|
|
197
|
+
/**
|
|
198
|
+
Follow a color from one location through one or more tiles to the other
|
|
199
|
+
end of the color line.
|
|
200
|
+
@param {Color} color - the color to follow
|
|
201
|
+
@param {Point} loc - the location to start
|
|
202
|
+
@param {string} from - the edge of the tile to start from
|
|
203
|
+
@returns {LineEnd} the ending location and a list of the tile ids the path
|
|
204
|
+
takes to get there
|
|
205
|
+
*/
|
|
206
|
+
follow(color: Color, loc: Point, from: string): LineEnd
|
|
207
|
+
/**
|
|
208
|
+
Given a tile and a color, follow the line for that color to each end.
|
|
209
|
+
@param {Color} color - the color of ends of interest
|
|
210
|
+
@param {Point} loc - the location of the tile of interest
|
|
211
|
+
@returns {LineEnd[]} a list of two items, each one end of the line
|
|
212
|
+
*/
|
|
213
|
+
findEnds(color: Color, loc: Point): LineEnd[]
|
|
214
|
+
/**
|
|
215
|
+
Determine if a given line ends the game.
|
|
216
|
+
@param {Point} locA - one end of the line
|
|
217
|
+
@param {Point} locB - the other end of the line
|
|
218
|
+
@returns {boolean} true if this line wins the game
|
|
219
|
+
*/
|
|
220
|
+
lineWin(locA: Point, locB: Point): boolean
|
|
221
|
+
/**
|
|
222
|
+
Determine if the game has ended.
|
|
223
|
+
@param {Tile[]} tiles - a list of the tiles placed during the last move
|
|
224
|
+
*/
|
|
225
|
+
checkWin(tiles: Tile[]): void
|
|
226
|
+
/**
|
|
227
|
+
Play a move. Can be called either as:
|
|
228
|
+
- play(moveNumber, notation) to ensure move safety, or
|
|
229
|
+
- play(notation) for quicker access.
|
|
230
|
+
@param {number|string} moveNumber - the move number or the notation
|
|
231
|
+
@param {string} [notation] - the notation, if a move number was provided
|
|
232
|
+
@returns {{dropped: Tile[], notation: string, valid: boolean}} the result of the move
|
|
233
|
+
*/
|
|
234
|
+
play(
|
|
235
|
+
moveNumber: number | string,
|
|
236
|
+
notation?: string,
|
|
237
|
+
): {
|
|
238
|
+
dropped: Tile[]
|
|
239
|
+
notation: string
|
|
240
|
+
valid: boolean
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
Play one or more moves.
|
|
244
|
+
@param {string|string[]} moves - the list of moves, provided either as a
|
|
245
|
+
space-separated string of notations, or as a list of notations. Move
|
|
246
|
+
numbers are optional, but if provided will be checked for accuracy.
|
|
247
|
+
*/
|
|
248
|
+
playMoves(moves: string | string[]): void
|
|
249
|
+
/** The formatted notation string for the current game, wrapped at 80 columns. */
|
|
250
|
+
get notation(): string
|
|
251
|
+
/**
|
|
252
|
+
Drop a tile onto the board. This is a lower level call. Use play() if possible instead.
|
|
253
|
+
@param {string|ValidTiles} type - a special move, a tile type, or a notation
|
|
254
|
+
@param {Point} [loc] - a location if type is a tile type
|
|
255
|
+
@param {string|boolean} [tentative] - if truthy, the move will not be saved
|
|
256
|
+
@returns {TileDrop} an object representing the results of the drop
|
|
257
|
+
*/
|
|
258
|
+
dropTile(
|
|
259
|
+
type: string | ValidTiles,
|
|
260
|
+
loc?: Point,
|
|
261
|
+
tentative?: string | boolean,
|
|
262
|
+
): TileDrop
|
|
263
|
+
/**
|
|
264
|
+
Symmetry helper. Rotates a move around the board in case we are trying to
|
|
265
|
+
play a symmetrical rather than an exact move.
|
|
266
|
+
@param {string} move - the notation of the move to be rotated
|
|
267
|
+
@returns {string[]} the four rotations of this move
|
|
268
|
+
*/
|
|
269
|
+
moveRotations(move: string): string[]
|
|
270
|
+
/**
|
|
271
|
+
Play a provisional move if it is valid.
|
|
272
|
+
@param {string} from - the normalized encoding of the starting position
|
|
273
|
+
@param {string} to - the normalized encoding of the ending position
|
|
274
|
+
@param {string} via - the move to be used to transition
|
|
275
|
+
@returns {false|string} if the provisional move is invalid: false; if the
|
|
276
|
+
provisional move will never be valid for any future moves:
|
|
277
|
+
'delete-provisional'; if the provisional move is valid, the correct
|
|
278
|
+
notation, which may be symmetrically adjusted as needed
|
|
279
|
+
*/
|
|
280
|
+
provisionalMove(from: string, to: string, via: string): false | string
|
|
281
|
+
/**
|
|
282
|
+
Get an encoded representation of the current position, useful for drawing
|
|
283
|
+
the board without having to do much analysis.
|
|
284
|
+
@returns {string} the current position code
|
|
285
|
+
*/
|
|
286
|
+
get icon(): string
|
|
287
|
+
/**
|
|
288
|
+
Get an encoded representation of the current position, with a set of
|
|
289
|
+
tiles highlighted differently, useful for showing the effects of a move.
|
|
290
|
+
@param {TileDrop} drops - the drops of the most recent play
|
|
291
|
+
@returns {string} the current position code, with drops highlighted
|
|
292
|
+
*/
|
|
293
|
+
dropsIcon(drops: TileDrop): string
|
|
294
|
+
/**
|
|
295
|
+
Symmetry helper, draw the board from different angles.
|
|
296
|
+
@param {boolean} [rightToLeft] - reverse order horizontally
|
|
297
|
+
@param {boolean} [bottomToTop] - reverse order vertically
|
|
298
|
+
@param {boolean} [rotate] - rotate the tiles by 90 degrees
|
|
299
|
+
@param {TileDrop} [drops] - the drops of the most recent play, if you want
|
|
300
|
+
them highlighted
|
|
301
|
+
@returns {string} an encoding of the position
|
|
302
|
+
*/
|
|
303
|
+
positionCode(
|
|
304
|
+
rightToLeft?: boolean,
|
|
305
|
+
bottomToTop?: boolean,
|
|
306
|
+
rotate?: boolean,
|
|
307
|
+
drops?: TileDrop,
|
|
308
|
+
): string
|
|
309
|
+
/**
|
|
310
|
+
Trax has the potential for symmetry, so this gives us the ability to
|
|
311
|
+
examine horizontal, vertical, and rotational symmetry for a color.
|
|
312
|
+
@returns {string} a position code that matches all symmetrical positions
|
|
313
|
+
*/
|
|
314
|
+
normalize(): string
|
|
315
|
+
/**
|
|
316
|
+
Get the normalized code for this position. All symmetrical positions will
|
|
317
|
+
result in the same normalized code.
|
|
318
|
+
@returns {string} the normalized position code
|
|
319
|
+
*/
|
|
320
|
+
get normalized(): string
|
|
321
|
+
}
|
|
322
|
+
export type Color = 'w' | 'b'
|
|
323
|
+
/**
|
|
324
|
+
* One end of a line and the tiles taken to get there.
|
|
325
|
+
*/
|
|
326
|
+
export type LineEnd = {
|
|
327
|
+
/**
|
|
328
|
+
* - the ending location
|
|
329
|
+
*/
|
|
330
|
+
loc: Point
|
|
331
|
+
/**
|
|
332
|
+
* - tile ids from start to end
|
|
333
|
+
*/
|
|
334
|
+
path: TileId[]
|
|
335
|
+
}
|
|
336
|
+
export type Notation = string
|
|
337
|
+
/**
|
|
338
|
+
* A tile type and a location determine a raw move.
|
|
339
|
+
*/
|
|
340
|
+
export type RawMove = {
|
|
341
|
+
/**
|
|
342
|
+
* - the tile type
|
|
343
|
+
*/
|
|
344
|
+
type: TileType
|
|
345
|
+
/**
|
|
346
|
+
* - the location
|
|
347
|
+
*/
|
|
348
|
+
loc: Point
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Treat the save state as an opaque object,
|
|
352
|
+
* produced by save() and fed into restore().
|
|
353
|
+
*/
|
|
354
|
+
export type SaveState = {
|
|
355
|
+
/**
|
|
356
|
+
* - game id
|
|
357
|
+
*/
|
|
358
|
+
id: string
|
|
359
|
+
/**
|
|
360
|
+
* - move number
|
|
361
|
+
*/
|
|
362
|
+
move: number
|
|
363
|
+
/**
|
|
364
|
+
* - current player (1 or 2)
|
|
365
|
+
*/
|
|
366
|
+
turn: number
|
|
367
|
+
/**
|
|
368
|
+
* - whether the game is over
|
|
369
|
+
*/
|
|
370
|
+
over: boolean
|
|
371
|
+
/**
|
|
372
|
+
* - leftmost tile column
|
|
373
|
+
*/
|
|
374
|
+
left: number
|
|
375
|
+
/**
|
|
376
|
+
* - rightmost tile column
|
|
377
|
+
*/
|
|
378
|
+
right: number
|
|
379
|
+
/**
|
|
380
|
+
* - topmost tile row
|
|
381
|
+
*/
|
|
382
|
+
top: number
|
|
383
|
+
/**
|
|
384
|
+
* - bottommost tile row
|
|
385
|
+
*/
|
|
386
|
+
bottom: number
|
|
387
|
+
/**
|
|
388
|
+
* - move notations
|
|
389
|
+
*/
|
|
390
|
+
moves: string[]
|
|
391
|
+
/**
|
|
392
|
+
* - frontier locations
|
|
393
|
+
*/
|
|
394
|
+
frontier: [TileId, Point][]
|
|
395
|
+
/**
|
|
396
|
+
* - serialized tiles
|
|
397
|
+
*/
|
|
398
|
+
tiles: string
|
|
399
|
+
/**
|
|
400
|
+
* - serialized winning path
|
|
401
|
+
*/
|
|
402
|
+
path: string
|
|
403
|
+
/**
|
|
404
|
+
* - whether an invalid tile was placed
|
|
405
|
+
*/
|
|
406
|
+
invalid: boolean
|
|
407
|
+
}
|
|
408
|
+
export type Slash = '/' | '\\' | '+'
|
|
409
|
+
/**
|
|
410
|
+
* A single tile on the board.
|
|
411
|
+
*/
|
|
412
|
+
export type Tile = {
|
|
413
|
+
/**
|
|
414
|
+
* - unique tile identifier
|
|
415
|
+
*/
|
|
416
|
+
id: TileId
|
|
417
|
+
/**
|
|
418
|
+
* - board location
|
|
419
|
+
*/
|
|
420
|
+
loc: Point
|
|
421
|
+
/**
|
|
422
|
+
* - tile type letter
|
|
423
|
+
*/
|
|
424
|
+
type: TileType
|
|
425
|
+
/**
|
|
426
|
+
* - move number when placed
|
|
427
|
+
*/
|
|
428
|
+
move: number
|
|
429
|
+
/**
|
|
430
|
+
* - sequence number among all tiles
|
|
431
|
+
*/
|
|
432
|
+
seq: number
|
|
433
|
+
}
|
|
434
|
+
export type TileId = string
|
|
435
|
+
/**
|
|
436
|
+
* When a tile is dropped, this object represents the results.
|
|
437
|
+
*/
|
|
438
|
+
export type TileDrop = {
|
|
439
|
+
/**
|
|
440
|
+
* - all tiles placed, including forced moves
|
|
441
|
+
*/
|
|
442
|
+
dropped: Tile[]
|
|
443
|
+
/**
|
|
444
|
+
* - the notation of the played move
|
|
445
|
+
*/
|
|
446
|
+
notation: Notation
|
|
447
|
+
/**
|
|
448
|
+
* - whether the move was legal
|
|
449
|
+
*/
|
|
450
|
+
valid: boolean
|
|
451
|
+
}
|
|
452
|
+
export type TileType = ValidTiles | 'x'
|
|
453
|
+
export type TraxVariant = 'trax' | 'traxloop' | 'trax8'
|
|
454
|
+
export type ValidTiles = 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
|
|
455
|
+
import { Point } from '@slugbugblue/point'
|
|
456
|
+
import type { PointLike } from '@slugbugblue/point'
|