diff options
author | Marvin Borner | 2025-02-09 21:45:44 +0100 |
---|---|---|
committer | Marvin Borner | 2025-02-09 21:46:26 +0100 |
commit | 89c7fc475dd7b11d3452ac48de2d9167665f50d7 (patch) | |
tree | 9b9d6a235aec836f0615627006dee81f39a2cc9f | |
parent | 93d736967d856cf181b1c78955f06f7d160d3eff (diff) |
-rw-r--r-- | index.html | 34 | ||||
-rw-r--r-- | main.js | 37 |
2 files changed, 57 insertions, 14 deletions
@@ -136,13 +136,19 @@ br = \\\\\(0 sd 3 2 1) </option> <option value="y = \(\(0 0) \(1 (0 0))) +\(y \\(0 1 1 1 1 \\0 1 1 1 1))" + > + Sierpiński carpet (3x3) + </option> + <option + value="y = \(\(0 0) \(1 (0 0))) tl = \\\\\(0 4 3 2 \(0 \(0 \\0 \\1 \\1 \\1) \\1 \\1 \\0)) tr = \\\\\(0 4 3 \(0 \\1 \(0 \\1 \\0 \\1 \\1) \\0 \\1) 1) bl = \\\\\(0 4 \(0 \\1 \\0 \(0 \\1 \\1 \\0 \\1) \\1) 2 1) br = \\\\\(0 \(0 \\0 \\1 \\1 \(0 \\1 \\1 \\1 \\0)) 3 2 1) \(y \\(0 (1 tl) (1 tr) (1 bl) (1 br)))" > - Sierpiński carpet (variant) + Sierpiński carpet (2x2 variant) </option> <option value="y = \(\(0 0) \(1 (0 0))) @@ -155,7 +161,13 @@ br = \\\\\(0 \\0 3 2 1) T-square </option> <option - value="-- variation of T-Square, mostly unrelated to Koch snowflakes + value="y = \(\(0 0) \(1 (0 0))) +\(y \\(0 \\1 1 \\1 1 1 1 \\1 1 \\1))" + > + Snowflake 3x3 + </option> + <option + value="-- variation of T-Square y = \(\(0 0) \(1 (0 0))) tl = \\\\\(0 \\1 3 2 1) tr = \\\\\(0 4 \\1 2 1) @@ -163,7 +175,7 @@ bl = \\\\\(0 4 3 \\1 1) br = \\\\\(0 4 3 2 \\1) \(y \\(0 (1 tl) (1 tr) (1 bl) (1 br)))" > - Snowflake + Snowflake 2x2 </option> <option value="s=\\0 @@ -174,6 +186,22 @@ y = \(\(0 0) \(1 (0 0))) Cantor dust </option> <option + value="-- basically a 3x3 T-square +y = \(\(0 0) \(1 (0 0))) +a = \\\\\\\\\\(0 9 8 7 6 5 4 3 2 \\0) +b = \\\\\\\\\\(0 9 8 7 6 5 4 3 \\0 1) +c = \\\\\\\\\\(0 9 8 7 6 5 4 \\0 2 1) +d = \\\\\\\\\\(0 9 8 7 6 5 \\0 3 2 1) +e = \\\\\\\\\\(0 9 8 7 6 \\0 4 3 2 1) +f = \\\\\\\\\\(0 9 8 7 \\0 5 4 3 2 1) +g = \\\\\\\\\\(0 9 8 \\0 6 5 4 3 2 1) +h = \\\\\\\\\\(0 9 \\0 7 6 5 4 3 2 1) +i = \\\\\\\\\\(0 \\0 8 7 6 5 4 3 2 1) +\(y \\(0 (1 a) (1 b) (1 c) (1 d) (1 e) (1 f) (1 g) (1 h) (1 i)))" + > + Minesweeper + </option> + <option value="y = \(\(0 0) \(1 (0 0))) stl = \\\\\(0 \\1 3 2 1) @@ -1,8 +1,8 @@ let MAXRES = 2; -let doCache = true; let errors = []; const error = (s) => { + clearCache(); errors.push(s); console.error(s); window.error.innerText = "invalid term: " + errors.toReversed().join(", "); @@ -12,6 +12,25 @@ const clearErrors = () => { window.error.innerText = ""; }; +/* caching */ + +let doCache = true; + +const allHashes = {}; +const incCache = {}; +const substCache = {}; +const whnfCache = {}; +const snfCache = {}; +const caches = [allHashes, incCache, substCache, whnfCache, snfCache]; + +const clearCache = () => { + caches.forEach((cache) => + Object.keys(cache).forEach((key) => { + delete cache[key]; + }), + ); +}; + /* canvas */ const WHITE = 0; @@ -40,6 +59,7 @@ const drawScreen = (worker, ctxs, colors) => { colors = colors.map((color) => color == WHITE ? "white" : color == BLACK ? "black" : "#cccccc", ); + worker.postMessage({ drawScreen: [colors, ctxs] }); }; @@ -49,7 +69,6 @@ const drawScreen = (worker, ctxs, colors) => { // `return null` and `if (foo === null) return null` are the monads of JavaScript!! // --- -const allHashes = {}; const hash = (s) => { let h = 0; for (let i = 0; i < s.length; i++) { @@ -332,9 +351,7 @@ const seemsScreeny = (t) => { t = t.body; let d = 0; while ((d++, t.type === "app")) t = t.left; - return d > 4 && Math.sqrt(d - 1) % 1 === 0 && t.type === "idx" && t.idx === 0 - ? d - 1 - : false; + return t.type === "idx" && t.idx === 0 ? d - 1 : false; }; const getSubScreens = (t) => { @@ -363,13 +380,13 @@ const cancelReduction = () => { ) ) { canceled = true; + clearCache(); return true; } } return canceled; }; -const incCache = {}; const inc = (i, t) => { if (cancelReduction() || t === null) { error("in inc"); @@ -399,7 +416,6 @@ const inc = (i, t) => { return newT; }; -const substCache = {}; const subst = (i, t, s) => { if (cancelReduction() || t === null) { error("in subst"); @@ -455,7 +471,6 @@ const gnf = (t) => { }; // weak head normal form -const whnfCache = {}; const whnf = (t) => { if (cancelReduction() || t === null) { error("in whnf"); @@ -490,7 +505,6 @@ const whnf = (t) => { // one of [((((0 tl) tr) bl) br) ...], [[0]], [[1]] // TODO: Is this form of caching fundamentally wrong? (incongruences after subst or idx shifts!?) // Does this only work accidentally because of WHNF, deliberate symmetry and closed terms or sth? -const snfCache = {}; const snf = (_t) => { if (doCache && _t !== null && _t.hash in snfCache) return snfCache[_t.hash]; @@ -503,7 +517,8 @@ const snf = (_t) => { t = abs(whnf(t.body)); if (t.body.type === "abs") return gnf(t); // not a screen, probably a pixel - while (t !== null && !seemsScreeny(t)) { + // yes `=== false` is relevant here + while (t !== null && seemsScreeny(t) === false) { switch (t.type) { case "app": const _left = whnf(t.left); @@ -562,7 +577,7 @@ const reduceLoop = (conf, _t) => { if (ctx.x[1] - ctx.x[0] < MAXRES) continue; let n; - if ((n = seemsScreeny(t))) { + if ((n = seemsScreeny(t)) && n > 3 && Math.sqrt(n) % 1 === 0) { const subScreens = getSubScreens(t); console.assert(n == subScreens.length); |