DKL9 GitList
Repositories
DKL9 home
functle
Code
Commits
Branches
Tags
Search
Tree:
171208b
Branches
Tags
master
functle
functle.html
Initial commit: vibe-code a prototype
dkl9
commited
171208b
at 2025-209 17:09:01
functle.html
Blame
History
Raw
<!DOCTYPE html> <html> <head> <style> body { font-family: sans-serif; } #plot { border: 1px solid #000; } #grid { display: grid; grid-template-rows: repeat(6, 1fr); gap: 5px; margin-top: 10px; } .row { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; } .cell { width: 40px; height: 40px; border: 1px solid #ccc; display: flex; align-items: center; justify-content: center; font-weight: bold; } .grey { background: #787c7e; color: #fff; } .yellow { background: #c9b458; color: #fff; } .green { background: #6aaa64; color: #fff; } #message { color: red; margin-top: 5px; } </style> </head> <body> <canvas id="plot" width="400" height="400"></canvas> <div> <input id="guessInput" placeholder="token1 token2 ... token6" style="width: 300px;"> <button id="submitBtn">Submit</button> <div id="message"></div> </div> <div id="grid"></div> <script> const allowed = { terminals: ["x", "1", "2"], unary: ["^2", "^3", "sin", "exp", "ln"], binary: ["+", "-", "*", "/"] }; const target = ["x", "sin", "1", "1", "+", "*"]; // 2*sin(x) const tl = target.length; const maxGuesses = 6; let currentRow = 0; const width = 400, height = 400; const ctx = document.getElementById("plot").getContext("2d"); const bound = 10; const xs = []; const targetYs = []; for (let i = 0; i <= width; i++) { const x = bound * (2 * i / width - 1); xs.push(x); targetYs.push(evalPostfix(target, x)); } const yMin = Math.min(...targetYs), yMax = Math.max(...targetYs); drawAxes(); drawCurve(targetYs, "green"); for (let i = 0; i < maxGuesses; i++) { const row = document.createElement("div"); row.className = "row"; for (let j = 0; j < tl; j++) { const cell = document.createElement("div"); cell.className = "cell"; row.appendChild(cell); } document.getElementById("grid").appendChild(row); } document.getElementById("submitBtn").onclick = () => { const inp = document.getElementById("guessInput").value.trim().split(/\s+/); document.getElementById("message").textContent = ""; if (inp.length !== tl) { document.getElementById("message").textContent = `Exactly ${tl} tokens.`; return; } for (const t of inp) { if (![...allowed.terminals, ...allowed.unary, ...allowed.binary].includes(t)) { document.getElementById("message").textContent = "Invalid token: " + t; return; } } let ys; try { ys = xs.map(x => evalPostfix(inp, x)); } catch (e) { document.getElementById("message").textContent = "Syntax error."; return; } if (closeEnough(ys, targetYs)) { fillRow(inp, "green"); alert("Correct."); document.getElementById("submitBtn").disabled = true; return; } markRow(inp); drawCurve(ys, "red"); currentRow++; if (currentRow >= maxGuesses) { alert("Out of guesses."); document.getElementById("submitBtn").disabled = true; } }; function evalPostfix(tokens, x) { const s = []; for (const t of tokens) { if (t === "x") s.push(x); else if (t === "1") s.push(1); else if (t === "2") s.push(2); else if (allowed.unary.includes(t)) { const v = s.pop(); if (t === "^2") s.push(v ** 2); if (t === "^3") s.push(v ** 3); if (t === "sin") s.push(Math.sin(v)); if (t === "exp") s.push(Math.exp(v)); if (t === "ln") s.push(Math.log(v)); } else { const b = s.pop(), a = s.pop(); if (t === "+") s.push(a + b); if (t === "-") s.push(a - b); if (t === "*") s.push(a * b); if (t === "/") s.push(a / b); } if (s.length < 0) throw 0; } if (s.length !== 1) throw 0; return s[0]; } function closeEnough(a, b) { for (let i = 0; i < a.length; i++) { if (isNaN(a[i]) || Math.abs(a[i] - b[i]) > 0.1 * (Math.abs(b[i]) + 1)) return false; } return true; } function fillRow(tokens, cls) { const row = document.getElementById("grid").children[currentRow]; for (let i = 0; i < 6; i++) { row.children[i].textContent = tokens[i]; row.children[i].classList.add(cls); } } function markRow(tokens) { const freq = {}; for (const t of target) freq[t] = (freq[t] || 0) + 1; const colors = Array(tl).fill("grey"); for (let i = 0; i < tl; i++) { if (tokens[i] === target[i]) { colors[i] = "green"; freq[tokens[i]]--; } } for (let i = 0; i < tl; i++) { if (colors[i] === "grey" && freq[tokens[i]] > 0) { colors[i] = "yellow"; freq[tokens[i]]--; } } const row = document.getElementById("grid").children[currentRow]; for (let i = 0; i < tl; i++) { row.children[i].textContent = tokens[i]; row.children[i].classList.add(colors[i]); } } function drawAxes() { ctx.clearRect(0, 0, width, height); ctx.beginPath(); // x-axis const y0 = mapY(0); ctx.moveTo(0, y0); ctx.lineTo(width, y0); // y-axis const x0 = mapX(0); ctx.moveTo(x0, 0); ctx.lineTo(x0, height); ctx.strokeStyle = "black"; ctx.stroke(); } function drawCurve(ys, color) { ctx.beginPath(); for (let i = 0; i < xs.length; i++) { const px = mapX(xs[i]), py = mapY(ys[i]); if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py); } ctx.strokeStyle = color; ctx.stroke(); } function mapX(x) { return (x + bound) / (2 * bound) * width; } function mapY(y) { return height - (y - yMin) / (yMax - yMin) * height; } </script> </body> </html>