eyeling 1.19.4 → 1.19.6

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.
Files changed (40) hide show
  1. package/HANDBOOK.md +48 -89
  2. package/examples/deck/extra.md +169 -0
  3. package/examples/extra/collatz-1000.js +138 -0
  4. package/examples/extra/control-system.js +68 -0
  5. package/examples/extra/deep-taxonomy-100000.js +95 -0
  6. package/examples/extra/delfour.js +110 -0
  7. package/examples/extra/euler-identity.js +41 -0
  8. package/examples/extra/fibonacci.js +81 -0
  9. package/examples/extra/goldbach-1000.js +112 -0
  10. package/examples/extra/gps.js +274 -0
  11. package/examples/extra/kaprekar-6174.js +112 -0
  12. package/examples/extra/matrix-mechanics.js +69 -0
  13. package/examples/extra/odrl-dpv-ehds-risk-ranked.js +255 -0
  14. package/examples/extra/output/collatz-1000.txt +18 -0
  15. package/examples/extra/output/control-system.txt +14 -0
  16. package/examples/extra/output/deep-taxonomy-100000.txt +15 -0
  17. package/examples/extra/output/delfour.txt +20 -0
  18. package/examples/extra/output/euler-identity.txt +12 -0
  19. package/examples/extra/output/fibonacci.txt +21 -0
  20. package/examples/extra/output/goldbach-1000.txt +17 -0
  21. package/examples/extra/output/gps.txt +33 -0
  22. package/examples/extra/output/kaprekar-6174.txt +17 -0
  23. package/examples/extra/output/matrix-mechanics.txt +14 -0
  24. package/examples/extra/output/odrl-dpv-ehds-risk-ranked.txt +48 -0
  25. package/examples/extra/output/path-discovery.txt +28 -0
  26. package/examples/extra/output/pn-junction-tunneling.txt +15 -0
  27. package/examples/extra/output/polynomial.txt +20 -0
  28. package/examples/extra/output/sudoku.txt +47 -0
  29. package/examples/extra/output/transistor-switch.txt +16 -0
  30. package/examples/extra/path-discovery.js +45114 -0
  31. package/examples/extra/pn-junction-tunneling.js +69 -0
  32. package/examples/extra/polynomial.js +181 -0
  33. package/examples/extra/sudoku.js +330 -0
  34. package/examples/extra/transistor-switch.js +93 -0
  35. package/examples/fibonacci.n3 +2 -0
  36. package/examples/output/fibonacci.n3 +1 -0
  37. package/eyeling.js +49 -45
  38. package/lib/engine.js +49 -45
  39. package/package.json +3 -2
  40. package/test/extra.test.js +100 -0
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Toy PN-junction tunneling model expressed as overlap counts between discrete energy levels.
6
+ * The curve is small enough to inspect directly, so the checks focus on the peak and negative differential region.
7
+ */
8
+
9
+ const N_FILLED = [1, 2, 3, 4];
10
+ const P_EMPTY_ZERO_BIAS = [3, 4, 5, 6];
11
+ const BIAS_POINTS = [0, 1, 2, 3, 4, 5, 6];
12
+
13
+ function overlapCount(lhs, rhs) {
14
+ let count = 0;
15
+ for (const left of lhs) {
16
+ for (const right of rhs) {
17
+ if (left === right) {
18
+ count += 1;
19
+ break;
20
+ }
21
+ }
22
+ }
23
+ return count;
24
+ }
25
+
26
+ // Shift the P-side levels across the bias points and record the overlap curve.
27
+ function main() {
28
+ const curve = [];
29
+ let peakIndex = 0;
30
+
31
+ for (let i = 0; i < BIAS_POINTS.length; i += 1) {
32
+ const shifted = P_EMPTY_ZERO_BIAS.map((value) => value - BIAS_POINTS[i]);
33
+ curve[i] = overlapCount(N_FILLED, shifted);
34
+ if (curve[i] > curve[peakIndex]) peakIndex = i;
35
+ }
36
+
37
+ const valleyIndex = 6;
38
+ const barrierNarrower = 1 < 8;
39
+ const peakBeforeValley = peakIndex < valleyIndex;
40
+ let negativeDifferential = false;
41
+ for (let i = peakIndex; i < 6; i += 1) if (curve[i + 1] < curve[i]) negativeDifferential = true;
42
+ const overlapCloses = curve[valleyIndex] === 0;
43
+ const fullOverlapPeak = curve[peakIndex] === 4;
44
+ const ok = barrierNarrower && peakBeforeValley && negativeDifferential && overlapCloses && fullOverlapPeak;
45
+
46
+ const lines = [];
47
+ lines.push('=== Answer ===');
48
+ lines.push(
49
+ 'In this toy PN-junction tunneling model, heavy doping narrows the depletion region enough for a tunneling window that rises to a peak and then falls.',
50
+ );
51
+ lines.push('');
52
+ lines.push('=== Reason Why ===');
53
+ lines.push('We count exact state overlap while forward bias shifts the empty P-side levels.');
54
+ lines.push(`bias -> overlap current proxy : ${BIAS_POINTS.map((bias, i) => `${bias}->${curve[i]}`).join(', ')}`);
55
+ lines.push(`peak point : ${BIAS_POINTS[peakIndex]} -> ${curve[peakIndex]}`);
56
+ lines.push(`high-bias point : ${BIAS_POINTS[valleyIndex]} -> ${curve[valleyIndex]}`);
57
+ lines.push('');
58
+ lines.push('=== Check ===');
59
+ lines.push(`heavily doped barrier is narrower : ${barrierNarrower ? 'yes' : 'no'}`);
60
+ lines.push(`peak occurs before overlap closes : ${peakBeforeValley ? 'yes' : 'no'}`);
61
+ lines.push(`negative differential region : ${negativeDifferential ? 'yes' : 'no'}`);
62
+ lines.push(`high-bias overlap closes : ${overlapCloses ? 'yes' : 'no'}`);
63
+ lines.push(`peak equals full overlap : ${fullOverlapPeak ? 'yes' : 'no'}`);
64
+
65
+ process.stdout.write(`${lines.join('\n')}\n`);
66
+ process.exit(ok ? 0 : 1);
67
+ }
68
+
69
+ main();
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Polynomial case with lightweight complex arithmetic and numerical root finding.
6
+ * The result is checked both by evaluating the polynomial at the roots and by reconstructing the coefficients.
7
+ */
8
+
9
+ const ROOT_TOL = 1e-10;
10
+ const COEFF_TOL = 1e-8;
11
+ const MAX_ITER = 200;
12
+
13
+ function cx(re, im) {
14
+ return { re, im };
15
+ }
16
+ function add(a, b) {
17
+ return cx(a.re + b.re, a.im + b.im);
18
+ }
19
+ function sub(a, b) {
20
+ return cx(a.re - b.re, a.im - b.im);
21
+ }
22
+ function mul(a, b) {
23
+ return cx(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re);
24
+ }
25
+ function divcx(a, b) {
26
+ const s = b.re * b.re + b.im * b.im;
27
+ return cx((a.re * b.re + a.im * b.im) / s, (a.im * b.re - a.re * b.im) / s);
28
+ }
29
+ function abscx(a) {
30
+ return Math.hypot(a.re, a.im);
31
+ }
32
+ function powu(a, e) {
33
+ let out = cx(1, 0);
34
+ for (let i = 0; i < e; i += 1) out = mul(out, a);
35
+ return out;
36
+ }
37
+ function dist(a, b) {
38
+ return abscx(sub(a, b));
39
+ }
40
+ function evalPoly(coeffs, x) {
41
+ let acc = cx(0, 0);
42
+ for (const coeff of coeffs) acc = add(mul(acc, x), coeff);
43
+ return acc;
44
+ }
45
+ function multiplyPolys(left, right) {
46
+ const out = new Array(left.length + right.length - 1).fill(null).map(() => cx(0, 0));
47
+ for (let i = 0; i < left.length; i += 1) {
48
+ for (let j = 0; j < right.length; j += 1) {
49
+ out[i + j] = add(out[i + j], mul(left[i], right[j]));
50
+ }
51
+ }
52
+ return out;
53
+ }
54
+ // Durand-Kerner-style iteration on a monic copy of the polynomial.
55
+ function rootsFromCoeffs(coeffs) {
56
+ const degree = coeffs.length - 1;
57
+ const monic = [];
58
+ const lead = coeffs[0];
59
+ let radius = 1.0;
60
+ for (let i = 0; i < coeffs.length; i += 1) {
61
+ monic[i] = divcx(coeffs[i], lead);
62
+ if (i > 0) {
63
+ const a = abscx(monic[i]);
64
+ if (a > radius - 1.0) radius = 1.0 + a;
65
+ }
66
+ }
67
+ const seed = cx(0.4, 0.9);
68
+ const roots = [];
69
+ for (let i = 0; i < degree; i += 1) roots[i] = mul(powu(seed, i), cx(radius, 0));
70
+
71
+ for (let iter = 0; iter < MAX_ITER; iter += 1) {
72
+ let maxDelta = 0.0;
73
+ for (let i = 0; i < degree; i += 1) {
74
+ let denom = cx(1, 0);
75
+ for (let j = 0; j < degree; j += 1) {
76
+ if (j !== i) denom = mul(denom, sub(roots[i], roots[j]));
77
+ }
78
+ if (abscx(denom) < 1e-18) denom = add(denom, cx(1e-12, 1e-12));
79
+ const delta = divcx(evalPoly(monic, roots[i]), denom);
80
+ roots[i] = sub(roots[i], delta);
81
+ const a = abscx(delta);
82
+ if (a > maxDelta) maxDelta = a;
83
+ }
84
+ if (maxDelta < ROOT_TOL) break;
85
+ }
86
+
87
+ return roots;
88
+ }
89
+ function sortRoots(roots) {
90
+ for (let i = 0; i < roots.length; i += 1) {
91
+ for (let j = i + 1; j < roots.length; j += 1) {
92
+ const leftReal = Math.abs(roots[i].im) < 1e-8;
93
+ const rightReal = Math.abs(roots[j].im) < 1e-8;
94
+ let swap = false;
95
+ if (leftReal && rightReal) swap = roots[j].re > roots[i].re;
96
+ else if (!leftReal && rightReal) swap = false;
97
+ else if (leftReal && !rightReal) swap = true;
98
+ else if (roots[j].im > roots[i].im || (Math.abs(roots[j].im - roots[i].im) < 1e-8 && roots[j].re > roots[i].re))
99
+ swap = true;
100
+ if (swap) {
101
+ const t = roots[i];
102
+ roots[i] = roots[j];
103
+ roots[j] = t;
104
+ }
105
+ }
106
+ }
107
+ }
108
+ function fmtG(value) {
109
+ const v = Math.abs(value) < 1e-8 ? 0 : value;
110
+ if (v === 0) return '0';
111
+ const s = Number(v).toPrecision(10);
112
+ return s
113
+ .replace(/(?:\.0+|(\.\d*?[1-9])0+)(e|$)/, '$1$2')
114
+ .replace(/\.0+$/, '')
115
+ .replace(/e\+?/, 'e');
116
+ }
117
+ function printCx(z) {
118
+ const re = Math.abs(z.re) < 1e-8 ? 0 : z.re;
119
+ const im = Math.abs(z.im) < 1e-8 ? 0 : z.im;
120
+ if (im === 0) return fmtG(re);
121
+ if (re === 0) return `${fmtG(im)}i`;
122
+ return `${fmtG(re)} ${im >= 0 ? '+' : '-'} ${fmtG(Math.abs(im))}i`;
123
+ }
124
+
125
+ // Solve, reconstruct, and validate the polynomial in three complementary ways.
126
+ // Build the final ARC-style report and exit non-zero if a check fails.
127
+ function main() {
128
+ const cases = [
129
+ [cx(1, 0), cx(-10, 0), cx(35, 0), cx(-50, 0), cx(24, 0)],
130
+ [cx(1, 0), cx(-9, -5), cx(14, 33), cx(24, -44), cx(-26, 0)],
131
+ ];
132
+ const labels = ['real quartic', 'complex quartic'];
133
+ let allOk = true;
134
+
135
+ const lines = [];
136
+ lines.push('=== Answer ===');
137
+ lines.push(
138
+ 'Both polynomial examples are solved consistently: the computed roots satisfy the source polynomials and reconstruct the original coefficients.',
139
+ );
140
+ lines.push('');
141
+ lines.push('=== Reason Why ===');
142
+ lines.push(
143
+ 'For each quartic, the program solves for the roots numerically, substitutes them back, and rebuilds the polynomial from those roots.',
144
+ );
145
+ for (let c = 0; c < 2; c += 1) {
146
+ const roots = rootsFromCoeffs(cases[c]);
147
+ sortRoots(roots);
148
+ const coeffs1 = [cx(1, 0), sub(cx(0, 0), roots[0])];
149
+ const coeffs2 = [cx(1, 0), sub(cx(0, 0), roots[1])];
150
+ const coeffs3 = [cx(1, 0), sub(cx(0, 0), roots[2])];
151
+ const coeffs4 = [cx(1, 0), sub(cx(0, 0), roots[3])];
152
+ const tmp1 = multiplyPolys(coeffs1, coeffs2);
153
+ const tmp2 = multiplyPolys(tmp1, coeffs3);
154
+ const rebuilt = multiplyPolys(tmp2, coeffs4);
155
+ let rootsValid = true;
156
+ let rebuildOk = true;
157
+ const residuals = [];
158
+ for (let i = 0; i < 4; i += 1) {
159
+ residuals[i] = evalPoly(cases[c], roots[i]);
160
+ if (abscx(residuals[i]) > 1e-6) rootsValid = false;
161
+ }
162
+ for (let i = 0; i < 5; i += 1) {
163
+ if (dist(rebuilt[i], cases[c][i]) > COEFF_TOL) rebuildOk = false;
164
+ }
165
+ allOk &&= rootsValid && rebuildOk;
166
+ lines.push('');
167
+ lines.push(`Example #${c + 1} (${labels[c]})`);
168
+ lines.push(`roots : ${roots.map(printCx).join(', ')}`);
169
+ lines.push(`residuals : ${residuals.map(printCx).join(', ')}`);
170
+ lines.push(`reconstruction ok : ${rebuildOk ? 'yes' : 'no'}`);
171
+ lines.push(`roots valid : ${rootsValid ? 'yes' : 'no'}`);
172
+ }
173
+ lines.push('');
174
+ lines.push('=== Check ===');
175
+ lines.push(`all examples valid : ${allOk ? 'yes' : 'no'}`);
176
+
177
+ process.stdout.write(`${lines.join('\n')}\n`);
178
+ process.exit(allOk ? 0 : 1);
179
+ }
180
+
181
+ main();
@@ -0,0 +1,330 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Sudoku solver specialized to a single-file search-and-propagation implementation.
6
+ * The state keeps row, column, and box usage bitmasks so constraints can be checked quickly.
7
+ */
8
+
9
+ const ALL_MASK = 0x1ff;
10
+ const DEFAULT_PUZZLE = '100007090030020008009600500005300900010080002600004000300000010040000007007000300';
11
+
12
+ function popcount16(x) {
13
+ let c = 0;
14
+ while (x) {
15
+ x &= x - 1;
16
+ c += 1;
17
+ }
18
+ return c;
19
+ }
20
+
21
+ function digitMask(d) {
22
+ return 1 << (d - 1);
23
+ }
24
+
25
+ function boxIndex(r, c) {
26
+ return Math.floor(r / 3) * 3 + Math.floor(c / 3);
27
+ }
28
+
29
+ function pushMove(state, move) {
30
+ state.moves.push(move);
31
+ }
32
+
33
+ function cloneState(src) {
34
+ return {
35
+ cells: src.cells.slice(),
36
+ rowUsed: src.rowUsed.slice(),
37
+ colUsed: src.colUsed.slice(),
38
+ boxUsed: src.boxUsed.slice(),
39
+ moves: src.moves.map((move) => ({ ...move })),
40
+ };
41
+ }
42
+
43
+ function place(state, idx, value) {
44
+ if (state.cells[idx] !== 0) return state.cells[idx] === value;
45
+ const r = Math.floor(idx / 9);
46
+ const c = idx % 9;
47
+ const b = boxIndex(r, c);
48
+ const bit = digitMask(value);
49
+ if ((state.rowUsed[r] | state.colUsed[c] | state.boxUsed[b]) & bit) return false;
50
+ state.cells[idx] = value;
51
+ state.rowUsed[r] |= bit;
52
+ state.colUsed[c] |= bit;
53
+ state.boxUsed[b] |= bit;
54
+ return true;
55
+ }
56
+
57
+ function candidates(state, idx) {
58
+ const r = Math.floor(idx / 9);
59
+ const c = idx % 9;
60
+ const b = boxIndex(r, c);
61
+ return ALL_MASK & ~(state.rowUsed[r] | state.colUsed[c] | state.boxUsed[b]);
62
+ }
63
+
64
+ function parsePuzzle(text) {
65
+ if (text.length !== 81) return null;
66
+ const out = new Array(81).fill(0);
67
+ for (let i = 0; i < 81; i += 1) {
68
+ const ch = text[i];
69
+ if (ch >= '1' && ch <= '9') out[i] = ch.charCodeAt(0) - 48;
70
+ else if (ch === '0' || ch === '.' || ch === '_') out[i] = 0;
71
+ else return null;
72
+ }
73
+ return out;
74
+ }
75
+
76
+ // Initialize the board and the occupancy bitmasks from the input puzzle.
77
+ function stateFromPuzzle(puzzle) {
78
+ const state = {
79
+ cells: new Array(81).fill(0),
80
+ rowUsed: new Array(9).fill(0),
81
+ colUsed: new Array(9).fill(0),
82
+ boxUsed: new Array(9).fill(0),
83
+ moves: [],
84
+ };
85
+ for (let i = 0; i < 81; i += 1) {
86
+ if (puzzle[i] && !place(state, i, puzzle[i])) return null;
87
+ }
88
+ return state;
89
+ }
90
+
91
+ function propagateSingles(state, stats) {
92
+ for (;;) {
93
+ let progress = false;
94
+ for (let idx = 0; idx < 81; idx += 1) {
95
+ if (state.cells[idx] !== 0) continue;
96
+ const mask = candidates(state, idx);
97
+ const count = popcount16(mask);
98
+ if (count === 0) return false;
99
+ if (count === 1) {
100
+ let digit = 0;
101
+ for (let d = 1; d <= 9; d += 1) {
102
+ if (mask & digitMask(d)) {
103
+ digit = d;
104
+ break;
105
+ }
106
+ }
107
+ pushMove(state, { index: idx, value: digit, candidatesMask: mask, forced: true });
108
+ if (!place(state, idx, digit)) return false;
109
+ stats.forcedMoves += 1;
110
+ progress = true;
111
+ }
112
+ }
113
+ if (!progress) return true;
114
+ }
115
+ }
116
+
117
+ function selectUnfilledCell(state) {
118
+ let found = false;
119
+ let bestCount = 10;
120
+ let bestIdx = -1;
121
+ let bestMask = 0;
122
+ for (let idx = 0; idx < 81; idx += 1) {
123
+ if (state.cells[idx] !== 0) continue;
124
+ const mask = candidates(state, idx);
125
+ const count = popcount16(mask);
126
+ if (count < bestCount) {
127
+ bestCount = count;
128
+ bestIdx = idx;
129
+ bestMask = mask;
130
+ found = true;
131
+ if (count === 2) break;
132
+ }
133
+ }
134
+ return found ? { idx: bestIdx, mask: bestMask } : null;
135
+ }
136
+
137
+ function solve(state, stats, depth) {
138
+ stats.recursiveNodes += 1;
139
+ if (depth > stats.maxDepth) stats.maxDepth = depth;
140
+ if (!propagateSingles(state, stats)) {
141
+ stats.backtracks += 1;
142
+ return false;
143
+ }
144
+ const selected = selectUnfilledCell(state);
145
+ if (!selected) return true;
146
+ for (let d = 1; d <= 9; d += 1) {
147
+ if (!(selected.mask & digitMask(d))) continue;
148
+ const next = cloneState(state);
149
+ pushMove(next, { index: selected.idx, value: d, candidatesMask: selected.mask, forced: false });
150
+ stats.guessedMoves += 1;
151
+ if (place(next, selected.idx, d) && solve(next, stats, depth + 1)) {
152
+ state.cells = next.cells;
153
+ state.rowUsed = next.rowUsed;
154
+ state.colUsed = next.colUsed;
155
+ state.boxUsed = next.boxUsed;
156
+ state.moves = next.moves;
157
+ return true;
158
+ }
159
+ }
160
+ stats.backtracks += 1;
161
+ return false;
162
+ }
163
+
164
+ function countSolutions(state, limit, countRef) {
165
+ if (countRef.count >= limit) return;
166
+ const dummy = {
167
+ forcedMoves: 0,
168
+ guessedMoves: 0,
169
+ recursiveNodes: 0,
170
+ backtracks: 0,
171
+ maxDepth: 0,
172
+ };
173
+ if (!propagateSingles(state, dummy)) return;
174
+ const selected = selectUnfilledCell(state);
175
+ if (!selected) {
176
+ countRef.count += 1;
177
+ return;
178
+ }
179
+ for (let d = 1; d <= 9; d += 1) {
180
+ if (!(selected.mask & digitMask(d))) continue;
181
+ const next = cloneState(state);
182
+ if (place(next, selected.idx, d)) countSolutions(next, limit, countRef);
183
+ if (countRef.count >= limit) return;
184
+ }
185
+ }
186
+
187
+ function unitComplete(vals) {
188
+ let seen = 0;
189
+ for (const v of vals) {
190
+ if (v < 1 || v > 9) return false;
191
+ const bit = digitMask(v);
192
+ if (seen & bit) return false;
193
+ seen |= bit;
194
+ }
195
+ return seen === ALL_MASK;
196
+ }
197
+
198
+ function replayMovesAreLegal(puzzle, solved) {
199
+ const state = stateFromPuzzle(puzzle);
200
+ if (!state) return false;
201
+ for (const move of solved.moves) {
202
+ if (state.cells[move.index] !== 0) return false;
203
+ const mask = candidates(state, move.index);
204
+ if (mask !== move.candidatesMask) return false;
205
+ if (!(mask & digitMask(move.value))) return false;
206
+ if (move.forced && popcount16(mask) !== 1) return false;
207
+ if (!place(state, move.index, move.value)) return false;
208
+ }
209
+ return true;
210
+ }
211
+
212
+ function boardLines(cells) {
213
+ const lines = [];
214
+ for (let r = 0; r < 9; r += 1) {
215
+ if (r > 0 && r % 3 === 0) lines.push('');
216
+ let line = '';
217
+ for (let c = 0; c < 9; c += 1) {
218
+ if (c > 0 && c % 3 === 0) line += '| ';
219
+ const v = cells[r * 9 + c];
220
+ line += v === 0 ? '. ' : `${v} `;
221
+ }
222
+ lines.push(line);
223
+ }
224
+ return lines;
225
+ }
226
+
227
+ // Solve the fixed puzzle and report both the solution and the internal consistency checks.
228
+ function main() {
229
+ const puzzle = parsePuzzle(DEFAULT_PUZZLE);
230
+ if (!puzzle) process.exit(1);
231
+ const initial = stateFromPuzzle(puzzle);
232
+ if (!initial) process.exit(1);
233
+
234
+ const stats = {
235
+ givens: 0,
236
+ blanks: 0,
237
+ forcedMoves: 0,
238
+ guessedMoves: 0,
239
+ recursiveNodes: 0,
240
+ backtracks: 0,
241
+ maxDepth: 0,
242
+ };
243
+ for (let i = 0; i < 81; i += 1) {
244
+ if (puzzle[i]) stats.givens += 1;
245
+ else stats.blanks += 1;
246
+ }
247
+
248
+ const solved = cloneState(initial);
249
+ const solvedOk = solve(solved, stats, 0);
250
+
251
+ const countState = cloneState(initial);
252
+ const countRef = { count: 0 };
253
+ countSolutions(countState, 2, countRef);
254
+ const solutionCount = countRef.count;
255
+ const unique = solutionCount === 1;
256
+
257
+ let givensPreserved = true;
258
+ let rowsOk = true;
259
+ let colsOk = true;
260
+ let boxesOk = true;
261
+ let replayOk = false;
262
+
263
+ if (solvedOk) {
264
+ for (let i = 0; i < 81; i += 1) if (puzzle[i] && puzzle[i] !== solved.cells[i]) givensPreserved = false;
265
+ for (let r = 0; r < 9; r += 1) {
266
+ const row = [];
267
+ for (let c = 0; c < 9; c += 1) row.push(solved.cells[r * 9 + c]);
268
+ if (!unitComplete(row)) rowsOk = false;
269
+ }
270
+ for (let c = 0; c < 9; c += 1) {
271
+ const col = [];
272
+ for (let r = 0; r < 9; r += 1) col.push(solved.cells[r * 9 + c]);
273
+ if (!unitComplete(col)) colsOk = false;
274
+ }
275
+ for (let b = 0; b < 9; b += 1) {
276
+ const br = Math.floor(b / 3) * 3;
277
+ const bc = (b % 3) * 3;
278
+ const box = [];
279
+ for (let dr = 0; dr < 3; dr += 1) {
280
+ for (let dc = 0; dc < 3; dc += 1) {
281
+ box.push(solved.cells[(br + dr) * 9 + (bc + dc)]);
282
+ }
283
+ }
284
+ if (!unitComplete(box)) boxesOk = false;
285
+ }
286
+ replayOk = replayMovesAreLegal(puzzle, solved);
287
+ }
288
+
289
+ const ok = solvedOk && givensPreserved && rowsOk && colsOk && boxesOk && replayOk && unique;
290
+
291
+ const lines = [];
292
+ lines.push('=== Answer ===');
293
+ lines.push(
294
+ unique
295
+ ? 'The puzzle is solved, and the completed grid is the unique valid Sudoku solution.'
296
+ : 'The puzzle is solved, and the completed grid is a valid Sudoku solution.',
297
+ );
298
+ lines.push('');
299
+ lines.push('Puzzle');
300
+ lines.push(...boardLines(puzzle));
301
+ lines.push('');
302
+ lines.push('Completed grid');
303
+ if (solvedOk) lines.push(...boardLines(solved.cells));
304
+ lines.push('');
305
+ lines.push('=== Reason Why ===');
306
+ lines.push(
307
+ 'The solver combines constraint propagation with depth-first search. It fills forced singles immediately and branches on the blank cell with the fewest candidates.',
308
+ );
309
+ lines.push(`givens : ${stats.givens}`);
310
+ lines.push(`blanks : ${stats.blanks}`);
311
+ lines.push(`forced placements : ${stats.forcedMoves}`);
312
+ lines.push(`guesses : ${stats.guessedMoves}`);
313
+ lines.push(`search nodes : ${stats.recursiveNodes}`);
314
+ lines.push(`backtracks : ${stats.backtracks}`);
315
+ lines.push(`solution unique : ${unique ? 'yes' : 'no'}`);
316
+ lines.push('');
317
+ lines.push('=== Check ===');
318
+ lines.push(`solver found solution : ${solvedOk ? 'yes' : 'no'}`);
319
+ lines.push(`givens preserved : ${givensPreserved ? 'yes' : 'no'}`);
320
+ lines.push(`rows complete : ${rowsOk ? 'yes' : 'no'}`);
321
+ lines.push(`columns complete : ${colsOk ? 'yes' : 'no'}`);
322
+ lines.push(`boxes complete : ${boxesOk ? 'yes' : 'no'}`);
323
+ lines.push(`recorded placements replay legally: ${replayOk ? 'yes' : 'no'}`);
324
+ lines.push(`uniqueness check : ${unique ? 'yes' : 'no'}`);
325
+
326
+ process.stdout.write(`${lines.join('\n')}\n`);
327
+ process.exit(ok ? 0 : 1);
328
+ }
329
+
330
+ main();
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Toy transistor-switch calculation in millivolts, microamps, and ohms.
6
+ * Two input cases are enough to demonstrate the OFF and saturated ON states and verify the arithmetic.
7
+ */
8
+
9
+ const VCC_MV = 5000;
10
+ const VIN_LOW_MV = 0;
11
+ const VIN_HIGH_MV = 5000;
12
+ const VBE_ON_MV = 700;
13
+ const VCE_SAT_MV = 200;
14
+ const RB_OHMS = 10000;
15
+ const RL_OHMS = 1000;
16
+ const BETA = 100;
17
+
18
+ // Evaluate one DC operating point using simple cutoff / active / saturation logic.
19
+ function evaluateState(inputMv) {
20
+ if (inputMv <= VBE_ON_MV) {
21
+ return {
22
+ inputMv,
23
+ baseCurrentUa: 0,
24
+ collectorGainLimitUa: 0,
25
+ collectorLoadLimitUa: 0,
26
+ collectorCurrentUa: 0,
27
+ loadVoltageMv: 0,
28
+ collectorEmitterVoltageMv: VCC_MV,
29
+ cutoff: true,
30
+ saturation: false,
31
+ };
32
+ }
33
+ const ib = Math.floor(((inputMv - VBE_ON_MV) * 1000) / RB_OHMS);
34
+ const gainLimit = ib * BETA;
35
+ const loadLimit = Math.floor(((VCC_MV - VCE_SAT_MV) * 1000) / RL_OHMS);
36
+ const ic = Math.min(gainLimit, loadLimit);
37
+ const sat = gainLimit >= loadLimit;
38
+ const loadV = Math.floor((ic * RL_OHMS) / 1000);
39
+ const vce = sat ? VCE_SAT_MV : VCC_MV - loadV;
40
+ return {
41
+ inputMv,
42
+ baseCurrentUa: ib,
43
+ collectorGainLimitUa: gainLimit,
44
+ collectorLoadLimitUa: loadLimit,
45
+ collectorCurrentUa: ic,
46
+ loadVoltageMv: loadV,
47
+ collectorEmitterVoltageMv: vce,
48
+ cutoff: false,
49
+ saturation: sat,
50
+ };
51
+ }
52
+
53
+ function stateName(state) {
54
+ return state.cutoff ? 'cutoff / OFF' : state.saturation ? 'saturation / ON' : 'active / linear';
55
+ }
56
+
57
+ // Compare the low-input and high-input operating points and verify the switching story.
58
+ function main() {
59
+ const low = evaluateState(VIN_LOW_MV);
60
+ const high = evaluateState(VIN_HIGH_MV);
61
+ const lowCutoff = low.cutoff && low.collectorCurrentUa === 0 && low.collectorEmitterVoltageMv === VCC_MV;
62
+ const highSat = high.saturation && high.collectorEmitterVoltageMv === VCE_SAT_MV;
63
+ const switchingCleanly = low.cutoff && high.saturation;
64
+ const loadLimited =
65
+ high.collectorCurrentUa === high.collectorLoadLimitUa && high.collectorGainLimitUa > high.collectorLoadLimitUa;
66
+ const ohmOk = high.loadVoltageMv === Math.floor((high.collectorCurrentUa * RL_OHMS) / 1000);
67
+ const ok = lowCutoff && highSat && switchingCleanly && loadLimited && ohmOk;
68
+
69
+ const lines = [];
70
+ lines.push('=== Answer ===');
71
+ lines.push(
72
+ 'In this toy transistor-switch model, a low input leaves the transistor OFF and a high input drives it ON in saturation.',
73
+ );
74
+ lines.push('');
75
+ lines.push('=== Reason Why ===');
76
+ lines.push(`low input state : ${stateName(low)}`);
77
+ lines.push(`high input state : ${stateName(high)}`);
78
+ lines.push(`high base current : ${high.baseCurrentUa} uA`);
79
+ lines.push(`high collector Ic : ${high.collectorCurrentUa} uA`);
80
+ lines.push(`load-limited Ic : ${high.collectorLoadLimitUa} uA`);
81
+ lines.push('');
82
+ lines.push('=== Check ===');
83
+ lines.push(`low input cutoff : ${lowCutoff ? 'yes' : 'no'}`);
84
+ lines.push(`high input saturation : ${highSat ? 'yes' : 'no'}`);
85
+ lines.push(`switching states differ : ${switchingCleanly ? 'yes' : 'no'}`);
86
+ lines.push(`on-state current is load-limited: ${loadLimited ? 'yes' : 'no'}`);
87
+ lines.push(`load voltage matches Ohm's law : ${ohmOk ? 'yes' : 'no'}`);
88
+
89
+ process.stdout.write(`${lines.join('\n')}\n`);
90
+ process.exit(ok ? 0 : 1);
91
+ }
92
+
93
+ main();
@@ -23,6 +23,7 @@
23
23
  10 :fibonacci ?F10.
