@slugbugblue/trax 0.7.0 → 0.8.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 +80 -4
- package/docs/engine.md +18 -3
- package/package.json +7 -3
- package/src/cli.js +994 -0
- package/{engine.js → src/engine.js} +20 -13
- package/{point.js → src/point.js} +0 -0
- package/{tty.js → src/tty.js} +81 -15
- package/src/version.js +2 -0
|
@@ -24,7 +24,7 @@ import { Point } from './point.js'
|
|
|
24
24
|
// Fun trax helper constants
|
|
25
25
|
|
|
26
26
|
const zero = new Point(0, 0)
|
|
27
|
-
const notationRegex = /^
|
|
27
|
+
const notationRegex = /^([@a-z]+)(\d+)([/\\+])$/i
|
|
28
28
|
|
|
29
29
|
const slash = { a: '\\', b: '+', c: '/', d: '/', e: '+', f: '\\' }
|
|
30
30
|
|
|
@@ -72,7 +72,13 @@ const codeRowLength = (row) =>
|
|
|
72
72
|
// This is where the magic happens
|
|
73
73
|
export const Trax = class {
|
|
74
74
|
// Static class properties
|
|
75
|
-
static
|
|
75
|
+
static names = {
|
|
76
|
+
trax: 'Trax',
|
|
77
|
+
traxloop: 'Loop Trax',
|
|
78
|
+
trax8: '8x8 Trax',
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static variants = new Set(Object.keys(this.names)) // Known variants
|
|
76
82
|
|
|
77
83
|
// Static class methods
|
|
78
84
|
static point = (x, y) => new Point(x, y)
|
|
@@ -122,13 +128,9 @@ export const Trax = class {
|
|
|
122
128
|
// Moves might be a notation string
|
|
123
129
|
if (moves) {
|
|
124
130
|
if (typeof moves === 'string') moves = moves.split(/\s+/)
|
|
125
|
-
for (
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (notationRegex.test(move.notation)) {
|
|
131
|
-
this.playMove(move.move, move.notation)
|
|
131
|
+
for (const move of moves) {
|
|
132
|
+
if (notationRegex.test(move)) {
|
|
133
|
+
this.dropTile(move)
|
|
132
134
|
}
|
|
133
135
|
}
|
|
134
136
|
}
|
|
@@ -170,6 +172,11 @@ export const Trax = class {
|
|
|
170
172
|
}
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
get name() {
|
|
176
|
+
// Get the name of this variant
|
|
177
|
+
return Trax.names[this.rules]
|
|
178
|
+
}
|
|
179
|
+
|
|
173
180
|
get count() {
|
|
174
181
|
// Get the number of tiles currently in play
|
|
175
182
|
return Object.keys(this.tiles).length
|
|
@@ -433,9 +440,9 @@ export const Trax = class {
|
|
|
433
440
|
return this.dropTile(notation)
|
|
434
441
|
}
|
|
435
442
|
|
|
436
|
-
playMove(
|
|
437
|
-
// Generic API call for
|
|
438
|
-
if (
|
|
443
|
+
playMove(moveNumber, notation) {
|
|
444
|
+
// Generic API call for playing a move with move number safety
|
|
445
|
+
if (moveNumber === this.move + 1) return this.dropTile(notation)
|
|
439
446
|
return { valid: false }
|
|
440
447
|
}
|
|
441
448
|
|
|
@@ -482,7 +489,7 @@ export const Trax = class {
|
|
|
482
489
|
loc = decoded.loc
|
|
483
490
|
}
|
|
484
491
|
|
|
485
|
-
if (this.validLocation(loc) && this.validTile(type, loc)) {
|
|
492
|
+
if (loc && this.validLocation(loc) && this.validTile(type, loc)) {
|
|
486
493
|
valid = true
|
|
487
494
|
const saved = this.save() // Just in case we need to roll back
|
|
488
495
|
notation = this.notate(type, loc) // Determine notation BEFORE we play the move
|
|
File without changes
|
package/{tty.js → src/tty.js}
RENAMED
|
@@ -22,13 +22,19 @@ import { Trax } from './engine.js'
|
|
|
22
22
|
const esc = '\u001B[' // Start of console color escape code
|
|
23
23
|
const off = esc + 'm' // Color reset code
|
|
24
24
|
|
|
25
|
-
//
|
|
25
|
+
// Colorize a string
|
|
26
|
+
export const color = (contents = '', fgcolor = '', bgcolor = '') => {
|
|
27
|
+
let ansi = esc
|
|
28
|
+
const c = []
|
|
29
|
+
if (fgcolor) c.push('38;5;' + fgcolor)
|
|
30
|
+
if (bgcolor) c.push('48;5;' + bgcolor)
|
|
31
|
+
ansi += c.join(';') + 'm'
|
|
32
|
+
return ansi + contents
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Display a message with optional color
|
|
26
36
|
export const outty = (message, fgcolor, bgcolor) => {
|
|
27
|
-
|
|
28
|
-
if (fgcolor) ansi += '38;5;' + fgcolor
|
|
29
|
-
if (bgcolor) ansi += '48;5;' + bgcolor
|
|
30
|
-
if (ansi) ansi += 'm'
|
|
31
|
-
console.log(ansi + message + off)
|
|
37
|
+
console.log(color(message, fgcolor, bgcolor) + off)
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
let set = 'trax' // Which color set should we draw with?
|
|
@@ -44,6 +50,28 @@ const colorSets = {
|
|
|
44
50
|
tentative: { b: 235, B: 18, e: 19, t: 244, w: 252, W: 217 },
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
export const name = (rules) => {
|
|
54
|
+
if (Trax.variants.has(rules)) {
|
|
55
|
+
return color(Trax.names[rules], colorSets[rules].t)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return rules
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const bubble = (clr, text) => {
|
|
62
|
+
const colors = {
|
|
63
|
+
w: { fg: 236, bg: 153 },
|
|
64
|
+
b: { fg: 250, bg: 18 },
|
|
65
|
+
wd: { fg: 236, bg: 248 },
|
|
66
|
+
bd: { fg: 248, bg: 236 },
|
|
67
|
+
wh: { fg: 63, bg: 123 },
|
|
68
|
+
bh: { fg: 220, bg: 20 },
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const c = colors[clr]
|
|
72
|
+
return color('', c.bg) + color(text, c.fg, c.bg) + off + color('', c.bg)
|
|
73
|
+
}
|
|
74
|
+
|
|
47
75
|
const ln = 'm\u2584' // Lower half block -- with the leading m to terminate ansi color escape
|
|
48
76
|
const up = 'm\u2588' // Full block
|
|
49
77
|
const lt = 'm\u2599' // Lower half and left half block
|
|
@@ -201,29 +229,67 @@ export const traxGame = (game = 'trax', moves = '') => {
|
|
|
201
229
|
return trax
|
|
202
230
|
}
|
|
203
231
|
|
|
204
|
-
|
|
205
|
-
|
|
232
|
+
const printNotation = (trax, tentative) => {
|
|
233
|
+
let b = false
|
|
234
|
+
let n = 1
|
|
235
|
+
let out = ''
|
|
236
|
+
let length = 0
|
|
237
|
+
const t = tentative ? trax.moves.length : 0
|
|
238
|
+
for (const move of trax.moves) {
|
|
239
|
+
const c = (b ? 'b' : 'w') + (t === n ? 'd' : '')
|
|
240
|
+
const notation = String(n) + ' ' + move
|
|
241
|
+
if (length + notation.length + 3 > process.stdout.columns) {
|
|
242
|
+
out += '\n'
|
|
243
|
+
length = 0
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
out += bubble(c, notation) + ' '
|
|
247
|
+
length += notation.length + 3
|
|
248
|
+
b = !b
|
|
249
|
+
n++
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
outty(out)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export const display = (game, players, tentative = false) => {
|
|
256
|
+
const trax = traxGame(game)
|
|
257
|
+
const saved = trax.save()
|
|
258
|
+
const colors = ['white', 'black']
|
|
259
|
+
if (!Array.isArray(players)) players = colors
|
|
206
260
|
let { icon } = trax
|
|
207
261
|
if (tentative) {
|
|
208
262
|
const drops = trax.dropTile(tentative)
|
|
209
|
-
if (drops.valid) {
|
|
263
|
+
if (drops.valid || drops.dropped.length > 0) {
|
|
210
264
|
icon = trax.dropsIcon(drops)
|
|
211
265
|
} else {
|
|
212
266
|
tentative = false
|
|
213
267
|
}
|
|
214
268
|
}
|
|
215
269
|
|
|
216
|
-
|
|
270
|
+
printNotation(trax, tentative)
|
|
217
271
|
printIcon(icon, trax.rules)
|
|
218
|
-
|
|
219
|
-
|
|
272
|
+
const nameColor = { 1: 'w', 2: 'b' }[trax.turn]
|
|
273
|
+
if (tentative) {
|
|
274
|
+
const otherColor = { w: 'bd', b: 'wd' }[nameColor] || 'wd'
|
|
275
|
+
outty('---' + bubble(otherColor, 'tentative position') + off + '---')
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const name = players[trax.turn - 1] || colors[trax.turn - 1]
|
|
220
279
|
if (trax.over) {
|
|
221
280
|
if (trax.turn) {
|
|
222
|
-
|
|
281
|
+
outty(bubble(nameColor + 'h', name) + off + ' wins')
|
|
223
282
|
} else {
|
|
224
|
-
|
|
283
|
+
outty('game end' + (tentative ? 's' : 'ed') + ' in a draw')
|
|
225
284
|
}
|
|
226
285
|
} else if (trax.turn) {
|
|
227
|
-
|
|
286
|
+
outty(
|
|
287
|
+
(tentative ? 'leaving ' : '') +
|
|
288
|
+
bubble(nameColor, name) +
|
|
289
|
+
off +
|
|
290
|
+
' to play',
|
|
291
|
+
)
|
|
228
292
|
}
|
|
293
|
+
|
|
294
|
+
if (tentative) trax.restore(saved)
|
|
229
295
|
}
|
package/src/version.js
ADDED