145 lines
4.7 KiB
Rust
145 lines
4.7 KiB
Rust
use std::cmp::Ordering;
|
|
use crate::day_solver::DaySolver;
|
|
|
|
use super::util;
|
|
|
|
pub struct Day13 {
|
|
packet_pairs: Vec<(Packet, Packet)>
|
|
}
|
|
|
|
impl Day13 {
|
|
|
|
pub fn create() -> Self {
|
|
// let lines = util::read_file("input/day13_example.txt");
|
|
let lines = util::read_file("input/day13.txt");
|
|
|
|
let mut line_iter = lines.iter();
|
|
let mut packet_pairs = Vec::new();
|
|
while let Some(line) = line_iter.next() {
|
|
if line.is_empty() {
|
|
continue
|
|
}
|
|
|
|
let left = Packet::parse(line);
|
|
let right = Packet::parse(line_iter.next().unwrap());
|
|
|
|
// println!("left: {:?}, right: {:?}", left, right);
|
|
packet_pairs.push((left, right));
|
|
}
|
|
|
|
// println!("{:?}", packet_pairs);
|
|
|
|
// Put the input into the day struct
|
|
return Day13 {
|
|
packet_pairs
|
|
}
|
|
}
|
|
|
|
fn compare(left: &Packet, right: &Packet) -> Ordering {
|
|
if let Packet::Num(n_left) = left {
|
|
if let Packet::Num(n_right) = right {
|
|
if n_left != n_right {
|
|
return if n_left < n_right { Ordering::Less } else { Ordering::Greater };
|
|
}
|
|
} else {
|
|
// The right value is a vec-packet, so we need to act like the left value is as well:
|
|
return Self::compare(&Packet::Vec(vec![Packet::Num(n_left.to_owned())]), right);
|
|
}
|
|
} else if let Packet::Vec(vec_left) = left {
|
|
// Left is a vec-packet
|
|
if let Packet::Vec(vec_right) = right {
|
|
for i in 0..vec_left.len().min(vec_right.len()) {
|
|
let comp = Self::compare(&vec_left[i], &vec_right[i]);
|
|
if comp != Ordering::Equal {
|
|
return comp
|
|
}
|
|
}
|
|
if vec_left.len() != vec_right.len() {
|
|
return if vec_left.len() < vec_right.len() { Ordering::Less } else { Ordering::Greater };
|
|
}
|
|
|
|
} else if let Packet::Num(n_right) = right {
|
|
// The left value is a vec-packet, so we need to act like the right value is as well:
|
|
return Self::compare(left, &Packet::Vec(vec![Packet::Num(n_right.to_owned())]));
|
|
}
|
|
}
|
|
|
|
return Ordering::Equal;
|
|
}
|
|
}
|
|
|
|
impl DaySolver for Day13 {
|
|
|
|
|
|
fn solve_part1(&mut self) -> String {
|
|
|
|
self.packet_pairs.iter().enumerate()
|
|
.filter_map(|(i, p)| {
|
|
let comp = Day13::compare(&p.0, &p.1);
|
|
// println!("{:?} vs {:?} is {:?}", p.0, p.1, comp);
|
|
if comp == Ordering::Less { Some(i + 1) } else { None }
|
|
})
|
|
.sum::<usize>().to_string()
|
|
}
|
|
|
|
fn solve_part2(&mut self) -> String {
|
|
|
|
let mut full_vec: Vec<Packet> = self.packet_pairs.iter()
|
|
.flat_map(|p| vec![p.0.to_owned(), p.1.to_owned()].into_iter())
|
|
.collect();
|
|
let div_packet1 = Packet::parse("[[2]]");
|
|
full_vec.push(div_packet1.to_owned());
|
|
let div_packet2 = Packet::parse("[[6]]");
|
|
full_vec.push(div_packet2.to_owned());
|
|
|
|
full_vec.sort_by(|l, r| Day13::compare(l, r));
|
|
|
|
full_vec.iter().enumerate()
|
|
.filter_map(|(i, p)| if p == &div_packet1 || p == &div_packet2 { Some(i + 1) } else { None })
|
|
.reduce(|a, b| a * b)
|
|
.unwrap()
|
|
.to_string()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
enum Packet {
|
|
Num(u8),
|
|
Vec(Vec<Packet>)
|
|
}
|
|
|
|
impl Packet {
|
|
fn parse(str: &str) -> Packet {
|
|
let (p, _) = Self::parse_internal(str);
|
|
p
|
|
}
|
|
|
|
fn parse_internal(str: &str) -> (Packet, usize) {
|
|
if str.chars().next() == Some('[') {
|
|
if str.starts_with("[]") {
|
|
// We're dealing with an empty vec:
|
|
(Packet::Vec(Vec::new()), 2)
|
|
} else {
|
|
// We're dealing with a vec
|
|
let mut idx = 0;
|
|
let mut vec_content = Vec::new();
|
|
loop {
|
|
idx += 1;
|
|
let (p, i) = Packet::parse_internal(&str[idx..]);
|
|
vec_content.push(p);
|
|
idx += i;
|
|
if str.chars().nth(idx) != Some(',') {
|
|
break;
|
|
}
|
|
};
|
|
assert_eq!(str.chars().nth(idx), Some(']'), "Vec not ending: {} at idx {}", str, idx);
|
|
(Packet::Vec(vec_content), idx + 1)
|
|
}
|
|
} else {
|
|
// We should be dealing with a number
|
|
let n_str = str.chars().take_while(|c| c.is_numeric()).collect::<String>();
|
|
let n = n_str.parse::<u8>().expect(format!("Vec is not a number: {}", str).as_str());
|
|
(Packet::Num(n), n_str.len())
|
|
}
|
|
}
|
|
} |