1
0
Fork 0

day(13): add initial solution

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-12-13 16:30:54 +01:00
parent 6beaf1606c
commit 7f7dffe686
Signed by: mfocko
GPG key ID: 7C47D46246790496
2 changed files with 197 additions and 0 deletions

23
samples/day13.txt Normal file
View file

@ -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]

174
src/bin/day13.rs Normal file
View file

@ -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<Pair>;
type Output = usize;
#[derive(Debug, Clone, PartialEq, Eq)]
enum Packet {
Integer(i32),
List(Vec<Packet>),
}
impl Packet {
fn is_integer(&self) -> bool {
matches!(self, Packet::Integer(_))
}
}
impl PartialOrd for Packet {
fn partial_cmp(&self, right: &Self) -> Option<Ordering> {
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<Self, Self::Err> {
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<Self, Self::Err> {
let (l, r) = s.split('\n').collect_tuple().unwrap();
Ok(Pair(l.parse()?, r.parse()?))
}
}
struct Day13;
impl Solution<Input, Output> for Day13 {
fn parse_input<P: AsRef<Path>>(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);