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