Skip to content

Commit b273e34

Browse files
committed
Rust/2024/24: add solution
1 parent 656311f commit b273e34

File tree

8 files changed

+218
-3
lines changed

8 files changed

+218
-3
lines changed

README.md

+2-2
Large diffs are not rendered by default.

Rust/2024/24.rs

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#![feature(test)]
2+
#![expect(unstable_name_collisions)]
3+
4+
use itertools::Itertools;
5+
use rustc_hash::{FxHashMap, FxHashSet};
6+
7+
#[derive(Debug)]
8+
struct Input {
9+
values: FxHashMap<String, bool>,
10+
gates: FxHashMap<String, (Gate, String, String)>,
11+
}
12+
13+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14+
enum Gate {
15+
And,
16+
Or,
17+
Xor,
18+
}
19+
20+
fn setup(input: &str) -> Input {
21+
let mut lines = input.lines();
22+
let values = lines
23+
.by_ref()
24+
.take_while(|l| !l.trim().is_empty())
25+
.map(|l| {
26+
let mut s = l.split(": ");
27+
let name = s.next().unwrap().into();
28+
let value = s.next().unwrap().trim() == "1";
29+
(name, value)
30+
})
31+
.collect();
32+
33+
let gates = lines
34+
.map(|l| {
35+
let mut s = l.split_whitespace();
36+
let a = s.next().unwrap().into();
37+
let gate = match s.next().unwrap() {
38+
"AND" => Gate::And,
39+
"OR" => Gate::Or,
40+
"XOR" => Gate::Xor,
41+
_ => panic!(),
42+
};
43+
let b = s.next().unwrap().into();
44+
s.next();
45+
let c = s.next().unwrap().into();
46+
(c, (gate, a, b))
47+
})
48+
.collect();
49+
50+
Input { values, gates }
51+
}
52+
53+
fn part1(input: &Input) -> usize {
54+
let mut forward = FxHashMap::<_, Vec<_>>::default();
55+
let mut unknown = input
56+
.gates
57+
.iter()
58+
.map(|(c, (_, a, b))| {
59+
forward.entry(a).or_default().push(c);
60+
forward.entry(b).or_default().push(c);
61+
let dependencies = [a, b]
62+
.into_iter()
63+
.filter(|&x| !input.values.contains_key(x))
64+
.collect::<FxHashSet<_>>();
65+
(c, dependencies)
66+
})
67+
.filter(|(_, v)| !v.is_empty())
68+
.collect::<FxHashMap<_, _>>();
69+
let mut values = input
70+
.values
71+
.iter()
72+
.map(|(p, &v)| (p, v))
73+
.collect::<FxHashMap<_, _>>();
74+
let mut stack = input
75+
.gates
76+
.keys()
77+
.filter(|&p| !unknown.contains_key(p))
78+
.collect::<Vec<_>>();
79+
while let Some(p) = stack.pop() {
80+
let (gate, ref a, ref b) = input.gates[p];
81+
let a = values[a];
82+
let b = values[b];
83+
let c = match gate {
84+
Gate::And => a & b,
85+
Gate::Or => a | b,
86+
Gate::Xor => a ^ b,
87+
};
88+
values.insert(p, c);
89+
90+
for &q in forward.get(p).into_iter().flatten() {
91+
if unknown.contains_key(q) {
92+
unknown.get_mut(q).unwrap().remove(p);
93+
if unknown[q].is_empty() {
94+
unknown.remove(q);
95+
stack.push(q);
96+
}
97+
}
98+
}
99+
}
100+
101+
values
102+
.keys()
103+
.filter(|k| k.starts_with('z'))
104+
.sorted_unstable()
105+
.rev()
106+
.fold(0, |acc, k| acc << 1 | (values[k] as usize))
107+
}
108+
109+
fn part2(input: &Input) -> String {
110+
let last_z = input
111+
.gates
112+
.keys()
113+
.filter(|k| k.starts_with('z'))
114+
.max()
115+
.unwrap();
116+
let mut forward = FxHashMap::<_, Vec<_>>::default();
117+
for (c, (_, a, b)) in &input.gates {
118+
forward.entry(a).or_default().push(c);
119+
forward.entry(b).or_default().push(c);
120+
}
121+
input
122+
.gates
123+
.keys()
124+
.filter(|&g| {
125+
let (gate, ref a, ref b) = input.gates[g];
126+
gate != Gate::Xor && g.starts_with('z') && g != last_z
127+
|| gate == Gate::Xor
128+
&& forward
129+
.get(g)
130+
.into_iter()
131+
.flatten()
132+
.any(|&x| input.gates[x].0 == Gate::Or)
133+
|| gate == Gate::And
134+
&& a != "x00"
135+
&& b != "x00"
136+
&& forward
137+
.get(g)
138+
.into_iter()
139+
.flatten()
140+
.any(|&x| input.gates[x].0 != Gate::Or)
141+
|| gate == Gate::Xor
142+
&& !g.starts_with('z')
143+
&& [a, b]
144+
.into_iter()
145+
.any(|x| input.gates.get(x).is_some_and(|x| x.0 == Gate::Xor))
146+
})
147+
.sorted_unstable()
148+
.map(|s| s.as_str())
149+
.intersperse(",")
150+
.collect()
151+
}
152+
153+
aoc::main!(2024, 24, ex: 1[a], 2[a]);

