diff --git a/src/bin/d13p1.rs b/src/bin/d13p1.rs new file mode 100644 index 0000000..0644fd4 --- /dev/null +++ b/src/bin/d13p1.rs @@ -0,0 +1,14 @@ +use aoc22::{day13, util}; + +pub fn main() { + let pairs = day13::parse_pairs(&util::parse_input()); + + let mut sum = 0; + for (i, pair) in pairs.iter().enumerate() { + if pair.0 < pair.1 { + sum += i + 1; + } + } + + println!("Sum of indices of pairs in right order: {}", sum); +} diff --git a/src/day13.rs b/src/day13.rs new file mode 100644 index 0000000..52fb493 --- /dev/null +++ b/src/day13.rs @@ -0,0 +1,116 @@ +use std::cmp::Ordering; + +use itertools::{EitherOrBoth, Itertools}; + +#[derive(Debug)] +pub enum Node { + List(Vec), + Num(usize), +} + +impl PartialOrd for Node { + fn partial_cmp(&self, other: &Self) -> Option { + match self { + Node::List(l1) => match other { + Node::Num(n2) => self.partial_cmp(&Node::List(vec![Node::Num(*n2)])), + Node::List(l2) => { + for pair in l1.iter().zip_longest(l2.iter()) { + match pair { + EitherOrBoth::Both(n1, n2) => { + if n1 < n2 { + return Some(Ordering::Less); + } else if n2 < n1 { + return Some(Ordering::Greater); + } + } + EitherOrBoth::Left(_) => return Some(Ordering::Greater), + EitherOrBoth::Right(_) => return Some(Ordering::Less), + } + } + Some(Ordering::Equal) + } + }, + Node::Num(n1) => match other { + Node::Num(n2) => n1.partial_cmp(n2), + Node::List(_) => Node::List(vec![Node::Num(*n1)]).partial_cmp(other), + }, + } + } +} + +impl PartialEq for Node { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } + + fn ne(&self, other: &Self) -> bool { + !self.eq(other) + } +} + +pub fn parse_pairs(input: &String) -> Vec<(Node, Node)> { + let mut result = Vec::new(); + + for mut p in &input.lines().chunks(3) { + let first = parse_list(p.next().unwrap()).0; + let second = parse_list(p.next().unwrap()).0; + assert!(p.next().unwrap_or("").is_empty()); + + result.push((first, second)); + } + + result +} + +enum ParseState { + Idle, + InNumber, +} + +fn parse_list(line: &str) -> (Node, usize) { + assert_eq!(line.chars().next(), Some('[')); + + let mut state = ParseState::Idle; + let mut i = 1; + let mut result = Vec::new(); + + let mut num_start = 0; + while i < line.len() { + let c = line.chars().nth(i).unwrap(); + match state { + ParseState::Idle => { + if c == '[' { + let (n, inc) = parse_list(&line[i..]); + result.push(n); + i += inc; + } else if c == ']' { + // End of list reached + break; + } else if c.is_numeric() { + num_start = i; + state = ParseState::InNumber; + } else if c != ',' { + panic!("Unknown char: {}", c); + } + } + ParseState::InNumber => { + if c == ',' { + let slice = &line[num_start..i]; + result.push(Node::Num(slice.parse().unwrap())); + state = ParseState::Idle; + } else if c == ']' { + // End of list reached + let slice = &line[num_start..i]; + result.push(Node::Num(slice.parse().unwrap())); + + break; + } else if !c.is_numeric() { + panic!("Unknown digit {}", c); + } + } + } + i += 1; + } + + (Node::List(result), i) +} diff --git a/src/lib.rs b/src/lib.rs index e14c52a..78de87a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub mod day1; pub mod day10; pub mod day11; pub mod day12; +pub mod day13; pub mod day2; pub mod day3; pub mod day4;