@slugbugblue/trax 0.18.0 → 0.20.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/src/puzzles.js CHANGED
@@ -26,6 +26,9 @@ export const sources = {
26
26
  book1: {
27
27
  name: 'Martin M. S. Pedersen',
28
28
  url: 'https://gnutrax.com/book',
29
+ copyright: '2011',
30
+ license: 'CC BY 4.0',
31
+ licenseUrl: 'https://creativecommons.org/licenses/by/4.0/',
29
32
  },
30
33
  }
31
34
 
@@ -764,7 +767,7 @@ export const puzzles = [
764
767
  level: 3,
765
768
  player: 2,
766
769
  max: 16,
767
- hints: ['A0+', 'C2\\'],
770
+ hint: 'A0+',
768
771
  },
769
772
  {
770
773
  id: 'hb4.trx',
@@ -811,7 +814,7 @@ export const puzzles = [
811
814
  hint: 'B1+',
812
815
  },
813
816
  {
814
- id: 'book_01.trx',
817
+ id: 'book.01',
815
818
  src: 'book1',
816
819
  game: 'traxloop',
817
820
  notation: '@0/ @1+ B0/ C1+ D2/ C3/',
@@ -822,18 +825,18 @@ export const puzzles = [
822
825
  hint: '@2/',
823
826
  },
824
827
  {
825
- id: 'book_02.trx',
828
+ id: 'book.02',
826
829
  src: 'book1',
827
830
  game: 'traxloop',
828
831
  notation: '@0+ B1+ C1/ B0/ B0/ B0/ B0/ D5/ E5/ E6+ C4/ C3+ B6+',
829
- icon: '0df:0ca:0df:cd:eecdc:0efae',
832
+ icon: '0df:0ca:0de:0cd:eecdc:0efae',
830
833
  level: 2,
831
834
  player: 2,
832
835
  max: 18,
833
836
  hints: ['D2\\', 'D3/'],
834
837
  },
835
838
  {
836
- id: 'book_03.trx',
839
+ id: 'book.03',
837
840
  src: 'book1',
838
841
  game: 'traxloop',
839
842
  notation: '@0/ @1/ @1+ @1/ @1+ C0/ D1/ E1+ D0+ E1+ F1\\ E0+',
@@ -844,18 +847,18 @@ export const puzzles = [
844
847
  hint: 'C1\\',
845
848
  },
846
849
  {
847
- id: 'book_04.trx',
850
+ id: 'book.04',
848
851
  src: 'book1',
849
852
  game: 'traxloop',
850
- notation: '@0+ B1/ @1/ A0/ C3/ A4+ @4+ @3/ a5\\',
853
+ notation: '@0+ B1/ @1/ A0/ C3/ A4+ @4+ @3/ A5\\',
851
854
  icon: '1caf:1dec:dcafd:aeec:fd',
852
855
  level: 3,
853
856
  player: 2,
854
857
  max: 16,
855
- hint: 'C0/',
858
+ hints: ['C0/', 'D0\\'],
856
859
  },
857
860
  {
858
- id: 'book_05.trx',
861
+ id: 'book.05',
859
862
  src: 'book1',
860
863
  game: 'traxloop',
861
864
  notation: '@0/ @1/ B0+ @2+ A0/ @2+',
@@ -866,7 +869,7 @@ export const puzzles = [
866
869
  hints: ['B4\\', 'C4/'],
867
870
  },
868
871
  {
869
- id: 'book_07.trx',
872
+ id: 'book.07',
870
873
  src: 'book1',
871
874
  game: 'traxloop',
872
875
  notation: '@0/ A2+ A0+ @2\\ B0+ C1+ B0/ B0/ A2+',
@@ -877,7 +880,7 @@ export const puzzles = [
877
880
  hint: 'C6+',
878
881
  },
879
882
  {
880
- id: 'book_08.trx',
883
+ id: 'book.08',
881
884
  src: 'book1',
882
885
  game: 'traxloop',
883
886
  notation: '@0/ @1/ A2/ A0/ B1/ @1+ @1/ A0/ @1/',
@@ -888,7 +891,7 @@ export const puzzles = [
888
891
  hint: 'A0\\',
889
892
  },
890
893
  {
891
- id: 'book_09.trx',
894
+ id: 'book.09',
892
895
  src: 'book1',
893
896
  game: 'traxloop',
894
897
  notation: '@0/ @1/ B0/ B0/ A0/ A5/ @3\\ @4/',
@@ -899,7 +902,7 @@ export const puzzles = [
899
902
  hint: 'A2\\',
900
903
  },
901
904
  {
902
- id: 'book_10.trx',
905
+ id: 'book.10',
903
906
  src: 'book1',
904
907
  game: 'traxloop',
905
908
  notation: '@0/ A0+ A0/ A4+ A0/ A0/ B4+ C4/ @4+ @4/ @4/',
@@ -907,10 +910,10 @@ export const puzzles = [
907
910
  level: 2,
908
911
  player: 2,
909
912
  max: 18,
910
- hint: 'E6+',
913
+ hints: ['D7\\', 'E6+'],
911
914
  },
912
915
  {
913
- id: 'book_11.trx',
916
+ id: 'book.11',
914
917
  src: 'book1',
915
918
  game: 'traxloop',
916
919
  notation: '@0+ B1+ C1/ C0/ B0/ @3+',
@@ -921,7 +924,7 @@ export const puzzles = [
921
924
  hint: 'B1\\',
922
925
  },
923
926
  {
924
- id: 'book_12.trx',
927
+ id: 'book.12',
925
928
  src: 'book1',
926
929
  game: 'traxloop',
927
930
  notation: '@0+ B1+ C1/ C0/ B0/ D2+',
@@ -929,8 +932,274 @@ export const puzzles = [
929
932
  level: 3,
930
933
  player: 1,
931
934
  max: 15,
935
+ hints: ['B4\\', 'C4/'],
936
+ },
937
+ {
938
+ id: 'book.13',
939
+ src: 'book1',
940
+ game: 'traxloop',
941
+ notation: '@0/ @1/ B2+ A0\\ @1+ @1\\ C4/ B4/',
942
+ icon: 'aefa:1cd:1fb:0dc',
943
+ level: 3,
944
+ player: 1,
945
+ max: 15,
946
+ hint: 'C5\\',
947
+ },
948
+ {
949
+ id: 'book.15',
950
+ src: 'book1',
951
+ game: 'traxloop',
952
+ notation: '@0/ A0/ @1+ A0\\ C1+ D1+ B0+ A0/ @5+ A2/ A0+ @1\\ A4+ @4+',
953
+ icon: 'caef:dfdca:cacdef:eefafbb:0faec:0aefd',
954
+ level: 3,
955
+ player: 1,
956
+ max: 21,
957
+ hints: ['B7\\', 'C7/'],
958
+ },
959
+ {
960
+ id: 'book.17',
961
+ src: 'book1',
962
+ game: 'traxloop',
963
+ notation: '@0/ @1/ B0+ C1/ @1\\ B0/ C0/ D0+ A2+ @2+',
964
+ icon: '2de:eecaf:0fdec:0acd',
965
+ level: 3,
966
+ player: 1,
967
+ max: 19,
968
+ hints: ['A1/', 'B1\\'],
969
+ },
970
+ {
971
+ id: 'book.18',
972
+ src: 'book1',
973
+ game: 'traxloop',
974
+ notation: '@0+ B1+ C1/ B2\\ B3\\ B4\\ B5\\',
975
+ icon: 'eec:0fd:0ac:0fd:0ac',
976
+ level: 2,
977
+ player: 2,
978
+ max: 14,
979
+ hint: 'D3+',
980
+ },
981
+ {
982
+ id: 'book.19',
983
+ src: 'book1',
984
+ game: 'traxloop',
985
+ notation: '@0+ B1+ @1/ @1/ B2\\',
986
+ icon: 'cdee:fa',
987
+ level: 2,
988
+ player: 2,
989
+ max: 12,
990
+ hint: 'E1\\',
991
+ },
992
+ {
993
+ id: 'book.20',
994
+ src: 'book1',
995
+ game: 'traxloop',
996
+ notation: '@0/ @1/ B0+ B0/ C3+ D3+ E3\\',
997
+ icon: '0c:de:cdeef',
998
+ level: 2,
999
+ player: 2,
1000
+ max: 14,
1001
+ hints: ['C4+', 'B4\\'],
1002
+ },
1003
+ {
1004
+ id: 'book.23',
1005
+ src: 'book1',
1006
+ game: 'traxloop',
1007
+ notation: '@0+ @1\\ @1\\ @1\\ @1+ A0+ @1/ B3\\ E3/',
1008
+ icon: 'cb:fbafae:0a1d',
1009
+ level: 2,
1010
+ player: 2,
1011
+ max: 12,
1012
+ hint: 'F1+',
1013
+ },
1014
+ {
1015
+ id: 'book.25',
1016
+ src: 'book1',
1017
+ game: 'traxloop',
1018
+ notation: '@0/ @1/ B0/ B0+ C1/ C0+ B0/ A2+ @1/ @3\\',
1019
+ icon: '0cdca:0fbde:facbd:afdc:facd',
1020
+ level: 3,
1021
+ player: 1,
1022
+ max: 17,
1023
+ hint: 'B0+',
1024
+ },
1025
+ {
1026
+ id: 'book.26',
1027
+ src: 'book1',
1028
+ game: 'traxloop',
1029
+ notation: '@0/ @1/ @1/ @1+ A0\\ B0+ @3/ @3/',
1030
+ icon: '1cbaf:cdfafa:dcbdcd',
1031
+ level: 4,
1032
+ player: 1,
1033
+ max: 21,
932
1034
  hint: 'B4\\',
933
1035
  },
1036
+ {
1037
+ id: 'book.28',
1038
+ src: 'book1',
1039
+ game: 'traxloop',
1040
+ notation: '@0/ @1/ B0/ C1/ C0/ @2+ A0+ D0+ @2\\ @3+ A4/ @4\\ A2/',
1041
+ icon: '3cde:dcaefaf:aefdcdc:fdcbdcd:0afacdc',
1042
+ level: 2,
1043
+ player: 2,
1044
+ max: 20,
1045
+ hint: 'G6+',
1046
+ },
1047
+ {
1048
+ id: 'book.29',
1049
+ src: 'book1',
1050
+ game: 'traxloop',
1051
+ notation: '@0/ B1+ B2\\ B3/',
1052
+ icon: 'de:af:0c',
1053
+ level: 3,
1054
+ player: 1,
1055
+ max: 13,
1056
+ hint: '@2/',
1057
+ },
1058
+ {
1059
+ id: 'book.30',
1060
+ src: 'book1',
1061
+ game: 'traxloop',
1062
+ notation:
1063
+ '@0/ @1/ @1/ D1+ A2+ E1+ E2+ E0+ F1\\ G1+ G2\\ F3+ E4\\ G3+ H2\\ C5\\ D5+ D6\\ D7\\',
1064
+ icon: '3efba:dcdeecaf:bdcdeeec:0afafd:0faec:2fd:2ac',
1065
+ level: 4,
1066
+ player: 2,
1067
+ max: 30,
1068
+ hints: ['H4/', 'G4\\'],
1069
+ },
1070
+ {
1071
+ id: 'book.31',
1072
+ src: 'book1',
1073
+ game: 'traxloop',
1074
+ notation: '@0/ @1/ C1/ A2+ B3+ A3/ D3\\ B4\\ D4+ C5+ E2\\ E3+',
1075
+ icon: 'cdcaf:ecdfa:decae:afde:1bd',
1076
+ level: 3,
1077
+ player: 1,
1078
+ max: 23,
1079
+ hints: ['E0/', '@4/'],
1080
+ },
1081
+ {
1082
+ id: 'book.32',
1083
+ src: 'book1',
1084
+ game: 'traxloop',
1085
+ notation: '@0/ @1+ C1/ B2+ A2/ B3+ D2/ E2\\ D3+ F2+ G2\\ G3\\ C4\\ C5+ A4+',
1086
+ icon: 'bdc:cbdcaef:fbaeefa:bafd:afb',
1087
+ level: 3,
1088
+ player: 2,
1089
+ max: 24,
1090
+ hint: 'G4+',
1091
+ },
1092
+ {
1093
+ id: 'book.35',
1094
+ src: 'book1',
1095
+ game: 'traxloop',
1096
+ notation: '@0+ B1+ A0+ @2+ @2+ @2+ A1+ @1/ E3/',
1097
+ icon: 'de1e:aeeeee:2fd',
1098
+ level: 4,
1099
+ player: 2,
1100
+ max: 20,
1101
+ hint: 'E4\\',
1102
+ },
1103
+ {
1104
+ id: 'book.38',
1105
+ src: 'book1',
1106
+ game: 'traxloop',
1107
+ notation: '@0/ B1/ C1/ D1/ A2+ E1+ D3\\ E3+ F3+ F4\\ G4\\ F5\\ G5\\',
1108
+ icon: 'dcdcb:bdcdca:0afaeef:4fa:4af',
1109
+ level: 3,
1110
+ player: 2,
1111
+ max: 22,
1112
+ hint: 'B4+',
1113
+ },
1114
+ {
1115
+ id: 'book.40',
1116
+ src: 'book1',
1117
+ game: 'traxloop',
1118
+ notation: '@0/ @1/ A2+ @2/ @2/ B1+ B3\\',
1119
+ icon: 'decd:cdec:fa',
1120
+ level: 3,
1121
+ player: 2,
1122
+ max: 14,
1123
+ hint: 'E2+',
1124
+ },
1125
+ {
1126
+ id: 'book.42',
1127
+ src: 'book1',
1128
+ game: 'traxloop',
1129
+ notation: '@0/ B1+ @1+ A2/ A3+ B0+ D2+ E2\\ D1/',
1130
+ icon: 'deeca:bdeef:c:d',
1131
+ level: 2,
1132
+ player: 2,
1133
+ max: 16,
1134
+ hint: 'F1/',
1135
+ },
1136
+ {
1137
+ id: 'book.43',
1138
+ src: 'book1',
1139
+ game: 'traxloop',
1140
+ notation:
1141
+ '@0/ A0/ A0/ A0+ @1\\ C1+ D1/ E1+ F1/ D0+ B1+ A0/ @1+ @1/ D0+ D0\\',
1142
+ icon: '2f:2ba:decaf:afdecb:1aeecbd:1fd:1ac:1fd',
1143
+ level: 3,
1144
+ player: 1,
1145
+ max: 27,
1146
+ hints: ['E6\\', 'F6/'],
1147
+ },
1148
+ {
1149
+ id: 'book.44',
1150
+ src: 'book1',
1151
+ game: 'traxloop',
1152
+ notation: '@0/ @1/ C1/ D1+ B2/ D3\\ E1\\ D0/ F2+ E4+ F3\\ F4\\',
1153
+ icon: '2dfa:cdcbae:0cdcdf:0fafba',
1154
+ level: 3,
1155
+ player: 1,
1156
+ max: 19,
1157
+ hint: 'D5+',
1158
+ },
1159
+ {
1160
+ id: 'book.45',
1161
+ src: 'book1',
1162
+ game: 'traxloop',
1163
+ notation: 'A0+ B1+ C1/ C0/ B0/ D2\\ A4\\ A5\\ C4+ @3+',
1164
+ icon: '1d:1cdf:eeec:0fde:0acd',
1165
+ level: 3,
1166
+ player: 1,
1167
+ max: 17,
1168
+ hint: 'E1/',
1169
+ },
1170
+ {
1171
+ id: 'book.47',
1172
+ src: 'book1',
1173
+ game: 'traxloop',
1174
+ notation: '@0/ A0/ @2+ B0+ B0+ @3\\ @3\\ @3\\ A2/',
1175
+ icon: '3b:c1cb:fafdc:2bd',
1176
+ level: 2,
1177
+ player: 2,
1178
+ max: 14,
1179
+ hint: 'A1\\',
1180
+ },
1181
+ {
1182
+ id: 'book.49',
1183
+ src: 'book1',
1184
+ game: 'traxloop',
1185
+ notation: '@0/ @1/ @1/ @1/ D0+ @2+ @2/ @2/ @2/ F3\\ G3\\',
1186
+ icon: '2cdcde:dcdecdcd:3faf',
1187
+ level: 3,
1188
+ player: 2,
1189
+ max: 16,
1190
+ hints: ['A1+', 'A3+'],
1191
+ },
1192
+ {
1193
+ id: 'book.50',
1194
+ src: 'book1',
1195
+ game: 'traxloop',
1196
+ notation: '@0/ @1/ @1/ @1+ @1/ @1/ A0/ A3/ D3+',
1197
+ icon: 'c:dcbdcd:cdcbdc',
1198
+ level: 3,
1199
+ player: 2,
1200
+ max: 16,
1201
+ hint: 'D1+',
1202
+ },
934
1203
  ]
935
1204
 
936
1205
  puzzles.sort(
package/src/threats.js CHANGED
@@ -21,7 +21,7 @@ const REGEX = {
21
21
  '?': 'b?', // Zero or one black piece
22
22
  }
23
23
 
24
- export const Threat = class {
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 const ThreatsDB = class {
75
+ export class ThreatsDB {
76
76
  #db = {}
77
77
  #depth = 0
78
78
 
@@ -83,7 +83,7 @@ export const ThreatsDB = class {
83
83
  }
84
84
 
85
85
  compose(depth, pattern) {
86
- pattern = pattern.replaceAll(/(?<=.)A/g, 'a').replaceAll(/W(?=.)/g, 'w')
86
+ pattern = pattern.replace(/(?<=.)A/g, 'a').replace(/W(?=.)/g, 'w')
87
87
  return this.add(depth, pattern)
88
88
  }
89
89
 
package/src/types.d.ts CHANGED
@@ -71,7 +71,7 @@ type FaultyThreats = {
71
71
 
72
72
  /** An object with keys representing each level, with arrays for each threat of
73
73
  * that level. */
74
- type FoundThreats = Record<string, FoundThreat[]>
74
+ type ColorThreats = Record<string, FoundThreat[]>
75
75
 
76
76
  /** All the threats found for both the white and black player. */
77
77
  type FoundThreatsCollection = { b: ColorThreats; w: ColorThreats }
@@ -116,8 +116,10 @@ type Puzzle = {
116
116
 
117
117
  type PuzzleSource = {
118
118
  name: string
119
- copyright?: string
120
119
  url?: string
120
+ copyright?: string
121
+ license?: string
122
+ licenseUrl?: string
121
123
  }
122
124
 
123
125
  /** Array of objects representing the spaces surrounding the perimeter of a
package/src/utils.js ADDED
@@ -0,0 +1,22 @@
1
+ /** Shared utilities
2
+ * @copyright 2023
3
+ * @author Chad Transtrum <chad@transtrum.net>
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ /** Convert milliseconds to a human readable string in ms, sec, or min units.
8
+ * @arg {number} ms - the number of milliseconds
9
+ * @returns {string} a short human-readable representation of the time
10
+ */
11
+ export const timeString = (ms) => {
12
+ if (ms < 1000) {
13
+ return (ms === Math.floor(ms) ? String(ms) : ms.toFixed(2)) + ' ms'
14
+ }
15
+
16
+ ms /= 1000
17
+ if (ms < 60) return ms.toFixed(3) + ' sec'
18
+
19
+ const min = Math.floor(ms / 60)
20
+ ms -= min * 60
21
+ return String(min) + ' min ' + ms.toFixed(3) + ' sec'
22
+ }
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '0.18.0'
2
+ export const version = '0.20.0'
@@ -1,42 +0,0 @@
1
- {
2
- "0.17.0": {
3
- "puzzles.firstmove.tutorial": {
4
- "count": 16,
5
- "ms": 2007
6
- },
7
- "puzzles.firstmove.beginner": {
8
- "count": 16,
9
- "ms": 2664
10
- },
11
- "puzzles.firstmove.tough": {
12
- "count": 1,
13
- "ms": 76
14
- },
15
- "puzzles.firstmove.total": {
16
- "count": 33,
17
- "ms": 4838
18
- }
19
- },
20
- "0.18.0": {
21
- "puzzles.firstmove.tutorial": {
22
- "count": 16,
23
- "ms": 10164
24
- },
25
- "puzzles.firstmove.beginner": {
26
- "count": 15,
27
- "ms": 17864
28
- },
29
- "puzzles.firstmove.tough": {
30
- "count": 26,
31
- "ms": 30349
32
- },
33
- "puzzles.firstmove.advanced": {
34
- "count": 1,
35
- "ms": 427
36
- },
37
- "puzzles.firstmove.total": {
38
- "count": 58,
39
- "ms": 59031
40
- }
41
- }
42
- }
@@ -1,190 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /** Let's try to solve the puzzles
4
- * @copyright 2023
5
- * @author Chad Transtrum <chad@transtrum.net>
6
- * @license Apache-2.0
7
- */
8
-
9
- import fs from 'node:fs'
10
- import process from 'node:process'
11
- import { fileURLToPath } from 'node:url'
12
-
13
- import { Trax } from '@slugbugblue/trax'
14
- import { suggest } from '@slugbugblue/trax/analyst'
15
- import { puzzles } from '@slugbugblue/trax/puzzles'
16
- import { version } from '@slugbugblue/trax/version'
17
-
18
- import * as tty from '@slugbugblue/trax/tty'
19
-
20
- let STUMPED = false
21
- const FINAL = {}
22
-
23
- const record = (name, data) => {
24
- FINAL['puzzles.firstmove.' + name] = data
25
- }
26
-
27
- const timeString = (ms) => {
28
- if (ms < 1000) {
29
- return (ms === Math.floor(ms) ? String(ms) : ms.toFixed(2)) + ' ms'
30
- }
31
-
32
- ms /= 1000
33
- if (ms < 60) return ms.toFixed(3) + ' sec'
34
-
35
- const min = Math.floor(ms / 60)
36
- ms -= min * 60
37
- return String(min) + ' min ' + ms.toFixed(3) + ' sec'
38
- }
39
-
40
- const time = (ms) => timeString(Date.now() - ms)
41
-
42
- const out = (messages) => {
43
- tty.outty(messages.join(' '))
44
- }
45
-
46
- const section = (title) => {
47
- out([tty.color('===', 250), tty.color(title, 39), tty.color('===', 250)])
48
- }
49
-
50
- const success = (puzzle, ms) => {
51
- out([tty.color('✓', 35), tty.color(puzzle, 250), tty.color(ms, 240)])
52
- }
53
-
54
- const puzzled = (puzzle, move) => {
55
- tty.display(new Trax(puzzle.game, puzzle.notation))
56
- tty.outty('Puzzled by ' + puzzle.id, 205)
57
- out([
58
- tty.color(' played', 250),
59
- tty.color(move, 127),
60
- tty.color('instead of', 250),
61
- tty.color(puzzle.hint || puzzle.hints.join(' '), 39),
62
- ])
63
- STUMPED = true
64
- }
65
-
66
- const finalize = (name, ms, count) => {
67
- out([
68
- tty.color('Finished', 195),
69
- tty.color(String(count) + ' ' + name + ' puzzles', 123),
70
- tty.color('in ' + time(ms), 195),
71
- ])
72
- }
73
-
74
- const solvePuzzleLevel = (name, level) => {
75
- if (STUMPED) return 0
76
- section(name + ' puzzles')
77
- name = name.toLowerCase()
78
- let count = 0
79
- const begin = Date.now()
80
- for (const puzzle of puzzles) {
81
- if (puzzle.level !== level) continue
82
- const start = Date.now()
83
- const game = new Trax(puzzle.game, puzzle.notation)
84
- const { move } = suggest(game).pick
85
- const solved = puzzle.hint
86
- ? move === puzzle.hint
87
- : puzzle.hints
88
- ? puzzle.hints.includes(move)
89
- : false
90
- if (solved) {
91
- success(puzzle.id, time(start))
92
- count++
93
- record(name, { count, ms: Date.now() - begin })
94
- } else {
95
- puzzled(puzzle, move)
96
- process.exitCode = level + 1
97
- return count
98
- }
99
- }
100
-
101
- finalize(name, begin, count)
102
- return count
103
- }
104
-
105
- // Gather the benchmark data
106
- let total = 0
107
- const timer = Date.now()
108
- total += solvePuzzleLevel('Tutorial', 0)
109
- total += solvePuzzleLevel('Beginner', 1)
110
- total += solvePuzzleLevel('Tough', 2)
111
- total += solvePuzzleLevel('Advanced', 3)
112
- total += solvePuzzleLevel('Genius', 4)
113
-
114
- record('total', { count: total, ms: Date.now() - timer })
115
- tty.outty(
116
- 'Benchmark: ' + total + ' puzzles in ' + time(timer),
117
- STUMPED ? 205 : 35,
118
- )
119
-
120
- tty.outty()
121
-
122
- // Load the previous benchmarks
123
- const FILE = new URL('benchmarks.json', import.meta.url)
124
- let CONTENTS
125
- try {
126
- CONTENTS = fs.readFileSync(FILE, 'utf8')
127
- } catch {
128
- CONTENTS = '{}'
129
- }
130
-
131
- const BENCHMARK = JSON.parse(CONTENTS)
132
-
133
- const PREV = Object.values(BENCHMARK).pop() || {}
134
-
135
- // Report the benchmark data
136
- const size = [0, 0, 0, 0, 0]
137
- const REPORT = []
138
- for (const name of Object.keys(FINAL)) {
139
- const report = [
140
- name,
141
- String(FINAL[name].count) + ' puzzles',
142
- 'in ' + timeString(FINAL[name].ms),
143
- 'avg ' + timeString(FINAL[name].ms / FINAL[name].count),
144
- ]
145
- if (PREV[name]) {
146
- const diff =
147
- FINAL[name].ms / FINAL[name].count - PREV[name].ms / PREV[name].count
148
- if (diff <= 0) {
149
- report.push('-' + timeString(Math.abs(diff)), '35')
150
- } else {
151
- report.push('+' + timeString(diff), '208')
152
- }
153
- } else {
154
- report.push('new', '250')
155
- }
156
-
157
- size[0] = Math.max(size[0], report[0].length)
158
- size[1] = Math.max(size[1], report[1].length)
159
- size[2] = Math.max(size[2], report[2].length)
160
- size[3] = Math.max(size[3], report[3].length)
161
- size[4] = Math.max(size[4], report[4].length)
162
- REPORT.push(report)
163
- }
164
-
165
- for (const line of REPORT) {
166
- out([
167
- tty.color(line[0].padEnd(size[0]), 39),
168
- tty.color(line[1].padStart(size[1]), 123),
169
- tty.color(line[2].padStart(size[2]), 195),
170
- tty.color(line[3].padEnd(size[3]), 245),
171
- tty.color(line[4].padStart(size[4]), Number(line[5])),
172
- ])
173
- }
174
-
175
- tty.outty()
176
-
177
- // Save the benchmark data to a file
178
- if (BENCHMARK[version]) {
179
- tty.outty('Not overwriting existing benchmark data')
180
- } else {
181
- BENCHMARK[version] = FINAL
182
- try {
183
- fs.writeFileSync(FILE, JSON.stringify(BENCHMARK, null, 2), 'utf8')
184
- const filename = fileURLToPath(FILE)
185
- tty.outty('Saved benchmark data to ' + tty.color(filename, 74))
186
- } catch (error) {
187
- tty.outty('Error saving benchmark data', 205)
188
- tty.outty(String(error.code) + ' ' + error.message, 127)
189
- }
190
- }