kni 4.0.2 → 5.0.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/entry.js ADDED
@@ -0,0 +1,88 @@
1
+ import Engine from './engine.js';
2
+ import Document from './document.js';
3
+ import story from 'virtual:story';
4
+
5
+ const handler = {
6
+ storageKey: 'kni',
7
+
8
+ shouldLog: true,
9
+ log(...args) {
10
+ if (this.shouldLog) {
11
+ console.log(...args);
12
+ }
13
+ },
14
+
15
+ load() {
16
+ if (window.location.hash.length > 1) {
17
+ const json = atob(window.location.hash.slice(1));
18
+ return JSON.parse(json);
19
+ }
20
+ const json = window.localStorage.getItem(this.storageKey);
21
+ if (json) {
22
+ const state = JSON.parse(json);
23
+ window.history.replaceState(state, '', `#${btoa(json)}`);
24
+ return state;
25
+ }
26
+ return null;
27
+ },
28
+ waypoint(waypoint) {
29
+ const json = JSON.stringify(waypoint);
30
+ window.history.pushState(waypoint, '', `#${btoa(json)}`);
31
+ localStorage.setItem(this.storageKey, json);
32
+ },
33
+ goto(label) {
34
+ this.log(label);
35
+ },
36
+ answer(text) {
37
+ this.log('>', text);
38
+ },
39
+ };
40
+
41
+ const meterFaultButton = document.createElement('a');
42
+ meterFaultButton.innerText = 'Continue…';
43
+ meterFaultButton.addEventListener('click', () => {
44
+ engine.clearMeterFault();
45
+ });
46
+
47
+ const doc = new Document(document.body, {
48
+ meterFaultButton,
49
+ pageTurnBehavior: 'fade',
50
+ });
51
+
52
+ const engine = new Engine({
53
+ story: story,
54
+ render: doc,
55
+ dialog: doc,
56
+ handler,
57
+ });
58
+
59
+ window.onpopstate = event => {
60
+ handler.log('>', 'back');
61
+ engine.resume(event.state);
62
+ };
63
+
64
+ window.onkeypress = event => {
65
+ const code = event.code;
66
+ const match = /^Digit(\d+)$/.exec(code);
67
+ if (match) {
68
+ engine.answer(match[1]);
69
+ } else if (code === 'KeyR') {
70
+ engine.reset();
71
+ }
72
+ };
73
+
74
+ const reset = document.querySelector('.reset');
75
+ if (reset) {
76
+ reset.onclick = () => {
77
+ engine.reset();
78
+ };
79
+ }
80
+
81
+ doc.clear();
82
+
83
+ try {
84
+ engine.resume(handler.load());
85
+ } catch (error) {
86
+ console.error('unable to load prior state, restarting', error);
87
+ engine.resume(null);
88
+ }
package/evaluate.js CHANGED
@@ -1,249 +1,242 @@
1
- 'use strict';
2
-
3
- module.exports = evaluate;
4
-
5
- function evaluate(scope, randomer, args) {
6
- var name = args[0];
7
- if (unary[name] && args.length === 2) {
8
- return unary[name](
9
- evaluate(scope, randomer, args[1]),
10
- scope,
11
- randomer
12
- );
13
- } else if (binary[name] && args.length === 3) {
14
- return binary[name](
15
- evaluate(scope, randomer, args[1]),
16
- evaluate(scope, randomer, args[2]),
17
- scope,
18
- randomer
19
- );
20
- } else if (name === 'val') {
21
- return args[1];
22
- } else if (name === 'get') {
23
- return scope.get(args[1]);
24
- // istanbul ignore else
25
- } else if (name === 'var') {
26
- return scope.get(nominate(scope, randomer, args));
27
- } else if (name === 'call') {
28
- var name = args[1][1];
29
- var f = functions[name];
30
- if (!f) {
31
- // TODO thread line number for containing instruction
32
- throw new Error('No function named ' + name);
33
- }
34
- var values = [];
35
- for (var i = 2; i < args.length; i++) {
36
- values.push(evaluate(scope, randomer, args[i]));
37
- }
38
- return f.apply(null, values);
39
- } else {
40
- throw new Error('Unexpected operator ' + JSON.stringify(args));
1
+ const evaluate = (scope, randomer, args) => {
2
+ const name = args[0];
3
+ if (unary[name] && args.length === 2) {
4
+ return unary[name](evaluate(scope, randomer, args[1]), scope, randomer);
5
+ } else if (binary[name] && args.length === 3) {
6
+ return binary[name](
7
+ evaluate(scope, randomer, args[1]),
8
+ evaluate(scope, randomer, args[2]),
9
+ scope,
10
+ randomer
11
+ );
12
+ } else if (name === 'val') {
13
+ return args[1];
14
+ } else if (name === 'get') {
15
+ return scope.get(args[1]);
16
+ } else if (name === 'var') {
17
+ return scope.get(nominate(scope, randomer, args));
18
+ } else if (name === 'call') {
19
+ const func = args[1][1];
20
+ const f = functions[func];
21
+ if (!f) {
22
+ // TODO thread line number for containing instruction
23
+ throw new Error(`No function named ${func}`);
24
+ }
25
+ const values = [];
26
+ for (let i = 2; i < args.length; i++) {
27
+ values.push(evaluate(scope, randomer, args[i]));
41
28
  }
42
- }
29
+ return f.apply(null, values);
30
+ } else {
31
+ throw new Error(`Unexpected operator ${JSON.stringify(args)}`);
32
+ }
33
+ };
43
34
 
35
+ const nominate = (scope, randomer, args) => {
36
+ if (args[0] === 'get') {
37
+ return args[1];
38
+ }
39
+ const literals = args[1];
40
+ const variables = args[2];
41
+ let name = '';
42
+ let i;
43
+ for (i = 0; i < variables.length; i++) {
44
+ name += literals[i] + evaluate(scope, randomer, variables[i]);
45
+ }
46
+ name += literals[i];
47
+ return name;
48
+ };
44
49
  evaluate.nominate = nominate;
45
- function nominate(scope, randomer, args) {
46
- if (args[0] === 'get') {
47
- return args[1];
50
+
51
+ const functions = {
52
+ abs: Math.abs,
53
+ acos: Math.acos,
54
+ asin: Math.asin,
55
+ atan2: Math.atan2,
56
+ atan: Math.atan,
57
+ exp: Math.exp,
58
+ log: Math.log,
59
+ max: Math.max,
60
+ min: Math.min,
61
+ pow: Math.pow,
62
+ sin: Math.sin,
63
+ tan: Math.tan,
64
+
65
+ floor: Math.floor,
66
+ ceil: Math.ceil,
67
+ round: Math.round,
68
+
69
+ sign: x => {
70
+ if (x < 0) {
71
+ return -1;
48
72
  }
49
- var literals = args[1];
50
- var variables = args[2];
51
- var name = '';
52
- for (var i = 0; i < variables.length; i++) {
53
- name += literals[i] + evaluate(scope, randomer, variables[i]);
73
+ if (x > 0) {
74
+ return 1;
54
75
  }
55
- name += literals[i];
56
- return name;
57
- }
58
-
59
- var functions = {
60
- abs: Math.abs,
61
- acos: Math.acos,
62
- asin: Math.asin,
63
- atan2: Math.atan2,
64
- atan: Math.atan,
65
- exp: Math.exp,
66
- log: Math.log,
67
- max: Math.max,
68
- min: Math.min,
69
- pow: Math.pow,
70
- sin: Math.sin,
71
- tan: Math.tan,
72
-
73
- floor: Math.floor,
74
- ceil: Math.floor,
75
- round: Math.floor,
76
-
77
- sign: function (x) {
78
- if (x < 0) {
79
- return -1;
80
- }
81
- if (x > 0) {
82
- return 1;
83
- }
84
- return 0;
85
- },
86
-
87
- mean: function () {
88
- var mean = 0;
89
- for (var i = 0; i < arguments.length; i++) {
90
- mean += arguments[i];
91
- }
92
- return mean / i;
93
- },
94
-
95
- root: function root(x, y) {
96
- if (y === 2 || y == null) {
97
- return Math.sqrt(x);
98
- }
99
- return Math.pow(x, 1 / y);
100
- },
101
-
102
- distance: function distance(x1, y1, x2, y2) {
103
- return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
104
- },
105
-
106
- manhattan: function distance(x1, y1, x2, y2) {
107
- return Math.abs(x2 - x1, 2) + Math.abs(y2 - y1);
108
- },
109
-
110
- // TODO parameterize these functions in terms of the expected turns to
111
- // go from 25% to 75% of capacity, to adjust the rate. This will maybe
112
- // almost make them understandable.
113
- //
114
- // sigmoid: function (steps, cap) {
115
- // if (steps === -Infinity) {
116
- // return 0;
117
- // } else if (steps === Infinity) {
118
- // return cap;
119
- // } else {
120
- // return cap / (1 + Math.pow(Math.E, -steps));
121
- // }
122
- // },
123
-
124
- // diomgis: function (pop, cap) {
125
- // if (pop <= 0) {
126
- // return -Infinity;
127
- // }
128
- // var ratio = cap / pop - 1;
129
- // if (ratio === 0) {
130
- // return Infinity;
131
- // }
132
- // return -Math.log(ratio, Math.E);
133
- // },
76
+ return 0;
77
+ },
78
+
79
+ mean: function () {
80
+ let mean = 0;
81
+ let i;
82
+ for (i = 0; i < arguments.length; i++) {
83
+ mean += arguments[i];
84
+ }
85
+ return mean / i;
86
+ },
134
87
 
88
+ root: (x, y) => {
89
+ if (y === 2 || y == null) {
90
+ return Math.sqrt(x);
91
+ }
92
+ return Math.pow(x, 1 / y);
93
+ },
94
+
95
+ distance: (x1, y1, x2, y2) => {
96
+ return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
97
+ },
98
+
99
+ manhattan: (x1, y1, x2, y2) => {
100
+ return Math.abs(x2 - x1) + Math.abs(y2 - y1);
101
+ },
102
+
103
+ // TODO parameterize these functions in terms of the expected turns to
104
+ // go from 25% to 75% of capacity, to adjust the rate. This will maybe
105
+ // almost make them understandable.
106
+ //
107
+ // sigmoid: (steps, cap) => {
108
+ // if (steps === -Infinity) {
109
+ // return 0;
110
+ // } else if (steps === Infinity) {
111
+ // return cap;
112
+ // } else {
113
+ // return cap / (1 + Math.pow(Math.E, -steps));
114
+ // }
115
+ // },
116
+
117
+ // diomgis: (pop, cap) => {
118
+ // if (pop <= 0) {
119
+ // return -Infinity;
120
+ // }
121
+ // const ratio = cap / pop - 1;
122
+ // if (ratio === 0) {
123
+ // return Infinity;
124
+ // }
125
+ // return -Math.log(ratio, Math.E);
126
+ // },
135
127
  };
136
128
 
137
- var binary = {
138
- '+': function (x, y) {
139
- return x + y;
140
- },
141
- '-': function (x, y) {
142
- return x - y;
143
- },
144
- '*': function (x, y) {
145
- return x * y;
146
- },
147
- '/': function (x, y) {
148
- return (x / y) >> 0;
149
- },
150
- '%': function (x, y) {
151
- return ((x % y) + y) % y;
152
- },
153
- '**': function (x, y) {
154
- return Math.pow(x, y);
155
- },
156
- 'or': function (x, y) {
157
- return x || y ? 1 : 0;
158
- },
159
- 'and': function (x, y) {
160
- return x && y ? 1 : 0;
161
- },
162
- '>=': function (x, y) {
163
- return x >= y ? 1 : 0;
164
- },
165
- '>': function (x, y) {
166
- return x > y ? 1 : 0;
167
- },
168
- '<=': function (x, y) {
169
- return x <= y ? 1 : 0;
170
- },
171
- '<': function (x, y) {
172
- return x < y ? 1 : 0;
173
- },
174
- '==': function (x, y) {
175
- return x === y ? 1 : 0;
176
- },
177
- '<>': function (x, y) {
178
- return x != y ? 1 : 0;
179
- },
180
- '#': function (x, y) {
181
- return hilbert(x, y);
182
- },
183
- '~': function (x, y, scope, randomer) {
184
- var r = 0;
185
- for (var i = 0; i < x; i++) {
186
- r += randomer.random() * y;
187
- }
188
- return Math.floor(r);
129
+ const binary = {
130
+ '+': (x, y) => {
131
+ return x + y;
132
+ },
133
+ '-': (x, y) => {
134
+ return x - y;
135
+ },
136
+ '*': (x, y) => {
137
+ return x * y;
138
+ },
139
+ '/': (x, y) => {
140
+ return (x / y) >> 0;
141
+ },
142
+ '%': (x, y) => {
143
+ return ((x % y) + y) % y;
144
+ },
145
+ '**': (x, y) => {
146
+ return Math.pow(x, y);
147
+ },
148
+ or: (x, y) => {
149
+ return x || y ? 1 : 0;
150
+ },
151
+ and: (x, y) => {
152
+ return x && y ? 1 : 0;
153
+ },
154
+ '>=': (x, y) => {
155
+ return x >= y ? 1 : 0;
156
+ },
157
+ '>': (x, y) => {
158
+ return x > y ? 1 : 0;
159
+ },
160
+ '<=': (x, y) => {
161
+ return x <= y ? 1 : 0;
162
+ },
163
+ '<': (x, y) => {
164
+ return x < y ? 1 : 0;
165
+ },
166
+ '==': (x, y) => {
167
+ return x === y ? 1 : 0;
168
+ },
169
+ '<>': (x, y) => {
170
+ return x != y ? 1 : 0;
171
+ },
172
+ '#': (x, y) => {
173
+ return hilbert(x, y);
174
+ },
175
+ '~': (x, y, _scope, randomer) => {
176
+ let r = 0;
177
+ for (let i = 0; i < x; i++) {
178
+ r += randomer.random() * y;
189
179
  }
180
+ return Math.floor(r);
181
+ },
190
182
  };
191
183
 
192
- // istanbul ignore next
193
- var unary = {
194
- 'not': function (x) {
195
- return x ? 0 : 1;
196
- },
197
- '-': function (x) {
198
- return -x;
199
- },
200
- '~': function (x, scope, randomer) {
201
- return Math.floor(randomer.random() * x);
202
- },
203
- '#': function (x) {
204
- return hash(x);
205
- }
184
+ const unary = {
185
+ not: x => {
186
+ return x ? 0 : 1;
187
+ },
188
+ '-': x => {
189
+ return -x;
190
+ },
191
+ '~': (x, _scope, randomer) => {
192
+ return Math.floor(randomer.random() * x);
193
+ },
194
+ '#': x => {
195
+ return hash(x);
196
+ },
206
197
  };
207
198
 
208
199
  // Robert Jenkins's 32 bit hash function
209
200
  // https://gist.github.com/badboy/6267743
201
+ const hash = a => {
202
+ a = a + 0x7ed55d16 + (a << 12);
203
+ a = a ^ 0xc761c23c ^ (a >>> 19);
204
+ a = a + 0x165667b1 + (a << 5);
205
+ a = (a + 0xd3a2646c) ^ (a << 9);
206
+ a = a + 0xfd7046c5 + (a << 3);
207
+ a = a ^ 0xb55a4f09 ^ (a >>> 16);
208
+ return a;
209
+ };
210
210
  evaluate.hash = hash;
211
- function hash(a) {
212
- a = (a+0x7ed55d16) + (a<<12);
213
- a = (a^0xc761c23c) ^ (a>>>19);
214
- a = (a+0x165667b1) + (a<<5);
215
- a = (a+0xd3a2646c) ^ (a<<9);
216
- a = (a+0xfd7046c5) + (a<<3);
217
- a = (a^0xb55a4f09) ^ (a>>>16);
218
- return a;
219
- }
220
211
 
221
212
  // hilbert in range from 0 to 2^32
222
213
  // x and y in range from 0 to 2^16
223
214
  // each dimension has origin at 2^15
224
- var dimensionWidth = (-1 >>> 16) + 1;
225
- var halfDimensionWidth = dimensionWidth / 2;
226
- function hilbert(x, y) {
227
- x += halfDimensionWidth;
228
- y += halfDimensionWidth;
229
- var rx = 0;
230
- var ry = y;
231
- var scalar = 0;
232
- for (var scale = dimensionWidth; scale > 0; scale /= 2) {
233
- rx = x & scale;
234
- ry = y & scale;
235
- scalar += scale * ((3 * rx) ^ ry);
236
- // rotate
237
- if (!ry) {
238
- if (rx) {
239
- x = scale - 1 - x;
240
- y = scale - 1 - y;
241
- }
242
- // transpose
243
- var t = x;
244
- x = y;
245
- y = t;
246
- }
215
+ const dimensionWidth = (-1 >>> 16) + 1;
216
+ const halfDimensionWidth = dimensionWidth / 2;
217
+ const hilbert = (x, y) => {
218
+ x += halfDimensionWidth;
219
+ y += halfDimensionWidth;
220
+ let rx = 0;
221
+ let ry = y;
222
+ let scalar = 0;
223
+ for (let scale = dimensionWidth; scale > 0; scale /= 2) {
224
+ rx = x & scale;
225
+ ry = y & scale;
226
+ scalar += scale * ((3 * rx) ^ ry);
227
+ // rotate
228
+ if (!ry) {
229
+ if (rx) {
230
+ x = scale - 1 - x;
231
+ y = scale - 1 - y;
232
+ }
233
+ // transpose
234
+ const t = x;
235
+ x = y;
236
+ y = t;
247
237
  }
248
- return scalar;
249
- }
238
+ }
239
+ return scalar;
240
+ };
241
+
242
+ export default evaluate;