2022 Day 13
This commit is contained in:
parent
a480259cd4
commit
1f5d80d7bc
1 changed files with 222 additions and 0 deletions
222
2022/src/bin/day13.rs
Normal file
222
2022/src/bin/day13.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
use std::{cmp::Ordering, fmt::Display, iter::Peekable, str::Chars};
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../../input/day13.txt");
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let packets = parse(INPUT);
|
||||||
|
|
||||||
|
println!("{:?}", part1(&packets));
|
||||||
|
println!("{:?}", part2(&packets));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(packets: &[Packet]) -> usize {
|
||||||
|
packets
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, packet)| {
|
||||||
|
if packet.left < packet.right {
|
||||||
|
Some(i + 1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(packets: &[Packet]) -> usize {
|
||||||
|
let p2 = Data::parse("[[2]]");
|
||||||
|
let p6 = Data::parse("[[6]]");
|
||||||
|
|
||||||
|
let mut packets: Vec<Data> = packets
|
||||||
|
.iter()
|
||||||
|
.flat_map(|p| vec![p.left.clone(), p.right.clone()])
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
packets.sort();
|
||||||
|
|
||||||
|
let mut i2 = 1; // 1-indexing
|
||||||
|
let mut i6 = 2; // 1-indexing + p2 placeholder
|
||||||
|
|
||||||
|
for p in packets {
|
||||||
|
if p < p2 {
|
||||||
|
i2 += 1;
|
||||||
|
}
|
||||||
|
if p < p6 {
|
||||||
|
i6 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i2 * i6
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &str) -> Vec<Packet> {
|
||||||
|
aoc::blocks(input)
|
||||||
|
.map(|block| {
|
||||||
|
let lines: Vec<&str> = aoc::lines(block).collect();
|
||||||
|
let left = Data::parse(lines[0]);
|
||||||
|
let right = Data::parse(lines[1]);
|
||||||
|
|
||||||
|
Packet { left, right }
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Packet {
|
||||||
|
left: Data,
|
||||||
|
right: Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Data {
|
||||||
|
Value(u32),
|
||||||
|
List(Vec<Data>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
fn parse(line: &str) -> Self {
|
||||||
|
let mut chars = line.chars().peekable();
|
||||||
|
let list = Data::parse_list(&mut chars);
|
||||||
|
assert!(chars.peek().is_none());
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_num(chars: &mut Peekable<Chars>) -> Self {
|
||||||
|
let mut digits = String::new();
|
||||||
|
while let Some(c) = chars.peek() {
|
||||||
|
if c.is_ascii_digit() {
|
||||||
|
digits += &chars.next().unwrap().to_string();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::Value(digits.parse().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_list(chars: &mut Peekable<Chars>) -> Self {
|
||||||
|
assert!(chars.next() == Some('['));
|
||||||
|
|
||||||
|
let mut list = vec![];
|
||||||
|
while let Some(c) = chars.peek() {
|
||||||
|
let val = match c {
|
||||||
|
']' => {
|
||||||
|
chars.next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
'[' => Self::parse_list(chars),
|
||||||
|
',' => {
|
||||||
|
chars.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => Self::parse_num(chars),
|
||||||
|
};
|
||||||
|
list.push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::List(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
fn lift(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Data::List(_) => self.clone(),
|
||||||
|
Data::Value(_) => Data::List(vec![self.clone()]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zip_cmp(l: &[Data], r: &[Data]) -> Ordering {
|
||||||
|
let mut ll = l.iter();
|
||||||
|
let mut rr = r.iter();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match (ll.next(), rr.next()) {
|
||||||
|
(None, None) => return Ordering::Equal,
|
||||||
|
(None, Some(_)) => return Ordering::Less,
|
||||||
|
(Some(_), None) => return Ordering::Greater,
|
||||||
|
(Some(lll), Some(rrr)) => {
|
||||||
|
let d = lll.cmp(rrr);
|
||||||
|
if d != Ordering::Equal {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Data {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.cmp(other) == Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Data {}
|
||||||
|
|
||||||
|
impl PartialOrd for Data {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Data {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
match (self, other) {
|
||||||
|
(Data::Value(l), Data::Value(r)) => l.cmp(r),
|
||||||
|
(Data::List(l), Data::List(r)) => Data::zip_cmp(l, r),
|
||||||
|
|
||||||
|
(Data::Value(_), Data::List(_)) => self.lift().cmp(other),
|
||||||
|
(Data::List(_), Data::Value(_)) => self.cmp(&other.lift()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Data {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Data::Value(v) => write!(f, "{}", v),
|
||||||
|
Data::List(l) => {
|
||||||
|
let items = l
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",");
|
||||||
|
|
||||||
|
write!(f, "[{}]", items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test1() {
|
||||||
|
// let line = "[[[[2],9,1,[2,2,4,8]],[1,8,8],9,[7,2,[7,0,1],0,[10,9,10,3]]]]";
|
||||||
|
// let line = "[[[2],9,1,[2,2,4,8]],[1,8,8],9,[7,2,[7,0,1],0,[10,9,10,3]]]";
|
||||||
|
// let line = "[[2],9,1,[2,2,4,8]],[1,8,8],9,[7,2,[7,0,1],0,[10,9,10,3]]";
|
||||||
|
// let line = "[[2],9,1,[2,2,4,8]]";
|
||||||
|
let line = "[[2],9]";
|
||||||
|
let data = Data::parse(line);
|
||||||
|
|
||||||
|
assert_eq!(data.to_string(), line);
|
||||||
|
|
||||||
|
use Data::{List, Value};
|
||||||
|
|
||||||
|
assert_eq!(data, List(vec![List(vec![Value(2)]), Value(9)]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parser() {
|
||||||
|
let out = parse(INPUT)
|
||||||
|
.iter()
|
||||||
|
.map(|p| format!("{}\n{}", p.left, p.right))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n\n")
|
||||||
|
+ "\n";
|
||||||
|
assert_eq!(out, INPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue