diff options
author | Prefetch | 2023-02-25 11:41:27 +0100 |
---|---|---|
committer | Prefetch | 2023-02-25 11:41:27 +0100 |
commit | 3b877bf4cc667eb8bcc787d145203600a4dba2d2 (patch) | |
tree | c1d247def29fcb58ae28e4ae4e4d73d1b4e1b27f /d10/src/main.rs |
Initial commit
Diffstat (limited to 'd10/src/main.rs')
-rw-r--r-- | d10/src/main.rs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/d10/src/main.rs b/d10/src/main.rs new file mode 100644 index 0000000..650c146 --- /dev/null +++ b/d10/src/main.rs @@ -0,0 +1,173 @@ +// Let the record show that I hated every second of solving this puzzle. + +use std::fs; + +#[derive(Copy, Clone, Debug)] +struct Bot { + lo: Option<usize>, + hi: Option<usize>, +} + +impl Bot { + fn new() -> Self { + Self { lo: None, hi: None } + } + + fn recv_chip(&mut self, val: usize) { + if self.lo.is_none() && self.hi.is_none() { + self.lo = Some(val); + } else if self.lo.is_some() && self.hi.is_none() { + let old_lo = self.lo.unwrap(); + if old_lo < val { + self.hi = Some(val); + } else { + self.lo = Some(val); + self.hi = Some(old_lo); + } + } else if self.lo.is_none() && self.hi.is_some() { + let old_hi = self.hi.unwrap(); + if old_hi > val { + self.lo = Some(val); + } else { + self.lo = Some(old_hi); + self.hi = Some(val); + } + } else if self.lo.is_some() && self.hi.is_some() { + // If both slots are occupied, we can't accept any more + } + } + + fn give_chip_lo(&mut self) -> Option<usize> { + let result = self.lo; + if result.is_some() { + self.lo = None; + } + result + } + + fn give_chip_hi(&mut self) -> Option<usize> { + let result = self.hi; + if result.is_some() { + self.hi = None; + } + result + } + + fn num_chips(&self) -> usize { + let mut result = 0; + + if self.lo.is_some() { + result += 1; + } + if self.hi.is_some() { + result += 1; + } + + result + } +} + +fn solve_puzzle(lines: &Vec<&str>, target: (usize, usize)) -> (usize, usize) { + let mut bots: Vec<Bot> = [Bot::new()].repeat(300); + let mut bins: Vec<Option<usize>> = [None].repeat(300); + + let mut part1 = None; + let mut part2 = None; + + let mut ln = 0; + // Loop 50k times until a self-consistent state is reached + for _i in 0..50000 { + let words: Vec<&str> = lines[ln].split_ascii_whitespace().collect(); + + // Take chip from input bin + if words[0] == "value" { + let to: usize = words[5].parse().unwrap(); + bots[to].recv_chip(words[1].parse().unwrap()); + } + + // Give chips to other bots or to output bins + if words[0] == "bot" { + let from: usize = words[1].parse().unwrap(); + + // Does the giver have two chips? If not, ignore this line (for now) + if bots[from].lo.is_some() && bots[from].hi.is_some() { + // Bot/bin indices to give chips to + let lo_to: usize = words[6].parse().unwrap(); + let hi_to: usize = words[11].parse().unwrap(); + + // Can the destination accept our chips? + let lo_avail = + (words[5] == "bot" && bots[lo_to].num_chips() < 2) || words[5] == "output"; + let hi_avail = + (words[10] == "bot" && bots[hi_to].num_chips() < 2) || words[10] == "output"; + if lo_avail && hi_avail { + // Give the low chip + let lo = bots[from].give_chip_lo().unwrap(); + if words[5] == "bot" { + bots[lo_to].recv_chip(lo); + } else if words[5] == "output" { + bins[lo_to] = Some(lo); // overwrite + } + + // Give the high chip + let hi = bots[from].give_chip_hi().unwrap(); + if words[10] == "bot" { + bots[hi_to].recv_chip(hi); + } else if words[10] == "output" { + bins[hi_to] = Some(hi); // overwrite + } + } + } + } + + // Which bot ends up comparing the target-valued chips? + for j in 0..bots.len() { + if bots[j].lo.is_some() && bots[j].lo.unwrap() == target.0 { + if bots[j].hi.is_some() && bots[j].hi.unwrap() == target.1 { + part1 = Some(j); + } + } + } + + // What is the product of the chips that end up in output bins 0, 1 and 2? + if bins[0].is_some() && bins[1].is_some() && bins[2].is_some() { + part2 = Some(bins[0].unwrap() * bins[1].unwrap() * bins[2].unwrap()); + } + + ln = (ln + 1) % lines.len(); + } + + (part1.unwrap(), part2.unwrap()) +} + +fn main() { + // Read instructions from input text file + let input = fs::read_to_string("input.txt").unwrap(); + let lines = input.lines().collect(); + + let (part1, part2) = solve_puzzle(&lines, (17, 61)); + + // Part 1 gives 101 for me + println!("Part 1 solution: {}", part1); + + // Part 2 gives 37789 for me + println!("Part 2 solution: {}", part2); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn part1_example1() { + let lines = vec![ + "value 5 goes to bot 2", + "bot 2 gives low to bot 1 and high to bot 0", + "value 3 goes to bot 1", + "bot 1 gives low to output 1 and high to bot 0", + "bot 0 gives low to output 2 and high to output 0", + "value 2 goes to bot 2", + ]; + assert_eq!(solve_puzzle(&lines, (2, 5)), (2, 30)); + } +} |