advent_of_code/year2016/
day10.rs1use crate::input::Input;
2
3type BotId = u8;
4
5#[derive(Copy, Clone)]
6enum OnDone {
7 GiveTo(BotId),
8 OutputTo(u8),
9}
10
11#[derive(Copy, Clone)]
12struct Bot {
13 low_to: OnDone,
14 high_to: OnDone,
15 received_chip: Option<u8>,
16}
17
18impl Default for Bot {
19 fn default() -> Self {
20 Self {
21 low_to: OnDone::OutputTo(0),
22 high_to: OnDone::OutputTo(0),
23 received_chip: None,
24 }
25 }
26}
27
28fn receive(
29 bots: &mut [Bot; 256],
30 first_three_outputs: &mut [u8; 3],
31 microchip: u8,
32 to_bot: BotId,
33 part1: bool,
34) -> Option<BotId> {
35 let bot = &mut bots[usize::from(to_bot)];
36
37 if let Some(first_microchip) = bot.received_chip {
38 let low_microchip = std::cmp::min(first_microchip, microchip);
39 let high_microchip = std::cmp::max(first_microchip, microchip);
40
41 if part1 && (low_microchip, high_microchip) == (17, 61) {
42 return Some(to_bot);
43 }
44
45 let low_to = bot.low_to;
46 let high_to = bot.high_to;
47
48 match low_to {
49 OnDone::GiveTo(recipient) => {
50 let desired_bot =
51 receive(bots, first_three_outputs, low_microchip, recipient, part1);
52 if desired_bot.is_some() {
53 return desired_bot;
54 }
55 }
56 OnDone::OutputTo(output_idx) => {
57 if output_idx < 3 {
58 first_three_outputs[output_idx as usize] = low_microchip;
59 }
60 }
61 }
62
63 match high_to {
64 OnDone::GiveTo(recipient) => {
65 let desired_bot =
66 receive(bots, first_three_outputs, high_microchip, recipient, part1);
67 if desired_bot.is_some() {
68 return desired_bot;
69 }
70 }
71 OnDone::OutputTo(output_idx) => {
72 if output_idx < 3 {
73 first_three_outputs[output_idx as usize] = high_microchip;
74 }
75 }
76 }
77 } else {
78 bot.received_chip = Some(microchip);
79 }
80
81 None
82}
83
84pub fn solve(input: &Input) -> Result<u32, String> {
85 let error_mapper = |_| "Invalid input";
86 let mut bots = [Bot::default(); 256];
87 let mut initial_values = Vec::new();
88
89 for line in input.text.lines() {
90 let parts = line.split(' ').collect::<Vec<_>>();
91 if parts[0] == "value" {
92 let value = parts[1].parse::<u8>().map_err(error_mapper)?;
94 let to_bot_id = parts[5].parse::<BotId>().map_err(error_mapper)?;
95 initial_values.push((value, to_bot_id));
96 } else if parts[0] == "bot" {
97 let bot_id = parts[1].parse::<u8>().map_err(error_mapper)?;
99 let low_to_number = parts[6].parse::<u8>().map_err(error_mapper)?;
100 let high_to_number = parts[11].parse::<u8>().map_err(error_mapper)?;
101
102 let low_to = if parts[5] == "bot" {
103 OnDone::GiveTo(low_to_number)
104 } else {
105 OnDone::OutputTo(low_to_number)
106 };
107
108 let high_to = if parts[10] == "bot" {
109 OnDone::GiveTo(high_to_number)
110 } else {
111 OnDone::OutputTo(high_to_number)
112 };
113
114 let bot = Bot {
115 low_to,
116 high_to,
117 received_chip: None,
118 };
119
120 bots[usize::from(bot_id)] = bot;
121 } else {
122 return Err("Invalid input".to_string());
123 }
124 }
125
126 let mut first_three_outputs = [0_u8; 3];
127 for &(value, to_bot_id) in &initial_values {
128 if let Some(desired_bot_id) = receive(
129 &mut bots,
130 &mut first_three_outputs,
131 value,
132 to_bot_id,
133 input.is_part_one(),
134 ) {
135 return Ok(u32::from(desired_bot_id));
136 }
137 }
138
139 if input.is_part_one() {
140 Err("Not bot comparing chips 17 and 61".to_string())
141 } else {
142 Ok(first_three_outputs.iter().map(|&v| u32::from(v)).product())
143 }
144}
145
146#[test]
147pub fn tests() {
148 use crate::input::{test_part_one, test_part_two};
149
150 let real_input = include_str!("day10_input.txt");
151 test_part_one!(real_input => 98);
152 test_part_two!(real_input => 4042);
153}