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