@slugbugblue/trax 1.1.0 → 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 +13 -18
- package/src/engine.d.ts +313 -0
- package/src/engine.js +113 -22
- 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
|
@@ -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.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Trax game engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"trax",
|
|
@@ -11,9 +11,13 @@
|
|
|
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
|
},
|
|
@@ -23,11 +27,12 @@
|
|
|
23
27
|
},
|
|
24
28
|
"scripts": {
|
|
25
29
|
"genversion": "genversion --esm src/version.js",
|
|
26
|
-
"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",
|
|
27
32
|
"test": "xo && c8 ava",
|
|
28
33
|
"prepare": "[ -n \"$CI\" ] || husky",
|
|
29
|
-
"preversion": "npm test",
|
|
30
|
-
"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",
|
|
31
36
|
"postversion": "git push && git push --tags"
|
|
32
37
|
},
|
|
33
38
|
"dependencies": {
|
|
@@ -35,8 +40,8 @@
|
|
|
35
40
|
"@slugbugblue/point": "^1.0.0"
|
|
36
41
|
},
|
|
37
42
|
"devDependencies": {
|
|
38
|
-
"ava": "^
|
|
39
|
-
"c8": "^
|
|
43
|
+
"ava": "^7.0.0",
|
|
44
|
+
"c8": "^11.0.0",
|
|
40
45
|
"genversion": "^3.0.2",
|
|
41
46
|
"husky": "^9.1.7",
|
|
42
47
|
"prettier": "^3.6.2",
|
|
@@ -60,15 +65,5 @@
|
|
|
60
65
|
"singleQuote": true,
|
|
61
66
|
"trailingComma": "all",
|
|
62
67
|
"useTabs": false
|
|
63
|
-
},
|
|
64
|
-
"xo": {
|
|
65
|
-
"prettier": true,
|
|
66
|
-
"space": true,
|
|
67
|
-
"rules": {
|
|
68
|
-
"curly": [
|
|
69
|
-
"error",
|
|
70
|
-
"multi-line"
|
|
71
|
-
]
|
|
72
|
-
}
|
|
73
68
|
}
|
|
74
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,11 +4,83 @@
|
|
|
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'
|
|
10
9
|
import { version } from './version.js'
|
|
11
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 */
|
|
83
|
+
|
|
12
84
|
// Fun trax helper constants
|
|
13
85
|
|
|
14
86
|
const zero = new Point(0, 0)
|
|
@@ -51,11 +123,11 @@ const symmetry = {
|
|
|
51
123
|
// Fun trax helper functions
|
|
52
124
|
|
|
53
125
|
/** Apply certain combinations of symmetry.
|
|
54
|
-
* @arg {
|
|
126
|
+
* @arg {ValidTiles} tile - the tile to apply symmetry to
|
|
55
127
|
* @arg {boolean} [rightToLeft] - mirror the tile
|
|
56
128
|
* @arg {boolean} [bottomToTop] - flip the tile
|
|
57
129
|
* @arg {boolean} [rotate] - rotate the tile counterclockwise
|
|
58
|
-
* @returns {
|
|
130
|
+
* @returns {ValidTiles}
|
|
59
131
|
*/
|
|
60
132
|
const applySymmetry = (tile, rightToLeft, bottomToTop, rotate) => {
|
|
61
133
|
if (rightToLeft) tile = symmetry.mirror[tile]
|
|
@@ -64,34 +136,35 @@ const applySymmetry = (tile, rightToLeft, bottomToTop, rotate) => {
|
|
|
64
136
|
return tile
|
|
65
137
|
}
|
|
66
138
|
|
|
67
|
-
//
|
|
139
|
+
// Note: String(undefined) === 'undefined', which is never a valid tile letter,
|
|
140
|
+
// so these functions correctly return false when t is undefined.
|
|
68
141
|
/** The color at the top of the tile.
|
|
69
|
-
* @arg {string} t - the tile to check
|
|
142
|
+
* @arg {string | undefined} t - the tile to check
|
|
70
143
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
71
144
|
*/
|
|
72
145
|
const upColor = (t) =>
|
|
73
|
-
'abc'.includes(t) ? 'b' : 'def'.includes(t) ? 'w' : false
|
|
146
|
+
'abc'.includes(String(t)) ? 'b' : 'def'.includes(String(t)) ? 'w' : false
|
|
74
147
|
|
|
75
148
|
/** The color at the bottom of the tile.
|
|
76
|
-
* @arg {string} t - the tile to check
|
|
149
|
+
* @arg {string | undefined} t - the tile to check
|
|
77
150
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
78
151
|
*/
|
|
79
152
|
const downColor = (t) =>
|
|
80
|
-
'bdf'.includes(t) ? 'b' : 'ace'.includes(t) ? 'w' : false
|
|
153
|
+
'bdf'.includes(String(t)) ? 'b' : 'ace'.includes(String(t)) ? 'w' : false
|
|
81
154
|
|
|
82
155
|
/** The color at the right edge of the tile.
|
|
83
|
-
* @arg {string} t - the tile to check
|
|
156
|
+
* @arg {string | undefined} t - the tile to check
|
|
84
157
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
85
158
|
*/
|
|
86
159
|
const rightColor = (t) =>
|
|
87
|
-
'ade'.includes(t) ? 'b' : 'bcf'.includes(t) ? 'w' : false
|
|
160
|
+
'ade'.includes(String(t)) ? 'b' : 'bcf'.includes(String(t)) ? 'w' : false
|
|
88
161
|
|
|
89
162
|
/** The color at the left edge of the tile.
|
|
90
|
-
* @arg {string} t - the tile to check
|
|
163
|
+
* @arg {string | undefined} t - the tile to check
|
|
91
164
|
* @returns {Color|false} the color or false if t is not a valid tile
|
|
92
165
|
*/
|
|
93
166
|
const leftColor = (t) =>
|
|
94
|
-
'cef'.includes(t) ? 'b' : 'abd'.includes(t) ? 'w' : false
|
|
167
|
+
'cef'.includes(String(t)) ? 'b' : 'abd'.includes(String(t)) ? 'w' : false
|
|
95
168
|
|
|
96
169
|
/** Add an empty space to the position encoding string.
|
|
97
170
|
* @arg {string} code - The position encoding string
|
|
@@ -99,7 +172,7 @@ const leftColor = (t) =>
|
|
|
99
172
|
*/
|
|
100
173
|
const addBlank = (code) => {
|
|
101
174
|
// Encode missing tiles as digits 0-9, for 1-10 missing
|
|
102
|
-
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
|
|
103
176
|
if (lastNumber > 47 && lastNumber < 57) {
|
|
104
177
|
return code.slice(0, -1) + String.fromCodePoint(lastNumber + 1)
|
|
105
178
|
}
|
|
@@ -140,17 +213,29 @@ export class Trax {
|
|
|
140
213
|
* @arg {number} playerNumber - the player number, 1 or 2
|
|
141
214
|
* @returns {Color} the color of that player, w or b
|
|
142
215
|
*/
|
|
143
|
-
static colorOf = (playerNumber) =>
|
|
216
|
+
static colorOf = (playerNumber) => {
|
|
217
|
+
/** @type {Record<number, Color>} */
|
|
218
|
+
const map = { 1: 'w', 2: 'b' }
|
|
219
|
+
return map[playerNumber]
|
|
220
|
+
}
|
|
144
221
|
/** Given a color, get the player number.
|
|
145
222
|
* @arg {string} color - the color, w or b
|
|
146
223
|
* @returns {number} the player number, 1 or 2
|
|
147
224
|
*/
|
|
148
|
-
static playerNumber = (color) =>
|
|
225
|
+
static playerNumber = (color) => {
|
|
226
|
+
/** @type {Record<string, number>} */
|
|
227
|
+
const map = { b: 2, w: 1 }
|
|
228
|
+
return map[color]
|
|
229
|
+
}
|
|
149
230
|
/** Given a color, get the other color.
|
|
150
231
|
* @arg {string} color - the color, w or b
|
|
151
232
|
* @returns {Color} the other color, b or w
|
|
152
233
|
*/
|
|
153
|
-
static other = (color) =>
|
|
234
|
+
static other = (color) => {
|
|
235
|
+
/** @type {Record<string, Color>} */
|
|
236
|
+
const map = { b: 'w', w: 'b' }
|
|
237
|
+
return map[color]
|
|
238
|
+
}
|
|
154
239
|
/** Encode a numeric column number into the Trax notation column letter.
|
|
155
240
|
* @arg {number} col - the colum number, with 0 just to the left of the tiles
|
|
156
241
|
* @returns {string} the encoded column letter
|
|
@@ -174,7 +259,8 @@ export class Trax {
|
|
|
174
259
|
col = col.toUpperCase()
|
|
175
260
|
let n = 0
|
|
176
261
|
while (col.length > 0) {
|
|
177
|
-
|
|
262
|
+
const cp = /** @type {number} */ (col.codePointAt(0))
|
|
263
|
+
n += (cp - 64) * 26 ** (col.length - 1)
|
|
178
264
|
col = col.slice(1)
|
|
179
265
|
}
|
|
180
266
|
|
|
@@ -315,10 +401,12 @@ export class Trax {
|
|
|
315
401
|
|
|
316
402
|
/** The type of tile at the given location.
|
|
317
403
|
* @arg {PointLike} loc - the location the tile is in
|
|
318
|
-
* @returns {
|
|
404
|
+
* @returns {ValidTiles|undefined} the type of tile, or undefined if no tile
|
|
319
405
|
*/
|
|
320
406
|
tileAt(loc) {
|
|
321
|
-
return
|
|
407
|
+
return /** @type {ValidTiles | undefined} */ (
|
|
408
|
+
(this.tiles[this.tileId(loc)] || {}).type
|
|
409
|
+
)
|
|
322
410
|
}
|
|
323
411
|
|
|
324
412
|
/** Is this tile valid?
|
|
@@ -438,7 +526,7 @@ export class Trax {
|
|
|
438
526
|
const invalids = {}
|
|
439
527
|
let check = loc.around
|
|
440
528
|
while (check.length > 0) {
|
|
441
|
-
const pos = check.shift()
|
|
529
|
+
const pos = /** @type {Point} */ (check.shift())
|
|
442
530
|
if (this.validLocation(pos)) {
|
|
443
531
|
const possibles = this.possibleTiles(pos)
|
|
444
532
|
if (possibles.length === 1) {
|
|
@@ -498,6 +586,7 @@ export class Trax {
|
|
|
498
586
|
* takes to get there.
|
|
499
587
|
*/
|
|
500
588
|
follow(color, loc, from) {
|
|
589
|
+
/** @type {TileId[]} */
|
|
501
590
|
const path = []
|
|
502
591
|
let id = this.tileId(loc)
|
|
503
592
|
let tile = this.tileAt(loc)
|
|
@@ -823,7 +912,9 @@ export class Trax {
|
|
|
823
912
|
/** @type string */
|
|
824
913
|
let encoded = applySymmetry(tile, rightToLeft, bottomToTop, rotate)
|
|
825
914
|
if (this.path.includes(this.tileId(loc))) {
|
|
826
|
-
encoded = String.fromCodePoint(
|
|
915
|
+
encoded = String.fromCodePoint(
|
|
916
|
+
/** @type {number} */ (encoded.codePointAt(0)) + this.turn * 6,
|
|
917
|
+
)
|
|
827
918
|
}
|
|
828
919
|
|
|
829
920
|
if (
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '1.1.
|
|
2
|
+
export const version = '1.1.1'
|