@slugbugblue/trax 0.3.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,34 +1,70 @@
1
1
  # @slugbugblue/trax
2
2
 
3
- ## 0.3.0
3
+ ## 0.7.0 - 2022-03-28
4
+
5
+ - Fixed a bug when including extra characters in a starting notation
6
+ - Added regression tests to detect/prevent this bug in the future
7
+
8
+ ## 0.6.0 - 2022-02-13
9
+
10
+ - Completed documentation for `engine.js` at [docs/engine.md](docs/engine.md)
11
+ - `x` and `y` locations are now handled in a `Point` class
12
+ - Renamed `tentativeIcon()` to `dropsIcon()`
13
+
14
+ ## 0.5.0 - 2022-01-29
15
+
16
+ This code base is now using [`xo`](https://github.com/xojs/xo) for style and
17
+ [`ava`](https://github.com/avajs/ava) for testing. Should be no functional
18
+ changes, but a lot of code was updated, including the names of all functions and
19
+ variables from snake_case to camelCase.
20
+
21
+ ## 0.4.0 - 2022-01-17
22
+
23
+ - Testing coverage of `engine.js` is now at 100%
24
+ - Testing revealed a few bugs, which are now fixed
25
+ - The name and signature for provisional move handling, which was broken, has
26
+ been changed. It is now called `provisional_moves()` and takes three
27
+ arguments:
28
+
29
+ - `from`: the normalized position code of the board before the move
30
+ - `to`: the normalized position code of the board after the move
31
+ - `via`: the move notation to go from `from` to `to`
32
+
33
+ ### 0.3.1 - 2022-01-07
34
+
35
+ - Make a faster implementation of `trax.possible_locations()`
36
+ - Display updates for tentative moves
37
+
38
+ ## 0.3.0 - 2021-12-29
4
39
 
5
40
  Display a tentative move on the screen
6
41
 
7
- * Add `trax.tentative_icon()` function
8
- * `tty.display()` now accepts a tentative move
42
+ - Add `trax.tentative_icon()` function
43
+ - `tty.display()` now accepts a tentative move
9
44
 
10
- ## 0.2.0
45
+ ## 0.2.0 - 2021-12-28
11
46
 
12
47
  Breaking changes:
13
48
 
14
- * Converted from CommonJS to ESM
15
- * `trax.normalized` now prepends turn information to the string
49
+ - Converted from CommonJS to ESM
50
+ - `trax.normalized` now prepends turn information to the string
16
51
 
17
52
  More convenience:
18
53
 
19
- * `trax.color`: the color of the player whose turn it is
20
- * `Trax.color_of[num]`: go from player number to color
21
- * `Trax.player_num[color]`: or from color to player number
22
- * `Trax.other[color]`: easily switch from 'w' to 'b' and back
54
+ - `trax.color`: the color of the player whose turn it is
55
+ - `Trax.color_of[num]`: go from player number to color
56
+ - `Trax.player_num[color]`: or from color to player number
57
+ - `Trax.other[color]`: easily switch from 'w' to 'b' and back
23
58
 
24
- ## 0.1.0
59
+ ## 0.1.0 - 2021-12-26
25
60
 
26
61
  Initial release:
27
62
 
28
- * engine.js
29
- * create a new Trax game with `trax = new Trax()`
30
- * play one move at a time with `trax.play('@0/')`
31
- * ... etc
63
+ - engine.js
64
+
65
+ - create a new Trax game with `trax = new Trax()`
66
+ - play one move at a time with `trax.play('@0/')`
67
+ - ... etc
32
68
 
33
- * tty.js
34
- * display a game with `tty.display(trax)`
69
+ - tty.js
70
+ - display a game with `tty.display(trax)`
package/README.md CHANGED
@@ -4,15 +4,15 @@ Trax game-playing engine and etc.
4
4
 
5
5
  ## Description
6
6
 
7
- Trax is a two-player boardless board game invented by David Smith.
8
- For more information about Trax,
9
- including its rules and history,
10
- see the official website at [traxgame.com][traxgame].
7
+ Trax is a two-player boardless board game invented by David Smith. For more
8
+ information about Trax, including its rules and history, see the official
9
+ website at [traxgame.com][traxgame].
11
10
 
12
- This goal of this javascript project
13
- is to allow Trax to be played programmatically.
14
- It can be used as an engine in a web browser
15
- or in nodejs.
11
+ This goal of this javascript project is to allow Trax to be played
12
+ programmatically. It can be used as an engine in a web browser or in nodejs.
13
+
14
+ The Trax engine now enjoys automated testing with 100% code coverage. Any future
15
+ changes to the engine should meet the same standard.
16
16
 
17
17
  ## Installation
18
18
 
@@ -22,11 +22,10 @@ npm install @slugbugblue/trax
22
22
 
23
23
  ## Usage
24
24
 
25
- The main Trax engine is provided as `engine.js`,
26
- which can be used as follows:
25
+ The main Trax engine is provided as `engine.js`, which can be used as follows:
27
26
 
28
27
  ```javascript
29
- import Trax from '@slugbugblue/trax'
28
+ import { Trax } from '@slugbugblue/trax'
30
29
 
31
30
  // default constructor gives you a Trax game
32
31
  let trax = new Trax()
@@ -43,88 +42,67 @@ let puzzle = new Trax('trax', '@0/ a0\\ @2/')
43
42
  puzzle.play('@2\\')
44
43
  ```
45
44
 
46
- Explore the file `engine.js` for more information
47
- until I get around to documenting the functionality.
45
+ For specifics, see the [engine.js documentation][engine-docs].
48
46
 
49
47
  ## Roadmap
50
48
 
51
- * Documentation
52
- * Test suite
53
- * Command line interface
54
- * Bot for solo games (?)
55
- * Puzzles
49
+ - Command line interface
50
+ - Bot for solo games (?)
51
+ - Puzzles
56
52
 
57
53
  ## Support
58
54
 
59
- This project is built by [Chad Transtrum][ctrans]
60
- for [slugbugblue.com][sbb].
61
- Issues can be opened on the
62
- [gitlab project page][repo].
55
+ This project is built by [Chad Transtrum][ctrans] for [slugbugblue.com][sbb].
56
+ Issues can be opened on the [gitlab project page][repo].
63
57
 
64
58
  ## Contributing
65
59
 
66
- Contributions are welcome.
67
- Ideally in the form of pull requests,
68
- but feel free to open an issue with a bug report
69
- or a suggestion as well.
70
-
71
- ## Authors and acknowledgment
72
-
73
- Many thanks to the late David Smith
74
- for coming up with the idea of Trax
75
- and for his generosity in allowing me to
76
- add the game to [GoldToken.com][goldtoken].
77
-
78
- Thanks to his widow Colleen Foley-Smith
79
- for extending that courtesy
80
- to allow me to include Trax on [slugbugblue.com][sbb]
81
- as well.
82
-
83
- I would also like to extend a huge heartfelt appreciation
84
- to the magnanimous [Donald G. Bailey][dgb],
85
- who, through his excellent [book][traxbook],
86
- taught me the basics (and more!) of Trax.
87
- I found him always ready to share his insights
88
- on the mechanics of the game,
89
- as well as various approaches to encoding its complexities.
90
- His undeserved kindness
91
- and infinite patience
92
- in indulging my many questions
93
- can never be repaid.
60
+ Contributions are welcome. Ideally in the form of pull requests, but feel free
61
+ to open an issue with a bug report or a suggestion as well.
62
+
63
+ ## Acknowledgments
64
+
65
+ Many thanks to the late David Smith for coming up with the idea of Trax and for
66
+ his generosity in allowing me to add the game to [GoldToken.com][goldtoken].
67
+
68
+ Thanks to his widow Colleen Foley-Smith for extending that courtesy to allow me
69
+ to include Trax on [slugbugblue.com][sbb] as well.
70
+
71
+ I would also like to extend a huge heartfelt appreciation to the magnanimous
72
+ [Donald G. Bailey][dgb], who, through his excellent [book][traxbook], taught me
73
+ the basics (and more!) of Trax. I found him always ready to share his insights
74
+ on the mechanics of the game, as well as various approaches to encoding its
75
+ complexities. His undeserved kindness and infinite patience in indulging my many
76
+ questions can never be repaid.
94
77
 
95
78
  ## License
96
79
 
97
- Copyright 2021 Chad Transtrum
80
+ Copyright 2019-2022 Chad Transtrum
98
81
 
99
- Licensed under the Apache License, Version 2.0 (the "License");
100
- you may not use the files in this project
101
- except in compliance with the License.
102
- You may obtain a copy of the License at
82
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
83
+ the files in this project except in compliance with the License. You may obtain
84
+ a copy of the License at
103
85
 
104
- http://www.apache.org/licenses/LICENSE-2.0
86
+ http://www.apache.org/licenses/LICENSE-2.0
105
87
 
106
- Unless required by applicable law or agreed to in writing, software
107
- distributed under the License is distributed on an "AS IS" BASIS,
108
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
109
- See the License for the specific language governing permissions and
110
- limitations under the License.
88
+ Unless required by applicable law or agreed to in writing, software distributed
89
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
90
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
91
+ specific language governing permissions and limitations under the License.
111
92
 
112
93
  ## Trax rules copyright
113
94
 
114
- In the United States, game mechanics may not be copyrighted;
95
+ In the United States, game mechanics are not eligible for coyright protection;
115
96
  however, the specific wording of game rules does fall under copyright law.
116
97
 
117
98
  The official rules for Trax are found at http://traxgame.com/about_rules.php.
118
99
 
119
- As Trax is a proprietary game,
120
- these rules are the intellectual property
121
- of David Smith and heirs,
122
- and are not to be used without permission.
123
-
124
-
100
+ As Trax is a proprietary game, these rules are the intellectual property of
101
+ David Smith and heirs, and are not to be used without permission.
125
102
 
126
103
  [ctrans]: mailto:chad@transtrum.net
127
104
  [dgb]: mailto:donald@traxgame.com
105
+ [engine-docs]: docs/engine.md
128
106
  [goldtoken]: https://goldtoken.com/
129
107
  [repo]: https://gitlab.com/slugbugblue/trax
130
108
  [sbb]: https://slugbugblue.com/
package/docs/engine.md ADDED
@@ -0,0 +1,399 @@
1
+ # engine.js API documentation
2
+
3
+ This module provides the logic to handle interacting with a Trax game, including
4
+ starting a game, making moves in the game, and determining if the game has been
5
+ won.
6
+
7
+ A few other functions/properties are also provided to assist with determining
8
+ the game state and what actions can be taken on the game.
9
+
10
+ ## Example usage
11
+
12
+ ```javascript
13
+ import { Trax } from '@slugbugblue/trax'
14
+
15
+ let trax = new Trax()
16
+ console.log(trax.possible_moves()) // "[ '@0/', '@0+' ]" -- initial moves
17
+
18
+ trax.play('@0/')
19
+ console.log(trax.turn) // "2" -- it is player 2's turn
20
+
21
+ trax.play('@1\\')
22
+ console.log(trax.color) // "w" -- it is white's turn
23
+
24
+ trax.play('A0/')
25
+ console.log(trax.over) // "true" -- the game is over
26
+ console.log(trax.winner) // "1" -- player 1 wins
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### Trax class
32
+
33
+ The Trax object can be called as a constructor, but it also has the following
34
+ class properties and methods:
35
+
36
+ - `Trax.variants`: a Set of the different rule sets the engine supports. Try
37
+ `Trax.variants.has(rule)` to see if your favorite rule set is supported. Or
38
+ `Trax.variants.forEach(s => { console.log(t) })` to list them all.
39
+
40
+ - `Trax.point(x, y)`: quick access to the [Point class][point-docs], for
41
+ two-dimensional locations used internally by the Trax engine and which are
42
+ required for some of the lower-level engine functions. Operates as a
43
+ constructor (without `new`) and returns a Point instance.
44
+
45
+ - `Trax.colorOf(playerNumber)`: Player 1 is white and Player 2 is black. So this
46
+ is a quick function to turn `1` into `'w'` and `2` into `'b'`. Quick and
47
+ dirty.
48
+
49
+ - `Trax.playerNumber(color)`: Quick and dirty way to turn `'w'` into `1` and
50
+ `'b'` into `2`.
51
+
52
+ - `Trax.other(color)`: Quick and dirty way to turn `'w'` into `'b'` and
53
+ vice-versa.
54
+
55
+ - `Trax.encodeCol(columnNumber)`: a function to turn a numeric column number
56
+ into the column letter used in Trax notation. The first column is `A`. The
57
+ empty column just to the left is `@`.
58
+
59
+ - `Trax.decodeCol(columnLetter)`: turns a column letter back into a number.
60
+
61
+ #### constructor
62
+
63
+ ```javascript
64
+ trax = new Trax(rules, moves, id)
65
+ ```
66
+
67
+ - `rules`: a string used to determine which trax variant will be played. If this
68
+ string is missing or is not found in `Trax.variants`, the default rule set of
69
+ `trax` will be used.
70
+
71
+ - `moves`: an array of moves or a space-separated string of moves to use as the
72
+ starting position of the game board. If missing, the board will be empty. Note
73
+ that if an array is used, each item in the array should be a notation string.
74
+ If a string is used instead, it is permissible to include the move numbers of
75
+ each move as well. As an example, the following are equivalent:
76
+
77
+ - `['@0/', '@1+', 'B0\\']`
78
+ - `'1. @0/ 2. @1+ 3. B0\\'`
79
+ - `@0/ @1+ b0\\`
80
+
81
+ - `id`: an optional string id that will be prepended to the key of each tile.
82
+ This is useful for setting the `id` value of HTML entities, but will probably
83
+ not be very useful for any other situations. You can likely safely ignore
84
+ this. Defaults to `'trax'`.
85
+
86
+ Returns an instance of the `Trax` class, which contains the following properties
87
+ and methods:
88
+
89
+ ### Trax instance
90
+
91
+ #### properties
92
+
93
+ - `id`: the string provided to the constructor
94
+ - `rules`: which of the `Trax.variants` is being played
95
+ - `move`: number, how many moves have been played
96
+ - `turn`: number, the player to make the next move
97
+ - `over`: boolean, `true` if the game is over
98
+ - `left`: number, the left-most column in play
99
+ - `right`: number, the right-most column in play
100
+ - `top`: number, the top-most row in play
101
+ - `bottom`: number, the bottom-most row in play
102
+ - note that each of these four numbers are using the internal coordinates of
103
+ the board rather than the Trax notation coordinates, since the latter
104
+ potentially change after every move
105
+ - `notation`: string, the notation of the current state, wrapped at 80 columns
106
+ - `tiles`: object, key/value pairs of data for each tile on the board
107
+ - key: a string composed of the game id and location of the tile
108
+ - value: an object containing the following key/value pairs:
109
+ - `type`: a string (`a` - `f`) representing the tile
110
+ - `loc`: an (x, y) Point object with the tile location
111
+ - `id`: the key of this object, provided here for easy cross-reference
112
+ - `move`: the move number this tile was placed on the board
113
+ - `seq`: the order in which this tile was played
114
+ - `path`: array, each item is a key of `tiles` involved in the winning path
115
+ - `invalid`: boolean, `true` only when a tile played into a cave results in an
116
+ illegal move
117
+
118
+ Note that while there is no protection on these properties, you should treat
119
+ them as read-only, since changing them directly will likely result in
120
+ unpredictable and invalid operations by the engine.
121
+
122
+ #### calculated properties
123
+
124
+ - `count`: number, the total number of tiles currently in play
125
+ - `color`: string, the color (`'w'` or `'b'`) of the player whose turn it is
126
+ - `gameOver`: boolean, `true` if the game is over
127
+ - `winner`: `false` if the game is still in progress, number of the winning
128
+ player otherwise (0 = tie)
129
+ - `height`: the number of rows in play
130
+ - `width`: the number of columns in play
131
+ - `moves`: an array of move notations for the current game
132
+ - `icon`: a string containing an encoded representation of the current board
133
+ position, useful for quickly drawing the game board without having to iterate
134
+ through the list of tiles (see [Encoding the icon](#encoding-the-icon) for
135
+ details on the structure of this code)
136
+ - `normalized`: the normalized code for this position
137
+
138
+ #### useful methods
139
+
140
+ ##### `save()`
141
+
142
+ This method encodes and returns the current state of the game into an object
143
+ that can later be restored. You should treat this object as opaque, to be used
144
+ only with the `restore()` method. Save a position before attempting tentative or
145
+ exploratory moves, so that you can restore the original position without having
146
+ to re-play all of the moves to arrive at that position.
147
+
148
+ `save()` and `restore()` are preferable to saving the current notation and
149
+ calling `new Trax()` with that notation, since it avoids all of the calculations
150
+ necessary to arrive at the same state.
151
+
152
+ ##### `restore(savedObj)`
153
+
154
+ This method accepts the returned value of the `save()` method and restores the
155
+ previously saved position.
156
+
157
+ ##### `possibleMoves()`
158
+
159
+ Returns a list of all moves (using game notation) that can be made from the
160
+ current position. Since it does not examine the result of forced tiles for each
161
+ move, it does not detect illegal cave positions, so there is no guarantee that
162
+ each move that can be played will be legal.
163
+
164
+ ##### `play(notation)`
165
+
166
+ Attempts to play the given `notation`. Updates the game instance if the notation
167
+ is valid for the current position.
168
+
169
+ ##### `playMove(currentMoveNumber, nextMoveNotation)`
170
+
171
+ Used to play a move, but with an extra safeguard around the status of the game
172
+ so that if this is called multiple times with the same values, it will ignore
173
+ subsequent calls, which can be useful in the context of asynchronous
174
+ communication and retries, such as when this engine is being used as the back
175
+ end of a web interface. For example, if no moves have been made yet in a game,
176
+ this can be called either as `playMove(0, '@0/')` or `playMove(0, '@0+')`.
177
+
178
+ ##### `provisionalMove(from, to, via)`
179
+
180
+ Test to see if a provisionally entered move is a match for the current position,
181
+ as determined by the normalized `from` position, playing the move notation
182
+ `via`, which must result in the normalized `to` position. Note that normalized
183
+ positions match symmetrically identical positions, so it's possible that `via`
184
+ isn't the actual move notation required. Symmetrical rotations of the notation
185
+ will be examined as well.
186
+
187
+ Returns `'delete-provisional'` if the provisional move will never be valid in
188
+ any future position. Returns `false` if the move doesn't match but may
189
+ potentially match a future position. Returns the potentially rotated move
190
+ notation if the provisional move was a match.
191
+
192
+ ##### `dropsIcon(drops)`
193
+
194
+ Returns an `icon` but with the included `drops` encoded distinctly so that they
195
+ can be distinguished from other tiles.
196
+
197
+ #### internal methods you probably don't need to use directly
198
+
199
+ Since these are not likely to be used directly, the documentation is a little
200
+ less complete.
201
+
202
+ ##### `tileId(location)`
203
+
204
+ Takes a `location` and returns a unique string id for the tile at that location.
205
+ The `tiles` property object uses the `tileId()` as a key for the tiles.
206
+
207
+ ##### `addTile(type, location)`
208
+
209
+ This function is used internally to place a tile of `type` on the board at
210
+ `location`. It has no validity checks, since that is handled in other parts of
211
+ the interface. It is not recommended to use this directly. It returns the tile
212
+ object that it adds to the board.
213
+
214
+ ##### `tileAt(location)`
215
+
216
+ Checks to see if a tile is at the specified `location`, and returns the tile
217
+ type or `undefined`.
218
+
219
+ ##### `validTile(type, location)`
220
+
221
+ Checks to see if a tile of `type` can be played at the given `location`. Returns
222
+ `true` if so. Note that this result is not a guarantee, since it does not check
223
+ forced tiles for illegal cave positions.
224
+
225
+ ##### `possibleTiles(location, slash)`
226
+
227
+ Returns a list of the possibly valid tiles at a given `location`. If the
228
+ optional `slash` parameter is included, it limits its search to tiles that also
229
+ match that `slash`.
230
+
231
+ ##### `validLocation(location)`
232
+
233
+ Returns true if a piece can be played at the given `location`. However, this
234
+ does not check for illegal cave positions.
235
+
236
+ ##### `possibleLocations()`
237
+
238
+ Returns a list of all locations where a tile may be played. Does not check for
239
+ illegal cave positions.
240
+
241
+ ##### `forcedMoves(location)`
242
+
243
+ After a tile is placed at `location`, play all the forced moves that result,
244
+ adding them to the board as well. Returns the list of all tile objects (as
245
+ returned from `addTile()`). It is during this function when illegal cave moves
246
+ are detected. When that happens, the tile at that location will be given a type
247
+ of `x`, and the `invalid` property of the Trax instance will be set to `true`,
248
+ but the tiles will not be removed. It is up to the calling function to check for
249
+ this condition and `restore` a previous position.
250
+
251
+ ##### `notate(type, location)`
252
+
253
+ Return the game notation when playing a tile of `type` at the given `location`.
254
+ This has to be done before the move is played, because if the move expands the
255
+ board to the left or upward, the notation will be invalid.
256
+
257
+ ##### `decodeNotation(notation)`
258
+
259
+ Returns an object with two keys: `type` and `location`.
260
+
261
+ ##### `follow(color, location, from)`
262
+
263
+ Follows the line of one `color` starting at the tile at the given `location`, in
264
+ the direction as if coming `from` a given edge. Returns an object giving the (x,
265
+ y) `loc` of the final tile, as well as a `path` array holding the tile id's
266
+
267
+ ##### `findEnds(color, location)`
268
+
269
+ Uses `follow()` to trace both ends of the given `color` from the given
270
+ `location`. Returns an array of two items, each containing an object describing
271
+ one of the ends of the line, as returned by `follow()`.
272
+
273
+ ##### `lineWin(locA, locB)`
274
+
275
+ Given `locA` as the (x, y) location of one end of a line and `locB` as the other
276
+ end, does the line constitute a line win? Returns `true` or `false`.
277
+
278
+ ##### `checkWin(tiles)`
279
+
280
+ Used after a play is made to determine if any of the played `tiles` results in a
281
+ win. Updates the instance's `over` and `turn` properties as needed. Returns
282
+ nothing.
283
+
284
+ ##### `updateNotation(notation)`
285
+
286
+ Handles updating the `notation` game instance property using the `notation` of
287
+ the current move. Returns nothing.
288
+
289
+ ##### `dropTile(notation, _, tentative)`
290
+
291
+ ##### `dropTile(type, location, tentative)`
292
+
293
+ Attempts to play a tile given either a `notation` or a `type` and `location`. If
294
+ `tentative` is provided and is truthy, the move will not actually be made, but
295
+ the return value will be the same as if it were made.
296
+
297
+ Returns an object with the following key/value pairs:
298
+
299
+ - `dropped`: a list of the tiles that were played by this move
300
+ - `notation`: the resulting notation of the move
301
+ - `valid`: `true` if the move is valid and results in a legal position
302
+
303
+ ##### `moveRotations(move)`
304
+
305
+ Rotates a given `move` around the board to assist with symmetry calculations.
306
+ Returns an array of possible symmetrical meanings of the given move.
307
+
308
+ ##### `positionCode(rightToLeft, bottomToTop, rotate, drops)`
309
+
310
+ This is a helper function to provide a string representation to a position,
311
+ applying optional symmetrical operations on it. By default, the position code
312
+ returned will be provided using a top to bottom, right to left, unrotated
313
+ approach. By setting `rightToLeft`, `topToBottom`, or `rotate` to `true`,
314
+ transformations can be applied to the position code to return any of 8 different
315
+ codes representing the 8 possible symmetries of any given position. If `drops`
316
+ is provided, it should be the array of `dropped` tiles returned by `dropTile()`,
317
+ and those tiles will be encoded differently. See
318
+ [Encoding the icon](#encoding-the-icon) for details on the encoding.
319
+
320
+ ##### `normalize()`
321
+
322
+ Returns a normalized position code icon. Every symmetrical position will return
323
+ the same normalized code, so you can determine if two different positions are
324
+ the same position with only changes in symmetry by calling this on both game
325
+ instances and comparing the resulting icon string. While this code should be
326
+ treated as if opaque, you can read about the way it is created from an
327
+ [encoded position code](#encoding-the-icon) in the section on
328
+ [normalizing the position code](#normalizing-a-position).
329
+
330
+ ## Trax tiles
331
+
332
+ There isn't an inherent order to the way in which Trax tiles are presented.
333
+ However, to allow for some sort of ease of encoding, the Trax module names each
334
+ tile with a lower-case letter from `a` to `f` as shown in the following
335
+ ASCII-art representations of each tile. The `##` characters are used to
336
+ represent black.
337
+
338
+ ```
339
+ Trax tiles
340
+ a b c d e f
341
+ ________ ________ ________ ________ _______ ________
342
+ |__## | |__##__| | ##__| |_/ | | | | | | | | \_|
343
+ |_ \###| |______| |###/ _| |__/###| |#| |#| |###\__|
344
+ |_\_|__| |__##__| |__|_/_| |__##__| |_|_|_| |__##__|
345
+
346
+ (white wins / black wins)
347
+ g m h n i o j p k q l r
348
+ ```
349
+
350
+ ### Encoding the icon
351
+
352
+ The `icon` computed property encodes the position of the board by replacing each
353
+ tile on the board with its corresponding letter as described immediately above.
354
+ In cases where the tile in question is part of a winning line or loop, the
355
+ character for that tile is increased by 6 letters for a white win, or by 12
356
+ letters for a black win. In addition, when requested, the icon can also include
357
+ information about which tiles were placed in the last move, and those tiles are
358
+ represented by their upper-case counterparts.
359
+
360
+ In the event that a given move results in an illegal position, one of the tiles
361
+ that make up the illegal position will be replaced by an `x` instead of one of
362
+ the listed tiles. This signifies that no possible tile can meet the forced moves
363
+ rules of that location. Only one of the tiles will be so marked, even though it
364
+ requires several contributing tiles to create a situation where a move is
365
+ illegal.
366
+
367
+ Spaces are encoded into the icon using single-digit numbers. `0` means there is
368
+ one space. `9` would indicate there are 10 spaces. Spaces at the left or in
369
+ between tiles are encoded. Empty spaces to the right of all tiles are ignored.
370
+
371
+ A colon is used to separate rows.
372
+
373
+ ### Normalizing a position
374
+
375
+ A normalized position is one where a single position code is chosen such that
376
+ symmetrical positions will be represented by a single position code.
377
+
378
+ Different from a standard position code, a normalized position code includes the
379
+ addition of a leading character indicating the state of the game. `W` means
380
+ either that it is white's turn or that white has won the game. `B` indicates
381
+ that black is to play or has already won. `T` means that the game has ended in a
382
+ tie.
383
+
384
+ ## License
385
+
386
+ Copyright 2019-2022 Chad Transtrum
387
+
388
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
389
+ the files in this project except in compliance with the License. You may obtain
390
+ a copy of the License at
391
+
392
+ http://www.apache.org/licenses/LICENSE-2.0
393
+
394
+ Unless required by applicable law or agreed to in writing, software distributed
395
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
396
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
397
+ specific language governing permissions and limitations under the License.
398
+
399
+ [point-docs]: point.md