Day five
This commit is contained in:
1
day-05-rust/.gitignore
vendored
Normal file
1
day-05-rust/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
target/
|
||||
7
day-05-rust/Cargo.lock
generated
Normal file
7
day-05-rust/Cargo.lock
generated
Normal file
@@ -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"
|
||||
6
day-05-rust/Cargo.toml
Normal file
6
day-05-rust/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "day-05-rust"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
60
day-05-rust/src/common.rs
Normal file
60
day-05-rust/src/common.rs
Normal file
@@ -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<R: Read>(mut input: &mut Peekable<Bytes<R>>) -> HashMap<Number, Vec<Rule>> {
|
||||
let mut rules_by_number = HashMap::<Number, Vec<Rule>>::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<R: Read>(mut input: &mut Peekable<Bytes<R>>) -> Vec<Number> {
|
||||
let mut numbers = Vec::<Number>::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<R: Read>(input: &mut Peekable<Bytes<R>>) -> 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
|
||||
}
|
||||
22
day-05-rust/src/main.rs
Normal file
22
day-05-rust/src/main.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
mod task1;
|
||||
mod task2;
|
||||
mod common;
|
||||
|
||||
fn main() {
|
||||
let args = std::env::args().collect::<Vec<String>>();
|
||||
|
||||
if args.len() != 3 {
|
||||
eprintln!("Usage: {} <1|2> <input file>", 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]),
|
||||
}
|
||||
}
|
||||
45
day-05-rust/src/task1.rs
Normal file
45
day-05-rust/src/task1.rs
Normal file
@@ -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<R: Read>(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::<HashSet<_>>();
|
||||
|
||||
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);
|
||||
}
|
||||
86
day-05-rust/src/task2.rs
Normal file
86
day-05-rust/src/task2.rs
Normal file
@@ -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<Rule>,
|
||||
outgoing: HashSet<Rule>,
|
||||
}
|
||||
|
||||
pub fn run<R: Read>(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::<HashSet<_>>();
|
||||
|
||||
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::<Number, Edges>::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::<Number>::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);
|
||||
}
|
||||
Reference in New Issue
Block a user