blob: fd05366f82ddce7c3c80242144b421d2919b9b83 (
plain) (
blame)
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
99
100
101
102
103
|
const ESCAPE_REGEX = /[.*+?^${}()|[\]\\]/g;
function escapeForRegex(value) {
return value.replace(ESCAPE_REGEX, "\\$&");
}
export class Tape {
constructor({
initialContent = "",
blankSymbol = "B",
minLength = 50,
padding = 40
} = {}) {
this.blankSymbol = blankSymbol;
this.minLength = minLength;
this.padding = padding;
this.reset(initialContent);
}
reset(initialContent = "") {
const targetLength = Math.max(this.minLength, initialContent.length + this.padding);
this.cells = Array(targetLength).fill(this.blankSymbol);
const startOffset = Math.floor((targetLength - initialContent.length) / 2);
for (let i = 0; i < initialContent.length; i++) {
this.cells[startOffset + i] = initialContent[i];
}
this.headIndex = startOffset;
}
get length() {
return this.cells.length;
}
getHeadIndex() {
return this.headIndex;
}
readHead() {
return this.getCell(this.headIndex);
}
writeHead(symbol) {
this.cells[this.headIndex] = symbol || this.blankSymbol;
}
readAt(index) {
return this.getCell(index);
}
writeAt(index, symbol) {
if (index < 0) {
throw new Error("Cannot write to a negative tape index");
}
this.ensureRightCapacity(index);
this.cells[index] = symbol || this.blankSymbol;
}
setHead(index) {
if (index < 0) {
throw new Error("Head index cannot be negative");
}
this.ensureRightCapacity(index);
this.headIndex = index;
}
moveLeft() {
if (this.headIndex === 0) {
this.cells.unshift(this.blankSymbol);
} else {
this.headIndex -= 1;
return;
}
}
moveRight() {
this.headIndex += 1;
if (this.headIndex >= this.cells.length) {
this.cells.push(this.blankSymbol);
}
}
getCell(index) {
if (index < 0 || index >= this.cells.length) {
return this.blankSymbol;
}
return this.cells[index];
}
ensureRightCapacity(index) {
while (index >= this.cells.length) {
this.cells.push(this.blankSymbol);
}
}
getContents({ trimTrailing = true } = {}) {
let snapshot = this.cells.join("");
if (trimTrailing) {
const regex = new RegExp(`${escapeForRegex(this.blankSymbol)}+$`, "g");
snapshot = snapshot.replace(regex, "");
}
return snapshot;
}
}
|