summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--18/Cargo.toml17
-rw-r--r--18/build.rs5
-rw-r--r--18/input100
-rw-r--r--18/src/expression.lalrpop34
-rw-r--r--18/src/main.rs363
-rw-r--r--18/src/types.rs32
-rw-r--r--18/tests/.main.rs.swnbin0 -> 12288 bytes
-rw-r--r--18/tests/main.rs19
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
10 files changed, 581 insertions, 0 deletions
diff --git a/18/Cargo.toml b/18/Cargo.toml
new file mode 100644
index 0000000..d5e4d18
--- /dev/null
+++ b/18/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "advent_18"
+version = "0.1.0"
+authors = ["Irene Knapp <ireneista@gmail.com>"]
+edition = "2018"
+
+[dependencies]
+advent_lib = { path = "../lib" }
+lalrpop-util = "0.19"
+
+[dev-dependencies]
+assert_cmd = "0.10"
+lalrpop = { version = "0.19", features = [ "lexer" ] }
+
+[build-dependencies]
+lalrpop = { version = "0.19", features = [ "lexer" ] }
+
diff --git a/18/build.rs b/18/build.rs
new file mode 100644
index 0000000..23c7d3f
--- /dev/null
+++ b/18/build.rs
@@ -0,0 +1,5 @@
+extern crate lalrpop;
+
+fn main() {
+    lalrpop::process_root().unwrap();
+}
diff --git a/18/input b/18/input
new file mode 100644
index 0000000..ccdfb2b
--- /dev/null
+++ b/18/input
@@ -0,0 +1,100 @@
+[2,[0,[9,[5,9]]]]
+[[2,[1,8]],3]
+[[[[7,2],6],[[7,8],3]],[9,[[6,9],2]]]
+[[[[7,2],[9,8]],7],[4,[[2,2],[5,0]]]]
+[[8,[2,2]],[5,[9,[4,9]]]]
+[[[[6,2],[4,8]],5],0]
+[[3,[3,[6,6]]],[6,9]]
+[[[9,5],[[8,2],[4,0]]],[[5,5],[[5,0],[1,9]]]]
+[[[[7,4],[8,1]],[2,[7,1]]],2]
+[[[[9,6],3],8],[[[9,8],7],[5,[0,8]]]]
+[[[4,[4,0]],[[7,3],3]],[8,[3,[8,2]]]]
+[[[[8,4],1],6],[[1,[8,7]],1]]
+[[[8,2],[[1,4],3]],[[4,5],[[9,1],[7,2]]]]
+[[[[5,0],[8,8]],[[4,2],4]],[2,[[4,3],[3,7]]]]
+[[[8,7],[2,1]],[9,3]]
+[[3,[7,4]],[0,3]]
+[4,[[[5,0],[5,2]],3]]
+[[[[0,1],0],8],[6,3]]
+[[7,[[9,8],[2,7]]],[[[8,8],[9,4]],[[0,5],[4,1]]]]
+[[[[3,7],[5,4]],[8,[1,8]]],[[1,8],[[6,9],9]]]
+[[[[7,4],[7,7]],7],[1,[[8,2],[1,8]]]]
+[[[[6,2],8],[[1,2],3]],[[[3,6],[4,9]],[[3,1],[9,8]]]]
+[[[3,[1,1]],[[6,5],[2,2]]],9]
+[[[[9,1],4],1],[[[1,3],3],[0,[1,4]]]]
+[[[5,0],[4,[6,8]]],[[2,4],[[0,3],[2,6]]]]
+[9,[[9,[1,5]],1]]
+[[1,[[6,0],[9,2]]],[[[4,2],7],[[2,9],6]]]
+[[[[8,2],8],9],[[[4,9],[3,8]],2]]
+[[[9,1],[6,5]],[[[9,5],5],1]]
+[[[[1,3],5],2],[1,1]]
+[[[[0,0],[8,1]],8],8]
+[[[[3,3],5],[[9,6],9]],[[3,[0,9]],7]]
+[[[6,5],1],1]
+[[[4,[1,3]],[[2,2],2]],[[8,0],[[8,1],[2,6]]]]
+[9,[[4,6],2]]
+[[[5,[8,8]],[[1,8],[4,9]]],[9,[3,6]]]
+[[[[9,3],3],0],8]
+[[[5,0],[[2,8],[1,1]]],[[[5,6],9],8]]
+[[[[5,0],[5,2]],[[7,0],[9,8]]],[3,[[5,7],[5,9]]]]
+[[3,[5,7]],1]
+[[[[2,5],[0,7]],9],[[[3,2],1],[7,1]]]
+[6,[7,[6,0]]]
+[[[8,5],[[1,7],[7,6]]],[[1,3],[5,[1,9]]]]
+[[[[9,4],[8,3]],1],[[1,6],[[2,5],1]]]
+[[[[6,5],[6,6]],[5,5]],[1,8]]
+[[[[7,7],[2,2]],3],[1,[[8,6],[5,1]]]]
+[[6,[2,4]],[[8,8],[[3,5],6]]]
+[[1,[[6,1],[9,3]]],[[2,0],5]]
+[[[5,9],[6,[1,9]]],[3,[4,[7,7]]]]
+[[[[3,6],[8,5]],[[9,4],[4,1]]],[3,3]]
+[[[3,9],[1,6]],2]
+[[[[0,9],7],6],[7,[9,[9,9]]]]
+[[[5,[6,0]],[8,[7,5]]],[[[8,8],0],[8,1]]]
+[[[[6,9],[9,0]],2],[[[0,3],[1,6]],[2,4]]]
+[[[[8,2],[3,0]],[[3,8],8]],[6,[[9,3],4]]]
+[[[6,6],2],[5,[1,4]]]
+[[1,[1,4]],[[[4,3],0],1]]
+[[[[9,9],3],0],[[[3,3],[2,8]],[1,0]]]
+[[[[1,1],[3,5]],[9,7]],4]
+[[[9,[3,6]],5],[[4,9],[9,3]]]
+[[8,7],[5,[7,[7,7]]]]
+[[[[0,5],[7,3]],[[8,6],8]],[[[4,4],[5,0]],[[2,2],2]]]
+[[[5,0],[[1,9],[5,8]]],[[1,5],[[9,3],[0,7]]]]
+[[[1,[1,5]],[8,[2,2]]],0]
+[[[6,[7,8]],[[0,2],5]],[3,[5,[8,0]]]]
+[[[[1,7],2],3],[[[8,7],[7,8]],[7,[5,5]]]]
+[[1,[7,[3,3]]],[8,[9,[3,0]]]]
+[[5,6],[[5,[2,8]],[[5,5],[8,8]]]]
+[[8,[[7,7],[4,0]]],[[5,[0,4]],[6,[6,2]]]]
+[[4,[[0,0],[0,1]]],[[3,1],[[6,7],4]]]
+[[[[3,2],[4,2]],[[4,4],[6,3]]],[9,[0,[1,9]]]]
+[[[[4,6],2],[[9,6],4]],[[9,[9,1]],[0,[1,8]]]]
+[[[5,8],[[6,5],[0,4]]],[[0,[6,3]],[2,0]]]
+[[6,8],[[5,5],[5,8]]]
+[[[7,3],[8,[6,7]]],[[[1,5],2],7]]
+[[6,[8,[8,9]]],[[[1,1],[3,0]],[[7,2],[3,7]]]]
+[[[[8,1],6],[9,[5,1]]],[[[5,9],[1,9]],5]]
+[[[[3,6],[5,7]],[[0,3],8]],[3,[[2,1],0]]]
+[[7,[5,1]],[[[3,6],9],[[4,0],6]]]
+[[[[3,8],8],0],[[1,[1,4]],[[4,5],[8,5]]]]
+[[[8,[0,6]],[4,3]],[8,[[1,5],8]]]
+[2,[[1,[9,7]],[[2,0],6]]]
+[[[[7,4],4],[[4,9],3]],[[[6,5],[0,5]],[[9,8],[2,6]]]]
+[[[3,[7,2]],[[7,7],4]],[[[3,4],[6,0]],[6,3]]]
+[[[1,9],[[9,8],9]],5]
+[[[4,2],2],[[[4,4],7],5]]
+[[[9,1],[2,[1,5]]],[[4,3],[4,[9,5]]]]
+[2,[[[8,4],1],[[2,4],2]]]
+[[[0,6],5],[1,[[2,0],6]]]
+[[[[2,4],[1,7]],[1,0]],[9,5]]
+[[7,[3,[2,0]]],[[7,8],8]]
+[[9,[1,0]],[[0,4],[[0,1],0]]]
+[0,9]
+[[[[2,9],[2,4]],[[5,6],8]],[[5,[1,4]],[3,[0,6]]]]
+[[5,[[5,8],0]],[[[0,6],[4,5]],[[8,9],[8,3]]]]
+[[[[5,2],[7,7]],[0,[4,1]]],[[8,7],[[5,3],7]]]
+[[[5,3],5],[0,0]]
+[3,5]
+[[2,6],5]
+[[5,[[6,0],3]],[[3,[8,7]],[2,0]]]
diff --git a/18/src/expression.lalrpop b/18/src/expression.lalrpop
new file mode 100644
index 0000000..49356f6
--- /dev/null
+++ b/18/src/expression.lalrpop
@@ -0,0 +1,34 @@
+use crate::types::{Pair, Value};
+
+grammar;
+
+pub Pair: Pair = {
+  LEFT_BRACKET <left:Value> COMMA <right:Value> RIGHT_BRACKET => {
+    Pair {
+      left: left,
+      right: right,
+    }
+  },
+};
+
+Value: Value = {
+  NUMBER => {
+    Value::Literal(<>.parse::<i64>().unwrap())
+  },
+  Pair => {
+    Value::Pair(Box::new(<>))
+  },
+};
+
+match {
+  r"\p{Zs}+" => { },
+
+  r"[0-9]+" => NUMBER,
+
+  "," => COMMA,
+
+  "[" => LEFT_BRACKET,
+
+  "]" => RIGHT_BRACKET,
+}
+
diff --git a/18/src/main.rs b/18/src/main.rs
new file mode 100644
index 0000000..df21bd0
--- /dev/null
+++ b/18/src/main.rs
@@ -0,0 +1,363 @@
+use advent_lib::prelude::*;
+
+use crate::types::{Pair, Value};
+#[macro_use] extern crate lalrpop_util;
+
+pub mod types;
+lalrpop_mod!(pub expression);
+
+
+#[derive(Debug, Clone)]
+enum Step {
+  Left,
+  Right,
+}
+
+
+fn main() -> Result<()> {
+  let mut args = std::env::args();
+  if args.len() != 2 {
+    eprintln!("Usage: advent input");
+  }
+  let _ = args.next();
+  let filename = args.next().unwrap();
+
+  let input = advent_lib::read_lines_file(&filename)?;
+
+  let parser = expression::PairParser::new();
+
+  let mut result = None;
+  for line in &input {
+    let expression = Box::new(parser.parse(line)?);
+
+    match result {
+      None => {
+        result = Some(expression);
+      }
+      Some(previous_result) => {
+        let mut new_expression = add(previous_result, expression);
+        reduce(&mut new_expression);
+        result = Some(new_expression);
+      }
+    }
+  }
+
+  let output = magnitude(&result.unwrap());
+  println!("{}", output);
+
+  let mut expressions = Vec::new();
+  for line in &input {
+    expressions.push(Box::new(parser.parse(line)?));
+  }
+
+  let mut max_sum = None;
+  for i in 0 .. expressions.len() - 2 {
+    for j in i + 1 .. expressions.len() - 1 {
+      let left = expressions[i].clone();
+      let right = expressions[j].clone();
+      let mut sum = add(left, right);
+      reduce(&mut sum);
+      let sum = magnitude(&sum);
+      match max_sum {
+        None => {
+          max_sum = Some(sum);
+        }
+        Some(old_sum) => {
+          if sum > old_sum {
+            max_sum = Some(sum);
+          }
+        }
+      }
+    }
+  }
+
+  println!("{}", max_sum.unwrap());
+
+  Ok(())
+}
+
+
+fn add(left: Box<Pair>, right: Box<Pair>) -> Box<Pair> {
+  Box::new(Pair {
+    left: Value::Pair(left),
+    right: Value::Pair(right),
+  })
+}
+
+
+fn reduce(expression: &mut Box<Pair>) {
+  loop {
+    match find_four_x_nested(&expression, Vec::new(), 0) {
+      None => { }
+      Some((path, left_addend, right_addend)) => {
+        match subtree_to_left(&path) {
+          None => { }
+          Some(left_path) => {
+            let subtree = get_subtree(expression, &left_path);
+            add_to_rightmost_value(subtree, left_addend);
+          }
+        }
+
+        match subtree_to_right(&path) {
+          None => { }
+          Some(right_path) => {
+            let subtree = get_subtree(expression, &right_path);
+            add_to_leftmost_value(subtree, right_addend);
+          }
+        }
+
+        replace_with_zero(expression, &path);
+
+        continue;
+      }
+    }
+
+    if perform_split(expression) {
+      continue;
+    }
+
+    break;
+  }
+}
+
+
+fn find_four_x_nested(expression: &Pair, path_so_far: Vec<Step>, depth: usize)
+  -> Option<(Vec<Step>, i64, i64)>
+{
+  if depth >= 4 {
+    match (&expression.left, &expression.right) {
+      (Value::Literal(left), Value::Literal(right)) => {
+        return Some((path_so_far, *left, *right))
+      }
+      //_ => { panic!("you don't say"); }
+      _ => { return None; }
+    }
+  }
+
+  match &expression.left {
+    Value::Literal(_) => { }
+    Value::Pair(left) => {
+      let mut path = path_so_far.clone();
+      path.push(Step::Left);
+      let result = find_four_x_nested(left.as_ref(), path, depth + 1);
+      if result.is_some() {
+        return result;
+      }
+    }
+  }
+
+  match &expression.right {
+    Value::Literal(_) => { }
+    Value::Pair(right) => {
+      let mut path = path_so_far.clone();
+      path.push(Step::Right);
+      let result = find_four_x_nested(right.as_ref(), path, depth + 1);
+      if result.is_some() {
+        return result;
+      }
+    }
+  }
+
+  None
+}
+
+
+fn subtree_to_left(path: &Vec<Step>) -> Option<Vec<Step>> {
+  let mut result = path.clone();
+
+  loop {
+    match result[result.len() - 1] {
+      Step::Left => {
+        result.pop();
+
+        if result.len() == 0 {
+          return None;
+        }
+      }
+      Step::Right => {
+        result.pop();
+        result.push(Step::Left);
+        return Some(result);
+      }
+    }
+  }
+}
+
+
+fn subtree_to_right(path: &Vec<Step>) -> Option<Vec<Step>> {
+  let mut result = path.clone();
+
+  loop {
+    match result[result.len() - 1] {
+      Step::Left => {
+        result.pop();
+        result.push(Step::Right);
+        return Some(result);
+      }
+      Step::Right => {
+        result.pop();
+
+        if result.len() == 0 {
+          return None;
+        }
+      }
+    }
+  }
+}
+
+
+fn get_subtree<'a>(pair: &'a mut Box<Pair>, path: &Vec<Step>) -> &'a mut Value {
+  let mut here: &mut Box<Pair> = pair;
+
+  for (i, step) in path.iter().enumerate() {
+    if i == path.len() - 1 {
+      match step {
+        Step::Left => {
+          return &mut here.left;
+        }
+        Step::Right => {
+          return &mut here.right;
+        }
+      }
+    } else {
+      match step {
+        Step::Left => {
+          match &mut here.left {
+            Value::Pair(left) => {
+              here = left;
+            }
+            _ => { panic!("left is not a pair"); }
+          }
+        }
+        Step::Right => {
+          match &mut here.right {
+            Value::Pair(right) => {
+              here = right;
+            }
+            _ => { panic!("right is not a pair"); }
+          }
+        }
+      }
+    }
+  }
+
+  panic!("empty path");
+}
+
+
+fn add_to_rightmost_value(subtree: &mut Value, addend: i64) {
+  match subtree {
+    Value::Literal(value) => {
+      *value += addend;
+    }
+    Value::Pair(pair) => {
+      add_to_rightmost_value(&mut pair.right, addend);
+    }
+  }
+}
+
+
+fn add_to_leftmost_value(subtree: &mut Value, addend: i64) {
+  match subtree {
+    Value::Literal(value) => {
+      *value += addend;
+    }
+    Value::Pair(pair) => {
+      add_to_leftmost_value(&mut pair.left, addend);
+    }
+  }
+}
+
+
+fn replace_with_zero(pair: &mut Box<Pair>, path: &Vec<Step>) {
+  let mut here: &mut Box<Pair> = pair;
+
+  for (i, step) in path.iter().enumerate() {
+    if i == path.len() - 1 {
+      match step {
+        Step::Left => {
+          here.left = Value::Literal(0);
+        }
+        Step::Right => {
+          here.right = Value::Literal(0);
+        }
+      }
+    } else {
+      match step {
+        Step::Left => {
+          match &mut here.left {
+            Value::Pair(left) => {
+              here = left;
+            }
+            _ => { panic!("left is not a pair"); }
+          }
+        }
+        Step::Right => {
+          match &mut here.right {
+            Value::Pair(right) => {
+              here = right;
+            }
+            _ => { panic!("right is not a pair"); }
+          }
+        }
+      }
+    }
+  }
+}
+
+
+fn perform_split(expression: &mut Box<Pair>) -> bool {
+  match &mut expression.left {
+    Value::Literal(n) => {
+      if *n >= 10 {
+        expression.left = Value::Pair(Box::new(Pair {
+          left: Value::Literal((*n as f64 / 2.0).floor() as i64),
+          right: Value::Literal((*n as f64 / 2.0).ceil() as i64),
+        }));
+        return true;
+      }
+    }
+    Value::Pair(left) => {
+      if perform_split(left) {
+        return true;
+      }
+    }
+  }
+
+  match &mut expression.right {
+    Value::Literal(n) => {
+      if *n >= 10 {
+        expression.right = Value::Pair(Box::new(Pair {
+          left: Value::Literal((*n as f64 / 2.0).floor() as i64),
+          right: Value::Literal((*n as f64 / 2.0).ceil() as i64),
+        }));
+        return true;
+      }
+    }
+    Value::Pair(right) => {
+      if perform_split(right) {
+        return true;
+      }
+    }
+  }
+
+  false
+}
+
+
+fn magnitude(expression: &Box<Pair>) -> i64 {
+  let mut result = 0;
+
+  result += 3 * match &expression.left {
+    Value::Literal(n) => *n,
+    Value::Pair(left) => magnitude(left),
+  };
+
+  result += 2 * match &expression.right {
+    Value::Literal(n) => *n,
+    Value::Pair(right) => magnitude(right),
+  };
+
+  result
+}
+
diff --git a/18/src/types.rs b/18/src/types.rs
new file mode 100644
index 0000000..6800fdc
--- /dev/null
+++ b/18/src/types.rs
@@ -0,0 +1,32 @@
+use std::fmt;
+
+
+#[derive(Clone)]
+pub enum Value {
+  Literal(i64),
+  Pair(Box<Pair>),
+}
+
+#[derive(Clone)]
+pub struct Pair {
+  pub left: Value,
+  pub right: Value,
+}
+
+
+impl fmt::Debug for Value {
+  fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+    match self {
+      Value::Literal(n) => { write!(formatter, "{}", n) }
+      Value::Pair(pair) => { write!(formatter, "{:?}", pair) }
+    }
+  }
+}
+
+
+impl fmt::Debug for Pair {
+  fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+    write!(formatter, "[{:?},{:?}]", self.left, self.right)
+  }
+}
+
diff --git a/18/tests/.main.rs.swn b/18/tests/.main.rs.swn
new file mode 100644
index 0000000..6017cf8
--- /dev/null
+++ b/18/tests/.main.rs.swn
Binary files differdiff --git a/18/tests/main.rs b/18/tests/main.rs
new file mode 100644
index 0000000..af55fe3
--- /dev/null
+++ b/18/tests/main.rs
@@ -0,0 +1,19 @@
+use assert_cmd::prelude::*;
+//use predicates::prelude::*;
+use std::process::Command;
+
+
+#[test]
+fn personal_input() -> Result<(), Box<dyn std::error::Error>> {
+  let mut command = Command::cargo_bin("advent_18")?;
+
+  command.arg("input");
+  command.assert().success().stdout(
+      "3216\n\
+      4643\n");
+
+
+
+  Ok(())
+}
+
diff --git a/Cargo.lock b/Cargo.lock
index 48af539..f55c263 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -137,6 +137,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "advent_18"
+version = "0.1.0"
+dependencies = [
+ "advent_lib",
+ "assert_cmd",
+ "lalrpop",
+ "lalrpop-util",
+]
+
+[[package]]
 name = "advent_lib"
 version = "0.1.0"
 dependencies = [
diff --git a/Cargo.toml b/Cargo.toml
index c2dfe1d..75704cb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,4 +18,5 @@ members = [
   "15",
   "16",
   "17",
+  "18",
 ]