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