lewisdale.dev/src/blog/posts/2022/12/advent-of-code-day-six.md
2023-12-26 14:35:09 +00:00

2.6 KiB

title date slug tags
Advent of Code: Day Six 2022-12-06T00:00:00 advent-of-code-day-six
advent-of-code-2022

Spoilers for Advent of Code below

Day six was a nice, welcome break from the struggle I had yesterday.

Part one

Given a set of characters relaying a message, find the index of packet start signal, which comes after the first four unique characters.

So if my input is:

mjqjpqmgbljsphdztnvjfqwrcgsmlb

then my output should be 5, because that is the index of the first set of unique characters - qjpq.

My first attempt was also my last attempt, as I used a HashSet of characters from a moving 5-char block. If the length was 5, that meant I'd found the index of my packet marker.

pub fn find_marker_index(input: &str) -> Option<usize> {
	let mut set: HashSet<char> = HashSet::new();

	for idx in 0..input.len() {
		set = HashSet::from_iter(input[idx..=idx+4].chars());
		if set.len() == 5 {
			return Some(idx+4);
		}
	}
	None
}

Part two

Much the same, except now we need to also find a message start signal, which comes after 14 unique characters. I updated my find_marker_index function to take an offset, and updated the logic to use it. I also reversed my range, because I realised that I would quite easily hit string overflow issues - it was simply luck that I hadn't yet:

pub fn find_marker_index(input: &str, marker_offset: usize) -> Option<usize> {
	let mut set: HashSet<char>;

	for idx in marker_offset..input.len() {
		set = HashSet::from_iter(input[idx-marker_offset..idx].chars());
		if set.len() == marker_offset {
			return Some(idx);
		}
	}
	None
}

As a final pass, I moved my function to a trait implemented on str, because I'm trying to learn how to properly work with them:

pub trait FindUnique {
	fn find_unique(&self, offset: usize) -> Option<usize>;
}

impl FindUnique for str {
	fn find_unique(&self, offset: usize) -> Option<usize> {
		for idx in offset..self.len() {
			let len = HashSet::<char>::from_iter(self[idx - offset..idx].chars()).len();
			if len == offset {
				return Some(idx);
			}
		}
		None
	}
}

Which means I can now just call my function straight from reading the file:

if let Some(idx) = read_file(...).unwrap().find_unique(14) {
	// Output
}

And that worked! Day six checked off, with a nice tidy solution that I'm very happy with.