xxxxxxxxxx
283
// script.js
// Deterministic backtracking with a runProgram check, no randomness.
// When a solution is found, update the top status bar.
// CORRECT SOLUTION REFRERENCE : 37221334433268
const program = [2,4,1,2,7,5,1,3,4,3,5,5,0,3,3,0];
let stack = [{target:[program], ans:0n, tried:Array(8).fill(false), chosen:null}];
let solutionA = null;
let totalAttempts = 0;
let logstate= "Searching"
const attemptsBody = document.getElementById('attempts-body');
const terminalLog = document.getElementById('terminal-log');
const linesOverlay = document.querySelector('.lines-overlay');
const statusBar = document.getElementById('status-bar');
let displayedRows = 0;
function combo(op, A, B, C) {
let opVal = BigInt(op);
if (opVal >= 0n && opVal <= 3n) return opVal;
if (opVal === 4n) return A;
if (opVal === 5n) return B;
if (opVal === 6n) return C;
throw "unrecognized combo operand";
}
function runProgram(A_initial) {
let A = BigInt(A_initial);
let B = 0n;
let C = 0n;
let result = [];
let adv3 = false;
for (let pointer = 0; pointer < program.length - 2; pointer += 2) {
let ins = BigInt(program[pointer]);
let operand = BigInt(program[pointer+1]);
switch(ins) {
case 0n:
if (adv3) throw "multiple ADVs";
if (operand !== 3n) throw "ADV operand != 3";
adv3 = true;
A = A >> 3n; // same as A = A // (2**3)
break;
case 1n:
B = B ^ operand;
break;
case 2n:
B = combo(operand, A, B, C) % 8n;
break;
case 3n:
throw "program has JNZ inside main body";
case 4n:
B = B ^ C;
break;
case 5n:
// OUT instruction
let outVal = combo(operand, A, B, C) % 8n;
result.push(Number(outVal));
break;
case 6n:
B = A >> combo(operand, A, B, C);
break;
case 7n:
C = A >> combo(operand, A, B, C);
break;
default:
throw "unknown instruction";
}
}
return result;
}
function simulateStep() {
if (solutionA !== null || stack.length===0) {
clearInterval(interval);
if (solutionA !== null) {
logMessage("Solution found: A = " + solutionA.toString());
statusBar.textContent = "Solution: A = " + solutionA.toString();
} else {
logMessage("No solution found (stack empty).");
statusBar.textContent = "No solution found.";
}
return;
}
let current = stack[stack.length-1];
let target = current.target;
if (target.length === 0) {
solutionA = current.ans;
logMessage("All matched! Solution A = " + solutionA.toString());
statusBar.textContent = "Solution: A = " + solutionA.toString();
clearInterval(interval);
return;
}
let tIndex = current.tried.findIndex(v=>!v);
if (tIndex === -1) {
// all tried, no success, backtrack
stack.pop();
logMessage("Backtracking...");
logstate = "Backtracking"
updateTable();
redrawLines();
return;
}
else {
logstate = "Searching"
}
current.tried[tIndex] = true;
totalAttempts++;
// Try candidate A
let newA = (current.ans << 3n) | BigInt(tIndex);
let output = runProgram(newA);
logMessage("Output: " + output.join(", "));
if (output.length > 0 && output[output.length-1] === target[target.length-1]) {
// success for this element
current.chosen = tIndex;
let newTarget = target.slice(0, target.length-1);
if (newTarget.length===0) {
solutionA = newA;
current.ans = newA;
msg = "Success at final step, full solution found: A="+solutionA.toString()
logMessage(msg);
statusBar.textContent = "Solution: A = " + solutionA.toString();
clearInterval(interval);
} else {
stack.push({target:newTarget, ans:newA, tried:Array(8).fill(false), chosen:null});
msg = "Matched an element, going deeper (matched "+(program.length-newTarget.length)+" so far)..."
logMessage(msg);
}
} else {
// failure
logMessage("Attempt t="+tIndex+" failed at level "+(program.length - target.length));
}
updateTable();
redrawLines();
}
function updateTable() {
// Add rows if stack grew
while (displayedRows < stack.length) {
addRow(displayedRows);
displayedRows++;
}
// Update existing rows
for (let i=0; i<stack.length; i++) {
updateRow(i);
}
// If stack shrank, remove extra rows
while (displayedRows > stack.length) {
attemptsBody.removeChild(attemptsBody.lastChild);
displayedRows--;
}
}
function addRow(index) {
const state = stack[index];
const level = program.length - state.target.length;
const row = document.createElement('tr');
row.className = 'level-row';
const infoCell = document.createElement('td');
infoCell.className = 'info-cell';
const attemptsCell = document.createElement('td');
attemptsCell.className = 'attempts-cell';
const attemptsGrid = document.createElement('div');
attemptsGrid.className = 'attempts-grid';
for (let t=0; t<8; t++) {
const circle = document.createElement('div');
circle.className = 'attempt-circle attempt-nottried';
circle.textContent = t;
attemptsGrid.appendChild(circle);
}
attemptsCell.appendChild(attemptsGrid);
infoCell.innerHTML = `
<div class="info-title">Level: ${level}</div>
<div class="info-text">A: ${state.ans.toString()}</div>
`;
row.appendChild(infoCell);
row.appendChild(attemptsCell);
attemptsBody.appendChild(row);
}
function updateRow(index) {
const state = stack[index];
const level = program.length - state.target.length;
const row = attemptsBody.children[index];
// Update info cell
const infoCell = row.querySelector('.info-cell');
infoCell.innerHTML = `
<div class="info-title">Level: ${level}</div>
<div class="info-text">A: ${state.ans.toString()}</div>
`;
// Update attempts
const attemptsCell = row.querySelector('.attempts-cell');
const circles = attemptsCell.querySelectorAll('.attempt-circle');
for (let t=0; t<8; t++) {
circles[t].className = 'attempt-circle'; // reset class
if (state.chosen === t) {
circles[t].classList.add('attempt-chosen');
} else if (state.tried[t] === false) {
circles[t].classList.add('attempt-nottried');
} else {
circles[t].classList.add('attempt-failed');
}
circles[t].textContent = t;
}
}
function redrawLines() {
linesOverlay.innerHTML = '';
for (let i=0; i<stack.length-1; i++) {
let current = stack[i];
let next = stack[i+1];
if (current.chosen !== null && next) {
let currentRow = attemptsBody.children[i];
let nextRow = attemptsBody.children[i+1];
let currentCircles = currentRow.querySelectorAll('.attempt-circle');
let nextCircles = nextRow.querySelectorAll('.attempt-circle');
let currentCircle = currentCircles[current.chosen];
if (next.chosen !== null) {
let nextCircle = nextCircles[next.chosen];
let cRect = currentCircle.getBoundingClientRect();
let nRect = nextCircle.getBoundingClientRect();
let svgRect = linesOverlay.getBoundingClientRect();
let x1 = cRect.left + cRect.width/2 - svgRect.left;
let y1 = cRect.top + cRect.height/2 - svgRect.top;
let x2 = nRect.left + nRect.width/2 - svgRect.left;
let y2 = nRect.top + nRect.height/2 - svgRect.top;
let path = document.createElementNS("http://www.w3.org/2000/svg","path");
let controlX = (x1+x2)/2;
let d = `M ${x1},${y1} C ${controlX},${y1} ${controlX},${y2} ${x2},${y2}`;
path.setAttribute('d', d);
path.setAttribute('stroke', 'rgba(46,204,113,0.7)');
path.setAttribute('stroke-width', '2');
path.setAttribute('fill', 'none');
linesOverlay.appendChild(path);
}
}
}
}
function logMessage(msg) {
const line = document.createElement('div');
line.className = 'terminal-line';
line.textContent = msg;
terminalLog.appendChild(line);
terminalLog.scrollTop = terminalLog.scrollHeight;
statusBar.textContent = logstate + " "+msg;
}
const interval = setInterval(simulateStep, 85);