use std::cmp::Ordering; #[path = "../lib.rs"] mod lib; enum Item { List(Vec), Number(u8), } impl Ord for Item { fn cmp(&self, other: &Self) -> Ordering { return match (self, other) { (Item::Number(a), Item::Number(b)) => a.cmp(b), (Item::List(a), Item::List(b)) => { for i in 0..a.len() { if i >= b.len() { return Ordering::Greater; } let c = a[i].cmp(&b[i]); if c != Ordering::Equal { return c; } } if a.len() == b.len() { return Ordering::Equal; } else { return Ordering::Less; } }, (_, Item::Number(i)) => self.cmp(&Item::List(vec![Item::Number(*i)])), (Item::Number(i), _) => other.cmp(&Item::List(vec![Item::Number(*i)])).reverse(), }; } } impl PartialOrd for Item { fn partial_cmp(&self, other: &Item) -> Option { Some(self.cmp(other)) } } impl PartialEq for Item { fn eq(&self, other: &Self) -> bool { return self.cmp(other) == Ordering::Equal; } } impl Eq for Item {} fn _parse_signal(s: String) -> (Item, String) { if s.starts_with("[") { let mut rest = s[1..].to_string(); let mut children = vec![]; if rest.starts_with("]") { return (Item::List(children), rest[1..].to_string()); } loop { let (child, tail) = _parse_signal(rest); children.push(child); if tail.starts_with("]") { rest = tail[1..].to_string(); break; } else { assert!(tail.starts_with(",")); rest = tail[1..].to_string(); } } return (Item::List(children), rest); } else { let a = s.find("]").unwrap_or(s.len()); let b = s.find(",").unwrap_or(s.len()); let end = a.min(b); let value = s[..end].parse().unwrap(); let rest = s[end..].to_string(); return (Item::Number(value), rest); } } fn parse_signal(s: String) -> Item { let (result, rest) = _parse_signal(s); assert_eq!(rest, ""); return result; } fn get_signals() -> Vec { let mut signals = vec![]; for line in lib::iter_input() { if line != "" { signals.push(parse_signal(line)); } } return signals; } fn part1(signals: &Vec) -> usize { let mut sum = 0; for i in 0..(signals.len() / 2) { let left = &signals[i * 2]; let right = &signals[i * 2 + 1]; if left < right { sum += i + 1; } } return sum; } fn part2(signals: &Vec) -> usize { let a = parse_signal("[[2]]".to_string()); let ai = signals.iter().filter(|x| **x < a).count() + 1; let b = parse_signal("[[6]]".to_string()); let bi = signals.iter().filter(|x| **x < b).count() + 1; return ai.min(bi) * (ai.max(bi) + 1) } fn main() { let signals = get_signals(); println!("part1: {}", part1(&signals)); println!("part2: {}", part2(&signals)); }