-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday_10.rs
174 lines (150 loc) · 4.3 KB
/
day_10.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
use std::fmt;
use std::{cell::RefCell, collections::HashMap};
#[derive(Clone, Copy, Debug)]
enum BotOutput {
Bot(usize),
Output(usize),
}
impl fmt::Display for BotOutput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BotOutput::Bot(id) => write!(f, "Bot({})", id),
BotOutput::Output(id) => write!(f, "Output({})", id),
}
}
}
#[derive(Clone, Debug)]
struct Bot {
values: Vec<usize>,
low: BotOutput,
high: BotOutput,
}
impl Default for Bot {
fn default() -> Self {
Bot {
values: vec![],
low: BotOutput::Output(0),
high: BotOutput::Output(0),
}
}
}
impl Bot {
fn add_chip(&mut self, chip: usize) {
if self.values.len() == 2 {
panic!("Cannot add chips here!");
}
self.values.push(chip);
self.values.sort();
}
fn set_low_high(&mut self, low: BotOutput, high: BotOutput) {
self.low = low;
self.high = high;
}
fn extract_chips(&mut self) -> [(usize, BotOutput); 2] {
if self.values.len() != 2 {
panic!("No chips to extract");
}
let ex_low = (self.values[0], self.low);
let ex_high = (self.values[1], self.high);
self.values = vec![];
[ex_low, ex_high]
}
}
type BotHM = HashMap<usize, RefCell<Bot>>;
fn parse_input(input: impl Into<String>) -> BotHM {
let mut bots = BotHM::new();
for line in input.into().lines() {
let parts: Vec<_> = line.split_whitespace().collect();
match parts[0] {
"value" => {
let bot_id = parts[5].parse::<usize>().unwrap();
let bot = bots.entry(bot_id).or_default();
let value = parts[1].parse::<usize>().unwrap();
bot.borrow_mut().add_chip(value);
}
"bot" => {
let bot_id = parts[1].parse::<usize>().unwrap();
let bot = bots.entry(bot_id).or_default();
let low_id = parts[6].parse::<usize>().unwrap();
let low_bo = match parts[5] {
"bot" => BotOutput::Bot(low_id),
"output" => BotOutput::Output(low_id),
_ => panic!("Invalid instruction: {}", line),
};
let high_id = parts[11].parse::<usize>().unwrap();
let high_bo = match parts[10] {
"bot" => BotOutput::Bot(high_id),
"output" => BotOutput::Output(high_id),
_ => panic!("Invalid instruction: {}", line),
};
bot.borrow_mut().set_low_high(low_bo, high_bo)
}
_ => panic!("Invalid instruction: {}", line),
}
}
bots
}
fn solve(input: impl Into<String>, chipstop: Option<Vec<usize>>) -> usize {
let mut outs: HashMap<usize, Vec<usize>> = HashMap::new();
let bots = parse_input(input);
let mut full_bots: Vec<_> = bots
.iter()
.filter(|(_, bot)| bot.borrow_mut().values.len() == 2)
.collect();
while !full_bots.is_empty() {
for (id, bot) in full_bots.iter() {
if bot.borrow_mut().values.len() < 2 {
continue;
}
if let Some(chipstopper) = &chipstop {
if chipstopper == &bot.borrow_mut().values {
return **id;
}
}
for (chip, direction) in bot.borrow_mut().extract_chips().iter() {
match direction {
BotOutput::Bot(bot_id) => {
let bot_out = bots.get(bot_id).unwrap();
bot_out.borrow_mut().add_chip(*chip);
}
BotOutput::Output(out_id) => {
let output = outs.entry(*out_id).or_default();
output.push(*chip);
}
}
}
}
full_bots = bots
.iter()
.filter(|(_, bot)| bot.borrow_mut().values.len() == 2)
.collect();
}
outs
.iter()
.filter(|(id, _)| **id <= 2)
.map(|(_, output)| output[0])
.product()
}
const LOW_CHIP: usize = 17;
const HIGH_CHIP: usize = 61;
pub fn day_10_v1(input: impl Into<String>) -> usize {
solve(input, Some(vec![LOW_CHIP, HIGH_CHIP]))
}
pub fn day_10_v2(input: impl Into<String>) -> usize {
solve(input, None)
}
solvable!(day_10, day_10_v1, day_10_v2, usize);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn works_with_samples_v1() {
let sample_one = "value 5 goes to bot 2\n\
bot 2 gives low to bot 1 and high to bot 0\n\
value 3 goes to bot 1\n\
bot 1 gives low to output 1 and high to bot 0\n\
bot 0 gives low to output 2 and high to output 0\n\
value 2 goes to bot 2";
assert_eq!(solve(sample_one, Some(vec![2, 5])), 2);
}
}