simponic.xyz/turing-machine/js/main.js

99 lines
2.2 KiB
JavaScript

const DISPLAY_CELLS = 15;
const TAPE_LEN = 200;
const MESSAGES = {
SET_CELL: "SET_CELL",
PAUSE: "PAUSE",
SIMULATE: "SIMULATE",
SET_READER: "SET_READER",
};
class Observable {
constructor() {
this.observers = [];
}
subscribe(f) {
this.observers.push(f);
}
unsubscribe(f) {
this.observers = this.observers.filter((subscriber) => subscriber !== f);
}
notify(data) {
this.observers.forEach((observer) => observer(data));
}
}
const state = new Observable();
const tape = Array(TAPE_LEN).fill(0);
state.subscribe((msg) => {
if (msg.type == MESSAGES.SET_CELL) {
tape[msg.cellId] = msg.value;
}
});
const tapeEl = document.getElementById("tape");
const inputCellId = (cellId) => `${cellId}-input`;
const updateCellButtonId = (cellId) => `${cellId}-button-update`;
const setCellFromInput = (cellId, inputId) => {
const input = document.getElementById(inputId);
tape[cellId] = input.value;
};
const cell = (cellId, initValue = 0) => {
const cellDiv = document.createElement("div");
cellDiv.classList.add("cell");
cellDiv.id = cellId;
const readingHead = document.createElement("div");
readingHead.classList.add("circle");
const input = document.createElement("input");
const inputId = inputCellId(cellId);
input.classList.add("cell-input");
input.id = inputId;
input.value = initValue;
input.addEventListener("focusin", () =>
state.notify({ type: MESSAGES.PAUSE })
);
input.addEventListener("focusout", () =>
state.notify({ type: MESSAGES.SET_CELL, cell: cellId, value: input.value })
);
state.subscribe((msg) => {
if (msg.type == MESSAGES.SET_CELL && msg.cell == cellId) {
input.value = msg.value;
}
if (msg.type == MESSAGES.SET_READER) {
if (msg.cell == cellId) {
cellDiv.classList.add("reading");
cellDiv.scrollIntoView({
behavior: "smooth",
});
} else cellDiv.classList.remove("reading");
}
});
cellDiv.appendChild(input);
cellDiv.appendChild(readingHead);
return cellDiv;
};
const main = () => {
const cells = tape.map((_, cellId) => cell(cellId));
for (const cell of cells) {
tapeEl.appendChild(cell);
}
state.notify({ type: MESSAGES.SET_READER, cell: 0 });
setTimeout(() => {}, 1000);
};
main();