Skip to content

Commit b0c05ba

Browse files
committed
submit day 20 part 1
1 parent 7cc833b commit b0c05ba

File tree

4 files changed

+247
-1
lines changed

4 files changed

+247
-1
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
3131
| [Day 17](./src/bin/17.rs) | `99.6ms` | `278.9ms` |
3232
| [Day 18](./src/bin/18.rs) | `5.0ms` | `41.7µs` |
3333
| [Day 19](./src/bin/19.rs) | `239.3µs` | `265.0µs` |
34+
| [Day 20](./src/bin/20.rs) | `2.1ms` | `-` |
3435

35-
**Total: 1965.82ms**
36+
**Total: 1967.92ms**
3637

3738
<!--- benchmarking table --->
3839

data/examples/20-1.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
broadcaster -> a, b, c
2+
%a -> b
3+
%b -> c
4+
%c -> inv
5+
&inv -> a

data/examples/20-2.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
broadcaster -> a
2+
%a -> inv, con
3+
&inv -> b
4+
%b -> con
5+
&con -> output

src/bin/20.rs

+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
use std::collections::{HashMap, VecDeque};
2+
3+
advent_of_code::solution!(20);
4+
5+
pub fn part_one(input: &str) -> Option<u64> {
6+
let mut program = Program::from_input(input);
7+
let mut pulse_count = PulseCount::new();
8+
9+
for _ in 0..1000 {
10+
program.run(&mut pulse_count);
11+
}
12+
13+
Some(pulse_count.high * pulse_count.low)
14+
}
15+
16+
pub fn part_two(input: &str) -> Option<u32> {
17+
None
18+
}
19+
20+
struct Program<'a> {
21+
modules: HashMap<&'a str, Module<'a>>,
22+
}
23+
24+
impl Program<'_> {
25+
fn from_input(input: &str) -> Program {
26+
let mut module_outputs = Vec::new();
27+
let mut modules = HashMap::new();
28+
29+
for line in input.lines() {
30+
let module = Module::from_line(line);
31+
32+
module_outputs.push((module.name, module.output_modules.clone()));
33+
modules.insert(module.name, module);
34+
}
35+
36+
for (module_name, outputs) in module_outputs.iter() {
37+
for output_module in outputs {
38+
if let Some(module) = modules.get_mut(output_module) {
39+
module.add_input(module_name);
40+
}
41+
}
42+
}
43+
44+
Program { modules }
45+
}
46+
47+
fn run(&mut self, pulse_count: &mut PulseCount) {
48+
let mut pulse_packets = VecDeque::from([PulsePacket::start()]);
49+
50+
while let Some(pulse_packet) = pulse_packets.pop_front() {
51+
pulse_count.add(pulse_packet.pulse);
52+
53+
if let Some(module) = self.modules.get_mut(pulse_packet.to) {
54+
if let Some(pulse) = module.process(pulse_packet) {
55+
pulse_packets.extend(module.output_modules.iter().map(|output_module| {
56+
PulsePacket {
57+
from: module.name,
58+
to: output_module,
59+
pulse,
60+
}
61+
}));
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
struct Module<'a> {
69+
name: &'a str,
70+
logic: Logic<'a>,
71+
output_modules: Vec<&'a str>,
72+
}
73+
74+
impl<'a> Module<'a> {
75+
fn from_line(line: &str) -> Module {
76+
let mut line_iterator = line.split(" -> ");
77+
let name_part = line_iterator.next().unwrap();
78+
let output_modules = line_iterator.next().unwrap().split(", ").collect();
79+
80+
match name_part.as_bytes()[0] {
81+
b'%' => Module {
82+
name: &name_part[1..],
83+
logic: Logic::new_flip_flop(),
84+
output_modules,
85+
},
86+
b'&' => Module {
87+
name: &name_part[1..],
88+
logic: Logic::new_conjunction(),
89+
output_modules,
90+
},
91+
b'b' => Module {
92+
name: name_part,
93+
logic: Logic::new_broadcast(),
94+
output_modules,
95+
},
96+
_ => panic!("Invalid module {}", name_part),
97+
}
98+
}
99+
100+
fn add_input(&mut self, input: &'a str) {
101+
self.logic.add_input(input);
102+
}
103+
104+
fn process(&mut self, pulse_packet: PulsePacket) -> Option<Pulse> {
105+
self.logic.process(pulse_packet)
106+
}
107+
}
108+
109+
enum Logic<'a> {
110+
FlipFlop { is_on: bool },
111+
Conjunction { inputs: Vec<(&'a str, Pulse)> },
112+
Broadcast,
113+
}
114+
115+
impl<'a> Logic<'a> {
116+
fn new_flip_flop() -> Logic<'a> {
117+
Logic::FlipFlop { is_on: false }
118+
}
119+
120+
fn new_conjunction() -> Logic<'a> {
121+
Logic::Conjunction { inputs: Vec::new() }
122+
}
123+
124+
fn new_broadcast() -> Logic<'a> {
125+
Logic::Broadcast
126+
}
127+
128+
fn add_input(&mut self, input: &'a str) {
129+
if let Logic::Conjunction { inputs } = self {
130+
inputs.push((input, Pulse::Low));
131+
}
132+
}
133+
134+
fn process(&mut self, pulse_packet: PulsePacket) -> Option<Pulse> {
135+
match self {
136+
Logic::FlipFlop { is_on } => match pulse_packet.pulse {
137+
Pulse::High => None,
138+
Pulse::Low => {
139+
*is_on = !*is_on;
140+
141+
if *is_on {
142+
Some(Pulse::High)
143+
} else {
144+
Some(Pulse::Low)
145+
}
146+
}
147+
},
148+
Logic::Conjunction { inputs } => {
149+
inputs
150+
.iter_mut()
151+
.find(|(name, _)| *name == pulse_packet.from)
152+
.unwrap()
153+
.1 = pulse_packet.pulse;
154+
155+
if pulse_packet.pulse == Pulse::High
156+
&& inputs.iter().all(|(_, pulse)| *pulse == Pulse::High)
157+
{
158+
Some(Pulse::Low)
159+
} else {
160+
Some(Pulse::High)
161+
}
162+
}
163+
Logic::Broadcast => Some(pulse_packet.pulse),
164+
}
165+
}
166+
}
167+
168+
#[derive(PartialEq, Copy, Clone)]
169+
enum Pulse {
170+
High,
171+
Low,
172+
}
173+
174+
struct PulseCount {
175+
high: u64,
176+
low: u64,
177+
}
178+
179+
impl PulseCount {
180+
fn new() -> PulseCount {
181+
PulseCount { high: 0, low: 0 }
182+
}
183+
184+
fn add(&mut self, pulse: Pulse) {
185+
match pulse {
186+
Pulse::High => self.high += 1,
187+
Pulse::Low => self.low += 1,
188+
}
189+
}
190+
}
191+
192+
struct PulsePacket<'a> {
193+
from: &'a str,
194+
to: &'a str,
195+
pulse: Pulse,
196+
}
197+
198+
impl<'a> PulsePacket<'a> {
199+
fn start() -> PulsePacket<'a> {
200+
PulsePacket {
201+
from: "",
202+
to: "broadcaster",
203+
pulse: Pulse::Low,
204+
}
205+
}
206+
}
207+
208+
#[cfg(test)]
209+
mod tests {
210+
use super::*;
211+
212+
#[test]
213+
fn test_part_one_1() {
214+
let result = part_one(&advent_of_code::template::read_file_part(
215+
"examples", DAY, 1,
216+
));
217+
assert_eq!(result, Some(32000000));
218+
}
219+
220+
#[test]
221+
fn test_part_one_2() {
222+
let result = part_one(&advent_of_code::template::read_file_part(
223+
"examples", DAY, 2,
224+
));
225+
assert_eq!(result, Some(11687500));
226+
}
227+
228+
#[test]
229+
fn test_part_two() {
230+
let result = part_two(&advent_of_code::template::read_file_part(
231+
"examples", DAY, 3,
232+
));
233+
assert_eq!(result, None);
234+
}
235+
}

0 commit comments

Comments
 (0)