Files
aoc2022/src/day13.rs
2022-12-13 23:03:59 +01:00

139 lines
3.3 KiB
Rust

use std::cmp::Ordering;
use std::fmt::{Debug, Formatter};
use itertools::Itertools;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete;
use nom::character::complete::newline;
use nom::multi::{many1, separated_list0, separated_list1};
use nom::sequence::delimited;
use nom::{IResult, Parser};
pub fn process_part_1(input: &str) -> usize {
let packets = parse_input(input).unwrap().1;
packets
.iter()
.tuples::<(_, _)>()
.enumerate()
.filter_map(|(i, (a, b))| match a.cmp(b) {
Ordering::Less => Some(i + 1),
Ordering::Equal => panic!("oh no"),
_ => None,
})
.sum()
}
pub fn process_part_2(input: &str) -> usize {
let packets = parse_input(input).unwrap().1;
let div_2 = Packet::List(vec![Packet::List(vec![Packet::Value(2)])]);
let div_6 = Packet::List(vec![Packet::List(vec![Packet::Value(6)])]);
packets
.iter()
.chain([&div_2, &div_6])
.sorted()
.enumerate()
.filter(|&(_i, item)| item == &div_2 || item == &div_6)
.map(|(i, _)| i + 1)
.product()
}
#[derive(Clone)]
enum Packet {
List(Vec<Packet>),
Value(u32),
}
impl Debug for Packet {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Packet::List(v) => write!(f, "{v:?}"),
Packet::Value(v) => write!(f, "{v}"),
}
}
}
impl Eq for Packet {}
impl PartialEq<Self> for Packet {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Packet::Value(a), Packet::Value(b)) => a == b,
(Packet::List(a), Packet::List(b)) => a == b,
(Packet::Value(a), Packet::List(b)) => &vec![Packet::Value(*a)] == b,
(Packet::List(a), Packet::Value(b)) => a == &vec![Packet::Value(*b)],
}
}
}
impl PartialOrd<Self> for Packet {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Packet {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Packet::Value(a), Packet::Value(b)) => a.cmp(b),
(Packet::List(a), Packet::List(b)) => a.cmp(b),
(Packet::Value(a), Packet::List(b)) => vec![Packet::Value(*a)].cmp(b),
(Packet::List(a), Packet::Value(b)) => a.cmp(&vec![Packet::Value(*b)]),
}
}
}
// I originally parsed tuples but for part 2 I needed the full list without tuples.
// so lets just parse without. We'll just tuple-ify the iterator afterwards.
fn parse_input(input: &str) -> IResult<&str, Vec<Packet>> {
separated_list1(many1(newline), parse_packet)(input)
}
fn parse_packet(input: &str) -> IResult<&str, Packet> {
alt((
complete::u32.map(Packet::Value),
delimited(tag("["), separated_list0(tag(","), parse_packet), tag("]")).map(Packet::List),
))(input)
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "[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]";
#[test]
fn day1() {
assert_eq!(process_part_1(INPUT), 13);
}
#[test]
fn day2() {
assert_eq!(process_part_2(INPUT), 140);
}
}