aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--index.html34
-rw-r--r--main.js37
2 files changed, 57 insertions, 14 deletions
diff --git a/index.html b/index.html
index 63e6c0a..9718cb0 100644
--- a/index.html
+++ b/index.html
@@ -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)
diff --git a/main.js b/main.js
index 4f5eae2..45335c3 100644
--- a/main.js
+++ b/main.js
@@ -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);