-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday17.ts
151 lines (138 loc) · 4.25 KB
/
day17.ts
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { input } from './input';
type Registers = {
A: number;
B: number;
C: number;
};
const myInput = JSON.parse(input);
type Instruction =
| 'adv'
| 'bxl'
| 'bst'
| 'jnz'
| 'bxc'
| 'out'
| 'bdv'
| 'cdv';
const map: readonly Instruction[] = [
'adv',
'bxl',
'bst',
'jnz',
'bxc',
'out',
'bdv',
'cdv',
];
function device(reg: Registers, instructions: number[]) {
const output: number[] = [];
function getComboOperand(add: number) {
if (add <= 3) {
return add;
}
if (add === 4) {
return reg.A;
}
if (add === 5) {
return reg.B;
}
if (add === 6) {
return reg.C;
}
throw new Error('bad address');
}
function doOperation(
instruction: Instruction,
operand: number,
pointer: number,
) {
switch (instruction) {
case 'adv':
case 'bdv':
case 'cdv': {
// The adv instruction (opcode 0) performs division. The numerator is the value in the A register.
// The denominator is found by raising 2 to the power of the instruction's combo operand. (So, an operand of
// 2 would divide A by 4 (2^2); an operand of 5 would divide A by 2^B.) The result of the division operation is
// truncated to an integer and then written to the A register.
const num = reg.A;
const op = getComboOperand(operand);
const den = Math.pow(2, op);
const result = Math.floor(num / den);
if (instruction === 'adv') reg.A = result;
if (instruction === 'bdv') reg.B = result;
if (instruction === 'cdv') reg.C = result;
break;
}
case 'bxl': {
// The bxl instruction (opcode 1) calculates the bitwise XOR of register B and the instruction's literal
// operand, then stores the result in register B.
const num = reg.B;
const result = Number(BigInt(num) ^ BigInt(operand));
reg.B = result;
break;
}
case 'bst': {
// The bst instruction (opcode 2) calculates the value of its combo operand modulo 8 (thereby keeping
// only its lowest 3 bits), then writes that value to the B register.
const num = getComboOperand(operand);
reg.B = num % 8;
break;
}
case 'jnz': {
// The jnz instruction (opcode 3) does nothing if the A register is 0. However, if the A register is not
// zero, it jumps by setting the instruction pointer to the value of its literal operand; if this instruction
// jumps, the instruction pointer is not increased by 2 after this instruction.
if (reg.A === 0) {
break;
}
return operand;
}
case 'bxc': {
// The bxc instruction (opcode 4) calculates the bitwise XOR of register B and register C, then stores the
// result in register B. (For legacy reasons, this instruction reads an operand but ignores it.)
const b = reg.B;
const c = reg.C;
reg.B = Number(BigInt(b) ^ BigInt(c));
break;
}
case 'out': {
// The out instruction (opcode 5) calculates the value of its combo operand modulo 8, then outputs that value.
// (If a program outputs multiple values, they are separated by commas.)
const num = getComboOperand(operand);
output.push(num % 8);
break;
}
default:
throw new Error('invalid operation ' + instruction);
}
return (pointer += 2);
}
for (let i = 0; i < instructions.length; ) {
const ins = map[instructions[i]];
const op = instructions[i + 1];
i = doOperation(ins, op, i);
}
return output.join(',');
}
// // part a
const program: number[] = myInput.program;
console.log(device(myInput.reg, program));
// part b
const q: { result: string; len: number }[] = [];
q.push({ result: '', len: 0 });
while (q.length) {
const item = q.shift()!;
if (item.len === program.length) {
console.log('B', parseInt(item.result, 2));
break;
}
const from = parseInt(item.result + '000', 2);
const to = parseInt(item.result + '111', 2);
const expect = program.slice((item.len + 1) * -1).join(',');
for (let a = from; a <= to; a++) {
const r = device({ A: a, B: 0, C: 0 }, program);
if (r === expect) {
q.push({ result: a.toString(2), len: item.len + 1 });
}
}
}