Skip to content

Commit 365c2da

Browse files
committed
Day 15
1 parent 5fbf9b9 commit 365c2da

File tree

4 files changed

+372
-1
lines changed

4 files changed

+372
-1
lines changed

Makefile

+6-1
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,9 @@ day13-2:
6666
day14:
6767
npx ts-node day14.ts
6868
day14-2:
69-
npx ts-node day14-2.ts
69+
npx ts-node day14-2.ts
70+
71+
day15:
72+
npx ts-node day15.ts
73+
day15-2:
74+
npx ts-node day15-2.ts

day15-2.ts

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import * as fs from "fs"
2+
import { findOxygen } from "./day15"
3+
4+
function load(program: string) {
5+
return fs.readFileSync(program, "utf8")
6+
.trim()
7+
.split(",")
8+
.map(l => parseInt(l))
9+
}
10+
11+
class Computer {
12+
13+
private instructions = [
14+
this.add,
15+
this.mul,
16+
this.get,
17+
this.put,
18+
this.jnz,
19+
this.jz,
20+
this.lt,
21+
this.eq,
22+
this.sbase,
23+
] as const
24+
25+
private mem: number[]
26+
private base = 0
27+
28+
input: () => number = () => { throw new Error("no input") }
29+
output: (o: number) => boolean = (o: number) => { console.log(o); return true }
30+
31+
constructor(program: number[]) {
32+
this.mem = program.slice()
33+
}
34+
35+
compute() {
36+
let iptr = 0
37+
38+
while (true) {
39+
const code = this.mem[iptr]
40+
const op = code % 100
41+
if (op == 99) {
42+
return
43+
}
44+
45+
const instr = this.instructions[op - 1]
46+
if (!instr) {
47+
throw new Error(`unknown instruction ${op}`)
48+
}
49+
50+
const vs = Array.from(Array(instr.length)).map((_, i) =>
51+
this.ptr(iptr + i + 1, Math.floor(code % 10 ** (i + 3) / (10 ** (i + 2)))))
52+
const newInstrPtr = instr.apply(this, vs)
53+
if (newInstrPtr === -1) {
54+
break
55+
}
56+
iptr = newInstrPtr ?? (iptr + instr.length + 1)
57+
}
58+
}
59+
60+
private ptr(ptr: number, mode: number) {
61+
switch (mode) {
62+
case 0: return this.mem[ptr]
63+
case 1: return ptr
64+
case 2: return this.mem[ptr] + this.base
65+
default: throw new Error(`unknown mode ${mode}`)
66+
}
67+
}
68+
69+
private m(ptr: number) {
70+
return this.mem[ptr] ?? 0
71+
}
72+
73+
private add(ptr1: number, ptr2: number, ptr3: number) {
74+
this.mem[ptr3] = this.m(ptr1) + this.m(ptr2)
75+
}
76+
private mul(ptr1: number, ptr2: number, ptr3: number) {
77+
this.mem[ptr3] = this.m(ptr1) * this.m(ptr2)
78+
}
79+
private put(ptr1: number) {
80+
return this.output(this.m(ptr1)) ? undefined : -1
81+
}
82+
private get(ptr1: number) {
83+
this.mem[ptr1] = this.input()
84+
}
85+
private jnz(ptr1: number, ptr2: number) {
86+
if (this.m(ptr1) !== 0) {
87+
return this.m(ptr2)
88+
}
89+
}
90+
private jz(ptr1: number, ptr2: number) {
91+
if (this.m(ptr1) === 0) {
92+
return this.m(ptr2)
93+
}
94+
}
95+
private lt(ptr1: number, ptr2: number, ptr3: number) {
96+
const val = (this.m(ptr1) < this.m(ptr2)) ? 1 : 0
97+
this.mem[ptr3] = val
98+
}
99+
private eq(ptr1: number, ptr2: number, ptr3: number) {
100+
const val = (this.m(ptr1) === this.m(ptr2)) ? 1 : 0
101+
this.mem[ptr3] = val
102+
}
103+
private sbase(ptr1: number) {
104+
this.base += this.m(ptr1)
105+
}
106+
}
107+
108+
const program = load("input-day15.txt")
109+
const oxygen = findOxygen()
110+
111+
class Robot {
112+
113+
state(position: Position) {
114+
const p = [...oxygen[1], ...position[1]]
115+
const computer = new Computer(program)
116+
computer.input = () => {
117+
if (p.length === 0) {
118+
throw new Error("path ended")
119+
}
120+
return p.shift()
121+
}
122+
let state: number
123+
computer.output = (o: number) => {
124+
if (p.length === 0) {
125+
state = o
126+
return false
127+
}
128+
return true
129+
}
130+
131+
computer.compute()
132+
return state
133+
}
134+
}
135+
136+
type Point = [number, number]
137+
type Path = number[]
138+
type Position = [Point, Path]
139+
140+
let visited: Point[] = []
141+
function hasVisited(p: Point) {
142+
return visited.findIndex(v => isEqual(v, p)) !== -1
143+
}
144+
145+
146+
let maxLength = 0
147+
let checkPositions: Position[] = [...neighbours([[16, 16], []])]
148+
while (checkPositions.length > 0) {
149+
checkPositions.forEach(p => visited.push(p[0]))
150+
151+
152+
let nextCheckPositions: Position[] = []
153+
while (checkPositions.length > 0) {
154+
const check = checkPositions.shift()
155+
const state = probe(check)
156+
if (state === 1) {
157+
const ns: Position[] = neighbours(check)
158+
.filter(n => !hasVisited(n[0]))
159+
160+
maxLength = Math.max(maxLength, check[1].length)
161+
nextCheckPositions = nextCheckPositions.concat(ns)
162+
}
163+
}
164+
checkPositions = nextCheckPositions
165+
}
166+
167+
console.log("max length", maxLength)
168+
169+
function isEqual(p1: Point, p2: Point) {
170+
return p1[0] === p2[0] && p1[1] === p2[1]
171+
}
172+
173+
function probe(p: Position) {
174+
return new Robot().state(p)
175+
}
176+
177+
function neighbours(p: Position): Position[] {
178+
return [
179+
[[p[0][0] + 0, p[0][1] - 1], [...p[1], 1]],
180+
[[p[0][0] + 0, p[0][1] + 1], [...p[1], 2]],
181+
[[p[0][0] - 1, p[0][1] + 0], [...p[1], 3]],
182+
[[p[0][0] + 1, p[0][1] + 0], [...p[1], 4]],
183+
]
184+
}

