@slugbugblue/trax 0.8.0 → 0.10.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/CHANGELOG.md +16 -0
- package/README.md +9 -10
- package/docs/point.md +8 -1
- package/package.json +6 -3
- package/src/cli.js +377 -748
- package/src/cmds/delete.js +71 -0
- package/src/cmds/help.js +81 -0
- package/src/cmds/import-export.js +250 -0
- package/src/cmds/list.js +155 -0
- package/src/cmds/new.js +131 -0
- package/src/cmds/play-try.js +129 -0
- package/src/cmds/select.js +47 -0
- package/src/cmds/undo.js +40 -0
- package/src/cmds/view.js +53 -0
- package/src/point.js +12 -0
- package/src/tty.js +15 -8
- package/src/version.js +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* Copyright 2022 Chad Transtrum
|
|
2
|
+
*
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
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.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// CLI play/try commands
|
|
17
|
+
|
|
18
|
+
const moveRx = /^\d+\.?$/
|
|
19
|
+
const notationRx = /^[@a-z]+\d+[bps/\\+]$/i
|
|
20
|
+
|
|
21
|
+
export const playCmd = {
|
|
22
|
+
name: 'play',
|
|
23
|
+
alt: ['move', 'mv'],
|
|
24
|
+
args: '<move> [...]',
|
|
25
|
+
comp: '<play>',
|
|
26
|
+
desc: 'play a move',
|
|
27
|
+
rx: [moveRx, notationRx],
|
|
28
|
+
help: [
|
|
29
|
+
'Enter the move in standard Trax notation. The final character of the',
|
|
30
|
+
'notation can be replaced with a letter for ease of entering at the',
|
|
31
|
+
'command line. Use <s> for "/", <b> for "\\", and <p> for "+".',
|
|
32
|
+
'Multiple moves can be submitted at once. Move numbers are optional,',
|
|
33
|
+
'but if included, they will be checked for accuracy.',
|
|
34
|
+
],
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const tryCmd = {
|
|
38
|
+
name: 'try',
|
|
39
|
+
alt: 'see',
|
|
40
|
+
args: '<move>',
|
|
41
|
+
comp: '<play>',
|
|
42
|
+
desc: 'see the effects of a move',
|
|
43
|
+
help: [
|
|
44
|
+
'View a move without committing to it. This is useful for seeing the',
|
|
45
|
+
'effects of forced tiles.',
|
|
46
|
+
],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const fixNotation = (move) => {
|
|
50
|
+
if (move.endsWith('b')) return move.slice(0, -1) + '\\'
|
|
51
|
+
if (move.endsWith('s')) return move.slice(0, -1) + '/'
|
|
52
|
+
if (move.endsWith('p')) return move.slice(0, -1) + '+'
|
|
53
|
+
return move
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
playCmd.fn = (CLI, ...moves) => {
|
|
57
|
+
if (moves.length === 0 || !moves[0]) {
|
|
58
|
+
CLI.error('You must provide a move.')
|
|
59
|
+
return CLI.do('help', 'play')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!CLI.GAME?.id) {
|
|
63
|
+
CLI.do('new')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (CLI.TRAX.over) {
|
|
67
|
+
return CLI.error('The game is over.')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const start = CLI.TRAX.move
|
|
71
|
+
let checkMove
|
|
72
|
+
|
|
73
|
+
for (let move of moves) {
|
|
74
|
+
if (notationRx.test(move)) {
|
|
75
|
+
const moveNumber = CLI.TRAX.move
|
|
76
|
+
move = fixNotation(move)
|
|
77
|
+
if (checkMove) {
|
|
78
|
+
CLI.TRAX.playMove(checkMove, move)
|
|
79
|
+
} else {
|
|
80
|
+
CLI.TRAX.play(move)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (CLI.TRAX.move === moveNumber) {
|
|
84
|
+
CLI.error(
|
|
85
|
+
'Move "' +
|
|
86
|
+
(checkMove ? checkMove + '. ' : '') +
|
|
87
|
+
move +
|
|
88
|
+
'" is invalid.',
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
} else if (moveRx.test(move)) {
|
|
92
|
+
checkMove = Number(move)
|
|
93
|
+
} else if (move) {
|
|
94
|
+
CLI.error('Move "' + move + '" is not in the correct notation.')
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (CLI.TRAX.move !== start) {
|
|
99
|
+
CLI.updateGameData()
|
|
100
|
+
CLI.do('view')
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
tryCmd.fn = (CLI, move) => {
|
|
105
|
+
if (move.length === 0) {
|
|
106
|
+
CLI.error('You must provide a move.')
|
|
107
|
+
return CLI.do('help', 'try')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!CLI.TRAX) {
|
|
111
|
+
CLI.do('new')
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (CLI.TRAX.over) {
|
|
115
|
+
return CLI.error('The game is over.')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (notationRx.test(move)) {
|
|
119
|
+
move = fixNotation(move)
|
|
120
|
+
const play = CLI.TRAX.dropTile(move, undefined, 'tentative')
|
|
121
|
+
if (play.valid || play.dropped.length > 0) {
|
|
122
|
+
CLI.display(CLI.TRAX, CLI.GAME.players, move)
|
|
123
|
+
} else {
|
|
124
|
+
CLI.error('Move is invalid.')
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
CLI.error('Move is invalid.')
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* Copyright 2022 Chad Transtrum
|
|
2
|
+
*
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
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.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// CLI select command
|
|
17
|
+
|
|
18
|
+
export const selectCmd = {
|
|
19
|
+
name: 'select',
|
|
20
|
+
alt: ['choose', '#'],
|
|
21
|
+
args: '#id [command]',
|
|
22
|
+
comp: '<id> <cmd>',
|
|
23
|
+
desc: 'select a different game',
|
|
24
|
+
rx: /^#\d+$/,
|
|
25
|
+
help: [
|
|
26
|
+
'Make another game the default game of future commands. If another',
|
|
27
|
+
'command is included, that command will be run immediately.',
|
|
28
|
+
],
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
selectCmd.fn = (CLI, id, ...cmds) => {
|
|
32
|
+
if (!id) {
|
|
33
|
+
CLI.error('Missing id.')
|
|
34
|
+
return CLI.do('help', 'select')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (id.startsWith('#')) id = id.slice(1)
|
|
38
|
+
CLI.load(id)
|
|
39
|
+
if (String(CLI.GAME?.id) === id) {
|
|
40
|
+
CLI.out(CLI.color(`Game #${id} selected.`))
|
|
41
|
+
if (cmds.length > 0) {
|
|
42
|
+
CLI.doNext(cmds.join(' '))
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
CLI.error('Invalid id. Type "list" to see available games.')
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/cmds/undo.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* Copyright 2022 Chad Transtrum
|
|
2
|
+
*
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
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.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// CLI undo command
|
|
17
|
+
|
|
18
|
+
export const undoCmd = {
|
|
19
|
+
name: 'undo',
|
|
20
|
+
args: '[n]',
|
|
21
|
+
comp: '<move>',
|
|
22
|
+
desc: 'undo the last move in a game',
|
|
23
|
+
help: [
|
|
24
|
+
'Backtrack one or more moves in a game. Type "undo" to take back the last',
|
|
25
|
+
'move, or "undo 2" to undo the last two moves.',
|
|
26
|
+
],
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
undoCmd.fn = (CLI, n) => {
|
|
30
|
+
n = Math.max(1, Math.floor(Number(n) || 1)) // Get an integer 1 or higher
|
|
31
|
+
|
|
32
|
+
const { moves } = CLI.TRAX
|
|
33
|
+
const undo = moves.slice(0, 0 - n)
|
|
34
|
+
if (moves.length === undo.length) {
|
|
35
|
+
CLI.error('Unable to undo.')
|
|
36
|
+
} else {
|
|
37
|
+
CLI.setGame(undo)
|
|
38
|
+
CLI.do('view')
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/cmds/view.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* Copyright 2022 Chad Transtrum
|
|
2
|
+
*
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
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.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// CLI view command
|
|
17
|
+
|
|
18
|
+
export const viewCmd = {
|
|
19
|
+
name: 'view',
|
|
20
|
+
alt: ['show', 'display'],
|
|
21
|
+
args: '[move number]',
|
|
22
|
+
comp: '<move>',
|
|
23
|
+
desc: 'show the game board',
|
|
24
|
+
help: [
|
|
25
|
+
'Show the current game. Include a move number to see the board as it was at',
|
|
26
|
+
'that move.',
|
|
27
|
+
],
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
viewCmd.fn = (CLI, move) => {
|
|
31
|
+
if (!CLI.GAME?.id) {
|
|
32
|
+
return CLI.error('No active game. Type "new" to start a game.')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const trax = CLI.TRAX
|
|
36
|
+
|
|
37
|
+
let show = Number.POSITIVE_INFINITY
|
|
38
|
+
if (move && Number(move) >= 0 && Number(move) <= trax.moves.length) {
|
|
39
|
+
show = Number(move)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const players = CLI.GAME.players || ['white', 'black']
|
|
43
|
+
|
|
44
|
+
CLI.out(
|
|
45
|
+
CLI.color('#' + CLI.ID + ' ') +
|
|
46
|
+
CLI.name(trax.rules) +
|
|
47
|
+
' ' +
|
|
48
|
+
CLI.bubble('w' + (trax.turn === 1 ? 'h' : ''), players[0]) +
|
|
49
|
+
CLI.color(' vs ') +
|
|
50
|
+
CLI.bubble('b' + (trax.turn === 2 ? 'h' : ''), players[1]),
|
|
51
|
+
)
|
|
52
|
+
CLI.display(trax, players, false, show)
|
|
53
|
+
}
|
package/src/point.js
CHANGED
|
@@ -23,6 +23,8 @@ export const Point = class {
|
|
|
23
23
|
#x = 0
|
|
24
24
|
#y = 0
|
|
25
25
|
|
|
26
|
+
static dirs = ['up', 'down', 'left', 'right']
|
|
27
|
+
|
|
26
28
|
constructor(x, y) {
|
|
27
29
|
if (is(x, 'obj') && is(x.x, 'num') && is(x.y, 'num')) {
|
|
28
30
|
// You can call this with new Point(point) or new Point({x,y})
|
|
@@ -76,6 +78,7 @@ export const Point = class {
|
|
|
76
78
|
dir(direction) {
|
|
77
79
|
const error = 'direction must be one of: up, down, left, right, u, d, l, r'
|
|
78
80
|
if (!is(direction, 'str')) throw new SyntaxError(error)
|
|
81
|
+
direction = direction.toLowerCase()
|
|
79
82
|
if (direction[0] === 'u') return this.up
|
|
80
83
|
if (direction[0] === 'd') return this.down
|
|
81
84
|
if (direction[0] === 'l') return this.left
|
|
@@ -99,6 +102,15 @@ export const Point = class {
|
|
|
99
102
|
return this.#x === that.x && this.#y === that.y
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
in(topLeft, bottomRight) {
|
|
106
|
+
return (
|
|
107
|
+
this.x >= topLeft.x &&
|
|
108
|
+
this.x <= bottomRight.x &&
|
|
109
|
+
this.y >= topLeft.y &&
|
|
110
|
+
this.y <= bottomRight.y
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
102
114
|
// Play nicely with the rest of the world
|
|
103
115
|
|
|
104
116
|
toString() {
|
package/src/tty.js
CHANGED
|
@@ -24,12 +24,10 @@ const off = esc + 'm' // Color reset code
|
|
|
24
24
|
|
|
25
25
|
// Colorize a string
|
|
26
26
|
export const color = (contents = '', fgcolor = '', bgcolor = '') => {
|
|
27
|
-
let ansi = esc
|
|
28
27
|
const c = []
|
|
29
28
|
if (fgcolor) c.push('38;5;' + fgcolor)
|
|
30
29
|
if (bgcolor) c.push('48;5;' + bgcolor)
|
|
31
|
-
|
|
32
|
-
return ansi + contents
|
|
30
|
+
return esc + c.join(';') + 'm' + contents
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
// Display a message with optional color
|
|
@@ -229,14 +227,14 @@ export const traxGame = (game = 'trax', moves = '') => {
|
|
|
229
227
|
return trax
|
|
230
228
|
}
|
|
231
229
|
|
|
232
|
-
const printNotation = (trax, tentative) => {
|
|
230
|
+
const printNotation = (trax, tentative, show = Number.POSITIVE_INFINITY) => {
|
|
233
231
|
let b = false
|
|
234
232
|
let n = 1
|
|
235
233
|
let out = ''
|
|
236
234
|
let length = 0
|
|
237
|
-
const t = tentative ? trax.moves.length :
|
|
235
|
+
const t = tentative ? trax.moves.length - 1 : show
|
|
238
236
|
for (const move of trax.moves) {
|
|
239
|
-
const c = (b ? 'b' : 'w') + (t
|
|
237
|
+
const c = (b ? 'b' : 'w') + (t < n ? 'd' : show === n ? 'h' : '')
|
|
240
238
|
const notation = String(n) + ' ' + move
|
|
241
239
|
if (length + notation.length + 3 > process.stdout.columns) {
|
|
242
240
|
out += '\n'
|
|
@@ -252,7 +250,12 @@ const printNotation = (trax, tentative) => {
|
|
|
252
250
|
outty(out)
|
|
253
251
|
}
|
|
254
252
|
|
|
255
|
-
export const display = (
|
|
253
|
+
export const display = (
|
|
254
|
+
game,
|
|
255
|
+
players,
|
|
256
|
+
tentative = false,
|
|
257
|
+
showMove = Number.POSITIVE_INFINITY,
|
|
258
|
+
) => {
|
|
256
259
|
const trax = traxGame(game)
|
|
257
260
|
const saved = trax.save()
|
|
258
261
|
const colors = ['white', 'black']
|
|
@@ -265,9 +268,13 @@ export const display = (game, players, tentative = false) => {
|
|
|
265
268
|
} else {
|
|
266
269
|
tentative = false
|
|
267
270
|
}
|
|
271
|
+
} else if (showMove <= trax.moves.length) {
|
|
272
|
+
icon = trax.dropsIcon({
|
|
273
|
+
dropped: Object.values(trax.tiles).filter((t) => t.move > showMove),
|
|
274
|
+
})
|
|
268
275
|
}
|
|
269
276
|
|
|
270
|
-
printNotation(trax, tentative)
|
|
277
|
+
printNotation(trax, tentative, showMove)
|
|
271
278
|
printIcon(icon, trax.rules)
|
|
272
279
|
const nameColor = { 1: 'w', 2: 'b' }[trax.turn]
|
|
273
280
|
if (tentative) {
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '0.
|
|
2
|
+
export const version = '0.10.1'
|