@slugbugblue/trax 0.12.0 → 0.13.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 +15 -0
- package/README.md +46 -7
- package/docs/analyst.md +44 -2
- package/package.json +6 -7
- package/src/analyst.js +96 -12
- package/src/cli.js +60 -30
- package/src/cmds/analyze.js +2 -2
- package/src/cmds/import-export.js +1 -1
- package/src/cmds/list.js +2 -2
- package/src/cmds/new.js +5 -3
- package/src/cmds/suggest.js +52 -0
- package/src/engine.js +167 -29
- package/src/point.js +54 -12
- package/src/puzzles.js +798 -0
- package/src/threats.js +31 -32
- package/src/tty.js +30 -15
- package/src/types.d.ts +105 -0
- package/src/version.js +1 -1
package/src/threats.js
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* You may obtain a copy of the License at
|
|
6
|
-
*
|
|
7
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
*
|
|
9
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
* See the License for the specific language governing permissions and
|
|
13
|
-
* limitations under the License.
|
|
1
|
+
/** Threats database: hand-coded threats
|
|
2
|
+
* @copyright 2022
|
|
3
|
+
* @author Chad Transtrum <chad@transtrum.net>
|
|
4
|
+
* @license Apache-2.0
|
|
14
5
|
*/
|
|
15
6
|
|
|
16
|
-
// Threats database: hand-coded threats
|
|
17
|
-
|
|
18
7
|
const REGEX = {
|
|
19
8
|
a: '[am]', // White that pairs with the next white
|
|
20
9
|
c: '[cp]', // White that forms a connectable pair with next white
|
|
@@ -30,10 +19,12 @@ class CustomInspectableThreat {
|
|
|
30
19
|
#depth = 0
|
|
31
20
|
#pattern = ''
|
|
32
21
|
#rx = null
|
|
22
|
+
#reforms = false
|
|
33
23
|
|
|
34
|
-
constructor(depth, pattern) {
|
|
24
|
+
constructor(depth, pattern, reforms = false) {
|
|
35
25
|
this.#depth = depth
|
|
36
26
|
this.#pattern = pattern
|
|
27
|
+
this.#reforms = reforms
|
|
37
28
|
|
|
38
29
|
let rx = ''
|
|
39
30
|
for (const char of pattern) {
|
|
@@ -55,16 +46,22 @@ class CustomInspectableThreat {
|
|
|
55
46
|
return this.#rx
|
|
56
47
|
}
|
|
57
48
|
|
|
49
|
+
get value() {
|
|
50
|
+
return this.#reforms ? 2 : 1
|
|
51
|
+
}
|
|
52
|
+
|
|
58
53
|
// To make life at the REPL a little easier
|
|
59
54
|
[Symbol.for('nodejs.util.inspect.custom')](_, out) {
|
|
60
55
|
const style = out.stylize
|
|
61
|
-
|
|
56
|
+
const display = [
|
|
62
57
|
'[' + style('Threat', 'special') + ']',
|
|
63
58
|
'{',
|
|
64
59
|
style(this.#pattern, 'string') + ':',
|
|
65
60
|
style(this.#depth, 'number'),
|
|
61
|
+
this.#reforms ? '!' : '',
|
|
66
62
|
'}',
|
|
67
|
-
]
|
|
63
|
+
]
|
|
64
|
+
return display.filter((d) => d !== '').join(' ')
|
|
68
65
|
}
|
|
69
66
|
}
|
|
70
67
|
|
|
@@ -78,9 +75,9 @@ class CustomInspectableThreatsDB {
|
|
|
78
75
|
}
|
|
79
76
|
}
|
|
80
77
|
|
|
81
|
-
add(depth, pattern) {
|
|
78
|
+
add(depth, pattern, reforms = false) {
|
|
82
79
|
this.#depth = Math.max(depth, this.#depth)
|
|
83
|
-
this.#db[pattern] = new CustomInspectableThreat(depth, pattern)
|
|
80
|
+
this.#db[pattern] = new CustomInspectableThreat(depth, pattern, reforms)
|
|
84
81
|
return this.#db[pattern]
|
|
85
82
|
}
|
|
86
83
|
|
|
@@ -127,22 +124,26 @@ const corners = {
|
|
|
127
124
|
|
|
128
125
|
export const threats = new CustomInspectableThreatsDB(Object.keys(corners))
|
|
129
126
|
|
|
130
|
-
// Attacks
|
|
131
|
-
const attacks = [
|
|
132
|
-
'a?w', // Simple attack and wide attack
|
|
133
|
-
]
|
|
134
|
-
attacks.map((a) => threats.add(1, a))
|
|
135
|
-
|
|
136
127
|
// Re-forming attacks
|
|
137
|
-
const
|
|
128
|
+
const reformAttacks = [
|
|
138
129
|
'rm?lr', // Cave/wide cave attack
|
|
139
|
-
'rp?lr',
|
|
140
130
|
'rbm?lbr', // Deep cave/deep wide cave attack (impossibly rare?)
|
|
141
|
-
'rbp?lbr',
|
|
142
131
|
'ralmrw', // Attack at top of cave
|
|
143
132
|
'arlmwr', // Reversed
|
|
144
133
|
]
|
|
145
|
-
|
|
134
|
+
reformAttacks.map((ra) => threats.add(1, ra, true))
|
|
135
|
+
|
|
136
|
+
const reformThreats = [
|
|
137
|
+
'rp?lr', // Cave/wide cave threat
|
|
138
|
+
'rbp?lbr', // Deep cave/deept wide cave attach (impossibly rare?)
|
|
139
|
+
]
|
|
140
|
+
reformThreats.map((rt) => threats.add(2, rt))
|
|
141
|
+
|
|
142
|
+
// Attacks
|
|
143
|
+
const attacks = [
|
|
144
|
+
'a?w', // Simple attack and wide attack
|
|
145
|
+
]
|
|
146
|
+
attacks.map((a) => threats.add(1, a))
|
|
146
147
|
|
|
147
148
|
// Create multi-stage threats
|
|
148
149
|
for (const one of Object.keys(corners)) {
|
|
@@ -160,5 +161,3 @@ for (const one of Object.keys(corners)) {
|
|
|
160
161
|
threats.add(3, one + '!b*b¡' + two)
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
|
-
|
|
164
|
-
// Create edge threats
|
package/src/tty.js
CHANGED
|
@@ -17,12 +17,21 @@
|
|
|
17
17
|
|
|
18
18
|
import process from 'node:process'
|
|
19
19
|
|
|
20
|
-
import { Trax } from '
|
|
20
|
+
import { Trax } from '@slugbugblue/trax'
|
|
21
21
|
|
|
22
22
|
const esc = '\u001B[' // Start of console color escape code
|
|
23
23
|
const off = esc + 'm' // Color reset code
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const ENV = process.env
|
|
25
|
+
const NERD = ENV.NERDFONT
|
|
26
|
+
const POWER = ENV.POWERLINE || ENV.P9K_TTY || ENV.P9K_SSH
|
|
27
|
+
const leftBubble = NERD ? '' : POWER ? '' : '▐'
|
|
28
|
+
const rightBubble = NERD ? '' : POWER ? '' : '▌'
|
|
29
|
+
|
|
30
|
+
/** Colorize a string.
|
|
31
|
+
* @arg {string} contents
|
|
32
|
+
* @arg {string|number} [fgcolor]
|
|
33
|
+
* @arg {string|number} [bgcolor]
|
|
34
|
+
*/
|
|
26
35
|
export const color = (contents = '', fgcolor = '', bgcolor = '') => {
|
|
27
36
|
const c = []
|
|
28
37
|
if (fgcolor) c.push('38;5;' + fgcolor)
|
|
@@ -35,9 +44,7 @@ export const outty = (message, fgcolor, bgcolor) => {
|
|
|
35
44
|
console.log(color(message, fgcolor, bgcolor) + off)
|
|
36
45
|
}
|
|
37
46
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// a little magic to display the game in progress
|
|
47
|
+
// A little magic to display the game in progress
|
|
41
48
|
const colorSets = {
|
|
42
49
|
// Colors for terminal sequence: <Esc>[38;5;<color_num>m
|
|
43
50
|
// b, B, w, W: color of line for each player, capital for a winning line
|
|
@@ -48,6 +55,8 @@ const colorSets = {
|
|
|
48
55
|
tentative: { b: 235, B: 18, e: 19, t: 244, w: 252, W: 217 },
|
|
49
56
|
}
|
|
50
57
|
|
|
58
|
+
let set = colorSets.trax // Which color set should we draw with?
|
|
59
|
+
|
|
51
60
|
export const name = (rules) => {
|
|
52
61
|
if (Trax.variants.has(rules)) {
|
|
53
62
|
return color(Trax.names[rules], colorSets[rules].t)
|
|
@@ -67,7 +76,12 @@ export const bubble = (clr, text) => {
|
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
const c = colors[clr]
|
|
70
|
-
return
|
|
79
|
+
return (
|
|
80
|
+
color(leftBubble, c.bg) +
|
|
81
|
+
color(text, c.fg, c.bg) +
|
|
82
|
+
off +
|
|
83
|
+
color(rightBubble, c.bg)
|
|
84
|
+
)
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
const ln = 'm\u2584' // Lower half block -- with the leading m to terminate ansi color escape
|
|
@@ -124,7 +138,7 @@ const tileTty = (tile, top) => {
|
|
|
124
138
|
}
|
|
125
139
|
}
|
|
126
140
|
|
|
127
|
-
let value =
|
|
141
|
+
let value = ''
|
|
128
142
|
if (tile in tiles) {
|
|
129
143
|
tile = tiles[tile]
|
|
130
144
|
if (top) {
|
|
@@ -154,7 +168,7 @@ const mergeTentative = () => {
|
|
|
154
168
|
|
|
155
169
|
const printIcon = (icon, setName) => {
|
|
156
170
|
set = colorSets[setName] || colorSets.trax
|
|
157
|
-
mergeTentative(
|
|
171
|
+
mergeTentative()
|
|
158
172
|
const on = esc + '38;5;' + String(set.t) + ';48;5;' + String(set.e) + 'm'
|
|
159
173
|
let o1 = ' '
|
|
160
174
|
let o2 = '1 '
|
|
@@ -208,10 +222,11 @@ const printIcon = (icon, setName) => {
|
|
|
208
222
|
}
|
|
209
223
|
}
|
|
210
224
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
225
|
+
/** Flexible way to get a Trax game object.
|
|
226
|
+
* @arg {Trax|TraxVariant} [game] - existing Trax instance or a string indicating the variant name
|
|
227
|
+
* @arg {string|string[]} [moves] - optional list or string of moves to be made on the game
|
|
228
|
+
* @returns {Trax} a Trax instance
|
|
229
|
+
*/
|
|
215
230
|
export const traxGame = (game = 'trax', moves = '') => {
|
|
216
231
|
let trax
|
|
217
232
|
if (game instanceof Trax) {
|
|
@@ -253,7 +268,7 @@ const printNotation = (trax, tentative, show = Number.POSITIVE_INFINITY) => {
|
|
|
253
268
|
export const display = (
|
|
254
269
|
game,
|
|
255
270
|
players,
|
|
256
|
-
tentative =
|
|
271
|
+
tentative = '',
|
|
257
272
|
showMove = Number.POSITIVE_INFINITY,
|
|
258
273
|
) => {
|
|
259
274
|
const trax = traxGame(game)
|
|
@@ -266,7 +281,7 @@ export const display = (
|
|
|
266
281
|
if (drops.valid || drops.dropped.length > 0) {
|
|
267
282
|
icon = trax.dropsIcon(drops)
|
|
268
283
|
} else {
|
|
269
|
-
tentative =
|
|
284
|
+
tentative = ''
|
|
270
285
|
}
|
|
271
286
|
} else if (showMove <= trax.moves.length) {
|
|
272
287
|
icon = trax.dropsIcon({
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/** Type information.
|
|
2
|
+
* @author Chad Transtrum <chad@transtrum.net>
|
|
3
|
+
* @license Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Color is a single character to represent white or black. */
|
|
7
|
+
type Color = 'w' | 'b'
|
|
8
|
+
|
|
9
|
+
/** Colorize is a fancy function for colorizing text. */
|
|
10
|
+
type Colorize = (text: string, def?: string | number) => string
|
|
11
|
+
|
|
12
|
+
/** Colorer is a little too fancy. Hence the gnarly typescript. */
|
|
13
|
+
type Colorer = {
|
|
14
|
+
(text: string, def?: string | number): string
|
|
15
|
+
black: Colorize
|
|
16
|
+
command: Colorize
|
|
17
|
+
default: Colorize
|
|
18
|
+
error: Colorize
|
|
19
|
+
fatal: Colorize
|
|
20
|
+
help: Colorize
|
|
21
|
+
id: Colorize
|
|
22
|
+
variable: Colorize
|
|
23
|
+
optional: Colorize
|
|
24
|
+
short: Colorize
|
|
25
|
+
white: Colorize
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** A point-like object has numerical x and y properties. */
|
|
29
|
+
type PointLike = {
|
|
30
|
+
x: number
|
|
31
|
+
y: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A puzzle. */
|
|
35
|
+
type Puzzle = {
|
|
36
|
+
id: string
|
|
37
|
+
src: string
|
|
38
|
+
game: TraxVariant
|
|
39
|
+
notation: string
|
|
40
|
+
icon: string
|
|
41
|
+
level: number
|
|
42
|
+
max: number
|
|
43
|
+
player: number
|
|
44
|
+
title?: string
|
|
45
|
+
desc?: string
|
|
46
|
+
hint?: string
|
|
47
|
+
hints?: string[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type PuzzleSource = {
|
|
51
|
+
name: string
|
|
52
|
+
copyright?: string
|
|
53
|
+
url?: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Treat the save state as an opaque object,
|
|
57
|
+
* produced by save() and fed into restore().
|
|
58
|
+
*/
|
|
59
|
+
type SaveState = {
|
|
60
|
+
id: string
|
|
61
|
+
move: number
|
|
62
|
+
turn: number
|
|
63
|
+
over: boolean
|
|
64
|
+
left: number
|
|
65
|
+
right: number
|
|
66
|
+
top: number
|
|
67
|
+
bottom: number
|
|
68
|
+
notation: string
|
|
69
|
+
tiles: string
|
|
70
|
+
path: string
|
|
71
|
+
invalid: boolean
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Representations of the different ways a tile can curve.
|
|
75
|
+
* Matches the symbols used in Trax notation.
|
|
76
|
+
*/
|
|
77
|
+
type Slash = '/' | '\\' | '+'
|
|
78
|
+
|
|
79
|
+
/** A single tile on the board. */
|
|
80
|
+
type Tile = {
|
|
81
|
+
id: TileId
|
|
82
|
+
loc: Point
|
|
83
|
+
type: TileType
|
|
84
|
+
move: number
|
|
85
|
+
seq: number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** When a tile is dropped, this object represents the results. */
|
|
89
|
+
type TileDrop = {
|
|
90
|
+
dropped: Tile[]
|
|
91
|
+
notation: string
|
|
92
|
+
valid: boolean
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** A TileId is just a string. */
|
|
96
|
+
type TileId = string
|
|
97
|
+
|
|
98
|
+
/** Invalid tiles are represented by 'x'. */
|
|
99
|
+
type TileType = ValidTiles | 'x'
|
|
100
|
+
|
|
101
|
+
/** All of the variants supported by the engine. */
|
|
102
|
+
type TraxVariant = 'trax' | 'traxloop' | 'trax8'
|
|
103
|
+
|
|
104
|
+
/** Tile types are represented by one of the following single characters. */
|
|
105
|
+
type ValidTiles = 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '0.
|
|
2
|
+
export const version = '0.13.0'
|