From 9dfb22a9eb14d7884b534f2ae34c4807424fe19e Mon Sep 17 00:00:00 2001 From: cos Date: Tue, 7 Dec 2021 08:52:05 +0100 Subject: Add day07, 2021 --- 2021/rust/Cargo.toml | 2 +- 2021/rust/day07/Cargo.toml | 9 +++ 2021/rust/day07/src/main.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 2021/rust/day07/Cargo.toml create mode 100644 2021/rust/day07/src/main.rs diff --git a/2021/rust/Cargo.toml b/2021/rust/Cargo.toml index 5badeb6..49ed1d7 100644 --- a/2021/rust/Cargo.toml +++ b/2021/rust/Cargo.toml @@ -6,7 +6,7 @@ members = [ "day04", "day05", "day06", -# "day07", + "day07", # "day08", # "day09", # "day10", diff --git a/2021/rust/day07/Cargo.toml b/2021/rust/day07/Cargo.toml new file mode 100644 index 0000000..645ee26 --- /dev/null +++ b/2021/rust/day07/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day07" +version = "0.1.0" +authors = ["cos "] +edition = "2021" + +[dependencies] +aoc = { path = "../../../common/rust/aoc" } +anyhow = "1.0" diff --git a/2021/rust/day07/src/main.rs b/2021/rust/day07/src/main.rs new file mode 100644 index 0000000..56fcde1 --- /dev/null +++ b/2021/rust/day07/src/main.rs @@ -0,0 +1,138 @@ +use { + anyhow::{ + anyhow, + Context, + Result, + }, + std::{ + collections::BTreeMap, + env::args, + fs::File, + io::{ + BufRead, + BufReader, + }, + path::Path, + }, +}; + +fn read_input>(filename: T) -> Result> { + let reader = BufReader::new(File::open(filename)?); + + reader.lines().next().ok_or(anyhow!(""))??.split(',').map( + |s| { + let n = s.parse()?; + Ok(n) + } + ).collect() +} + +fn part1<'a, I: Copy + IntoIterator>(input: I) -> Result { + let mut subs: BTreeMap = BTreeMap::new(); + let mut fuel = 0; + for position in input { + *subs.entry(*position).or_insert(0) += 1; + } + + while subs.len() > 1 { + let first_position = *subs.keys().next().ok_or(anyhow!("Couldn't get first position."))?; + let last_position = *subs.keys().rev().next() + .ok_or(anyhow!("Couldn't get last position."))?; + let first_value = *subs.get(&first_position).ok_or(anyhow!("Couldn't get first value."))?; + let last_value = *subs.get(&last_position).ok_or(anyhow!("Couldn't get last value."))?; + if first_value <= last_value { + let value = subs.remove(&first_position) + .ok_or(anyhow!("Couldn't remove first value"))?; + let new_position = first_position + 1; + *subs.entry(new_position).or_insert(0) += value; + fuel += value; + } + if first_value >= last_value { + let value = subs.remove(&last_position).ok_or(anyhow!("Couldn't remove last value"))?; + let new_position = last_position - 1; + *subs.entry(new_position).or_insert(0) += value; + fuel += value; + } + } + Ok(fuel) +} + +fn part2<'a, I: Copy + IntoIterator>(input: I) -> Result { + #[derive(Debug)] + struct Occupancy { + cost: usize, + vessel_count: usize, + } + + impl Occupancy { + fn new() -> Self { + let cost = 0; + let vessel_count = 0; + Self { + cost, + vessel_count, + } + } + + fn add_vessel(&mut self) { + self.cost += 1; + self.vessel_count += 1; + } + + fn merge(&mut self, other: Occupancy) -> Result<()> { + self.cost += other.cost + other.vessel_count; + self.vessel_count += other.vessel_count; + Ok(()) + } + } + + let mut subs: BTreeMap = BTreeMap::new(); + let mut fuel = 0; + for position in input { + subs.entry(*position).or_insert_with(Occupancy::new).add_vessel(); + } + + while subs.len() > 1 { + let first_position = *subs.keys().next().ok_or(anyhow!("Couldn't get first position."))?; + let last_position = *subs.keys().rev().next() + .ok_or(anyhow!("Couldn't get last position."))?; + let first_costs = (*subs.get(&first_position).ok_or(anyhow!("Couldn't get first value."))?) + .cost; + let first_fuel = first_costs; + let last_costs = (*subs.get(&last_position).ok_or(anyhow!("Couldn't get last value."))?) + .cost; + let last_fuel = last_costs; + if first_fuel <= last_fuel { + let value = subs.remove(&first_position) + .ok_or(anyhow!("Couldn't remove first value"))?; + let new_position = first_position + 1; + let costs = subs.entry(new_position).or_insert_with(Occupancy::new); + costs.merge(value)?; + fuel += first_fuel; + } + if first_fuel >= last_fuel { + let value = subs.remove(&last_position).ok_or(anyhow!("Couldn't remove last value"))?; + let new_position = last_position - 1; + let costs = subs.entry(new_position).or_insert_with(Occupancy::new); + costs.merge(value)?; + fuel += last_fuel; + } + } + Ok(fuel) +} + +fn main() -> Result<()> { + let ( do_part_1, do_part_2 ) = aoc::do_parts(); + + let filename = args().nth(1).ok_or(anyhow!("Missing input filename"))?; + let input = read_input(filename).context("Could not read input")?; + if do_part_1 { + let solution = part1(&input).context("No solution for part 1")?; + println!("Part1, solution found to be: {}", solution); + } + if do_part_2 { + let solution = part2(&input).context("No solution for part 2")?; + println!("Part2, solution found to be: {}", solution); + } + Ok(()) +} -- cgit v1.2.3