// 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)),
}
}
}