From 14a90754c20a1cd6c4d410fb76b6d788ca3d706d Mon Sep 17 00:00:00 2001 From: Siphalor Date: Thu, 5 Dec 2024 22:08:53 +0100 Subject: [PATCH] Day five --- day-05-rust/.gitignore | 1 + day-05-rust/Cargo.lock | 7 ++++ day-05-rust/Cargo.toml | 6 +++ day-05-rust/src/common.rs | 60 +++++++++++++++++++++++++++ day-05-rust/src/main.rs | 22 ++++++++++ day-05-rust/src/task1.rs | 45 ++++++++++++++++++++ day-05-rust/src/task2.rs | 86 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 227 insertions(+) create mode 100644 day-05-rust/.gitignore create mode 100644 day-05-rust/Cargo.lock create mode 100644 day-05-rust/Cargo.toml create mode 100644 day-05-rust/src/common.rs create mode 100644 day-05-rust/src/main.rs create mode 100644 day-05-rust/src/task1.rs create mode 100644 day-05-rust/src/task2.rs diff --git a/day-05-rust/.gitignore b/day-05-rust/.gitignore new file mode 100644 index 0000000..9f97022 --- /dev/null +++ b/day-05-rust/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/day-05-rust/Cargo.lock b/day-05-rust/Cargo.lock new file mode 100644 index 0000000..7e8d8b5 --- /dev/null +++ b/day-05-rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "day-05-rust" +version = "0.1.0" diff --git a/day-05-rust/Cargo.toml b/day-05-rust/Cargo.toml new file mode 100644 index 0000000..70e9e2d --- /dev/null +++ b/day-05-rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day-05-rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day-05-rust/src/common.rs b/day-05-rust/src/common.rs new file mode 100644 index 0000000..58c241b --- /dev/null +++ b/day-05-rust/src/common.rs @@ -0,0 +1,60 @@ +use std::collections::HashMap; +use std::io::{Bytes, Read}; +use std::iter::Peekable; +use crate::common; + +pub type Number = i32; + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Rule { + pub first: Number, + pub second: Number, +} + +pub fn read_rules(mut input: &mut Peekable>) -> HashMap> { + let mut rules_by_number = HashMap::>::new(); + + while let Some(Ok(ch)) = input.peek() { + if ch == &b'\n' { + input.next(); + break; + } + let first = common::read_number(&mut input); + input.next(); + let second = common::read_number(&mut input); + input.next(); + + let rule = Rule { first, second }; + rules_by_number + .entry(rule.first) + .or_default() + .push(rule.clone()); + rules_by_number.entry(rule.second).or_default().push(rule); + } + rules_by_number +} + +pub fn read_number_list(mut input: &mut Peekable>) -> Vec { + let mut numbers = Vec::::new(); + + while let Some(Ok(ch)) = input.peek() { + if ch == &b'\n' { + break; + } else if ch == &b',' { + input.next(); + continue; + } + let number = common::read_number(&mut input); + numbers.push(number); + } + numbers +} + +pub fn read_number(input: &mut Peekable>) -> Number { + let mut number: Number = 0; + while let Some(Ok(b'0'..=b'9')) = input.peek() { + number *= 10; + number += (input.next().unwrap().unwrap() - b'0') as Number; + } + number +} diff --git a/day-05-rust/src/main.rs b/day-05-rust/src/main.rs new file mode 100644 index 0000000..fb9ec3b --- /dev/null +++ b/day-05-rust/src/main.rs @@ -0,0 +1,22 @@ +mod task1; +mod task2; +mod common; + +fn main() { + let args = std::env::args().collect::>(); + + if args.len() != 3 { + eprintln!("Usage: {} <1|2> ", args[0]); + std::process::exit(1); + } + + match args[1].as_str() { + "1" => { + task1::run(std::fs::File::open(&args[2]).expect("File not found")); + } + "2" => { + task2::run(std::fs::File::open(&args[2]).expect("File not found")); + } + _ => eprintln!("Unknown task: {}", args[2]), + } +} diff --git a/day-05-rust/src/task1.rs b/day-05-rust/src/task1.rs new file mode 100644 index 0000000..66eec73 --- /dev/null +++ b/day-05-rust/src/task1.rs @@ -0,0 +1,45 @@ +use crate::common::{read_number_list, read_rules, Number}; +use std::collections::HashSet; +use std::io::Read; +use std::ops::Rem; + +pub fn run(read: R) { + let mut input = read.bytes().peekable(); + + let rules_by_number = read_rules(&mut input); + + let mut result: Number = 0; + + while let Some(Ok(ch)) = input.peek() { + if ch == &b'\n' { + input.next(); + continue; + } + + let numbers = read_number_list(&mut input); + + let rules = numbers + .iter() + .flat_map(|number| rules_by_number.get(number)) + .flatten() + .filter(|rule| numbers.contains(&rule.first) && numbers.contains(&rule.second)) + .collect::>(); + + if rules.iter().all(|rule| { + numbers + .iter() + .position(|number| *number == rule.first) + .zip(numbers.iter().position(|number| *number == rule.second)) + .map(|(first_index, second_index)| first_index < second_index) + .unwrap_or(false) + }) { + if numbers.len().rem(2) == 1 { + result += numbers[numbers.len() / 2]; + } else { + eprintln!("Length of numbers is not odd!") + } + } + } + + println!("Result {}", result); +} diff --git a/day-05-rust/src/task2.rs b/day-05-rust/src/task2.rs new file mode 100644 index 0000000..3b32e78 --- /dev/null +++ b/day-05-rust/src/task2.rs @@ -0,0 +1,86 @@ +use crate::common::{read_number_list, read_rules, Number, Rule}; +use std::collections::{HashMap, HashSet}; +use std::io::Read; +use std::ops::{Not, Rem}; + +#[derive(Debug, Default, Clone)] +struct Edges { + incoming: HashSet, + outgoing: HashSet, +} + +pub fn run(read: R) { + let mut input = read.bytes().peekable(); + + let rules_by_number = read_rules(&mut input); + + let mut result: Number = 0; + + while let Some(Ok(ch)) = input.peek() { + if ch == &b'\n' { + input.next(); + continue; + } + + let numbers = read_number_list(&mut input); + + let rules = numbers + .iter() + .flat_map(|number| rules_by_number.get(number)) + .flatten() + .filter(|rule| numbers.contains(&rule.first) && numbers.contains(&rule.second)) + .collect::>(); + + if !rules.iter().all(|rule| { + numbers + .iter() + .position(|number| *number == rule.first) + .zip(numbers.iter().position(|number| *number == rule.second)) + .map(|(first_index, second_index)| first_index < second_index) + .unwrap_or(false) + }) { + let mut edges_by_nodes = HashMap::::new(); + rules.iter().for_each(|rule| { + edges_by_nodes + .entry(rule.first) + .or_default() + .outgoing + .insert((*rule).clone()); + edges_by_nodes + .entry(rule.second) + .or_default() + .incoming + .insert((*rule).clone()); + }); + + let mut sorted_numbers = Vec::::with_capacity(numbers.len()); + while edges_by_nodes.is_empty().not() { + if let Some(start_node) = edges_by_nodes + .iter() + .filter(|(_node, edges)| edges.incoming.is_empty()) + .next() + .map(|(node, _edges)| *node) + { + sorted_numbers.push(start_node); + let edges = edges_by_nodes.remove(&start_node).unwrap(); + for outgoing in edges.outgoing { + if let Some(target_edges) = edges_by_nodes.get_mut(&outgoing.second) { + target_edges.incoming.remove(&outgoing); + } + } + } else { + eprintln!("Inconsistent situation"); + break; + } + } + + if sorted_numbers.len().rem(2) == 1 { + result += sorted_numbers[sorted_numbers.len() / 2]; + } else { + eprintln!("Line doesn't have odd length") + } + } + } + + println!("Result {}", result); +}