134 lines
3.6 KiB
Rust
134 lines
3.6 KiB
Rust
use std::fs;
|
|
use std::str::FromStr;
|
|
|
|
fn main() {
|
|
const FILE_PATH: &str = "input";
|
|
println!("Hi this is the thirteenth day of AOC2022, first we will read the file {}", FILE_PATH);
|
|
let contents = fs::read_to_string(FILE_PATH)
|
|
.expect("Should have been able to read the file");
|
|
|
|
let mut mes = parse(&contents);
|
|
println!("The sum of indexes of ordered packets is: {}", mes.chunks(2).map(|l| l[0] < l[1]).enumerate().filter(|(_, b)| *b).map(|(i,_)| i+1).sum::<usize>());
|
|
mes.push(parse_line("[[2]]"));
|
|
mes.push(parse_line("[[6]]"));
|
|
mes.sort();
|
|
println!("The distress decoder key is: {}", mes.iter().enumerate().filter(|(_ ,i)| **i == parse_line("[[2]]") || **i == parse_line("[[6]]")).map(|(n,_)| n+1).fold(1, |x,y| x*y));
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
enum Item{
|
|
Num(i32),
|
|
List(Vec<Item>)
|
|
}
|
|
use std::cmp::Ordering;
|
|
impl PartialOrd for Item{
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
match self {
|
|
Item::Num(s) => {
|
|
match other {
|
|
Item::Num(o) => {
|
|
s.partial_cmp(o)
|
|
},
|
|
Item::List(_) => {
|
|
(Item::List(vec![self.clone()])).partial_cmp(other)
|
|
},
|
|
}
|
|
},
|
|
Item::List(s) => {
|
|
match other {
|
|
Item::List(o) => {
|
|
s.partial_cmp(o)
|
|
},
|
|
Item::Num(_) => {
|
|
self.partial_cmp(&Item::List(vec![other.clone()]))
|
|
},
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|
|
impl Ord for Item {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.partial_cmp(other).expect("Order must exist")
|
|
}
|
|
}
|
|
|
|
fn parse_line(s: &str) -> Vec<Item>{
|
|
let mut out = Vec::new();
|
|
let mut s: Vec<_> = s[1..s.len()-1].chars().collect();
|
|
let mut construct = String::new();
|
|
let mut inside = 0;
|
|
while s.len() > 0 {
|
|
let c = s[0];
|
|
if c == '['{
|
|
inside +=1;
|
|
construct.push(s.remove(0));
|
|
} else if c == ']' {
|
|
inside -=1;
|
|
construct.push(s.remove(0));
|
|
if inside == 0 {
|
|
out.push(Item::List(parse_line(&construct)));
|
|
construct = String::new();
|
|
}
|
|
} else if c == ','{
|
|
if construct.len() > 0 && inside == 0 {
|
|
out.push(Item::Num(i32::from_str(&construct).expect("NaN")));
|
|
construct = String::new();
|
|
}
|
|
if inside > 0 {
|
|
construct.push(c);
|
|
}
|
|
s.remove(0);
|
|
} else {
|
|
construct.push(s.remove(0));
|
|
}
|
|
}
|
|
if construct.len() > 0 {
|
|
out.push(Item::Num(i32::from_str(&construct).expect("NaN")));
|
|
}
|
|
out
|
|
}
|
|
|
|
fn parse(s: &str) -> Vec<Vec<Item>>{
|
|
s.lines().filter(|l| *l !="").map(parse_line).collect()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
const INPUT: &str = r#"[1,1,3,1,1]
|
|
[1,1,5,1,1]
|
|
|
|
[[1],[2,3,4]]
|
|
[[1],4]
|
|
|
|
[9]
|
|
[[8,7,6]]
|
|
|
|
[[4,4],4,4]
|
|
[[4,4],4,4,4]
|
|
|
|
[7,7,7,7]
|
|
[7,7,7]
|
|
|
|
[]
|
|
[3]
|
|
|
|
[[[]]]
|
|
[[]]
|
|
|
|
[1,[2,[3,[4,[5,6,7]]]],8,9]
|
|
[1,[2,[3,[4,[5,6,0]]]],8,9]"#;
|
|
use super::*;
|
|
#[test]
|
|
fn lists1() {
|
|
assert_eq!(parse(INPUT).chunks(2).map(|l| l[0] < l[1]).enumerate().filter(|(_, b)| *b).map(|(i,_)| i+1).sum::<usize>(), 13);
|
|
}
|
|
#[test]
|
|
fn lists2() {
|
|
let mut mes = parse(INPUT);
|
|
mes.push(parse_line("[[2]]"));
|
|
mes.push(parse_line("[[6]]"));
|
|
mes.sort();
|
|
assert_eq!(mes.iter().enumerate().filter(|(_ ,i)| **i == parse_line("[[2]]") || **i == parse_line("[[6]]")).map(|(n,_)| n+1).fold(1, |x,y| x*y), 140);
|
|
}
|
|
} |