Skip to content

Commit db241ff

Browse files
committed
2024:15 ⭐️⭐
Took a little bit to do first part, took a very long time to do part 2 Turned out there was a nasty bug hiding in line 134 which lead to moving of walls when surrounded by boxes. Phew.
1 parent 9e55d9b commit db241ff

File tree

2 files changed

+336
-0
lines changed

2 files changed

+336
-0
lines changed

2024/15/day15.js

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
const { off } = require('process')
4+
5+
let input = fs.readFileSync(path.join(__dirname, 'input.txt'), { encoding: 'utf8' })
6+
7+
function parseMapIntoList(input) {
8+
return input
9+
.split('\n')
10+
.flatMap(
11+
(l, row) => l.split('')
12+
.map((c, col) => { return { c: c, x: col, y: row } }))
13+
}
14+
15+
function printMap(map, move = '@') {
16+
let dim = map.reduce((p, c) => [
17+
Math.min(p[0], c.x),
18+
Math.max(p[1], c.x),
19+
Math.min(p[2], c.y),
20+
Math.max(p[3], c.y)], [Infinity, -Infinity, Infinity, -Infinity])
21+
22+
let mapLines = []
23+
for (let y = dim[2]; y <= dim[3]; y++) {
24+
let line = []
25+
for (let x = dim[0]; x <= dim[1]; x++) {
26+
let point = map.find(p => p.x == x && p.y == y)
27+
if (point) {
28+
line.push(point.c == '@' ? move : point.c)
29+
} else {
30+
line.push('.')
31+
}
32+
}
33+
mapLines.push(line.join(''))
34+
}
35+
console.log(mapLines.join('\n'))
36+
}
37+
38+
39+
const directions = {
40+
'>': { x: 1, y: 0 },
41+
'<': { x: -1, y: 0 },
42+
'v': { x: 0, y: 1 },
43+
'^': { x: 0, y: -1 },
44+
}
45+
46+
function executeMoves(map, moves) {
47+
let robot = map.find(p => p.c == '@')
48+
for (const move of moves) {
49+
let offset = directions[move]
50+
let newPosition = { x: robot.x + offset.x, y: robot.y + offset.y }
51+
let newPositionPoint = map.find(p => p.x == newPosition.x && p.y == newPosition.y)
52+
if (!newPositionPoint) {
53+
robot.x = newPosition.x
54+
robot.y = newPosition.y
55+
} else if (newPositionPoint.c == '#') {
56+
continue
57+
} else if (newPositionPoint.c == 'O') {
58+
let boxes = [newPositionPoint]
59+
let lookAhead
60+
do {
61+
let lookAheadPos = { x: robot.x + offset.x * (boxes.length + 1), y: robot.y + offset.y * (boxes.length + 1) }
62+
lookAhead = map.find(p => p.x == lookAheadPos.x && p.y == lookAheadPos.y)
63+
if (!lookAhead || lookAhead.c != 'O') {
64+
break
65+
}
66+
boxes.push(lookAhead)
67+
} while (true)
68+
if (!lookAhead) {
69+
for (const box of boxes) {
70+
box.x += offset.x
71+
box.y += offset.y
72+
}
73+
robot.x += offset.x
74+
robot.y += offset.y
75+
}
76+
} else {
77+
throw "Confused"
78+
}
79+
}
80+
81+
return robot
82+
}
83+
84+
function executeMoves2(map, moves) {
85+
let robot = map.find(p => p.c == '@')
86+
for (const move of moves) {
87+
let offset = directions[move]
88+
let newPosition = { x: robot.x + offset.x, y: robot.y + offset.y }
89+
let newPositionPoint = map.find(p => p.x == newPosition.x && p.y == newPosition.y)
90+
if (!newPositionPoint) {
91+
robot.x = newPosition.x
92+
robot.y = newPosition.y
93+
} else if (newPositionPoint.c == '#') {
94+
continue
95+
} else if (newPositionPoint.c == '[' || newPositionPoint.c == ']') {
96+
let boxes = []
97+
if (newPositionPoint.c == '[') {
98+
boxes.push(newPositionPoint, map.find(p => p.x == newPositionPoint.x + 1 && p.y == newPositionPoint.y && p.c == ']'))
99+
} else {
100+
boxes.push(newPositionPoint, map.find(p => p.x == newPositionPoint.x - 1 && p.y == newPositionPoint.y && p.c == '['))
101+
}
102+
103+
if (move == '<' || move == '>') {
104+
105+
let lookAhead
106+
do {
107+
let lookAheadPos = { x: robot.x + offset.x * (boxes.length + 1), y: robot.y + offset.y * (boxes.length + 1) }
108+
lookAhead = map.find(p => p.x == lookAheadPos.x && p.y == lookAheadPos.y)
109+
if (!lookAhead || (lookAhead.c != '[' && lookAhead.c != ']')) {
110+
break
111+
}
112+
boxes.push(lookAhead)
113+
} while (true)
114+
115+
if (!lookAhead) {
116+
for (const box of boxes) {
117+
box.x += offset.x
118+
box.y += offset.y
119+
}
120+
robot.x += offset.x
121+
robot.y += offset.y
122+
}
123+
124+
} else {
125+
// GOIN UP or DOWN and have to find boxes in a different way
126+
127+
let line = newPosition.y
128+
let lookAhead
129+
do {
130+
let lookAheadPosList = boxes.filter(b => b && b.y == line)
131+
line += offset.y
132+
lookAhead = lookAheadPosList.map(b => map.find(p => p.x == b.x && p.y == line))
133+
//has only empty space or no parts of boxes
134+
if (lookAhead.every(p => !p) || lookAhead.some(p => p && p.c == '#')) {
135+
break
136+
}
137+
// add all boxes
138+
let newLookAhead = []
139+
140+
for (const point of lookAhead) {
141+
// add missing parts for boxes
142+
newLookAhead.push(point)
143+
if (point) {
144+
if (point.c == '[') {
145+
if (!lookAhead.find(p => p && p.x == point.x + 1 && p.c == ']')) {
146+
let boxPart = map.find(p => point.y == p.y && p.x == point.x + 1 && p.c == ']')
147+
if (!boxPart) throw `Missing box part for ${point}`
148+
newLookAhead.push(boxPart)
149+
}
150+
} else if (point.c == ']') {
151+
if (!lookAhead.find(p => p && p.x == point.x - 1 && p.c == '[')) {
152+
let boxPart = map.find(p => point.y == p.y && p.x == point.x - 1 && p.c == '[')
153+
if (!boxPart) throw `Missing box part for ${point}`
154+
newLookAhead.push(boxPart)
155+
}
156+
}
157+
}
158+
}
159+
160+
boxes.push(...newLookAhead)
161+
} while (true)
162+
163+
if (lookAhead.every(p => !p)) {
164+
for (const box of boxes) {
165+
if (box) {
166+
box.x += offset.x
167+
box.y += offset.y
168+
}
169+
}
170+
robot.x += offset.x
171+
robot.y += offset.y
172+
}
173+
174+
}
175+
} else {
176+
console.log(newPositionPoint)
177+
throw "Confused"
178+
}
179+
}
180+
}
181+
182+
function evaluateGPS(map, point = 'O') {
183+
return map.filter(p => p.c == point).reduce((p, c) => p + (c.x + 100 * c.y), 0)
184+
}
185+
186+
// input = `#######
187+
// #...#.#
188+
// #.....#
189+
// #...O.#
190+
// #..O..#
191+
// #..OO@#
192+
// #..O..#
193+
// #.....#
194+
// #######
195+
196+
// <vv<<^^<<^^`
197+
198+
// input = `##########
199+
// #..O..O.O#
200+
// #......O.#
201+
// #.OO..O.O#
202+
// #..O@..O.#
203+
// #O#..O...#
204+
// #O..O..O.#
205+
// #.OO.O.OO#
206+
// #....O...#
207+
// ##########
208+
209+
// <vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
210+
// vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
211+
// ><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
212+
// <<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
213+
// ^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
214+
// ^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
215+
// >^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
216+
// <><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
217+
// ^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
218+
// v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^`
219+
220+
// input = `
221+
// ########################
222+
// ##..............@.....##
223+
// ##..##....[]...[].....##
224+
// ##[]...........[].[]..##
225+
// ##..####[]..[][][][]..##
226+
// ##....[][]..[]....[]..##
227+
// ######........##[][]..##
228+
// ##............[][][]..##
229+
// ##..[][][][]......[]..##
230+
// ##....................##
231+
// ########################
232+
233+
// vvv
234+
// `
235+
236+
let [mapInput, movesInput] = input.split('\n\n')
237+
238+
let map = parseMapIntoList(mapInput).filter(p => p.c != '.')
239+
let moves = movesInput.split('\n').flatMap(l => l.split(''))
240+
241+
executeMoves(map, moves)
242+
243+
console.log(
244+
evaluateGPS(map)
245+
)
246+
247+
let expansion = {
248+
'#': ['#', '#'],
249+
'.': ['.', '.'],
250+
'O': ['[', ']'],
251+
'@': ['@', '.']
252+
}
253+
254+
let newMapInput = mapInput
255+
.split('\n')
256+
.map(line => line.split('').flatMap(x => expansion[x]).join(''))
257+
.join('\n')
258+
259+
let map2 = parseMapIntoList(newMapInput).filter(p => p.c != '.')
260+
261+
executeMoves2(map2, moves)
262+
263+
console.log(
264+
evaluateGPS(map2, '[')
265+
)

0 commit comments

Comments
 (0)