day(13): add initial solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
6beaf1606c
commit
7f7dffe686
2 changed files with 197 additions and 0 deletions
23
samples/day13.txt
Normal file
23
samples/day13.txt
Normal 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
174
src/bin/day13.rs
Normal 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);
|
Loading…
Reference in a new issue