@slugbugblue/trax 0.17.0 → 0.19.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/.husky/pre-commit +4 -0
- package/CHANGELOG.md +32 -6
- package/Dockerfile +9 -0
- package/README.md +14 -5
- package/benchmark/benchmarks.json +60 -0
- package/benchmark/puzzles.bench.js +190 -0
- package/docs/analyst.md +16 -2
- package/docs/engine.md +2 -2
- package/docs/lru.md +151 -0
- package/package.json +7 -3
- package/src/analyst.js +139 -8
- package/src/cli.js +10 -1
- package/src/cmds/analyze.js +24 -4
- package/src/cmds/import-export.js +2 -7
- package/src/cmds/view.js +5 -2
- package/src/engine.js +8 -1
- package/src/lru.js +153 -0
- package/src/point.js +1 -1
- package/src/puzzles.js +135 -9
- package/src/threats.js +25 -4
- package/src/types.d.ts +15 -1
- package/src/version.js +1 -1
package/src/puzzles.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** This is a collection of puzzles.
|
|
2
|
-
* @copyright 2022
|
|
2
|
+
* @copyright 2022-2023
|
|
3
3
|
* @author Chad Transtrum <chad@transtrum.net>
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -23,6 +23,10 @@ export const sources = {
|
|
|
23
23
|
name: 'Donald G. Bailey',
|
|
24
24
|
url: 'http://www.traxgame.com/games_puzzles.php',
|
|
25
25
|
},
|
|
26
|
+
book1: {
|
|
27
|
+
name: 'Martin M. S. Pedersen',
|
|
28
|
+
url: 'https://gnutrax.com/book',
|
|
29
|
+
},
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
/** @type {Puzzle[]} */
|
|
@@ -396,7 +400,7 @@ export const puzzles = [
|
|
|
396
400
|
level: 2,
|
|
397
401
|
player: 2,
|
|
398
402
|
max: 10,
|
|
399
|
-
|
|
403
|
+
hints: ['A0\\', 'D0/'],
|
|
400
404
|
},
|
|
401
405
|
{
|
|
402
406
|
id: 'eb8.trx',
|
|
@@ -440,7 +444,7 @@ export const puzzles = [
|
|
|
440
444
|
level: 2,
|
|
441
445
|
player: 1,
|
|
442
446
|
max: 11,
|
|
443
|
-
hints: ['A0/', 'C4\\', '
|
|
447
|
+
hints: ['A0/', 'C4\\', 'D4/'],
|
|
444
448
|
},
|
|
445
449
|
{
|
|
446
450
|
id: 'iw3.trx',
|
|
@@ -598,14 +602,15 @@ export const puzzles = [
|
|
|
598
602
|
},
|
|
599
603
|
{
|
|
600
604
|
id: 'ib10.trx',
|
|
605
|
+
title: "Sucker's Opening",
|
|
601
606
|
src: 'traxgame',
|
|
602
607
|
game: 'traxloop',
|
|
603
|
-
notation: '@0/
|
|
608
|
+
notation: '@0/ @1/ B0\\',
|
|
604
609
|
icon: '0a:cd',
|
|
605
610
|
level: 3,
|
|
606
611
|
player: 2,
|
|
607
|
-
max:
|
|
608
|
-
hint: '
|
|
612
|
+
max: 14,
|
|
613
|
+
hint: '@2\\',
|
|
609
614
|
},
|
|
610
615
|
{
|
|
611
616
|
id: 'ib11.trx',
|
|
@@ -745,7 +750,7 @@ export const puzzles = [
|
|
|
745
750
|
game: 'traxloop',
|
|
746
751
|
notation: '@0/ A2+ A3+ A4\\ B3\\ B4+ B5\\ C5/ C4+ D4/ D5+ E5/ E4/',
|
|
747
752
|
icon: 'd:b:ba:aeecd:0fdec',
|
|
748
|
-
level:
|
|
753
|
+
level: 2,
|
|
749
754
|
player: 2,
|
|
750
755
|
max: 18,
|
|
751
756
|
hints: ['B1+', 'B2/', 'D3+'],
|
|
@@ -758,8 +763,8 @@ export const puzzles = [
|
|
|
758
763
|
icon: 'ecd',
|
|
759
764
|
level: 3,
|
|
760
765
|
player: 2,
|
|
761
|
-
max:
|
|
762
|
-
|
|
766
|
+
max: 16,
|
|
767
|
+
hints: ['A0+', 'C2\\'],
|
|
763
768
|
},
|
|
764
769
|
{
|
|
765
770
|
id: 'hb4.trx',
|
|
@@ -805,6 +810,127 @@ export const puzzles = [
|
|
|
805
810
|
max: 16,
|
|
806
811
|
hint: 'B1+',
|
|
807
812
|
},
|
|
813
|
+
{
|
|
814
|
+
id: 'book_01.trx',
|
|
815
|
+
src: 'book1',
|
|
816
|
+
game: 'traxloop',
|
|
817
|
+
notation: '@0/ @1+ B0/ C1+ D2/ C3/',
|
|
818
|
+
icon: 'dcba:bdcd:1dc',
|
|
819
|
+
level: 2,
|
|
820
|
+
player: 1,
|
|
821
|
+
max: 13,
|
|
822
|
+
hint: '@2/',
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
id: 'book_02.trx',
|
|
826
|
+
src: 'book1',
|
|
827
|
+
game: 'traxloop',
|
|
828
|
+
notation: '@0+ B1+ C1/ B0/ B0/ B0/ B0/ D5/ E5/ E6+ C4/ C3+ B6+',
|
|
829
|
+
icon: '0df:0ca:0df:cd:eecdc:0efae',
|
|
830
|
+
level: 2,
|
|
831
|
+
player: 2,
|
|
832
|
+
max: 18,
|
|
833
|
+
hints: ['D2\\', 'D3/'],
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
id: 'book_03.trx',
|
|
837
|
+
src: 'book1',
|
|
838
|
+
game: 'traxloop',
|
|
839
|
+
notation: '@0/ @1/ @1+ @1/ @1+ C0/ D1/ E1+ D0+ E1+ F1\\ E0+',
|
|
840
|
+
icon: '3e:1deef:1cdec:bdecd',
|
|
841
|
+
level: 3,
|
|
842
|
+
player: 1,
|
|
843
|
+
max: 19,
|
|
844
|
+
hint: 'C1\\',
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
id: 'book_04.trx',
|
|
848
|
+
src: 'book1',
|
|
849
|
+
game: 'traxloop',
|
|
850
|
+
notation: '@0+ B1/ @1/ A0/ C3/ A4+ @4+ @3/ a5\\',
|
|
851
|
+
icon: '1caf:1dec:dcafd:aeec:fd',
|
|
852
|
+
level: 3,
|
|
853
|
+
player: 2,
|
|
854
|
+
max: 16,
|
|
855
|
+
hint: 'C0/',
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
id: 'book_05.trx',
|
|
859
|
+
src: 'book1',
|
|
860
|
+
game: 'traxloop',
|
|
861
|
+
notation: '@0/ @1/ B0+ @2+ A0/ @2+',
|
|
862
|
+
icon: 'cd:ecde:0ecd',
|
|
863
|
+
level: 2,
|
|
864
|
+
player: 1,
|
|
865
|
+
max: 15,
|
|
866
|
+
hints: ['B4\\', 'C4/'],
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
id: 'book_07.trx',
|
|
870
|
+
src: 'book1',
|
|
871
|
+
game: 'traxloop',
|
|
872
|
+
notation: '@0/ A2+ A0+ @2\\ B0+ C1+ B0/ B0/ A2+',
|
|
873
|
+
icon: 'cdf:eca:0ee:0e:fd:0b',
|
|
874
|
+
level: 2,
|
|
875
|
+
player: 2,
|
|
876
|
+
max: 14,
|
|
877
|
+
hint: 'C6+',
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
id: 'book_08.trx',
|
|
881
|
+
src: 'book1',
|
|
882
|
+
game: 'traxloop',
|
|
883
|
+
notation: '@0/ @1/ A2/ A0/ B1/ @1+ @1/ A0/ @1/',
|
|
884
|
+
icon: 'cdfaf:0cbdc:0facd:0afdc',
|
|
885
|
+
level: 3,
|
|
886
|
+
player: 2,
|
|
887
|
+
max: 18,
|
|
888
|
+
hint: 'A0\\',
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
id: 'book_09.trx',
|
|
892
|
+
src: 'book1',
|
|
893
|
+
game: 'traxloop',
|
|
894
|
+
notation: '@0/ @1/ B0/ B0/ A0/ A5/ @3\\ @4/',
|
|
895
|
+
icon: '1d:1cd:dfdc:cacd:0fdc',
|
|
896
|
+
level: 3,
|
|
897
|
+
player: 1,
|
|
898
|
+
max: 15,
|
|
899
|
+
hint: 'A2\\',
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
id: 'book_10.trx',
|
|
903
|
+
src: 'book1',
|
|
904
|
+
game: 'traxloop',
|
|
905
|
+
notation: '@0/ A0+ A0/ A4+ A0/ A0/ B4+ C4/ @4+ @4/ @4/',
|
|
906
|
+
icon: '2caf:2dfa:2caf:cdeeec:fafd:2b',
|
|
907
|
+
level: 2,
|
|
908
|
+
player: 2,
|
|
909
|
+
max: 18,
|
|
910
|
+
hint: 'E6+',
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
id: 'book_11.trx',
|
|
914
|
+
src: 'book1',
|
|
915
|
+
game: 'traxloop',
|
|
916
|
+
notation: '@0+ B1+ C1/ C0/ B0/ @3+',
|
|
917
|
+
icon: '1d:1cd:eeec',
|
|
918
|
+
level: 1,
|
|
919
|
+
player: 1,
|
|
920
|
+
max: 9,
|
|
921
|
+
hint: 'B1\\',
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
id: 'book_12.trx',
|
|
925
|
+
src: 'book1',
|
|
926
|
+
game: 'traxloop',
|
|
927
|
+
notation: '@0+ B1+ C1/ C0/ B0/ D2+',
|
|
928
|
+
icon: '0d:0cde:eecd',
|
|
929
|
+
level: 3,
|
|
930
|
+
player: 1,
|
|
931
|
+
max: 15,
|
|
932
|
+
hint: 'B4\\',
|
|
933
|
+
},
|
|
808
934
|
]
|
|
809
935
|
|
|
810
936
|
puzzles.sort(
|
package/src/threats.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Threats database: hand-coded threats
|
|
2
|
-
* @copyright 2022
|
|
2
|
+
* @copyright 2022-2023
|
|
3
3
|
* @author Chad Transtrum <chad@transtrum.net>
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -21,7 +21,7 @@ const REGEX = {
|
|
|
21
21
|
'?': 'b?', // Zero or one black piece
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export
|
|
24
|
+
export class Threat {
|
|
25
25
|
#depth = 0
|
|
26
26
|
#pattern = ''
|
|
27
27
|
#rx
|
|
@@ -72,7 +72,7 @@ export const Threat = class {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
export
|
|
75
|
+
export class ThreatsDB {
|
|
76
76
|
#db = {}
|
|
77
77
|
#depth = 0
|
|
78
78
|
|
|
@@ -89,7 +89,7 @@ export const ThreatsDB = class {
|
|
|
89
89
|
|
|
90
90
|
add(depth, pattern, reforms = false) {
|
|
91
91
|
this.#depth = Math.max(depth, this.#depth)
|
|
92
|
-
if (pattern in this.#db) throw new Error('Duplicate pattern:' + pattern)
|
|
92
|
+
if (pattern in this.#db) throw new Error('Duplicate pattern: ' + pattern)
|
|
93
93
|
this.#db[pattern] = new Threat(depth, pattern, reforms)
|
|
94
94
|
return this.#db[pattern]
|
|
95
95
|
}
|
|
@@ -175,6 +175,8 @@ for (const one of Object.keys(corners)) {
|
|
|
175
175
|
threats.compose(3, one + '!bbrmW') // Same, but slightly different layout
|
|
176
176
|
threats.compose(3, 'ab*lrb¡' + one) // Reverse
|
|
177
177
|
threats.compose(3, 'alrbb¡' + one) // Reverse of different layout
|
|
178
|
+
threats.compose(4, one + '!b*b¡ra?lr') // Partial edge with attack into hollow
|
|
179
|
+
threats.compose(4, 'rm?wr!b*b¡' + one) // Reverse
|
|
178
180
|
|
|
179
181
|
for (const two of Object.keys(corners)) {
|
|
180
182
|
end = two.replace(/[aA]/, 'm').replace('C', 'p')
|
|
@@ -188,9 +190,14 @@ for (const one of Object.keys(corners)) {
|
|
|
188
190
|
if (post) {
|
|
189
191
|
threats.compose(2, one + post + '!' + end) // L
|
|
190
192
|
threats.compose(3, one + post + '!br' + end) // Three-stage
|
|
193
|
+
threats.compose(3, one + post + 'r' + end) // Defense forms an L
|
|
191
194
|
threats.compose(3, one + '!br¡?' + end) // Attack to form an L threat
|
|
192
195
|
}
|
|
193
196
|
|
|
197
|
+
if (pre && post) {
|
|
198
|
+
threats.compose(3, start + 'r' + end) // Defense forms an L
|
|
199
|
+
}
|
|
200
|
+
|
|
194
201
|
threats.compose(3, one + '!b*b¡' + two) // Edge threat
|
|
195
202
|
}
|
|
196
203
|
}
|
|
@@ -200,3 +207,17 @@ threats.add(3, 'Arlbmwr') // Reversed
|
|
|
200
207
|
|
|
201
208
|
threats.add(4, 'rb¡c?w!br') // Connectable pair on an edge
|
|
202
209
|
threats.add(4, 'ArlbmrW') // Wide cave ready for an attack
|
|
210
|
+
|
|
211
|
+
// Threats to solve puzzle iw1.trx
|
|
212
|
+
threats.add(5, 'A?rwarlrar?W') // Back to back white corners next to a corner
|
|
213
|
+
threats.add(4, 'A?rlr!bralrar?W') // ... activated ... becomes:
|
|
214
|
+
threats.add(4, 'A?rlrbrmrwar?W') // Corner surrounded by corners
|
|
215
|
+
threats.add(4, 'A?rlr!bramrar?W') // ... activated ...
|
|
216
|
+
threats.add(3, 'A?rlr!brm?wr!brmrW') // ... defended ...
|
|
217
|
+
|
|
218
|
+
// Threats to solve puzzle ib10.trx
|
|
219
|
+
threats.add(6, 'Arw!b?rarlr') // Sucker's Opening
|
|
220
|
+
threats.add(5, 'Arw!b?brbralr') // ... activated ... becomes:
|
|
221
|
+
threats.add(4, 'Arw!b?brb¡arbW') // Wide corner opposite nearly formed edge
|
|
222
|
+
threats.add(5, 'Arw!b?brb¡rmrW') // ... or hollow corner opposite same edge
|
|
223
|
+
threats.add(4, 'Arw!b?brb¡rmwr') // ... activated ...
|
package/src/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Type information.
|
|
2
|
+
* @copyright 2022-2023
|
|
2
3
|
* @author Chad Transtrum <chad@transtrum.net>
|
|
3
4
|
* @license Apache-2.0
|
|
4
5
|
*/
|
|
@@ -44,6 +45,7 @@ type EdgeLocation = {
|
|
|
44
45
|
pw?: boolean
|
|
45
46
|
zb?: string
|
|
46
47
|
zw?: string
|
|
48
|
+
idx?: number
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
type EdgeObject = {
|
|
@@ -53,7 +55,19 @@ type EdgeObject = {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
/** Object representing a concrete threat found in a position. */
|
|
56
|
-
type FoundThreat = {
|
|
58
|
+
type FoundThreat = {
|
|
59
|
+
threat: string
|
|
60
|
+
match: string
|
|
61
|
+
at: number
|
|
62
|
+
value: number
|
|
63
|
+
level: number
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Threats found for each color that cannot actually be activated. */
|
|
67
|
+
type FaultyThreats = {
|
|
68
|
+
b: FoundThreat[]
|
|
69
|
+
w: FoundThreat[]
|
|
70
|
+
}
|
|
57
71
|
|
|
58
72
|
/** An object with keys representing each level, with arrays for each threat of
|
|
59
73
|
* that level. */
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '0.
|
|
2
|
+
export const version = '0.19.0'
|