use nom::{ branch::alt, bytes::complete::tag, character::complete::{line_ending, u32}, combinator::map, multi::{separated_list0, separated_list1}, sequence::{delimited, pair, preceded}, IResult, }; use std::{cmp::Ordering, fs}; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_13.txt")?; let message = EncodedMessage::parser(&input).unwrap().1; dbg!(message.ordered_index_sum()); dbg!(message.decoder_key()); Ok(()) } #[derive(Debug)] struct EncodedMessage { message_pairs: Vec<(Message, Message)>, ordered_indices: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] enum Message { List(Vec), Value(u32), } impl EncodedMessage { fn parser(input: &str) -> IResult<&str, Self> { map( separated_list1( pair(line_ending, line_ending), pair(Message::parser, preceded(line_ending, Message::parser)), ), EncodedMessage::new, )(input) } fn new(message_pairs: Vec<(Message, Message)>) -> EncodedMessage { let mut ordered_indices = Vec::new(); for (i, (left, right)) in message_pairs.iter().enumerate() { if left <= right { ordered_indices.push(i + 1); } } EncodedMessage { message_pairs, ordered_indices, } } fn ordered_index_sum(&self) -> usize { self.ordered_indices.iter().sum() } fn decoder_key(&self) -> usize { let mut all_packets: Vec = self .message_pairs .iter() .flat_map(|(left, right)| [left.clone(), right.clone()]) .collect(); let divider_1 = Message::List(vec![Message::List(vec![Message::Value(2)])]); let divider_2 = Message::List(vec![Message::List(vec![Message::Value(6)])]); all_packets.push(divider_1.clone()); all_packets.push(divider_2.clone()); all_packets.sort(); let index_1 = all_packets.iter().position(|m| *m == divider_1).unwrap() + 1; let index_2 = all_packets.iter().position(|m| *m == divider_2).unwrap() + 1; index_1 * index_2 } } impl Message { fn parser(input: &str) -> IResult<&str, Self> { alt(( map(u32, Message::Value), map( delimited( tag("["), separated_list0(tag(","), Message::parser), tag("]"), ), Message::List, ), ))(input) } } impl PartialOrd for Message { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Message { fn cmp(&self, other: &Self) -> Ordering { match (self, other) { (Message::Value(left), Message::Value(right)) => left.cmp(right), (Message::List(left), Message::List(right)) => { for i in 0..left.len() { if i == right.len() { return Ordering::Greater; } let inner_ord = left[i].cmp(&right[i]); if inner_ord != Ordering::Equal { return inner_ord; } } left.len().cmp(&right.len()) } (Message::Value(left), Message::List(right)) => { if right.len() == 0 { Ordering::Greater } else { let inner_ord = Message::Value(*left).cmp(&right[0]); if inner_ord != Ordering::Equal { inner_ord } else { 1.cmp(&right.len()) } } } (Message::List(left), Message::Value(right)) => { if left.len() == 0 { Ordering::Less } else { let inner_ord = left[0].cmp(&Message::Value(*right)); if inner_ord != Ordering::Equal { inner_ord } else { left.len().cmp(&1) } } } } } }