Skip to content

Commit

Permalink
Day 8! 🛜
Browse files Browse the repository at this point in the history
  • Loading branch information
bozdoz committed Dec 9, 2023
1 parent 59d28d6 commit 8a77627
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 42 deletions.
85 changes: 85 additions & 0 deletions BLOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,90 @@
# What Am I Learning Each Day?

### Day 8

**Difficulty: 3/10 ★★★☆☆☆☆☆☆☆**

**Time: ~2 hr**

**Run Time: ~5.4ms**

I totally forgot about lcm (least common multiplier), and I'm sure I've solved a puzzle like this in previous years (though I can't find my implementation).

I copied over some functions I found for implementing lcm, and part 2 seemed to work just fine.

I thought today's parsing was pretty simple:

```rust
let mut elements = HashMap::new();

for line in lines.skip(1) {
let key = &line[..3];
let left = &line[7..10];
let right = &line[12..15];

elements.insert(key, (left, right));
}
```

First time using a view(?) on a slice(?).

I was tempted to save the start_keys to the struct, but it worked a lot better to just supply that to the `count_path` function.

I find it odd to get the last character of a &str:

```rust
if elem.0.chars().nth(2).unwrap() == 'A' {
Some(*elem.0)
} else {
None
}
```

I also found it frustrating to determine how and when to add the `mut` keyword, in the count_path function:

```rust
fn count_path(&self, key: &str) -> usize {
// iterate instructions, return # of iterations
let mut key = key;
let mut i = 0;
let len = self.instructions.len();

loop {
let (l, r) = self.elements.get(key).unwrap();

key = match self.instructions[i % len] {
Dir::L => { l }
Dir::R => { r }
};

i += 1;

if key.chars().nth(2).unwrap() == 'Z' {
return i;
}
}
}
```

That `let mut key = key;` looks awfully strange to me, but the tests pass, so I guess it's great.

Probably my first time using a `loop`.

I did successfully, finally use lifetimes in the Network struct:

```rust
struct Network<'a> {
instructions: Vec<Dir>,
elements: HashMap<&'a str, (&'a str, &'a str)>,
}

impl Network<'_> {
fn new(contents: &str) -> Network<'_> {
// ...
```

I *think* what it means is that all the `&str` references should live as long as the Network instance.

### Day 7

**Difficulty: 4/10 ★★★★☆☆☆☆☆☆**
Expand Down
106 changes: 64 additions & 42 deletions day-08/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
use std::{time::Instant, fs, collections::HashMap};
use std::{ time::Instant, fs, collections::HashMap };
use lib::get_part;

#[derive(Debug, PartialEq)]
enum Dir {
L,
R
R,
}

// first time with lifetimes?
struct Network<'a> {
instructions: Vec<Dir>,
elements: HashMap<&'a str, (&'a str, &'a str)>,
/** part 2 keys are not just "AAA", but anything ending in "A" */
start_keys: Vec<&'a str>
}

impl Network<'_> {
fn new(contents: &str) -> Network<'_> {
let mut lines = contents.lines();

let instructions: Vec<Dir> = lines.next().unwrap().chars().map(|x| {
if x == 'L' {
return Dir::L
}
Dir::R
}).collect();

let instructions: Vec<Dir> = lines
.next()
.unwrap()
.chars()
.map(|x| {
if x == 'L' {
return Dir::L;
}
Dir::R
})
.collect();

let mut elements = HashMap::new();

Expand All @@ -36,56 +39,62 @@ impl Network<'_> {
elements.insert(key, (left, right));
}

Network { instructions, elements, start_keys: vec![] }
Network { instructions, elements }
}
fn add_start_keys(&mut self) {
let mut start_keys: Vec<&str> = vec![];
for (key, _) in self.elements.iter() {
if key.chars().nth(2).unwrap() == 'A' {
start_keys.push(key);
}
}

self.start_keys = start_keys;
fn get_start_keys(&self) -> Vec<&str> {
self.elements
.iter()
.filter_map(|elem| {
if elem.0.chars().nth(2).unwrap() == 'A' {
Some(*elem.0)
} else {
None
}
})
.collect::<Vec<&str>>()
}
fn count_path_from(&self, keys: &Vec<&str>) -> (usize, Vec<&str>) {
fn count_path(&self, key: &str) -> usize {
// iterate instructions, return # of iterations
let mut key = keys[0];
let mut key = key;
let mut i = 0;
let len = self.instructions.len();

loop {
let (l, r) = self.elements.get(key).unwrap();

key = match self.instructions[i % len] {
Dir::L => { l }
Dir::R => { r }
};

i += 1;

if key.chars().nth(2).unwrap() == 'Z' {
return (i, vec!["AAA"])
if key.chars().nth(2).unwrap() == 'Z' {
return i;
}
}
}
}

fn part_one(network: &Network) -> usize {
network.count_path_from(&vec!["AAA"]).0
network.count_path("AAA")
}

fn part_two(network: &mut Network) -> usize {
network.add_start_keys();
network.count_path_from(&network.start_keys).0
fn part_two(network: &Network) -> usize {
let keys = network.get_start_keys();

keys.iter()
.map(|x| network.count_path(x))
.reduce(lcm)
.unwrap()
}

fn main() {
let (one, two) = get_part();
let start = Instant::now();
let contents = fs::read_to_string("./src/input.txt").unwrap();

let mut network = Network::new(contents.as_str());
let network = Network::new(contents.as_str());

if one {
let now = Instant::now();
Expand All @@ -95,13 +104,29 @@ fn main() {

if two {
let now = Instant::now();
let ans = part_two(&mut network);
let ans = part_two(&network);
println!("Part two: {:?} {:?}", ans, now.elapsed());
}

println!("Time: {:?}", start.elapsed())
}

fn lcm(a: usize, b: usize) -> usize {
if a == 0 {
return b;
}

(a * b) / gcd(a, b)
}

fn gcd(a: usize, b: usize) -> usize {
if a == 0 {
return b;
}

gcd(b % a, a)
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -111,7 +136,7 @@ mod tests {
#[test]
fn test_parsing() {
let network = Network::new(EXAMPLE);

assert_eq!(network.instructions.len(), 3);
// ne!
assert_ne!(network.instructions[0], Dir::R);
Expand All @@ -130,7 +155,8 @@ mod tests {
assert_eq!(ans, 6);
}

const EXAMPLE_2: &str = "LR
const EXAMPLE_2: &str =
"LR
11A = (11B, XXX)
11B = (XXX, 11Z)
Expand All @@ -143,19 +169,15 @@ XXX = (XXX, XXX)";

#[test]
fn test_start_keys() {
let mut network = Network::new(EXAMPLE_2);

assert_eq!(network.start_keys.len(), 0);

network.add_start_keys();
let network = Network::new(EXAMPLE_2);

assert_eq!(network.start_keys.len(), 2);
assert_eq!(network.get_start_keys().len(), 2);
}

#[test]
fn test_part_two() {
let mut network = Network::new(EXAMPLE_2);
let ans = part_two(&mut network);
let network = Network::new(EXAMPLE_2);
let ans = part_two(&network);

assert_eq!(ans, 6);
}
Expand Down

0 comments on commit 8a77627

Please sign in to comment.