day15.ts

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import * as fs from "fs"
2+
3+
function load(program: string) {
4+
return fs.readFileSync(program, "utf8")
5+
.trim()
6+
.split(",")
7+
.map(l => parseInt(l))
8+
}
9+
10+
class Computer {
11+
12+
private instructions = [
13+
this.add,
14+
this.mul,
15+
this.get,
16+
this.put,
17+
this.jnz,
18+
this.jz,
19+
this.lt,
20+
this.eq,
21+
this.sbase,
22+
] as const
23+
24+
private mem: number[]
25+
private base = 0
26+
27+
input: () => number = () => { throw new Error("no input") }
28+
output: (o: number) => boolean = (o: number) => { console.log(o); return true }
29+
30+
constructor(program: number[]) {
31+
this.mem = program.slice()
32+
}
33+
34+
compute() {
35+
let iptr = 0
36+
37+
while (true) {
38+
const code = this.mem[iptr]
39+
const op = code % 100
40+
if (op == 99) {
41+
return
42+
}
43+
44+
const instr = this.instructions[op - 1]
45+
if (!instr) {
46+
throw new Error(`unknown instruction ${op}`)
47+
}
48+
49+
const vs = Array.from(Array(instr.length)).map((_, i) =>
50+
this.ptr(iptr + i + 1, Math.floor(code % 10 ** (i + 3) / (10 ** (i + 2)))))
51+
const newInstrPtr = instr.apply(this, vs)
52+
if (newInstrPtr === -1) {
53+
break
54+
}
55+
iptr = newInstrPtr ?? (iptr + instr.length + 1)
56+
}
57+
}
58+
59+
private ptr(ptr: number, mode: number) {
60+
switch (mode) {
61+
case 0: return this.mem[ptr]
62+
case 1: return ptr
63+
case 2: return this.mem[ptr] + this.base
64+
default: throw new Error(`unknown mode ${mode}`)
65+
}
66+
}
67+
68+
private m(ptr: number) {
69+
return this.mem[ptr] ?? 0
70+
}
71+
72+
private add(ptr1: number, ptr2: number, ptr3: number) {
73+
this.mem[ptr3] = this.m(ptr1) + this.m(ptr2)
74+
}
75+
private mul(ptr1: number, ptr2: number, ptr3: number) {
76+
this.mem[ptr3] = this.m(ptr1) * this.m(ptr2)
77+
}
78+
private put(ptr1: number) {
79+
return this.output(this.m(ptr1)) ? undefined : -1
80+
}
81+
private get(ptr1: number) {
82+
this.mem[ptr1] = this.input()
83+
}
84+
private jnz(ptr1: number, ptr2: number) {
85+
if (this.m(ptr1) !== 0) {
86+
return this.m(ptr2)
87+
}
88+
}
89+
private jz(ptr1: number, ptr2: number) {
90+
if (this.m(ptr1) === 0) {
91+
return this.m(ptr2)
92+
}
93+
}
94+
private lt(ptr1: number, ptr2: number, ptr3: number) {
95+
const val = (this.m(ptr1) < this.m(ptr2)) ? 1 : 0
96+
this.mem[ptr3] = val
97+
}
98+
private eq(ptr1: number, ptr2: number, ptr3: number) {
99+
const val = (this.m(ptr1) === this.m(ptr2)) ? 1 : 0
100+
this.mem[ptr3] = val
101+
}
102+
private sbase(ptr1: number) {
103+
this.base += this.m(ptr1)
104+
}
105+
}
106+
107+
const program = load("input-day15.txt")
108+
109+
class Robot {
110+
111+
state(position: Position) {
112+
const p = [position[0], position[1].slice()]
113+
const computer = new Computer(program)
114+
computer.input = () => {
115+
if (p[1].length === 0) {
116+
throw new Error("path ended")
117+
}
118+
return p[1].shift()
119+
}
120+
let state: number
121+
computer.output = (o: number) => {
122+
if (p[1].length === 0) {
123+
state = o
124+
return false
125+
}
126+
return true
127+
}
128+
129+
computer.compute()
130+
return state
131+
}
132+
}
133+
134+
type Point = [number, number]
135+
type Path = number[]
136+
type Position = [Point, Path]
137+
138+
export function findOxygen(): Position {
139+
let visited: Point[] = []
140+
function hasVisited(p: Point) {
141+
return visited.findIndex(v => isEqual(v, p)) !== -1
142+
}
143+
144+
let checkPositions: Position[] = [...neighbours([[0, 0], []])]
145+
while (checkPositions.length > 0) {
146+
checkPositions.forEach(p => visited.push(p[0]))
147+
148+
let nextCheckPositions: Position[] = []
149+
while (checkPositions.length > 0) {
150+
const check = checkPositions.shift()
151+
const state = probe(check)
152+
if (state === 2) {
153+
return check
154+
} else if (state === 1) {
155+
const ns: Position[] = neighbours(check)
156+
.filter(n => !hasVisited(n[0]))
157+
nextCheckPositions = nextCheckPositions.concat(ns)
158+
}
159+
}
160+
checkPositions = nextCheckPositions
161+
}
162+
}
163+
164+
console.log(findOxygen()[1].length)
165+
166+
function isEqual(p1: Point, p2: Point) {
167+
return p1[0] === p2[0] && p1[1] === p2[1]
168+
}
169+
170+
function probe(p: Position) {
171+
return new Robot().state(p)
172+
}
173+
174+
function neighbours(p: Position): Position[] {
175+
return [
176+
[[p[0][0] + 0, p[0][1] - 1], [...p[1], 1]],
177+
[[p[0][0] + 0, p[0][1] + 1], [...p[1], 2]],
178+
[[p[0][0] - 1, p[0][1] + 0], [...p[1], 3]],
179+
[[p[0][0] + 1, p[0][1] + 0], [...p[1], 4]],
180+
]
181+
}

