diff --git a/index.html b/index.html index 77be7ff..b9a8038 100644 --- a/index.html +++ b/index.html @@ -1,19 +1,72 @@ - Cellular automata - + Cellular Automaton Explorer + - + +

Cellular Automaton Explorer

+ + +
+
+ +
diff --git a/main.js b/main.js index 94931e5..a8078b8 100644 --- a/main.js +++ b/main.js @@ -1,77 +1,86 @@ -'use strict'; +let drawing = 1; -const rules = { - "111": "0", - "110": "1", - "101": "0", - "100": "1", - "011": "1", - "010": "0", - "001": "1", - "000": "0" -} +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); + return Math.floor(Math.random() * (max - min) + min); } function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } -function evolve(state, acc) { +function evolve(state, acc, rules) { const [x, y, z, ...xs] = state; if (!xs.length) { - return acc[0] + acc + acc[acc.length - 1] - } - else { - const rule = x + y + z; - const new_acc = acc.concat(rules[rule]); - return evolve(y + z + xs.join(""), new_acc) + 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 cell_dim = 2 + const cellDim = 5; Object.keys(state).forEach( - function (key) { - context.moveTo(key * cell_dim, acc * cell_dim) - context.fillRect(key * cell_dim, acc * cell_dim, cell_dim, cell_dim) - if(state[key] == "1") { - context.fillStyle="black"; - }else { - if (acc % 2) { - context.fillStyle="white"; - }else { - context.fillStyle="white"; - } - } - }) + (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; + }, + ); } -window.addEventListener("load", async function() { - const canvas = document.getElementById("canvas") - canvas.width = window.innerWidth - canvas.height = window.innerHeight - const ctx = canvas.getContext("2d") +const start = document.getElementById('start'); - const initial_state = [...Array(canvas.width)].map( - _=> getRandomInt(0, 2).toString() - ).join("") +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; + }, {}); - console.log("initial state length : ", initial_state.length) + const ctx = canvas.getContext('2d'); - var new_state = evolve(initial_state, "") - var acc = 0 - - while(acc < canvas.width) { - draw(new_state, ctx, acc) - new_state = evolve(new_state, "") - acc++ - await sleep(100) + 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); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..25a8f8e --- /dev/null +++ b/style.css @@ -0,0 +1,39 @@ +* { + margin: 0; + padding: 0; +} + +body { + background: black; + color: white; + display: flex; + font-family: Courier New; +} + +h1 { + font-size: large; + font-weight: bold; +} + +sidebar { + flex: auto; + padding: 10px; +} + +.form-field { + display: flex; + margin: 10px; +} + +.menu-row { + flex: 1; +} + +label, .form-field label { + margin-right: 10px; + font-weight: bold; +} + +#main { + flex: 4; +}