From f26a4b8a1f648842e4ce8676754a66e0189e41e1 Mon Sep 17 00:00:00 2001 From: cos Date: Mon, 5 Dec 2022 20:54:23 +0000 Subject: Add day03, 2022 --- 2022/rust/Cargo.toml | 2 +- 2022/rust/day03/Cargo.toml | 9 ++++ 2022/rust/day03/src/main.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 2022/rust/day03/Cargo.toml create mode 100644 2022/rust/day03/src/main.rs diff --git a/2022/rust/Cargo.toml b/2022/rust/Cargo.toml index 0707ddf..b2641a6 100644 --- a/2022/rust/Cargo.toml +++ b/2022/rust/Cargo.toml @@ -2,7 +2,7 @@ members = [ "day01", "day02", -# "day03", + "day03", # "day04", # "day05", # "day06", diff --git a/2022/rust/day03/Cargo.toml b/2022/rust/day03/Cargo.toml new file mode 100644 index 0000000..115d7fa --- /dev/null +++ b/2022/rust/day03/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day03" +version = "0.1.0" +authors = ["cos "] +edition = "2021" + +[dependencies] +aoc = { path = "../../../common/rust/aoc" } +anyhow = "1.0" diff --git a/2022/rust/day03/src/main.rs b/2022/rust/day03/src/main.rs new file mode 100644 index 0000000..a3e4fb3 --- /dev/null +++ b/2022/rust/day03/src/main.rs @@ -0,0 +1,103 @@ +use { + anyhow::{ + anyhow, + Context, + Result, + }, + std::{ + env::args, + fs::File, + io::{ + BufRead, + BufReader, + }, + path::Path, + }, +}; + +fn item_priority(item: char) -> Option { + match item { + 'a'..='z' => Some((item as u32 - 'a' as u32 + 1) as usize), + 'A'..='Z' => Some((item as u32 - 'A' as u32 + 27) as usize), + _ => None, + } +} + +#[derive(Debug)] +struct Rucksack { + compartments: Vec, +} + +impl Rucksack { + fn new(items: &str) -> Self { + let (first, second) = items.split_at(items.len()/2); + let compartments = vec![String::from(first), String::from(second)]; + Self { + compartments, + } + } + + fn contains(&self, needle: char) -> bool { + self.compartments[0].contains(needle) || self.compartments[1].contains(needle) + } + + fn common_items(&self) -> String { + self.compartments[0].chars().filter(|item| self.compartments[1].contains(*item)).collect() + } + + fn find_badge(&self, other: &Rucksack) -> String { + self.compartments[0].chars().chain(self.compartments[1].chars()).filter(|item| + other.contains(*item)).collect() + } +} + +fn read_input>(filename: T) -> Result> { + let reader = BufReader::new(File::open(filename)?); + + reader.lines().map( + |v| { + let s = v?; + Ok(Rucksack::new(&s)) + } + ).collect() +} + +fn part1(input: &[Rucksack]) -> Result { + Ok(input.iter().filter_map(|rucksack| { + if let Some(item) = rucksack.common_items().chars().next() { + item_priority(item) + } else { + None + } + }).sum()) +} + +fn part2(input: &[Rucksack]) -> Result { + Ok(input.chunks(3).filter_map(|rucksacks| { + let some_candidates = rucksacks[0].find_badge(&rucksacks[1]); + let other_candidates = rucksacks[0].find_badge(&rucksacks[2]); + let common: String = some_candidates.chars().filter(|item| + other_candidates.contains(*item)).collect(); + if let Some(item) = common.chars().next() { + item_priority(item) + } else { + None + } + }).sum()) +} + +fn main() -> Result<()> { + let ( do_part_1, do_part_2 ) = aoc::do_parts(); + + let filename = args().nth(1).ok_or_else(|| 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