Turing machine #2
90
turing-machine/css/styles.css
Normal file
90
turing-machine/css/styles.css
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
* {
|
||||||
|
font-family: "Trebuchet MS", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: #bbbbbb;
|
||||||
|
border: 1px solid white;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
padding: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background-color: #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
width: 90%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
height: 5rem;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
border: 1px solid black;
|
||||||
|
|
||||||
|
overflow-x: scroll;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
position: relative;
|
||||||
|
height: 80%;
|
||||||
|
border: 3px solid black;
|
||||||
|
transition: border 0.1s ease-in-out;
|
||||||
|
transition: background 0.1s ease-in-out;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
gap: 0.2rem;
|
||||||
|
|
||||||
|
padding: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -15px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: wheat;
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 0.001;
|
||||||
|
transition: opacity 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell.reading .circle {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading {
|
||||||
|
border-color: green;
|
||||||
|
background-color: wheat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-input {
|
||||||
|
width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
14
turing-machine/index.html
Normal file
14
turing-machine/index.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Turing Machine Simulator</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Simponic's State System</h1>
|
||||||
|
<div id="tape" class="tape"></div>
|
||||||
|
</div>
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
98
turing-machine/js/main.js
Normal file
98
turing-machine/js/main.js
Normal file
@ -0,0 +1,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();
|
Loading…
Reference in New Issue
Block a user