summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGard Spreemann <gspr@nonempty.org>2023-12-09 15:02:49 +0100
committerGard Spreemann <gspr@nonempty.org>2023-12-09 15:02:49 +0100
commit76ead139ec963f9dffb212e77f8e81936d023dc7 (patch)
treee0846b8684eaa4d633ff7c596f0177d652ad800f
parent746349953d09bb13a53b60d42434b4d72a3158e9 (diff)
Day 8, part 2
-rw-r--r--08/Cargo.toml6
-rw-r--r--08/src/part-1.rs17
-rw-r--r--08/src/part-2.rs47
-rw-r--r--08/src/stuff.rs56
-rw-r--r--08/test-3.txt10
5 files changed, 120 insertions, 16 deletions
diff --git a/08/Cargo.toml b/08/Cargo.toml
index 56de1ce..86d1d7c 100644
--- a/08/Cargo.toml
+++ b/08/Cargo.toml
@@ -7,8 +7,8 @@ edition = "2021"
name = "part-1"
path = "src/part-1.rs"
-#[[bin]]
-#name = "part-2"
-#path = "src/part-2.rs"
+[[bin]]
+name = "part-2"
+path = "src/part-2.rs"
[dependencies]
diff --git a/08/src/part-1.rs b/08/src/part-1.rs
index bdfb409..89d51b5 100644
--- a/08/src/part-1.rs
+++ b/08/src/part-1.rs
@@ -2,7 +2,7 @@ mod stuff;
use std::collections::{HashMap};
-use crate::stuff::{ascii_to_u64, is_all_ascii_ws, read_helper, Direction, Node};
+use crate::stuff::{ascii_to_u64, is_all_ascii_ws, read_helper, walk, Direction, Node};
pub const START: Node = [b'A', b'A', b'A'];
pub const FINISH: Node = [b'Z', b'Z', b'Z'];
@@ -41,16 +41,7 @@ fn main() {
nodes.insert(node, (node_l, node_r));
}
- let mut node: Node = START;
- for (i, instruction) in instructions.into_iter().cycle().enumerate() {
- if node == FINISH {
- println!("{}", i);
- break;
- }
- let (left, right) = nodes.get(& node).expect("Non-existent node");
- match instruction {
- Direction::L => { node = *left; },
- Direction::R => { node = *right; }
- }
- }
+ let res = walk(START, |node| node == FINISH, & nodes, & instructions);
+ println!("{}", res);
+
}
diff --git a/08/src/part-2.rs b/08/src/part-2.rs
new file mode 100644
index 0000000..90d4356
--- /dev/null
+++ b/08/src/part-2.rs
@@ -0,0 +1,47 @@
+mod stuff;
+
+use std::collections::{HashMap};
+
+use crate::stuff::{is_all_ascii_ws, lcm, read_helper, walk, Direction, Node};
+
+fn main() {
+ let mut stdin = std::io::stdin().lock();
+
+ let mut buf: Vec<u8> = Vec::new();
+
+ let num_bytes = read_helper(&mut stdin, &mut buf, b'\n').expect("IO error");
+ if num_bytes == 0 { panic!("Malformed input"); }
+ let instructions: Vec<Direction> = (& buf).into_iter()
+ .map(|& c| Direction::try_from(c).expect("Malformed input"))
+ .collect();
+
+ let num_bytes = read_helper(&mut stdin, &mut buf, b'\n').expect("IO error");
+ assert!(is_all_ascii_ws(& buf));
+
+ let mut nodes: HashMap<Node, (Node, Node)> = HashMap::new();
+ let mut starts: Vec<Node> = Vec::new();
+ loop {
+ let num_bytes = read_helper(&mut stdin, &mut buf, b'=').expect("IO error");
+ if num_bytes == 0 { break; }
+ let node: Node = core::array::from_fn(|i| buf[i]);
+
+ let num_bytes = read_helper(&mut stdin, &mut buf, b',').expect("IO error");
+ if num_bytes == 0 { panic!("Malformed input"); }
+ let node_l: Node = core::array::from_fn(|i| buf[2+i]);
+
+ let num_bytes = read_helper(&mut stdin, &mut buf, b'\n').expect("IO error");
+ if num_bytes == 0 { panic!("Malformed input"); }
+ let node_r: Node = core::array::from_fn(|i| buf[1+i]);
+
+ if node[2] == b'A' { starts.push(node); }
+ nodes.insert(node, (node_l, node_r));
+ }
+
+ let mut res: u64 = 1;
+ for start in (& starts).into_iter() {
+ let n: u64 = walk(*start, |node| node[2] == b'Z', & nodes, & instructions).try_into().unwrap();
+ res = lcm(res, n);
+ }
+
+ println!("{}", res);
+}
diff --git a/08/src/stuff.rs b/08/src/stuff.rs
index 835c65e..7e88605 100644
--- a/08/src/stuff.rs
+++ b/08/src/stuff.rs
@@ -1,3 +1,4 @@
+use std::collections::{HashMap};
use std::io::{BufRead};
pub fn ascii_to_u64(s: & [u8]) -> u64 {
@@ -40,9 +41,64 @@ impl TryFrom<u8> for Direction {
pub type Node = [u8; 3];
+pub fn gcd(mut m: u64, mut n: u64) -> u64 {
+ if m < n {
+ std::mem::swap(&mut m, &mut n);
+ }
+
+ while n > 0 {
+ let r: u64 = m % n;
+ m = n;
+ n = r;
+ }
+ m
+}
+
+pub fn lcm(m: u64, n: u64) -> u64 {
+ m*(n/gcd(m, n))
+}
+
+pub fn walk<'a, I, F>(start: Node, is_finish: F, map: & HashMap<Node, (Node, Node)>, instructions: I) -> usize
+where I: IntoIterator<Item = &'a Direction>,
+<I as IntoIterator>::IntoIter: Clone,
+F: Fn(Node) -> bool {
+ let mut node: Node = start;
+ for (i, instruction) in instructions.into_iter().cycle().enumerate() {
+ if is_finish(node) {
+ return i;
+ }
+ let (left, right) = map.get(& node).expect("Non-existent node");
+ match instruction {
+ Direction::L => { node = *left; },
+ Direction::R => { node = *right; }
+ }
+ }
+ unreachable!("Non-terminating map")
+}
+
#[cfg(test)]
mod tests {
use super::*;
+ #[test]
+ fn test_gcd() {
+ assert_eq!(gcd(1238124652, 22146), 2);
+ }
+
+ #[test]
+ fn test_gcd_2() {
+ assert_eq!(gcd(5025124, 1040), 52);
+ }
+
+ #[test]
+ fn test_gcd_3() {
+ assert_eq!(gcd(1040, 5025124), 52);
+ }
+
+ #[test]
+ fn test_lcm() {
+ assert_eq!(lcm(1040, 5025124), 100502480);
+ }
+
}
diff --git a/08/test-3.txt b/08/test-3.txt
new file mode 100644
index 0000000..5b3fa58
--- /dev/null
+++ b/08/test-3.txt
@@ -0,0 +1,10 @@
+LR
+
+11A = (11B, XXX)
+11B = (XXX, 11Z)
+11Z = (11B, XXX)
+22A = (22B, XXX)
+22B = (22C, 22C)
+22C = (22Z, 22Z)
+22Z = (22B, 22B)
+XXX = (XXX, XXX)