From 7f7dffe68688c64a8aa8dad813126f9169ecaa8a Mon Sep 17 00:00:00 2001 From: Matej Focko Date: Tue, 13 Dec 2022 16:30:54 +0100 Subject: [PATCH] day(13): add initial solution Signed-off-by: Matej Focko --- samples/day13.txt | 23 ++++++ src/bin/day13.rs | 174 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 samples/day13.txt create mode 100644 src/bin/day13.rs diff --git a/samples/day13.txt b/samples/day13.txt new file mode 100644 index 0000000..27c8912 --- /dev/null +++ b/samples/day13.txt @@ -0,0 +1,23 @@ +[1,1,3,1,1] +[1,1,5,1,1] + +[[1],[2,3,4]] +[[1],4] + +[9] +[[8,7,6]] + +[[4,4],4,4] +[[4,4],4,4,4] + +[7,7,7,7] +[7,7,7] + +[] +[3] + +[[[]]] +[[]] + +[1,[2,[3,[4,[5,6,7]]]],8,9] +[1,[2,[3,[4,[5,6,0]]]],8,9] \ No newline at end of file diff --git a/src/bin/day13.rs b/src/bin/day13.rs new file mode 100644 index 0000000..c2dc234 --- /dev/null +++ b/src/bin/day13.rs @@ -0,0 +1,174 @@ +use std::{cmp::Ordering, fmt::Display, str::FromStr}; + +use aoc_2022::*; + +use color_eyre::Report; +use itertools::Itertools; +// use tracing::debug; + +type Input = Vec; +type Output = usize; + +#[derive(Debug, Clone, PartialEq, Eq)] +enum Packet { + Integer(i32), + List(Vec), +} + +impl Packet { + fn is_integer(&self) -> bool { + matches!(self, Packet::Integer(_)) + } +} + +impl PartialOrd for Packet { + fn partial_cmp(&self, right: &Self) -> Option { + match (self, right) { + (Packet::Integer(l), Packet::Integer(r)) => Some(l.cmp(r)), + (Packet::List(l), Packet::List(r)) => { + if let Some(x) = l + .iter() + .zip(r) + .map(|(l, r)| l.partial_cmp(r).unwrap()) + .find(|x| x.is_ne()) + { + Some(x) + } else { + Some(l.len().cmp(&r.len())) + } + } + (l, r) => { + if l.is_integer() { + Packet::List(vec![l.clone()]).partial_cmp(r) + } else { + l.partial_cmp(&Packet::List(vec![r.clone()])) + } + } + } + } +} + +impl Ord for Packet { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap() + } +} + +impl Display for Packet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Packet::Integer(x) => write!(f, "{x}"), + Packet::List(lst) => write!(f, "[{}]", lst.iter().map(|p| format!("{p}")).join(",")), + } + } +} + +impl FromStr for Packet { + type Err = Report; + + fn from_str(s: &str) -> Result { + fn parse(s: &str, mut i: usize) -> Result<(usize, Packet), Report> { + // try to parse an integer + let num = s + .chars() + .skip(i) + .take_while(|c| c.is_ascii_digit()) + .join(""); + if !num.is_empty() { + let integer = num.parse()?; + return Ok((i + num.len(), Packet::Integer(integer))); + } + + // we got a '[' and we should traverse the contents of the list + i += 1; + + let mut packets = Vec::new(); + while i < s.len() && &s[i..i + 1] != "]" { + if &s[i..i + 1] == "," { + // skipping commas + i += 1; + } + + let (new_i, packet) = parse(s, i)?; + + i = new_i; + packets.push(packet); + } + + Ok((i + 1, Packet::List(packets))) + } + + let parsed_packet = parse(s, 0)?; + Ok(parsed_packet.1) + } +} + +#[derive(Debug)] +struct Pair(Packet, Packet); + +impl Pair { + fn right_order(&self) -> Ordering { + let Pair(l, r) = self; + l.cmp(r) + } +} + +impl FromStr for Pair { + type Err = Report; + + fn from_str(s: &str) -> Result { + let (l, r) = s.split('\n').collect_tuple().unwrap(); + Ok(Pair(l.parse()?, r.parse()?)) + } +} + +struct Day13; +impl Solution for Day13 { + fn parse_input>(pathname: P) -> Input { + file_to_string(pathname) + .trim_end_matches('\n') + .split("\n\n") + .map(|p| p.parse().unwrap()) + .collect_vec() + } + + fn part_1(input: &Input) -> Output { + (1..) + .zip(input.iter()) + .filter(|(_, p)| p.right_order().is_lt()) + .map(|(i, _)| i) + .sum() + } + + fn part_2(input: &Input) -> Output { + let dividers = vec![ + Packet::List(vec![Packet::List(vec![Packet::Integer(2)])]), + Packet::List(vec![Packet::List(vec![Packet::Integer(6)])]), + ]; + + let mut packets = input + .iter() + .flat_map(|Pair(l, r)| vec![l.clone(), r.clone()]) + .collect_vec(); + packets.append(&mut dividers.clone()); + + packets.sort(); + + // for p in &packets { + // debug!("{}", p); + // } + + (1..) + .zip(packets.iter()) + .filter(|(_, p)| dividers.contains(p)) + .map(|(i, _)| i) + .product() + } +} + +fn main() -> Result<()> { + // Day13::run("sample") + Day13::main() +} + +test_sample!(day_13, Day13, 13, 140);