-
Notifications
You must be signed in to change notification settings - Fork 17
/
duet.js
94 lines (79 loc) · 2.42 KB
/
duet.js
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
// Helper, I use this a bit
const isStr = val => typeof val === 'string';
class Duet {
constructor(program) {
this.program = JSON.parse(JSON.stringify(program));
this.registers = Duet.getUniqueRegisters(this.program);
this.index = 0;
this.finished = false;
this.last_sound_played = null;
}
snd(value) {
this.last_sound_played = this.getValueAtRegister(value);
}
set(register, value) {
this.registers[register] = this.getValueAtRegister(value);
}
add(register, value) {
this.registers[register] += this.getValueAtRegister(value);
}
mul(register, value) {
this.registers[register] *= this.getValueAtRegister(value);
}
mod(register, value) {
this.registers[register] %= this.getValueAtRegister(value);
}
/**
* `rcv X` recovers the frequency of the last sound played,
* but only when the value of `X` is not zero. (If it is zero,
* the command does nothing.)
*
* In practice, this is what "halts" the program, where returning
* `true` halts, and `false` continues.
*/
rcv(value) {
if (this.getValueAtRegister(value) !== 0) {
this.finished = true;
return true;
} else {
return false;
}
}
jgz(value, offset) {
if (this.getValueAtRegister(value) > 0) {
this.index += this.getValueAtRegister(offset);
return true;
} else {
return false;
}
}
static getUniqueRegisters(program, return_object = true) {
let registers = {};
for (let instruction of program) {
let { x, y } = instruction;
if (isStr(x)) {
registers[x] = 0;
}
if (isStr(y)) {
registers[y] = 0;
}
}
return return_object ? registers : Object.keys(registers);
}
getValueAtRegister(value) {
return isStr(value) ? this.registers[value] : value;
}
run() {
while (!this.finished) {
let { type, x, y } = this.program[this.index];
let value = this[type](x, y);
if (type === 'jgz' && value === true) {
// Do nothing, we jumped. Otherwise, skip the `jgz` instruction
} else {
this.index++;
}
}
return this.last_sound_played;
}
}
module.exports = Duet;