Skip to content

Commit f75bad3

Browse files
committed
24th day
1 parent 76be42a commit f75bad3

File tree

3 files changed

+280
-0
lines changed

3 files changed

+280
-0
lines changed

data/examples/24-1.txt

Lines changed: 47 additions & 0 deletions
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

data/examples/24-2.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
x00 XOR y00 -> e01
13+
x00 AND y00 -> c00
14+
x01 XOR y01 -> w01
15+
x01 AND y01 -> q01
16+
c00 XOR q01 -> z01
17+
c00 AND q01 -> z00
18+
w01 OR e01 -> c01
19+
x02 XOR y02 -> q02
20+
x02 AND y02 -> w02
21+
c01 XOR q02 -> z02
22+
c01 AND q02 -> e02
23+
w02 OR e02 -> c02
24+
x03 XOR y03 -> z03
25+
x03 AND y03 -> w03
26+
c02 XOR q03 -> q03
27+
c02 AND q03 -> e03
28+
w03 OR e03 -> c03
29+
x04 XOR y04 -> q04
30+
x04 AND y04 -> w04
31+
c03 XOR q04 -> e04
32+
c03 AND q04 -> z04
33+
w04 OR e04 -> z05

src/bin/24.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
advent_of_code::solution!(24);
2+
3+
use advent_of_code::maneatingape::hash::*;
4+
use advent_of_code::maneatingape::parse::*;
5+
6+
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
7+
enum Operator {
8+
And,
9+
Or,
10+
Xor,
11+
}
12+
13+
type Gate<'a> = (&'a str, Operator, &'a str, &'a str);
14+
15+
fn parse_data(input: &str) -> (Vec<bool>, Vec<Gate>) {
16+
let (left, right) = input.split_once("\n\n").unwrap();
17+
18+
let inputs = left.lines().map(|line| &line[5..] == "1").collect();
19+
20+
let gates = right
21+
.lines()
22+
.map(|line| {
23+
let mut iter = line.split_ascii_whitespace();
24+
let l = iter.next().unwrap();
25+
let op = iter.next().unwrap();
26+
let r = iter.next().unwrap();
27+
let res = iter.last().unwrap();
28+
29+
let operator = match op {
30+
"AND" => Operator::And,
31+
"OR" => Operator::Or,
32+
"XOR" => Operator::Xor,
33+
_ => unreachable!(),
34+
};
35+
36+
(l, operator, r, res)
37+
})
38+
.collect();
39+
40+
(inputs, gates)
41+
}
42+
43+
fn find_max_z_number(gates: &[Gate]) -> usize {
44+
let z_count = gates
45+
.iter()
46+
.filter(|(_, _, _, res)| res.starts_with("z"))
47+
.count();
48+
49+
z_count - 1
50+
}
51+
52+
fn solve(
53+
input_x: &[bool],
54+
input_y: &[bool],
55+
gates_rev: &FastMap<&str, (&str, Operator, &str)>,
56+
name: &str,
57+
) -> bool {
58+
if name.starts_with("x") {
59+
return input_x[name.unsigned::<usize>()];
60+
}
61+
62+
if name.starts_with("y") {
63+
return input_y[name.unsigned::<usize>()];
64+
}
65+
66+
let (left_name, operator, right_name) = &gates_rev[name];
67+
let left = solve(input_x, input_y, gates_rev, left_name);
68+
let right = solve(input_x, input_y, gates_rev, right_name);
69+
70+
match operator {
71+
Operator::And => left & right,
72+
Operator::Or => left | right,
73+
Operator::Xor => left ^ right,
74+
}
75+
}
76+
77+
pub fn part_one(input: &str) -> Option<u64> {
78+
let (inputs, gates) = parse_data(input);
79+
80+
let max_z_number = find_max_z_number(&gates);
81+
82+
let gates_rev = gates
83+
.into_iter()
84+
.map(|(l, o, r, res)| (res, (l, o, r)))
85+
.collect::<FastMap<_, _>>();
86+
87+
let mut result = 0;
88+
89+
let x = &inputs[..inputs.len() / 2];
90+
let y = &inputs[inputs.len() / 2..];
91+
for i in 0..=max_z_number {
92+
let z = solve(x, y, &gates_rev, &format!("z{:02}", i));
93+
result |= (z as u64) << i;
94+
}
95+
96+
Some(result)
97+
}
98+
99+
/*
100+
x_0 XOR y_0 = z_0
101+
x_0 AND y_0 = c_0
102+
for i in 1..z_max {
103+
x_i XOR y_i = s_i_0
104+
x_i AND y_i = c_i_0
105+
c_{i-1} XOR s_i_0 = z_i
106+
c_{i-1} AND s_i_0 = c_i_1
107+
c_i_0 OR c_i_1 = c_i
108+
}
109+
*/
110+
pub fn part_two(input: &str) -> Option<String> {
111+
let (_, gates) = parse_data(input);
112+
113+
let input_with_operator = gates
114+
.iter()
115+
.flat_map(|(l, o, r, _)| [(*l, *o), (*r, *o)])
116+
.collect::<FastSet<_>>();
117+
118+
let max_z_name = format!("z{:02}", find_max_z_number(&gates));
119+
120+
let mut result = gates
121+
.into_iter()
122+
.filter(|&(input, operator, _, res)| {
123+
if input == "x00" || input == "y00" {
124+
if operator == Operator::Xor && res != "z00" {
125+
return true;
126+
}
127+
128+
if operator == Operator::And && res.starts_with("z") {
129+
return true;
130+
}
131+
132+
return false;
133+
}
134+
135+
if operator == Operator::Xor {
136+
if input.starts_with("x") || input.starts_with("y") {
137+
if !input_with_operator.contains(&(res, Operator::Xor)) {
138+
return true;
139+
}
140+
141+
if !input_with_operator.contains(&(res, Operator::And)) {
142+
return true;
143+
}
144+
145+
if res.starts_with("z") {
146+
return true;
147+
}
148+
} else if !res.starts_with("z") {
149+
return true;
150+
}
151+
}
152+
153+
if operator == Operator::And {
154+
if res.starts_with("z") {
155+
return true;
156+
}
157+
158+
if (input.starts_with("x") || input.starts_with("y"))
159+
&& !input_with_operator.contains(&(res, Operator::Or))
160+
{
161+
return true;
162+
}
163+
}
164+
165+
if operator == Operator::Or && res.starts_with("z") && res != max_z_name {
166+
return true;
167+
}
168+
169+
false
170+
})
171+
.map(|(_, _, _, res)| res)
172+
.collect::<Vec<_>>();
173+
174+
result.sort_unstable();
175+
let result = result.join(",");
176+
177+
Some(result)
178+
}
179+
180+
#[cfg(test)]
181+
mod tests {
182+
use super::*;
183+
184+
#[test]
185+
fn test_part_one() {
186+
let input = advent_of_code::template::read_file_part("examples", DAY, 1);
187+
let result = part_one(&input);
188+
assert_eq!(result, Some(2024));
189+
}
190+
191+
#[test]
192+
fn test_part_two() {
193+
let input = advent_of_code::template::read_file_part("examples", DAY, 2);
194+
let result = part_two(&input);
195+
assert_eq!(
196+
result,
197+
Some(String::from("e01,e04,q01,q03,w01,z00,z03,z04"))
198+
);
199+
}
200+
}

0 commit comments

Comments
 (0)