24
24
  100 :fibonacci ?F100.
25
25
  1000 :fibonacci ?F1000.
26
+ 10000 :fibonacci ?F10000.
26
27
  } => {
27
28
  :test :is {
28
29
  0 :fibonacci ?F0.
@@ -30,6 +31,7 @@
30
31
  10 :fibonacci ?F10.
31
32
  100 :fibonacci ?F100.
32
33
  1000 :fibonacci ?F1000.
34
+ 10000 :fibonacci ?F10000.
33
35
  }.
34
36
  }.
35
37
 
@@ -6,4 +6,5 @@
6
6
  10 :fibonacci 55 .
7
7
  100 :fibonacci 354224848179261915075 .
8
8
  1000 :fibonacci 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 .
9
+ 10000 :fibonacci 33644764876431783266621612005107543310302148460680063906564769974680081442166662368155595513633734025582065332680836159373734790483865268263040892463056431887354544369559827491606602099884183933864652731300088830269235673613135117579297437854413752130520504347701602264758318906527890855154366159582987279682987510631200575428783453215515103870818298969791613127856265033195487140214287532698187962046936097879900350962302291026368131493195275630227837628441540360584402572114334961180023091208287046088923962328835461505776583271252546093591128203925285393434620904245248929403901706233888991085841065183173360437470737908552631764325733993712871937587746897479926305837065742830161637408969178426378624212835258112820516370298089332099905707920064367426202389783111470054074998459250360633560933883831923386783056136435351892133279732908133732642652633989763922723407882928177953580570993691049175470808931841056146322338217465637321248226383092103297701648054726243842374862411453093812206564914032751086643394517512161526545361333111314042436854805106765843493523836959653428071768775328348234345557366719731392746273629108210679280784718035329131176778924659089938635459327894523777674406192240337638674004021330343297496902028328145933418826817683893072003634795623117103101291953169794607632737589253530772552375943788434504067715555779056450443016640119462580972216729758615026968443146952034614932291105970676243268515992834709891284706740862008587135016260312071903172086094081298321581077282076353186624611278245537208532365305775956430072517744315051539600905168603220349163222640885248852433158051534849622434848299380905070483482449327453732624567755879089187190803662058009594743150052402532709746995318770724376825907419939632265984147498193609285223945039707165443156421328157688908058783183404917434556270520223564846495196112460268313970975069382648706613264507665074611512677522748621598642530711298441182622661057163515069260029861704945425047491378115154139941550671256271197133252763631939606902895650288268608362241082050562430701794976171121233066073310059947366875 .
9
10
  } .