Rust/2024/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ aoc::year! {
2222
"21.rs",
2323
"22.rs",
2424
"23.rs",
25-
// "24.rs",
25+
"24.rs",
2626
"25.rs",
2727
}

Rust/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -430,5 +430,8 @@ path = "2024/22.rs"
430430
name = "2024_23"
431431
path = "2024/23.rs"
432432
[[bin]]
433+
name = "2024_24"
434+
path = "2024/24.rs"
435+
[[bin]]
433436
name = "2024_25"
434437
path = "2024/25.rs"

examples/2024/24/1

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
x00: 1
2+
x01: 1
3+
x02: 1
4+
y00: 0
5+
y01: 1
6+
y02: 0
7+
8+
x00 AND y00 -> z00
9+
x01 XOR y01 -> z01
10+
x02 OR y02 -> z02

examples/2024/24/1.1

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4

examples/2024/24/2

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
x00: 1
2+
x01: 0
3+
x02: 1
4+
x03: 1
5+
x04: 0
6+
y00: 1
7+
y01: 1
8+
y02: 1
9+
y03: 1
10+
y04: 1
11+
12+
ntg XOR fgs -> mjb
13+
y02 OR x01 -> tnw
14+
kwq OR kpj -> z05
15+
x00 OR x03 -> fst
16+
tgd XOR rvg -> z01
17+
vdt OR tnw -> bfw
18+
bfw AND frj -> z10
19+
ffh OR nrd -> bqk
20+
y00 AND y03 -> djm
21+
y03 OR y00 -> psh
22+
bqk OR frj -> z08
23+
tnw OR fst -> frj
24+
gnj AND tgd -> z11
25+
bfw XOR mjb -> z00
26+
x03 OR x00 -> vdt
27+
gnj AND wpb -> z02
28+
x04 AND y00 -> kjc
29+
djm OR pbm -> qhw
30+
nrd AND vdt -> hwm
31+
kjc AND fst -> rvg
32+
y04 OR y02 -> fgs
33+
y01 AND x02 -> pbm
34+
ntg OR kjc -> kwq
35+
psh XOR fgs -> tgd
36+
qhw XOR tgd -> z09
37+
pbm OR djm -> kpj
38+
x03 XOR y03 -> ffh
39+
x00 XOR y04 -> ntg
40+
bfw OR bqk -> z06
41+
nrd XOR fgs -> wpb
42+
frj XOR qhw -> z04
43+
bqk OR frj -> z07
44+
y03 OR x01 -> nrd
45+
hwm AND bqk -> z03
46+
tgd XOR rvg -> z12
47+
tnw OR pbm -> gnj

examples/2024/24/2.1

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2024

0 commit comments

Comments
 (0)