day 13
This commit is contained in:
138
src/day13.rs
Normal file
138
src/day13.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user