Skip to content

Commit 7668d08

Browse files
committed
full solution for day 10
1 parent 4d6b1e7 commit 7668d08

File tree

2 files changed

+72
-74
lines changed

2 files changed

+72
-74
lines changed

src/2025/day10.js

Lines changed: 70 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,87 @@
1+
import { memoize } from "../utils/memoize.js";
2+
3+
// Helper function to generate all combinations
4+
function* product(...arrays) {
5+
if (arrays.length === 0) yield [];
6+
else {
7+
const [head, ...tail] = arrays;
8+
for (const item of head) {
9+
for (const rest of product(...tail)) {
10+
yield [item, ...rest];
11+
}
12+
}
13+
}
14+
}
15+
116
function parse(input) {
17+
let parseTuple = str => str.slice(1, -1).split(",").map(Number);
218
let machines = input.split("\n").map(line => {
3-
let [indicator, ...buttons] = line.split(" ");
4-
let joltage = buttons.pop();
5-
indicator = indicator
6-
.slice(1, -1)
7-
.split("")
8-
.map((x, i) => (x === "#" ? i : null))
9-
.filter(x => x !== null);
10-
buttons = buttons.map(button => {
11-
button = button
12-
.slice(1, -1)
13-
.split(",")
14-
.map(x => parseInt(x, 10));
15-
return new Set(button);
16-
});
17-
joltage = joltage
18-
.slice(1, -1)
19-
.split(",")
20-
.map(x => parseInt(x, 10));
21-
return { indicator: new Set(indicator), buttons: buttons, joltage };
19+
const parts = line.split(" ");
20+
const dia = Array.from(parts[0].slice(1, -1)).map(c => (c === "#" ? 1 : 0));
21+
const buttons = parts.slice(1, -1).map(x => parseTuple(x));
22+
const jolts = parseTuple(parts[parts.length - 1]);
23+
return { dia, buttons, jolts };
2224
});
2325
return machines;
2426
}
2527

26-
function minimumPresses(machine) {
27-
let { indicator, buttons } = machine;
28-
let queue = [];
29-
let visited = new Set();
30-
buttons.forEach(button => {
31-
queue.push({ pressed: 1, state: button });
32-
});
33-
while (queue.length > 0) {
34-
let { pressed, state } = queue.shift();
35-
let stateKey = Array.from(state)
36-
.sort((a, b) => a - b)
37-
.join(",");
38-
if (visited.has(stateKey)) continue;
39-
visited.add(stateKey);
40-
if (indicator.symmetricDifference(state).size === 0) {
41-
return pressed;
42-
}
43-
buttons.forEach(button => {
44-
queue.push({
45-
pressed: pressed + 1,
46-
state: button.symmetricDifference(state),
47-
});
48-
});
49-
}
50-
}
51-
52-
function minimumPresses2(machine) {
53-
let { buttons, joltage } = machine;
54-
let queue = [];
55-
let visited = new Set();
56-
queue.push({ pressed: 0, state: [...joltage], pushes: [] });
57-
while (queue.length > 0) {
58-
let { pressed, state, pushes } = queue.shift();
59-
let stateKey = state.join(",");
60-
if (visited.has(stateKey)) continue;
61-
visited.add(stateKey);
62-
if (state.every(x => x === 0)) return pressed;
63-
if (state.some(x => x < 0)) continue;
64-
for (let i = 0; i < buttons.length; i++) {
65-
let button = buttons[i];
66-
let next = [...state];
67-
button.forEach(pos => next[pos]--);
68-
queue.push({
69-
pressed: pressed + 1,
70-
state: next,
71-
pushes: pushes.concat(i),
72-
});
28+
function producePatterns(buttons, jolts) {
29+
const ops = {},
30+
patterns = {};
31+
for (const pressed of product(...Array(buttons.length).fill([0, 1]))) {
32+
const jolt = Array(jolts.length).fill(0);
33+
for (let i = 0; i < pressed.length; i++) {
34+
if (pressed[i]) {
35+
for (const j of buttons[i]) jolt[j] += pressed[i];
36+
}
7337
}
38+
const lights = jolt.map(x => x % 2);
39+
const key = JSON.stringify(pressed);
40+
const lightsKey = JSON.stringify(lights);
41+
ops[key] = jolt;
42+
if (!patterns[lightsKey]) patterns[lightsKey] = [];
43+
patterns[lightsKey].push(pressed);
7444
}
45+
return { ops, patterns };
7546
}
7647

7748
export function part1(input) {
7849
let machines = parse(input);
79-
let result = 0;
80-
machines.forEach(machine => (result += minimumPresses(machine)));
81-
return result;
50+
let p1 = 0;
51+
for (const { dia, buttons, jolts } of machines) {
52+
const { patterns } = producePatterns(buttons, jolts);
53+
const diaKey = JSON.stringify(dia);
54+
p1 += Math.min(...patterns[diaKey].map(x => x.reduce((a, b) => a + b, 0)));
55+
}
56+
return p1;
8257
}
8358

8459
export function part2(input) {
60+
let p2 = 0;
8561
let machines = parse(input);
86-
let result = 0;
87-
machines.forEach(machine => (result += minimumPresses2(machine)));
88-
return result;
62+
63+
for (const { buttons, jolts } of machines) {
64+
const { ops, patterns } = producePatterns(buttons, jolts);
65+
66+
let presses = memoize(target => {
67+
if (target.every(x => x === 0)) return 0;
68+
if (target.some(x => x < 0)) return Infinity;
69+
70+
const lights = target.map(x => x % 2);
71+
const lightsKey = JSON.stringify(lights);
72+
if (!patterns[lightsKey]) return Infinity;
73+
74+
let total = Infinity;
75+
for (const pressed of patterns[lightsKey]) {
76+
const diff = ops[JSON.stringify(pressed)];
77+
const newTarget = diff.map((a, i) => (target[i] - a) / 2);
78+
const sum = pressed.reduce((a, b) => a + b, 0);
79+
total = Math.min(total, sum + 2 * presses(newTarget));
80+
}
81+
return total;
82+
});
83+
84+
p2 += presses(jolts);
85+
}
86+
return p2;
8987
}

src/2025/day10.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ describe("day10 2025", () => {
3636
).toEqual(33);
3737
});
3838

39-
test.skip("it should work for part 2 input", () => {
40-
expect(part2(input)).toEqual(0); // solved with z3, will implement in code later
39+
test("it should work for part 2 input", () => {
40+
expect(part2(input)).toEqual(15489);
4141
});
4242
});
4343
});

0 commit comments

Comments
 (0)