Untitled

 avatar
unknown
plain_text
2 months ago
3.0 kB
70
Indexable
pub fn solution(test: bool) -> ((usize, Duration), (usize, Duration)) {
    let lines;
    if test {
        lines = include_str!("../../../AdventOfCodeInputs/problem_inputs_2024/day_18_test.txt");
    } else {
        lines = include_str!("../../../AdventOfCodeInputs/problem_inputs_2024/day_18.txt");
    }
    (solve01(lines), solve02(lines))
}

fn solve01(lines: &str) -> (usize, Duration) {
    let now = Instant::now();
    let maze = Maze::from_str(lines, (71, 71), 1024);
    let start = (0, 0);
    let end = (maze.bounds.0 - 1, maze.bounds.1 - 1);
    let result = maze.find_shortest_path(start, end).unwrap();
    (result, now.elapsed())
}

fn solve02(lines: &str) -> (usize, Duration) {
    let now = Instant::now();
    let mut low = 1024;
    let mut high = lines.lines().count();
    let mut result = 0;

    while low <= high {
        let mid = (low + high) / 2;
        let maze = Maze::from_str(lines, (71, 71), mid);
        let start = (0, 0);
        let end = (maze.bounds.0 - 1, maze.bounds.1 - 1);

        if maze.find_shortest_path(start, end).is_some() {
            result = mid;
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }

    dbg!(lines.lines().nth(result));
    (0, now.elapsed())
}

type Pos = (isize, isize);
struct Maze {
    blocks: FxHashSet<Pos>,
    bounds: (isize, isize),
}

impl Maze {
    fn from_str(lines: &str, bounds: (isize, isize), bytes_to_count: usize) -> Self {
        let mut blocks = FxHashSet::default();
        for pos in lines.lines().take(bytes_to_count) {
            let (xstr, ystr) = pos.split_once(',').unwrap();
            let x = xstr.parse::<isize>().unwrap();
            let y = ystr.parse::<isize>().unwrap();
            blocks.insert((x, y));
        }
        Self { blocks, bounds }
    }

    fn find_shortest_path(&self, start: Pos, end: Pos) -> Option<usize> {
        let mut dist = FxHashSet::default();
        let mut heap = VecDeque::new();
        heap.push_back((0, start));

        while let Some((cost, pos)) = heap.pop_front() {
            if pos == end {
                return Some(cost);
            }

            if !dist.insert(pos) {
                continue;
            }

            for neighbour in self.get_neighbours(pos) {
                if !dist.contains(&neighbour) {
                    heap.push_back((cost + 1, neighbour));
                }
            }
        }

        None
    }

    fn get_neighbours(&self, pos: Pos) -> Vec<Pos> {
        let mut neighbours = Vec::new();
        let (x, y) = pos;
        for (dx, dy) in &[(0, 1), (0, -1), (1, 0), (-1, 0)] {
            let next = (x + dx, y + dy);
            if next.0 < 0 || next.1 < 0 || next.0 >= self.bounds.0 || next.1 >= self.bounds.1 {
                continue;
            }
            if self.blocks.contains(&next) {
                continue;
            }
            neighbours.push(next);
        }
        neighbours
    }
}
Leave a Comment