Skip to content

Commit e940ffb

Browse files
committed
Day 24: Crossed Wires
1 parent 03b2dbf commit e940ffb

2 files changed

Lines changed: 144 additions & 0 deletions

File tree

lib/2024/24.rb

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
setup, outputs = INPUT.split("\n\n")
2+
3+
WIRE_MATCHER = /\A(?<wire>.+): (?<value>0|1)\z/
4+
WIRES = setup.split("\n").each_with_object({}) do |line, wires|
5+
match = line.match(WIRE_MATCHER)
6+
wires[match[:wire]] = match[:value].to_i(2)
7+
end
8+
9+
GATE_MATCHER = /\A(?<w1>.+) (?<gate>.+) (?<w2>.+) -> (?<output>.+)\z/
10+
GATES = outputs.split("\n").each_with_object({}) do |line, gates|
11+
match = line.match(GATE_MATCHER)
12+
gates[match[:output]] = [match[:w1], match[:w2], match[:gate]]
13+
end
14+
15+
def value_for(wire, wires, gates)
16+
wires[wire] ||= begin
17+
w1, w2, gate = gates[wire]
18+
19+
v1 = value_for(w1, wires, gates)
20+
v2 = value_for(w2, wires, gates)
21+
22+
case gate
23+
when "XOR" then v1 ^ v2
24+
when "AND" then v1 & v2
25+
when "OR" then v1 | v2
26+
end
27+
end
28+
end
29+
30+
def value_on(wires, prefix)
31+
keys = wires.keys.select { |w| w.start_with?(prefix) }
32+
keys.sort.reverse.map { |k| wires[k] }.join.to_i(2)
33+
end
34+
35+
def value(wires, gates)
36+
wires = wires.dup
37+
38+
gates.keys.each do |output|
39+
value_for(output, wires, gates)
40+
end
41+
42+
value_on(wires, "z")
43+
end
44+
45+
solve!("The final value on the Z wires is:", value(WIRES, GATES))
46+
47+
def used_for?(wire, gates, &block)
48+
gates.any? { |_, (w1, w2, g)| (w1 == wire || w2 == wire) && block.call(g) }
49+
end
50+
51+
HIGHEST_OUTPUT_BIT = GATES.keys.select { |k| k.start_with?("z") }.max
52+
53+
invalid_outputs = GATES.each_with_object([]) do |(output, (w1, w2, gate)), invalid|
54+
invalid_operations = [
55+
output.start_with?("z") && gate != "XOR" && output != HIGHEST_OUTPUT_BIT,
56+
gate == "AND" && w1 != "x00" && w2 != "x00" && used_for?(output, GATES) { |op| op != "OR" },
57+
gate == "XOR" && [output, w1, w2].none? { |w| w.start_with?("x", "y", "z") },
58+
gate == "XOR" && used_for?(output, GATES) { |op| op == "OR" }
59+
]
60+
61+
invalid << output if invalid_operations.any?
62+
end
63+
64+
solve!("The swapped outputs are:", invalid_outputs.sort.join(","))

spec/2024/24_spec.rb

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
require "spec_helper"
2+
3+
RSpec.describe "Day 24: Crossed Wires" do
4+
let(:runner) { Runner.new("2024/24") }
5+
6+
describe "Part One" do
7+
let(:solution) { runner.execute!(input, part: 1) }
8+
9+
it "calculates the number produced on the z wires" do
10+
expect(runner.execute!(<<~TXT, part: 1)).to eq(4)
11+
x00: 1
12+
x01: 1
13+
x02: 1
14+
y00: 0
15+
y01: 1
16+
y02: 0
17+
18+
x00 AND y00 -> z00
19+
x01 XOR y01 -> z01
20+
x02 OR y02 -> z02
21+
TXT
22+
23+
expect(runner.execute!(<<~TXT, part: 1)).to eq(2024)
24+
x00: 1
25+
x01: 0
26+
x02: 1
27+
x03: 1
28+
x04: 0
29+
y00: 1
30+
y01: 1
31+
y02: 1
32+
y03: 1
33+
y04: 1
34+
35+
ntg XOR fgs -> mjb
36+
y02 OR x01 -> tnw
37+
kwq OR kpj -> z05
38+
x00 OR x03 -> fst
39+
tgd XOR rvg -> z01
40+
vdt OR tnw -> bfw
41+
bfw AND frj -> z10
42+
ffh OR nrd -> bqk
43+
y00 AND y03 -> djm
44+
y03 OR y00 -> psh
45+
bqk OR frj -> z08
46+
tnw OR fst -> frj
47+
gnj AND tgd -> z11
48+
bfw XOR mjb -> z00
49+
x03 OR x00 -> vdt
50+
gnj AND wpb -> z02
51+
x04 AND y00 -> kjc
52+
djm OR pbm -> qhw
53+
nrd AND vdt -> hwm
54+
kjc AND fst -> rvg
55+
y04 OR y02 -> fgs
56+
y01 AND x02 -> pbm
57+
ntg OR kjc -> kwq
58+
psh XOR fgs -> tgd
59+
qhw XOR tgd -> z09
60+
pbm OR djm -> kpj
61+
x03 XOR y03 -> ffh
62+
x00 XOR y04 -> ntg
63+
bfw OR bqk -> z06
64+
nrd XOR fgs -> wpb
65+
frj XOR qhw -> z04
66+
bqk OR frj -> z07
67+
y03 OR x01 -> nrd
68+
hwm AND bqk -> z03
69+
tgd XOR rvg -> z12
70+
tnw OR pbm -> gnj
71+
TXT
72+
end
73+
end
74+
75+
describe "Part Two" do
76+
# NOTE: The solution only finds invalid outputs within _addition_
77+
# calculations, and isn't generic enough to solve for other operations like
78+
# the AND example from the exercise.
79+
end
80+
end

0 commit comments

Comments
 (0)