let drawing = 1; const form = Array.from(document.forms.rules.elements); const canvas = document.getElementById('canvas'); const main = document.getElementById('main'); canvas.width = main.offsetWidth; canvas.height = main.offsetHeight; const dead = document.getElementById('dead'); const live = document.getElementById('live'); function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); // The maximum is exclusive and the minimum is inclusive return Math.floor(Math.random() * (max - min) + min); } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function evolve(state, acc, rules) { const [x, y, z, ...xs] = state; if (!xs.length) { return acc[acc.length - 1] + acc + acc[0]; } const rule = x + y + z; const newAcc = acc.concat(rules[rule]); return evolve(y + z + xs.join(''), newAcc, rules); } function draw(state, context, acc) { const cellDim = 5; Object.keys(state).forEach( (key) => { context.moveTo(key * cellDim, acc * cellDim); context.fillRect(key * cellDim, acc * cellDim, cellDim, cellDim); if (state[key] === '1') context.fillStyle = live.value; else context.fillStyle = dead.value; }, ); } const start = document.getElementById('start'); start.addEventListener('click', async () => { drawing = 1; const rules = form.reduce((a, i) => { if (i !== undefined && i.type === 'checkbox') { if (i.checked) a[i.name] = '1'; else a[i.name] = '0'; } return a; }, {}); const ctx = canvas.getContext('2d'); const initialState = [...Array(canvas.width)].map( (_) => getRandomInt(0, 2).toString(), ).join(''); let newState = evolve(initialState, '', rules); let acc = 0; while (acc < canvas.width) { if (drawing === 0) { break; } draw(newState, ctx, acc); newState = evolve(newState, '', rules); acc += 1; await sleep(60); } }); const reset = document.getElementById('reset'); reset.addEventListener('click', async () => { drawing = 0; const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); });