@slugbugblue/trax 0.5.0 → 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 +43 -24
- package/README.md +44 -69
- package/docs/engine.md +342 -7
- package/docs/point.md +134 -0
- package/engine.js +134 -119
- package/package.json +16 -5
- package/point.js +116 -0
- package/tty.js +13 -17
- package/.eslintrc.backup.yaml +0 -68
- package/jsconfig.json +0 -8
package/point.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
const is = (v, s) => (typeof v).slice(0, 3) === s // Sigh
|
|
17
|
+
|
|
18
|
+
// Are you tired of doing x,y movements in multiple statements? I am.
|
|
19
|
+
|
|
20
|
+
// Point: an immutable two-dimensional location (x,y)
|
|
21
|
+
// with functions for moving around quickly to neighboring points
|
|
22
|
+
export const Point = class {
|
|
23
|
+
#x = 0
|
|
24
|
+
#y = 0
|
|
25
|
+
|
|
26
|
+
constructor(x, y) {
|
|
27
|
+
if (is(x, 'obj') && is(x.x, 'num') && is(x.y, 'num')) {
|
|
28
|
+
// You can call this with new Point(point) or new Point({x,y})
|
|
29
|
+
this.#x = x.x
|
|
30
|
+
this.#y = x.y
|
|
31
|
+
} else {
|
|
32
|
+
// Or with new Point(x, y)
|
|
33
|
+
if (!is(x, 'num')) throw new SyntaxError('x must be a number')
|
|
34
|
+
if (!is(y, 'num')) throw new SyntaxError('y must be a number')
|
|
35
|
+
this.#x = x
|
|
36
|
+
this.#y = y
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get x() {
|
|
41
|
+
return this.#x
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
set x(_) {
|
|
45
|
+
throw new ReferenceError('Point is immutable')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get y() {
|
|
49
|
+
return this.#y
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
set y(_) {
|
|
53
|
+
throw new ReferenceError('Point is immutable')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get up() {
|
|
57
|
+
return new Point(this.#x, this.#y - 1)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get down() {
|
|
61
|
+
return new Point(this.#x, this.#y + 1)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get left() {
|
|
65
|
+
return new Point(this.#x - 1, this.#y)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get right() {
|
|
69
|
+
return new Point(this.#x + 1, this.#y)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get around() {
|
|
73
|
+
return [this.up, this.down, this.left, this.right]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
dir(direction) {
|
|
77
|
+
const error = 'direction must be one of: up, down, left, right, u, d, l, r'
|
|
78
|
+
if (!is(direction, 'str')) throw new SyntaxError(error)
|
|
79
|
+
if (direction[0] === 'u') return this.up
|
|
80
|
+
if (direction[0] === 'd') return this.down
|
|
81
|
+
if (direction[0] === 'l') return this.left
|
|
82
|
+
if (direction[0] === 'r') return this.right
|
|
83
|
+
throw new SyntaxError(error)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
distX(from) {
|
|
87
|
+
return Math.abs(this.#x - from.x)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
distY(from) {
|
|
91
|
+
return Math.abs(this.#y - from.y)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
distance(from) {
|
|
95
|
+
return Math.hypot(this.distX(from), this.distY(from))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
eq(that) {
|
|
99
|
+
return this.#x === that.x && this.#y === that.y
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Play nicely with the rest of the world
|
|
103
|
+
|
|
104
|
+
toString() {
|
|
105
|
+
return 'Point(' + this.#x + ',' + this.#y + ')'
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
toJSON() {
|
|
109
|
+
return { x: this.#x, y: this.#y }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
[Symbol.for('nodejs.util.inspect.custom')](_, options) {
|
|
113
|
+
const [y, s, n] = [options.stylize, 'special', 'number']
|
|
114
|
+
return `${y('Point', s)}(${y(this.#x, n)},${y(this.#y, n)})`
|
|
115
|
+
}
|
|
116
|
+
}
|
package/tty.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import process from 'node:process'
|
|
19
19
|
|
|
20
|
-
import Trax from './engine.js'
|
|
20
|
+
import { Trax } from './engine.js'
|
|
21
21
|
|
|
22
22
|
const esc = '\u001B[' // Start of console color escape code
|
|
23
23
|
const off = esc + 'm' // Color reset code
|
|
@@ -53,19 +53,13 @@ const bg = (n) => '48;5;' + String(set[n]) // Background color_num
|
|
|
53
53
|
const sp = () => esc + bg('e') + 'm ' // Lower space
|
|
54
54
|
// tiles are displayed on two lines; the top half of the first line is empty
|
|
55
55
|
// and the second half is composed of three characters, up color surrounded by tile color
|
|
56
|
-
const uptty = (clr) =>
|
|
57
|
-
esc +
|
|
58
|
-
fg(
|
|
59
|
-
'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
fg(clr) +
|
|
64
|
-
ln +
|
|
65
|
-
esc +
|
|
66
|
-
fg('t') +
|
|
67
|
-
ln +
|
|
68
|
-
' '
|
|
56
|
+
const uptty = (clr) => {
|
|
57
|
+
const left = esc + fg('t') + ';' + bg('e') + ln
|
|
58
|
+
const center = esc + fg(clr) + ln
|
|
59
|
+
const right = esc + fg('t') + ln + ' '
|
|
60
|
+
return left + center + right
|
|
61
|
+
}
|
|
62
|
+
|
|
69
63
|
// The top half of the second line has both horizontal lines with a center transition
|
|
70
64
|
// while the bottom half is the tile background color surrounding the down color
|
|
71
65
|
const horiztty = (clr) => esc + fg('t') + ';' + bg(clr) + ln
|
|
@@ -174,12 +168,14 @@ const printIcon = (icon, setName) => {
|
|
|
174
168
|
if (width * 4 < columns - 4 && info.length < rows - 2) {
|
|
175
169
|
let colOut = ' '
|
|
176
170
|
for (let col = 1; col <= width; col++) {
|
|
177
|
-
colOut += ' ' + Trax.
|
|
171
|
+
colOut += ' ' + Trax.encodeCol(col).padEnd(3)
|
|
178
172
|
}
|
|
179
173
|
|
|
180
174
|
console.info(on + colOut.padEnd((width + 1) * 4) + off)
|
|
181
|
-
for (const line of info)
|
|
175
|
+
for (const line of info) {
|
|
182
176
|
console.info(on + line.o + ''.padEnd((width - line.w) * 4) + ' ' + off)
|
|
177
|
+
}
|
|
178
|
+
|
|
183
179
|
console.info(on + ''.padEnd((width + 1) * 4) + off)
|
|
184
180
|
} else {
|
|
185
181
|
console.warn('Console is too small to display this game')
|
|
@@ -211,7 +207,7 @@ export const displayGame = (game = 'trax', moves = '', tentative = false) => {
|
|
|
211
207
|
if (tentative) {
|
|
212
208
|
const drops = trax.dropTile(tentative)
|
|
213
209
|
if (drops.valid) {
|
|
214
|
-
icon = trax.
|
|
210
|
+
icon = trax.dropsIcon(drops)
|
|
215
211
|
} else {
|
|
216
212
|
tentative = false
|
|
217
213
|
}
|
package/.eslintrc.backup.yaml
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
root: true
|
|
2
|
-
|
|
3
|
-
extends:
|
|
4
|
-
- eslint:recommended
|
|
5
|
-
|
|
6
|
-
parserOptions:
|
|
7
|
-
sourceType: module
|
|
8
|
-
|
|
9
|
-
env:
|
|
10
|
-
node: true
|
|
11
|
-
es2021: true
|
|
12
|
-
|
|
13
|
-
globals:
|
|
14
|
-
crypto: readonly
|
|
15
|
-
|
|
16
|
-
rules:
|
|
17
|
-
curly:
|
|
18
|
-
- error
|
|
19
|
-
- multi-line
|
|
20
|
-
- consistent
|
|
21
|
-
dot-location:
|
|
22
|
-
- error
|
|
23
|
-
- property
|
|
24
|
-
dot-notation: warn
|
|
25
|
-
eqeqeq:
|
|
26
|
-
- warn
|
|
27
|
-
- smart
|
|
28
|
-
guard-for-in: warn
|
|
29
|
-
indent:
|
|
30
|
-
- warn
|
|
31
|
-
- 2
|
|
32
|
-
- MemberExpression: 0
|
|
33
|
-
SwitchCase: 1
|
|
34
|
-
linebreak-style:
|
|
35
|
-
- error
|
|
36
|
-
- unix
|
|
37
|
-
max-len:
|
|
38
|
-
- warn
|
|
39
|
-
- code: 99
|
|
40
|
-
tabWidth: 2
|
|
41
|
-
no-alert: error
|
|
42
|
-
no-caller: error
|
|
43
|
-
no-div-regex: warn
|
|
44
|
-
no-else-return:
|
|
45
|
-
- error
|
|
46
|
-
- allowElseIf: false
|
|
47
|
-
no-eval: error
|
|
48
|
-
no-extra-parens: warn
|
|
49
|
-
no-invalid-this: error
|
|
50
|
-
no-new: error
|
|
51
|
-
no-unused-vars:
|
|
52
|
-
- warn
|
|
53
|
-
- vars: all
|
|
54
|
-
args: all
|
|
55
|
-
caughtErrors: all
|
|
56
|
-
no-with: error
|
|
57
|
-
quotes:
|
|
58
|
-
- warn
|
|
59
|
-
- single
|
|
60
|
-
- avoidEscape: true
|
|
61
|
-
allowTemplateLiterals: true
|
|
62
|
-
semi:
|
|
63
|
-
- error
|
|
64
|
-
- never
|
|
65
|
-
- beforeStatementContinuationChars: always
|
|
66
|
-
wrap-iife:
|
|
67
|
-
- error
|
|
68
|
-
- inside
|