|
@@ -0,0 +1,149 @@
|
|
|
|
+
|
|
|
|
+#[derive(Clone, Debug)]
|
|
|
|
+pub enum PacketVal {
|
|
|
|
+ scalar(u32),
|
|
|
|
+ list(Vec<PacketVal>)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub enum Cmp {
|
|
|
|
+ good,
|
|
|
|
+ bad,
|
|
|
|
+ idk
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl PacketVal {
|
|
|
|
+ pub fn append(&mut self, val: PacketVal) {
|
|
|
|
+ match self {
|
|
|
|
+ PacketVal::list(l) => l.push(val),
|
|
|
|
+ _ => panic!("Cannot append to a scalar!")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn lst_to_lst(left: &Vec<PacketVal>, other: &Vec<PacketVal>, skip_check: bool) -> Cmp {
|
|
|
|
+ for (l, r) in left.iter().zip(other.iter()) {
|
|
|
|
+ match l.lt(r) {
|
|
|
|
+ Cmp::good => return Cmp::good,
|
|
|
|
+ Cmp::bad => return Cmp::bad,
|
|
|
|
+ Cmp::idk => continue,
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if left.len() < other.len() {
|
|
|
|
+ return Cmp::good
|
|
|
|
+ } else if left.len() == other.len() {
|
|
|
|
+ // println!("moo");
|
|
|
|
+ return Cmp::idk
|
|
|
|
+ } else {
|
|
|
|
+ return Cmp::bad
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn list_cmp(left: &Vec<PacketVal>, other: &PacketVal) -> Cmp {
|
|
|
|
+ match other {
|
|
|
|
+ PacketVal::list(l) => PacketVal::lst_to_lst(left, l, false),
|
|
|
|
+ PacketVal::scalar(s) => PacketVal::lst_to_lst(left, &[PacketVal::scalar(*s)].to_vec(), true)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn scalar_cmp(s: u32, other: &PacketVal) -> Cmp {
|
|
|
|
+ match other {
|
|
|
|
+ PacketVal::scalar(r) => if s < *r { Cmp::good } else if s == *r { Cmp::idk } else { Cmp::bad },
|
|
|
|
+ PacketVal::list(l) => PacketVal::lst_to_lst(&[PacketVal::scalar(s)].to_vec(), l, true),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn lt(&self, other: &PacketVal) -> Cmp {
|
|
|
|
+ match &self {
|
|
|
|
+ &PacketVal::scalar(s) => PacketVal::scalar_cmp(*s, other),
|
|
|
|
+ &PacketVal::list(l) => PacketVal::list_cmp(l, other),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+pub fn parse_line(line: &str) -> PacketVal {
|
|
|
|
+ let mut pack_stack: Vec<PacketVal> = Vec::new();
|
|
|
|
+ let mut char = line.chars().peekable();
|
|
|
|
+
|
|
|
|
+ while let Some(curr_char) = char.next() {
|
|
|
|
+ if curr_char == '[' {
|
|
|
|
+ pack_stack.push(PacketVal::list(Vec::new()));
|
|
|
|
+ } else if curr_char == ']' {
|
|
|
|
+ let popped = pack_stack.pop().unwrap();
|
|
|
|
+ if pack_stack.len() == 0 {
|
|
|
|
+ return popped;
|
|
|
|
+ }
|
|
|
|
+ pack_stack.last_mut().unwrap().append(popped);
|
|
|
|
+ } else if curr_char.is_digit(10) {
|
|
|
|
+ if char.peek().unwrap() == &'0' {
|
|
|
|
+ pack_stack.last_mut().unwrap().append(PacketVal::scalar(10));
|
|
|
|
+ char.next();
|
|
|
|
+ } else {
|
|
|
|
+ let digi = curr_char.to_digit(10).unwrap();
|
|
|
|
+ let pv = PacketVal::scalar(digi);
|
|
|
|
+ let mut thing = pack_stack.pop().unwrap();
|
|
|
|
+ thing.append(pv);
|
|
|
|
+ pack_stack.push(thing);
|
|
|
|
+ }
|
|
|
|
+ } else if curr_char == ',' {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ unreachable!()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub fn part_one(input: &str) -> Option<u32> {
|
|
|
|
+ let mut lines = input.lines();
|
|
|
|
+ let mut count = 0;
|
|
|
|
+ let mut idx = 1;
|
|
|
|
+
|
|
|
|
+ loop {
|
|
|
|
+ let left_line = lines.next().unwrap();
|
|
|
|
+ let left = parse_line(left_line);
|
|
|
|
+ // println!("l: {:?}", left);
|
|
|
|
+ let right_line = lines.next().unwrap();
|
|
|
|
+ let right = parse_line(right_line);
|
|
|
|
+ // println!("r: {:?}", right);
|
|
|
|
+
|
|
|
|
+ match left.lt(&right) {
|
|
|
|
+ Cmp::good => count += idx,
|
|
|
|
+ Cmp::bad => {},
|
|
|
|
+ Cmp::idk => println!("yo idx {} is weird", idx)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ idx += 1;
|
|
|
|
+ match lines.next() {
|
|
|
|
+ Some(_) => continue,
|
|
|
|
+ _ => break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Some(count)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub fn part_two(input: &str) -> Option<u32> {
|
|
|
|
+ None
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn main() {
|
|
|
|
+ let input = &advent_of_code::read_file("inputs", 13);
|
|
|
|
+ advent_of_code::solve!(1, part_one, input);
|
|
|
|
+ advent_of_code::solve!(2, part_two, input);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(test)]
|
|
|
|
+mod tests {
|
|
|
|
+ use super::*;
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn test_part_one() {
|
|
|
|
+ let input = advent_of_code::read_file("examples", 13);
|
|
|
|
+ assert_eq!(part_one(&input), Some(13));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn test_part_two() {
|
|
|
|
+ let input = advent_of_code::read_file("examples", 13);
|
|
|
|
+ assert_eq!(part_two(&input), None);
|
|
|
|
+ }
|
|
|
|
+}
|