input-day15.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3,1033,1008,1033,1,1032,1005,1032,31,1008,1033,2,1032,1005,1032,58,1008,1033,3,1032,1005,1032,81,1008,1033,4,1032,1005,1032,104,99,1002,1034,1,1039,102,1,1036,1041,1001,1035,-1,1040,1008,1038,0,1043,102,-1,1043,1032,1,1037,1032,1042,1105,1,124,1002,1034,1,1039,101,0,1036,1041,1001,1035,1,1040,1008,1038,0,1043,1,1037,1038,1042,1106,0,124,1001,1034,-1,1039,1008,1036,0,1041,101,0,1035,1040,1001,1038,0,1043,1001,1037,0,1042,1105,1,124,1001,1034,1,1039,1008,1036,0,1041,1002,1035,1,1040,102,1,1038,1043,101,0,1037,1042,1006,1039,217,1006,1040,217,1008,1039,40,1032,1005,1032,217,1008,1040,40,1032,1005,1032,217,1008,1039,37,1032,1006,1032,165,1008,1040,37,1032,1006,1032,165,1102,1,2,1044,1106,0,224,2,1041,1043,1032,1006,1032,179,1101,1,0,1044,1105,1,224,1,1041,1043,1032,1006,1032,217,1,1042,1043,1032,1001,1032,-1,1032,1002,1032,39,1032,1,1032,1039,1032,101,-1,1032,1032,101,252,1032,211,1007,0,73,1044,1105,1,224,1102,1,0,1044,1105,1,224,1006,1044,247,1002,1039,1,1034,1001,1040,0,1035,101,0,1041,1036,101,0,1043,1038,101,0,1042,1037,4,1044,1105,1,0,58,87,52,69,28,16,88,43,75,16,91,2,94,51,62,80,96,46,64,98,72,8,54,71,47,84,88,44,81,7,90,13,80,42,62,68,85,27,34,2,13,89,87,79,63,76,9,82,58,60,93,63,78,79,43,32,84,25,34,80,87,15,89,96,1,50,75,25,67,82,27,3,89,48,99,33,36,77,86,62,99,19,86,92,6,56,24,96,2,79,9,3,84,41,94,79,76,91,66,50,82,88,85,13,88,18,93,79,12,98,46,75,52,99,95,11,16,25,17,77,55,87,17,74,76,81,41,77,80,92,46,20,99,22,16,41,90,64,89,53,3,61,88,97,14,2,33,79,62,79,90,80,77,71,45,40,51,62,67,82,42,27,97,17,72,77,12,38,97,85,85,35,92,82,3,84,96,40,27,93,96,18,45,98,16,49,82,52,90,43,81,10,88,94,15,42,77,67,84,88,51,35,84,20,99,7,9,79,65,86,39,93,52,98,11,19,83,75,92,27,72,77,77,78,99,18,53,35,75,14,23,90,15,83,15,98,74,14,75,67,98,93,64,97,97,58,77,88,28,19,1,82,96,69,92,34,1,90,45,79,27,25,85,59,89,88,13,91,93,38,95,55,24,61,79,56,63,61,80,10,76,84,24,80,41,83,37,86,81,93,53,33,75,78,6,81,66,84,98,3,37,84,48,89,88,70,93,96,17,94,38,82,39,74,65,90,9,77,55,53,78,10,98,27,96,11,18,86,54,98,53,86,66,19,93,52,99,44,85,79,19,7,53,86,13,90,46,33,86,19,52,79,60,92,94,97,4,99,83,67,84,58,10,96,5,91,75,47,74,93,68,76,74,50,45,99,15,85,13,99,96,30,99,84,59,81,51,64,74,9,27,2,99,34,49,76,61,28,87,56,84,81,32,6,88,48,57,89,43,76,77,15,80,91,45,9,6,52,93,84,77,17,82,32,67,97,92,74,54,46,99,80,5,83,74,85,64,89,36,41,77,47,94,24,86,45,23,99,59,90,43,61,95,98,91,90,33,91,15,19,88,49,54,86,75,42,67,43,54,97,10,10,42,85,10,11,60,76,17,90,43,80,80,34,90,85,71,70,40,80,97,31,55,80,3,58,99,31,31,99,31,90,90,57,29,85,76,22,14,77,76,87,21,88,77,85,33,81,77,94,57,56,18,83,54,90,90,2,89,87,36,13,85,36,85,70,96,20,85,82,43,34,97,93,27,40,44,80,97,2,81,16,44,12,91,35,90,24,49,75,71,96,5,29,65,80,87,35,51,92,43,94,30,84,88,10,99,4,71,76,65,77,71,1,89,90,58,28,77,42,57,81,87,13,16,72,74,32,98,83,8,75,79,10,96,11,92,34,84,13,1,77,78,71,21,63,78,37,98,86,53,84,75,1,60,75,66,86,22,78,32,31,78,97,97,89,23,88,78,4,75,59,99,65,13,85,70,74,77,83,39,62,76,81,33,98,87,25,41,90,48,42,33,24,94,86,15,94,89,21,23,81,29,36,99,93,60,20,90,19,66,52,90,80,97,95,21,86,45,80,78,7,37,80,84,22,6,97,79,34,87,27,43,52,97,84,72,9,89,93,2,75,82,60,92,12,87,89,59,74,64,90,38,71,89,12,26,81,6,53,78,96,8,81,91,69,68,89,76,79,50,77,19,83,14,75,26,76,34,78,1,83,70,80,39,99,62,95,89,99,6,79,93,80,10,83,50,79,80,92,41,78,20,86,9,84,53,87,13,74,0,0,21,21,1,10,1,0,0,0,0,0,0

0 commit comments

Comments
 (0)