-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday10.rs
137 lines (123 loc) · 4.15 KB
/
day10.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
use std::{collections::HashMap, str::FromStr};
use itertools::Itertools;
use scan_fmt::scan_fmt;
use crate::utils::aoc;
#[derive(Debug)]
struct Instruction {
bot: i32,
lo: Target,
hi: Target,
}
impl FromStr for Instruction {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (bot, target_lo, lo, target_hi, hi) = scan_fmt!(
s,
"bot {d} gives low to {} {d} and high to {} {d}",
i32,
String,
i32,
String,
i32
)
.unwrap();
Ok(Instruction {
bot,
lo: Target::new(&target_lo, lo),
hi: Target::new(&target_hi, hi),
})
}
}
#[derive(Debug)]
enum Target {
Bot(i32),
Output(i32),
}
impl Target {
fn new(s: &str, i: i32) -> Self {
match s {
"bot" => Self::Bot(i),
"output" => Self::Output(i),
_ => panic!(),
}
}
}
pub struct OldSolver;
impl OldSolver {
fn get_instructions(input: &str) -> HashMap<i32, Instruction> {
input
.lines()
.filter(|l| l.starts_with("bot"))
.map(|l| l.parse::<Instruction>().unwrap())
.map(|i| (i.bot, i))
.collect::<HashMap<_, _>>()
}
fn get_initial_state(input: &str) -> HashMap<i32, Vec<i32>> {
input
.lines()
.filter(|l| l.starts_with("value"))
.filter_map(|l| scan_fmt!(l, "value {d} goes to bot {d}", i32, i32).ok())
.map(|(value, bot)| (bot, value))
.into_group_map()
}
}
impl aoc::OldSolver<2016, 10> for OldSolver {
type Part1 = i32;
type Part2 = i32;
fn solve_part_one(&self, input: &str) -> Self::Part1 {
let instructions = OldSolver::get_instructions(input);
let mut state = OldSolver::get_initial_state(input);
loop {
let current = state.clone();
// For every bot with 2 microchips, give it to the bot next in line based on its instruction.
for (bot, microchips) in current.into_iter().filter(|(_, v)| v.len() == 2) {
let (lo, hi) = (
microchips[0].min(microchips[1]),
microchips[0].max(microchips[1]),
);
let instruction = &instructions[&bot];
state.remove(&bot);
// Ignore output bins.
if let Target::Bot(bot) = instruction.lo {
state.entry(bot).or_insert(Vec::new()).push(lo);
}
if let Target::Bot(bot) = instruction.hi {
state.entry(bot).or_insert(Vec::new()).push(hi);
}
if lo == 17 && hi == 61 {
return bot;
}
}
}
}
fn solve_part_two(&self, input: &str) -> Self::Part2 {
let instructions = OldSolver::get_instructions(input);
let mut state = OldSolver::get_initial_state(input);
let mut bins = HashMap::new();
while !bins.contains_key(&0) || !bins.contains_key(&1) || !bins.contains_key(&2) {
let current = state.clone();
// For every bot with 2 microchips, give it to the bot next in line based on its instruction.
for (bot, microchips) in current.into_iter().filter(|(_, v)| v.len() == 2) {
let (lo, hi) = (
microchips[0].min(microchips[1]),
microchips[0].max(microchips[1]),
);
let instruction = &instructions[&bot];
state.remove(&bot);
match instruction.lo {
Target::Bot(bot) => state.entry(bot).or_insert(Vec::new()).push(lo),
Target::Output(bin) => {
bins.insert(bin, lo);
}
}
match instruction.hi {
Target::Bot(bot) => state.entry(bot).or_insert(Vec::new()).push(hi),
Target::Output(bin) => {
bins.insert(bin, hi);
}
}
}
}
bins[&0] * bins[&1] * bins[&2]
}
}