summaryrefslogtreecommitdiff
path: root/turing-machine/js/main.js
blob: 68aaa39dd5a525909aef787443b7a13ba7a180e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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();