@slugbugblue/trax 1.0.1 → 1.1.1
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.1.1.md +5 -0
- package/gl-sast-report.json +1 -0
- package/package.json +17 -19
- package/src/engine.d.ts +313 -0
- package/src/engine.js +116 -22
- package/src/version.js +1 -1
- package/CHANGELOG.md +0 -233
- package/CONTRIBUTING.md +0 -113
- package/docs/engine.md +0 -429
- package/src/types.d.ts +0 -84
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"15.2.2","vulnerabilities":[],"scan":{"analyzer":{"id":"semgrep","name":"Semgrep","url":"https://gitlab.com/gitlab-org/security-products/analyzers/semgrep","vendor":{"name":"GitLab"},"version":"6.15.1"},"scanner":{"id":"semgrep","name":"Semgrep","url":"https://github.com/returntocorp/semgrep","vendor":{"name":"GitLab"},"version":"1.145.0"},"type":"sast","start_time":"2026-02-28T20:29:59","end_time":"2026-02-28T20:30:11","status":"success","observability":{"events":[{"event":"collect_sast_scan_metrics_from_pipeline","property":"54b1ad92-5d39-416b-9075-916f3da22681","label":"semgrep","value":0,"version":"6.15.1","exit_code":0,"override_count":0,"passthrough_count":0,"custom_exclude_path_count":0,"time_s":12,"file_count":7}]}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slugbugblue/trax",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Trax game engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"trax",
|
|
@@ -11,20 +11,28 @@
|
|
|
11
11
|
"bugs": "https://gitlab.com/slugbugblue/trax/issues",
|
|
12
12
|
"license": "Apache-2.0",
|
|
13
13
|
"author": "Chad Transtrum <chad@transtrum.net>",
|
|
14
|
-
"types": "./src/
|
|
14
|
+
"types": "./src/engine.d.ts",
|
|
15
|
+
"typings": "./src/engine.d.ts",
|
|
15
16
|
"exports": {
|
|
16
|
-
".":
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./src/engine.d.ts",
|
|
19
|
+
"default": "./src/engine.js"
|
|
20
|
+
},
|
|
17
21
|
"./version": "./src/version.js",
|
|
18
22
|
"./version.js": "./src/version.js"
|
|
19
23
|
},
|
|
20
|
-
"repository":
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://gitlab.com/slugbugblue/trax.git"
|
|
27
|
+
},
|
|
21
28
|
"scripts": {
|
|
22
29
|
"genversion": "genversion --esm src/version.js",
|
|
23
|
-
"git-add": "git add src/version.js",
|
|
30
|
+
"git-add": "git add src/version.js src/engine.d.ts",
|
|
31
|
+
"ts-build": "tsc -p tsconfig.build.json && rm -f src/version.d.ts",
|
|
24
32
|
"test": "xo && c8 ava",
|
|
25
33
|
"prepare": "[ -n \"$CI\" ] || husky",
|
|
26
|
-
"preversion": "npm test",
|
|
27
|
-
"version": "npm run genversion ; npm run git-add",
|
|
34
|
+
"preversion": "npm audit --audit-level=high && npm test",
|
|
35
|
+
"version": "npm run genversion ; npm run ts-build ; npm run git-add",
|
|
28
36
|
"postversion": "git push && git push --tags"
|
|
29
37
|
},
|
|
30
38
|
"dependencies": {
|
|
@@ -32,8 +40,8 @@
|
|
|
32
40
|
"@slugbugblue/point": "^1.0.0"
|
|
33
41
|
},
|
|
34
42
|
"devDependencies": {
|
|
35
|
-
"ava": "^
|
|
36
|
-
"c8": "^
|
|
43
|
+
"ava": "^7.0.0",
|
|
44
|
+
"c8": "^11.0.0",
|
|
37
45
|
"genversion": "^3.0.2",
|
|
38
46
|
"husky": "^9.1.7",
|
|
39
47
|
"prettier": "^3.6.2",
|
|
@@ -57,15 +65,5 @@
|
|
|
57
65
|
"singleQuote": true,
|
|
58
66
|
"trailingComma": "all",
|
|
59
67
|
"useTabs": false
|
|
60
|
-
},
|
|
61
|
-
"xo": {
|
|
62
|
-
"prettier": true,
|
|
63
|
-
"space": true,
|
|
64
|
-
"rules": {
|
|
65
|
-
"curly": [
|
|
66
|
-
"error",
|
|
67
|
-
"multi-line"
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
68
|
}
|
|
71
69
|
}
|
package/src/engine.d.ts
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/** A digital representation of a Trax game. */
|
|
2
|
+
export class Trax {
|
|
3
|
+
/** @readonly */
|
|
4
|
+
static readonly version: '1.1.1'
|
|
5
|
+
/** @readonly @type {Record<TraxVariant, string>} */
|
|
6
|
+
static readonly names: Record<TraxVariant, string>
|
|
7
|
+
/** @readonly */
|
|
8
|
+
static readonly variants: Set<string>
|
|
9
|
+
/** Create an x,y Point object with special functions.
|
|
10
|
+
* @arg {number|PointLike} x - either the x value, or an object with x,y keys
|
|
11
|
+
* @arg {number} [y] - if x is a number, y must be provided as well
|
|
12
|
+
* @returns {Point} a new Point object
|
|
13
|
+
*/
|
|
14
|
+
static point: (x: number | PointLike, y?: number) => Point
|
|
15
|
+
/** Given a player number, get the color.
|
|
16
|
+
* @arg {number} playerNumber - the player number, 1 or 2
|
|
17
|
+
* @returns {Color} the color of that player, w or b
|
|
18
|
+
*/
|
|
19
|
+
static colorOf: (playerNumber: number) => Color
|
|
20
|
+
/** Given a color, get the player number.
|
|
21
|
+
* @arg {string} color - the color, w or b
|
|
22
|
+
* @returns {number} the player number, 1 or 2
|
|
23
|
+
*/
|
|
24
|
+
static playerNumber: (color: string) => number
|
|
25
|
+
/** Given a color, get the other color.
|
|
26
|
+
* @arg {string} color - the color, w or b
|
|
27
|
+
* @returns {Color} the other color, b or w
|
|
28
|
+
*/
|
|
29
|
+
static other: (color: string) => Color
|
|
30
|
+
/** Encode a numeric column number into the Trax notation column letter.
|
|
31
|
+
* @arg {number} col - the colum number, with 0 just to the left of the tiles
|
|
32
|
+
* @returns {string} the encoded column letter
|
|
33
|
+
*/
|
|
34
|
+
static encodeCol: (col: number) => string
|
|
35
|
+
/** Decode a Trax notation column letter back to a number.
|
|
36
|
+
* @arg {string} col - the Trax column letter
|
|
37
|
+
* @returns {number} the column number
|
|
38
|
+
*/
|
|
39
|
+
static decodeCol: (col: string) => number
|
|
40
|
+
/** Create a new Trax game
|
|
41
|
+
* @arg {TraxVariant} [rules='trax'] - the variant to play
|
|
42
|
+
* @arg {string|string[]} [moves=''] - the initial moves to pre-play
|
|
43
|
+
* @arg {string} [id='trax'] - an id used to differentiate tiles from multiple games
|
|
44
|
+
*/
|
|
45
|
+
constructor(rules?: TraxVariant, moves?: string | string[], id?: string)
|
|
46
|
+
id: string
|
|
47
|
+
rules: TraxVariant
|
|
48
|
+
move: number
|
|
49
|
+
turn: number
|
|
50
|
+
over: boolean
|
|
51
|
+
left: number
|
|
52
|
+
right: number
|
|
53
|
+
top: number
|
|
54
|
+
bottom: number
|
|
55
|
+
notation: string
|
|
56
|
+
/** @type {Record<TileId, Tile>} */
|
|
57
|
+
tiles: Record<TileId, Tile>
|
|
58
|
+
/** @type TileId[] */
|
|
59
|
+
path: TileId[]
|
|
60
|
+
invalid: boolean
|
|
61
|
+
/** Save the current game data to a variable.
|
|
62
|
+
* @returns {SaveState} an opaque save state object
|
|
63
|
+
* @see restore for restoring the state
|
|
64
|
+
*/
|
|
65
|
+
save(): SaveState
|
|
66
|
+
/** Restore a previously saved position.
|
|
67
|
+
* @arg {SaveState} saved - the previously saved state
|
|
68
|
+
* @see save for saving the state
|
|
69
|
+
*/
|
|
70
|
+
restore(saved: SaveState): void
|
|
71
|
+
/** The name of this variant. */
|
|
72
|
+
get name(): string
|
|
73
|
+
/** The number of tiles currently in play. */
|
|
74
|
+
get count(): number
|
|
75
|
+
/** The color of the current player, w or b. */
|
|
76
|
+
get color(): Color
|
|
77
|
+
/** True if the game is over. */
|
|
78
|
+
get gameOver(): boolean
|
|
79
|
+
/** 1 or 2 for a win, 0 for a tie, false if the game is still in progress. */
|
|
80
|
+
get winner(): number | false
|
|
81
|
+
/** Provides the tile ID for the tile at the given location.
|
|
82
|
+
* @arg {PointLike} loc
|
|
83
|
+
* returns {TileId}
|
|
84
|
+
*/
|
|
85
|
+
tileId(loc: PointLike): string
|
|
86
|
+
/** Add a tile to the board. Note that no validity checking is done here,
|
|
87
|
+
* except that invalid tiles are not actually placed on the board, so this
|
|
88
|
+
* should only be called externally.
|
|
89
|
+
* @arg {TileType} type
|
|
90
|
+
* @arg {Point} loc
|
|
91
|
+
* @returns {Tile} the tile placed on the board.
|
|
92
|
+
*/
|
|
93
|
+
addTile(type: TileType, loc: Point): Tile
|
|
94
|
+
/** The type of tile at the given location.
|
|
95
|
+
* @arg {PointLike} loc - the location the tile is in
|
|
96
|
+
* @returns {ValidTiles|undefined} the type of tile, or undefined if no tile
|
|
97
|
+
*/
|
|
98
|
+
tileAt(loc: PointLike): ValidTiles | undefined
|
|
99
|
+
validTile(type: string, loc: Point): type is ValidTiles
|
|
100
|
+
/** Get a list of possible tiles that can be played in this location.
|
|
101
|
+
* @arg {Point} loc - the location to check
|
|
102
|
+
* @arg {string | boolean} s=false - if provided, a direction modifier, '/', '\\', or '+'
|
|
103
|
+
* @returns {TileType[]}
|
|
104
|
+
*/
|
|
105
|
+
possibleTiles(loc: Point, s?: string | boolean): TileType[]
|
|
106
|
+
get height(): number
|
|
107
|
+
get width(): number
|
|
108
|
+
/** Determine if a location is valid to play in.
|
|
109
|
+
* @arg {Point} loc - the location to check
|
|
110
|
+
* @returns {boolean}
|
|
111
|
+
*/
|
|
112
|
+
validLocation(loc: Point): boolean
|
|
113
|
+
/** Find all possible locations to play in. Note that these are not
|
|
114
|
+
* necessarily valid locations, just empty ones that border existing tiles.
|
|
115
|
+
*/
|
|
116
|
+
possibleLocations(): Point[]
|
|
117
|
+
/** Find all possible moves as a list of notations,
|
|
118
|
+
* ie: ['@1+', '@1/', '@1\\', ...]
|
|
119
|
+
*
|
|
120
|
+
* Note that moves are not guaranteed to be valid.
|
|
121
|
+
*/
|
|
122
|
+
possibleMoves(): string[]
|
|
123
|
+
/** Called after a move was just played, to determine the forced moves.
|
|
124
|
+
* @arg {Point} loc - the location just played at
|
|
125
|
+
* @returns {Tile[]} a list of tiles that should be added as part of the move
|
|
126
|
+
*/
|
|
127
|
+
forcedMoves(loc: Point): Tile[]
|
|
128
|
+
/** Determine the notation for a move. Note that this must be determined
|
|
129
|
+
* BEFORE the move is placed on the board.
|
|
130
|
+
* @arg {ValidTiles} type - the tile placed on the board
|
|
131
|
+
* @arg {Point} loc - the location the tile is placed
|
|
132
|
+
* @returns {string} the notation of the move
|
|
133
|
+
*/
|
|
134
|
+
notate(type: ValidTiles, loc: Point): string
|
|
135
|
+
/** Turn a move notation into a tile type and location.
|
|
136
|
+
* @arg {string} notation - a notation for a single move to be played at
|
|
137
|
+
* the current board position
|
|
138
|
+
* @returns {RawMove} the tile type and location of the move
|
|
139
|
+
*/
|
|
140
|
+
decodeNotation(notation: string): RawMove
|
|
141
|
+
/** Follow a color from one location through one or more tiles to the other
|
|
142
|
+
* end of the color line.
|
|
143
|
+
* @arg {Color} color - the color to follow
|
|
144
|
+
* @arg {Point} loc - the location to start
|
|
145
|
+
* @arg {string} from - the edge of the tile to start from
|
|
146
|
+
* @returns {LineEnd} the ending location and a list of the tile ids the path
|
|
147
|
+
* takes to get there.
|
|
148
|
+
*/
|
|
149
|
+
follow(color: Color, loc: Point, from: string): LineEnd
|
|
150
|
+
/** Given a tile and a color, follow the line for that color to each end.
|
|
151
|
+
* @arg {Color} color - the color of ends of interest
|
|
152
|
+
* @arg { Point} loc - the location of the tile of interest
|
|
153
|
+
* @returns {LineEnd[]} a list of two items, each one end of the line
|
|
154
|
+
*/
|
|
155
|
+
findEnds(color: Color, loc: Point): LineEnd[]
|
|
156
|
+
/** Determine if a given line ends the game.
|
|
157
|
+
* @arg {Point} locA - one end of the line
|
|
158
|
+
* @arg {Point} locB - the other end of the line
|
|
159
|
+
* @returns {boolean} - true if this line wins the game
|
|
160
|
+
*/
|
|
161
|
+
lineWin(locA: Point, locB: Point): boolean
|
|
162
|
+
/** Determine if the game has ended.
|
|
163
|
+
* @arg {Tile[]} tiles - a list of the tiles placed during the last move.
|
|
164
|
+
*/
|
|
165
|
+
checkWin(tiles: Tile[]): void
|
|
166
|
+
/** Play a move. Can be called either as:
|
|
167
|
+
* - play(moveNumber, notation) to ensure move safety, or
|
|
168
|
+
* - play(notation) for quicker access.
|
|
169
|
+
* @arg moveNumber {(number|string)} the move number or the notation
|
|
170
|
+
* @arg {string} [notation] - the notation, if a move number was provided
|
|
171
|
+
* @returns {{dropped: Tile[], notation: string, valid: boolean}}
|
|
172
|
+
*/
|
|
173
|
+
play(
|
|
174
|
+
moveNumber: number | string,
|
|
175
|
+
notation?: string,
|
|
176
|
+
): {
|
|
177
|
+
dropped: Tile[]
|
|
178
|
+
notation: string
|
|
179
|
+
valid: boolean
|
|
180
|
+
}
|
|
181
|
+
/** Play one or more moves.
|
|
182
|
+
* @arg {string|string[]} moves - the list of moves, provided either as a
|
|
183
|
+
* space-separated string of notations, or as a list of notations. Move
|
|
184
|
+
* numbers are optional, but if provided will be checked for accuracy.
|
|
185
|
+
*/
|
|
186
|
+
playMoves(moves: string | string[]): void
|
|
187
|
+
/** Add the current move notation to the notation string
|
|
188
|
+
* @arg {string} notation - the notation of the current move
|
|
189
|
+
*/
|
|
190
|
+
updateNotation(notation: string): void
|
|
191
|
+
/** An array of the moves made in the game. */
|
|
192
|
+
get moves(): string[]
|
|
193
|
+
/** Drop a tile onto the board. This is a lower level call. Use play() if possible instead.
|
|
194
|
+
* @arg {string|ValidTiles} type - a special move, a tile type, or a notation
|
|
195
|
+
* @arg {Point} [loc] - a location if type is a tile type
|
|
196
|
+
* @arg {string|boolean} [tentative] - if truthy, the move will not be saved
|
|
197
|
+
* @returns {TileDrop} an object representing the results of the drop
|
|
198
|
+
*/
|
|
199
|
+
dropTile(
|
|
200
|
+
type: string | ValidTiles,
|
|
201
|
+
loc?: Point,
|
|
202
|
+
tentative?: string | boolean,
|
|
203
|
+
): TileDrop
|
|
204
|
+
/** Symmetry helper. Rotates a move around the board in case we are trying to
|
|
205
|
+
* play a symmetrical rather than an exact move.
|
|
206
|
+
* @arg {string} move - the notation of the move to be rotated
|
|
207
|
+
* @returns {string[]} the four rotations of this move
|
|
208
|
+
*/
|
|
209
|
+
moveRotations(move: string): string[]
|
|
210
|
+
/** Play a provisional move if it is valid.
|
|
211
|
+
* @arg {string} from - the normalized encoding of the starting position
|
|
212
|
+
* @arg {string} to - the normalized encoding of the ending position
|
|
213
|
+
* @arg {string} via - the move to be used to transition
|
|
214
|
+
* @returns {false|string} if the provisional move is invalid: false; if the
|
|
215
|
+
* provisional move will never be valid for any future moves:
|
|
216
|
+
* 'delete-provisional'; if the provisional move is valid, the correct
|
|
217
|
+
* notation, which may be symmetrically adjusted as needed
|
|
218
|
+
*/
|
|
219
|
+
provisionalMove(from: string, to: string, via: string): false | string
|
|
220
|
+
/** Get an encoded representation of the current position, useful for drawing
|
|
221
|
+
* the board without having to do much analysis.
|
|
222
|
+
* @returns {string} the current position code
|
|
223
|
+
*/
|
|
224
|
+
get icon(): string
|
|
225
|
+
/** Get an encoded representation of the current position, with a set of
|
|
226
|
+
* tiles highlighted differently, useful for showing the effects of a move.
|
|
227
|
+
* @arg {TileDrop} drops - the drops of the most recent play
|
|
228
|
+
* @returns {string} the current position code, with drops highlighted
|
|
229
|
+
*/
|
|
230
|
+
dropsIcon(drops: TileDrop): string
|
|
231
|
+
/** Symmetry helper, draw the board from different angles.
|
|
232
|
+
* @arg {boolean} [rightToLeft] - reverse order horizontally
|
|
233
|
+
* @arg {boolean} [bottomToTop] - reverse order vertically
|
|
234
|
+
* @arg {boolean} [rotate] - rotate the tiles by 90 degrees
|
|
235
|
+
* @arg {TileDrop} [drops] - the drops of the most recent play, if you want
|
|
236
|
+
* them highlighted
|
|
237
|
+
* @returns {string} an encoding of the position
|
|
238
|
+
*/
|
|
239
|
+
positionCode(
|
|
240
|
+
rightToLeft?: boolean,
|
|
241
|
+
bottomToTop?: boolean,
|
|
242
|
+
rotate?: boolean,
|
|
243
|
+
drops?: TileDrop,
|
|
244
|
+
): string
|
|
245
|
+
/** Trax has the potential for symmetry, so this gives us the ability to
|
|
246
|
+
* examine horizontal, vertical, and rotational symmetry for a color.
|
|
247
|
+
* @returns {string} a position code that matches all symmetrical positions
|
|
248
|
+
*/
|
|
249
|
+
normalize(): string
|
|
250
|
+
/** Get the normalized code for this position. All symmetrical positions will
|
|
251
|
+
* result in the same normalized code.
|
|
252
|
+
*/
|
|
253
|
+
get normalized(): string
|
|
254
|
+
}
|
|
255
|
+
export type Color = 'w' | 'b'
|
|
256
|
+
/**
|
|
257
|
+
* One end of a line and the tiles taken to get there.
|
|
258
|
+
*/
|
|
259
|
+
export type LineEnd = {
|
|
260
|
+
loc: Point
|
|
261
|
+
path: TileId[]
|
|
262
|
+
}
|
|
263
|
+
export type Notation = string
|
|
264
|
+
/**
|
|
265
|
+
* A tile type and a location determine a raw move.
|
|
266
|
+
*/
|
|
267
|
+
export type RawMove = {
|
|
268
|
+
type: TileType
|
|
269
|
+
loc: Point
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Treat the save state as an opaque object,
|
|
273
|
+
* produced by save() and fed into restore().
|
|
274
|
+
*/
|
|
275
|
+
export type SaveState = {
|
|
276
|
+
id: string
|
|
277
|
+
move: number
|
|
278
|
+
turn: number
|
|
279
|
+
over: boolean
|
|
280
|
+
left: number
|
|
281
|
+
right: number
|
|
282
|
+
top: number
|
|
283
|
+
bottom: number
|
|
284
|
+
notation: Notation
|
|
285
|
+
tiles: string
|
|
286
|
+
path: string
|
|
287
|
+
invalid: boolean
|
|
288
|
+
}
|
|
289
|
+
export type Slash = '/' | '\\' | '+'
|
|
290
|
+
/**
|
|
291
|
+
* A single tile on the board.
|
|
292
|
+
*/
|
|
293
|
+
export type Tile = {
|
|
294
|
+
id: TileId
|
|
295
|
+
loc: Point
|
|
296
|
+
type: TileType
|
|
297
|
+
move: number
|
|
298
|
+
seq: number
|
|
299
|
+
}
|
|
300
|
+
export type TileId = string
|
|
301
|
+
/**
|
|
302
|
+
* When a tile is dropped, this object represents the results.
|
|
303
|
+
*/
|
|
304
|
+
export type TileDrop = {
|
|
305
|
+
dropped: Tile[]
|
|
306
|
+
notation: Notation
|
|
307
|
+
valid: boolean
|
|
308
|
+
}
|
|
309
|
+
export type TileType = ValidTiles | 'x'
|
|
310
|
+
export type TraxVariant = 'trax' | 'traxloop' | 'trax8'
|
|
311
|
+
export type ValidTiles = 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
|
|
312
|
+
import type { PointLike } from '@slugbugblue/point'
|
|
313
|
+
import { Point } from '@slugbugblue/point'
|
package/src/engine.js
CHANGED
|
@@ -4,9 +4,82 @@
|
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/** @import { PointLike } from '@slugbugblue/point' */
|
|
9
8
|
import { Point } from '@slugbugblue/point'
|
|
9
|
+
import { version } from './version.js'
|
|
10
|
+
|
|
11
|
+
// Type definitions
|
|
12
|
+
|
|
13
|
+
/** Color is a single character to represent white or black. */
|
|
14
|
+
/** @typedef {'w' | 'b'} Color */
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* One end of a line and the tiles taken to get there.
|
|
18
|
+
* @typedef {Object} LineEnd
|
|
19
|
+
* @property {Point} loc
|
|
20
|
+
* @property {TileId[]} path
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** A notation of a move. */
|
|
24
|
+
/** @typedef {string} Notation */
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A tile type and a location determine a raw move.
|
|
28
|
+
* @typedef {Object} RawMove
|
|
29
|
+
* @property {TileType} type
|
|
30
|
+
* @property {Point} loc
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Treat the save state as an opaque object,
|
|
35
|
+
* produced by save() and fed into restore().
|
|
36
|
+
* @typedef {Object} SaveState
|
|
37
|
+
* @property {string} id
|
|
38
|
+
* @property {number} move
|
|
39
|
+
* @property {number} turn
|
|
40
|
+
* @property {boolean} over
|
|
41
|
+
* @property {number} left
|
|
42
|
+
* @property {number} right
|
|
43
|
+
* @property {number} top
|
|
44
|
+
* @property {number} bottom
|
|
45
|
+
* @property {Notation} notation
|
|
46
|
+
* @property {string} tiles
|
|
47
|
+
* @property {string} path
|
|
48
|
+
* @property {boolean} invalid
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/** Representations of the different ways a tile can curve. */
|
|
52
|
+
/** @typedef {'/' | '\\' | '+'} Slash */
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A single tile on the board.
|
|
56
|
+
* @typedef {Object} Tile
|
|
57
|
+
* @property {TileId} id
|
|
58
|
+
* @property {Point} loc
|
|
59
|
+
* @property {TileType} type
|
|
60
|
+
* @property {number} move
|
|
61
|
+
* @property {number} seq
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/** A TileId is just a string. */
|
|
65
|
+
/** @typedef {string} TileId */
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* When a tile is dropped, this object represents the results.
|
|
69
|
+
* @typedef {Object} TileDrop
|
|
70
|
+
* @property {Tile[]} dropped
|
|
71
|
+
* @property {Notation} notation
|
|
72
|
+
* @property {boolean} valid
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/** Invalid tiles are represented by 'x'. */
|
|
76
|
+
/** @typedef {ValidTiles | 'x'} TileType */
|
|
77
|
+
|
|
78
|
+
/** All of the variants supported by the engine. */
|
|
79
|
+
/** @typedef {'trax' | 'traxloop' | 'trax8'} TraxVariant */
|
|
80
|
+
|
|
81
|
+
/** Tile type names are single letters a-f encoding edge colors. */
|
|
82
|
+
/** @typedef {'a' | 'b' | 'c' | 'd' | 'e' | 'f'} ValidTiles */
|
|
10
83
|
|
|
11
84
|
// Fun trax helper constants
|
|
12
85
|
|
|
@@ -50,11 +123,11 @@ const symmetry = {
|
|
|
50
123
|
// Fun trax helper functions
|
|
51
124
|
|
|
52
125
|
/** Apply certain combinations of symmetry.
|
|
53
|
-
* @arg {
|
|
126
|
+
* @arg {ValidTiles} tile - the tile to apply symmetry to
|
|
54
127
|
* @arg {boolean} [rightToLeft] - mirror the tile
|
|
55
128
|
* @arg {boolean} [bottomToTop] - flip the tile
|
|
56
129
|
* @arg {boolean} [rotate] - rotate the tile counterclockwise
|
|
57
|
-
* @returns {
|
|
130
|
+
* @returns {ValidTiles}
|
|
58
131
|
*/
|
|
59
132
|
const applySymmetry = (tile, rightToLeft, bottomToTop, rotate) => {
|
|
60
133
|
if (rightToLeft) tile = symmetry.mirror[tile]
|
|
@@ -63,34 +136,35 @@ const applySymmetry = (tile, rightToLeft, bottomToTop, rotate) => {
|
|
|
63
136
|
return tile
|
|
64
137
|
}
|
|
65
138
|
|
|
66
|
-
//
|
|
139
|
+
// Note: String(undefined) === 'undefined', which is never a valid tile letter,
|
|
140
|
+
// so these functions correctly return false when t is undefined.
|
|
67
141
|
/** The color at the top of the tile.
|
|
68
|
-
* @arg {string} t - the tile to check
|
|
142
|
+
* @arg {string | undefined} t - the tile to check
|
|
69
143
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
70
144
|
*/
|
|
71
145
|
const upColor = (t) =>
|
|
72
|
-
'abc'.includes(t) ? 'b' : 'def'.includes(t) ? 'w' : false
|
|
146
|
+
'abc'.includes(String(t)) ? 'b' : 'def'.includes(String(t)) ? 'w' : false
|
|
73
147
|
|
|
74
148
|
/** The color at the bottom of the tile.
|
|
75
|
-
* @arg {string} t - the tile to check
|
|
149
|
+
* @arg {string | undefined} t - the tile to check
|
|
76
150
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
77
151
|
*/
|
|
78
152
|
const downColor = (t) =>
|
|
79
|
-
'bdf'.includes(t) ? 'b' : 'ace'.includes(t) ? 'w' : false
|
|
153
|
+
'bdf'.includes(String(t)) ? 'b' : 'ace'.includes(String(t)) ? 'w' : false
|
|
80
154
|
|
|
81
155
|
/** The color at the right edge of the tile.
|
|
82
|
-
* @arg {string} t - the tile to check
|
|
156
|
+
* @arg {string | undefined} t - the tile to check
|
|
83
157
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
84
158
|
*/
|
|
85
159
|
const rightColor = (t) =>
|
|
86
|
-
'ade'.includes(t) ? 'b' : 'bcf'.includes(t) ? 'w' : false
|
|
160
|
+
'ade'.includes(String(t)) ? 'b' : 'bcf'.includes(String(t)) ? 'w' : false
|
|
87
161
|
|
|
88
162
|
/** The color at the left edge of the tile.
|
|
89
|
-
* @arg {string} t - the tile to check
|
|
163
|
+
* @arg {string | undefined} t - the tile to check
|
|
90
164
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
91
165
|
*/
|
|
92
166
|
const leftColor = (t) =>
|
|
93
|
-
'cef'.includes(t) ? 'b' : 'abd'.includes(t) ? 'w' : false
|
|
167
|
+
'cef'.includes(String(t)) ? 'b' : 'abd'.includes(String(t)) ? 'w' : false
|
|
94
168
|
|
|
95
169
|
/** Add an empty space to the position encoding string.
|
|
96
170
|
* @arg {string} code - The position encoding string
|
|
@@ -98,7 +172,7 @@ const leftColor = (t) =>
|
|
|
98
172
|
*/
|
|
99
173
|
const addBlank = (code) => {
|
|
100
174
|
// Encode missing tiles as digits 0-9, for 1-10 missing
|
|
101
|
-
const lastNumber = code.codePointAt(code.length - 1) //
|
|
175
|
+
const lastNumber = /** @type {number} */ (code.codePointAt(code.length - 1)) // Undefined if code is empty, which is ok
|
|
102
176
|
if (lastNumber > 47 && lastNumber < 57) {
|
|
103
177
|
return code.slice(0, -1) + String.fromCodePoint(lastNumber + 1)
|
|
104
178
|
}
|
|
@@ -118,6 +192,8 @@ const codeRowLength = (row) =>
|
|
|
118
192
|
/** A digital representation of a Trax game. */
|
|
119
193
|
export class Trax {
|
|
120
194
|
// Static class properties
|
|
195
|
+
/** @readonly */
|
|
196
|
+
static version = version
|
|
121
197
|
/** @readonly @type {Record<TraxVariant, string>} */
|
|
122
198
|
static names = {
|
|
123
199
|
trax: 'Trax',
|
|
@@ -137,17 +213,29 @@ export class Trax {
|
|
|
137
213
|
* @arg {number} playerNumber - the player number, 1 or 2
|
|
138
214
|
* @returns {Color} the color of that player, w or b
|
|
139
215
|
*/
|
|
140
|
-
static colorOf = (playerNumber) =>
|
|
216
|
+
static colorOf = (playerNumber) => {
|
|
217
|
+
/** @type {Record<number, Color>} */
|
|
218
|
+
const map = { 1: 'w', 2: 'b' }
|
|
219
|
+
return map[playerNumber]
|
|
220
|
+
}
|
|
141
221
|
/** Given a color, get the player number.
|
|
142
222
|
* @arg {string} color - the color, w or b
|
|
143
223
|
* @returns {number} the player number, 1 or 2
|
|
144
224
|
*/
|
|
145
|
-
static playerNumber = (color) =>
|
|
225
|
+
static playerNumber = (color) => {
|
|
226
|
+
/** @type {Record<string, number>} */
|
|
227
|
+
const map = { b: 2, w: 1 }
|
|
228
|
+
return map[color]
|
|
229
|
+
}
|
|
146
230
|
/** Given a color, get the other color.
|
|
147
231
|
* @arg {string} color - the color, w or b
|
|
148
232
|
* @returns {Color} the other color, b or w
|
|
149
233
|
*/
|
|
150
|
-
static other = (color) =>
|
|
234
|
+
static other = (color) => {
|
|
235
|
+
/** @type {Record<string, Color>} */
|
|
236
|
+
const map = { b: 'w', w: 'b' }
|
|
237
|
+
return map[color]
|
|
238
|
+
}
|
|
151
239
|
/** Encode a numeric column number into the Trax notation column letter.
|
|
152
240
|
* @arg {number} col - the colum number, with 0 just to the left of the tiles
|
|
153
241
|
* @returns {string} the encoded column letter
|
|
@@ -171,7 +259,8 @@ export class Trax {
|
|
|
171
259
|
col = col.toUpperCase()
|
|
172
260
|
let n = 0
|
|
173
261
|
while (col.length > 0) {
|
|
174
|
-
|
|
262
|
+
const cp = /** @type {number} */ (col.codePointAt(0))
|
|
263
|
+
n += (cp - 64) * 26 ** (col.length - 1)
|
|
175
264
|
col = col.slice(1)
|
|
176
265
|
}
|
|
177
266
|
|
|
@@ -312,10 +401,12 @@ export class Trax {
|
|
|
312
401
|
|
|
313
402
|
/** The type of tile at the given location.
|
|
314
403
|
* @arg {PointLike} loc - the location the tile is in
|
|
315
|
-
* @returns {
|
|
404
|
+
* @returns {ValidTiles|undefined} the type of tile, or undefined if no tile
|
|
316
405
|
*/
|
|
317
406
|
tileAt(loc) {
|
|
318
|
-
return
|
|
407
|
+
return /** @type {ValidTiles | undefined} */ (
|
|
408
|
+
(this.tiles[this.tileId(loc)] || {}).type
|
|
409
|
+
)
|
|
319
410
|
}
|
|
320
411
|
|
|
321
412
|
/** Is this tile valid?
|
|
@@ -435,7 +526,7 @@ export class Trax {
|
|
|
435
526
|
const invalids = {}
|
|
436
527
|
let check = loc.around
|
|
437
528
|
while (check.length > 0) {
|
|
438
|
-
const pos = check.shift()
|
|
529
|
+
const pos = /** @type {Point} */ (check.shift())
|
|
439
530
|
if (this.validLocation(pos)) {
|
|
440
531
|
const possibles = this.possibleTiles(pos)
|
|
441
532
|
if (possibles.length === 1) {
|
|
@@ -495,6 +586,7 @@ export class Trax {
|
|
|
495
586
|
* takes to get there.
|
|
496
587
|
*/
|
|
497
588
|
follow(color, loc, from) {
|
|
589
|
+
/** @type {TileId[]} */
|
|
498
590
|
const path = []
|
|
499
591
|
let id = this.tileId(loc)
|
|
500
592
|
let tile = this.tileAt(loc)
|
|
@@ -820,7 +912,9 @@ export class Trax {
|
|
|
820
912
|
/** @type string */
|
|
821
913
|
let encoded = applySymmetry(tile, rightToLeft, bottomToTop, rotate)
|
|
822
914
|
if (this.path.includes(this.tileId(loc))) {
|
|
823
|
-
encoded = String.fromCodePoint(
|
|
915
|
+
encoded = String.fromCodePoint(
|
|
916
|
+
/** @type {number} */ (encoded.codePointAt(0)) + this.turn * 6,
|
|
917
|
+
)
|
|
824
918
|
}
|
|
825
919
|
|
|
826
920
|
if (
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '1.
|
|
2
|
+
export const version = '1.1.1'
|