|
1 | 1 | import subsets from "@lib/subsets.ts"; |
| 2 | +import { parseManual } from "../../manuals.ts"; |
2 | 3 |
|
3 | 4 | export default function solve(input: string) { |
4 | | - const lines = input.split("\n").map((line) => { |
5 | | - const [lightsText, ...rest] = line.split(" "); |
6 | | - const lights = +`0b${ |
7 | | - Array.from(lightsText.slice(1, -1), (c) => (c === "#" ? "1" : "0")) |
8 | | - .reverse().join("") |
9 | | - }`; |
10 | | - const buttons = rest.slice(0, -1) |
11 | | - .map((text) => |
12 | | - text.slice(1, -1).split(",").map(Number) |
13 | | - .reduce((sum, n) => sum + 2 ** n, 0) |
14 | | - ); |
15 | | - const requirements = rest.at(-1)!.slice(1, -1).split(",").map(Number); |
16 | | - return { lights, buttons, requirements }; |
17 | | - }); |
| 5 | + const manual = parseManual(input); |
18 | 6 | let sum = 0; |
19 | | - for (const { lights, buttons } of lines) { |
20 | | - let min = Infinity; |
21 | | - for (const presses of subsets(new Set(buttons))) { |
22 | | - if (presses.size >= min) continue; |
23 | | - let actual = 0; |
24 | | - for (const press of presses) actual ^= press; |
25 | | - if (actual !== lights) continue; |
26 | | - min = presses.size; |
| 7 | + for (const { lights, buttons } of manual) { |
| 8 | + const lightsMask = Array.from(lights, (c, i) => (c === "#" ? 1 << i : 0)) |
| 9 | + .reduce((mask, bit) => mask | bit, 0); |
| 10 | + const buttonMasks = buttons.map((indices) => |
| 11 | + indices.reduce((mask, i) => mask | (1 << i), 0) |
| 12 | + ); |
| 13 | + let minPresses = Infinity; |
| 14 | + for (const presses of subsets(new Set(buttonMasks))) { |
| 15 | + if (presses.size >= minPresses) continue; |
| 16 | + let pressMask = 0; |
| 17 | + for (const mask of presses) pressMask ^= mask; |
| 18 | + if (pressMask === lightsMask) minPresses = presses.size; |
27 | 19 | } |
28 | | - sum += min; |
| 20 | + sum += minPresses; |
29 | 21 | } |
30 | 22 | return sum; |
31 | 23 | } |
0 commit comments