1
0

day 6 part 2 performance

This commit is contained in:
2024-12-06 07:19:24 +01:00
parent 8157a9bf7e
commit 9c5d12c6b0

View File

@@ -14,9 +14,18 @@ type RiddleResult = usize;
type Point = (i32, i32); type Point = (i32, i32);
fn part1(input: &str) -> RiddleResult { fn part1(input: &str) -> RiddleResult {
let (m, mut pos, _) = parse(input); let (m, pos) = parse(input);
let mut dir = '^'; let dir = '^';
let visited = get_visited(&m, pos, dir);
visited.len()
}
fn get_visited(
m: &HashMap<(i32, i32), char>,
mut pos: (i32, i32),
mut dir: char,
) -> HashSet<(i32, i32)> {
let mut visited = HashSet::new(); let mut visited = HashSet::new();
while m.contains_key(&pos) { while m.contains_key(&pos) {
let (x, y) = pos; let (x, y) = pos;
@@ -40,27 +49,22 @@ fn part1(input: &str) -> RiddleResult {
pos = next; pos = next;
} }
} }
visited.len() visited
} }
fn part2(input: &str) -> RiddleResult { fn part2(input: &str) -> RiddleResult {
let (m, pos, opens) = parse(input); let (m, pos) = parse(input);
let dir = '^'; let dir = '^';
opens get_visited(&m, pos, dir)
.into_iter() .into_iter()
.filter(|open| { .filter(|open| is_loop(&m, *open, pos, dir))
let mut m = m.clone();
m.insert(*open, '#');
is_loop(m, pos, dir)
})
.count() .count()
} }
fn parse(input: &str) -> (HashMap<Point, char>, Point, HashSet<Point>) { fn parse(input: &str) -> (HashMap<Point, char>, Point) {
let mut m = HashMap::new(); let mut m = HashMap::new();
let mut pos = None; let mut pos = None;
let mut opens = HashSet::new();
input.lines().enumerate().for_each(|(y, line)| { input.lines().enumerate().for_each(|(y, line)| {
line.char_indices().for_each(|(x, c)| { line.char_indices().for_each(|(x, c)| {
let x = x as i32; let x = x as i32;
@@ -71,22 +75,16 @@ fn parse(input: &str) -> (HashMap<Point, char>, Point, HashSet<Point>) {
} else { } else {
m.insert((x, y), c); m.insert((x, y), c);
} }
if c == '.' {
opens.insert((x, y));
}
}); });
}); });
(m, pos.unwrap(), opens) (m, pos.unwrap())
} }
fn is_loop(m: HashMap<Point, char>, mut pos: Point, mut dir: char) -> bool { fn is_loop(m: &HashMap<Point, char>, block: Point, mut pos: Point, mut dir: char) -> bool {
let mut visited = HashSet::new(); let mut visited = HashSet::new();
while m.contains_key(&pos) { while m.contains_key(&pos) {
let (x, y) = pos; let (x, y) = pos;
if visited.contains(&(pos, dir)) {
return true;
}
visited.insert((pos, dir));
let next = match dir { let next = match dir {
'^' => (x, y - 1), '^' => (x, y - 1),
'v' => (x, y + 1), 'v' => (x, y + 1),
@@ -94,7 +92,14 @@ fn is_loop(m: HashMap<Point, char>, mut pos: Point, mut dir: char) -> bool {
'>' => (x + 1, y), '>' => (x + 1, y),
_ => unreachable!(), _ => unreachable!(),
}; };
if let Some('#') = m.get(&next) { let blocked = next == block || Some(&'#') == m.get(&next);
if blocked {
// we only check for loops on a collision to speed things up
if visited.contains(&(pos, dir)) {
return true;
}
visited.insert((pos, dir));
dir = match dir { dir = match dir {
'^' => '>', '^' => '>',
'v' => '<', 'v' => '<',