// Copyright 2022 Christian Ulrich // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . use std::cmp::{Ordering, PartialOrd}; use std::io; #[derive(Debug, PartialEq, Clone)] pub enum Token { Integer(u64), List(Vec), } pub struct PacketPairs {} impl Token { fn parse_integer(input: &str) -> Result { Ok(Self::Integer( input.parse().map_err(|_| "cannot parse integer")?, )) } fn parse_list(input: &str) -> Result { let mut elements = Vec::new(); let mut element = String::new(); let mut bracket_counter = 0; for c in input.chars() { match c { ']' if { bracket_counter > 0 } => { element.push(c); bracket_counter -= 1; } '[' => { element.push(c); bracket_counter += 1; } ',' if { bracket_counter == 0 } => { elements.push(Self::from_str(&element)?); element.clear(); } _ => element.push(c), } } if element.len() > 0 { elements.push(Self::from_str(&element)?); } Ok(Self::List(elements)) } pub fn from_str(input: &str) -> Result { let input = input.trim(); if input.starts_with('[') && input.ends_with(']') { Self::parse_list(&input[1..input.len() - 1]) } else { Self::parse_integer(input) } } } impl PartialOrd for Token { fn partial_cmp(&self, other: &Self) -> Option { type T = Token; match (self, other) { (T::Integer(a), T::Integer(b)) => a.partial_cmp(b), (T::List(a), T::List(b)) => { let common_len = usize::min(a.len(), b.len()); for (left, right) in Iterator::zip(a[..common_len].iter(), b[..common_len].iter()) { if left > right { return Some(Ordering::Greater); } if left < right { return Some(Ordering::Less); } } if a.len() > common_len { return Some(Ordering::Greater); } if b.len() > common_len { return Some(Ordering::Less); } Some(Ordering::Equal) } (T::List(_), T::Integer(_)) => self.partial_cmp(&T::List(vec![other.clone()])), (T::Integer(_), T::List(_)) => T::List(vec![self.clone()]).partial_cmp(other), } } } pub fn packet_pairs() -> PacketPairs { PacketPairs {} } impl Iterator for PacketPairs { type Item = Result<(Token, Token), &'static str>; fn next(&mut self) -> Option { const ERROR: &str = "cannot parse packet pair"; let left = match io::stdin().lines().next()?.unwrap().as_str() { "" => return None, line => Token::from_str(&line), }; let right = match io::stdin().lines().next()?.unwrap().as_str() { "" => return None, line => Token::from_str(&line), }; match io::stdin().lines().next()?.unwrap().as_str() { "" => match (left, right) { (Ok(left), Ok(right)) => Some(Ok((left, right))), e => { println!("{:?}", e); Some(Err(ERROR)) } }, _ => Some(Err(ERROR)), } } }