generated from janezicmatej/aoc-template
	solution: day 21
This commit is contained in:
		
							
								
								
									
										11
									
								
								data/examples/21.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								data/examples/21.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
...........
 | 
			
		||||
.....###.#.
 | 
			
		||||
.###.##..#.
 | 
			
		||||
..#.#...#..
 | 
			
		||||
....#.#....
 | 
			
		||||
.##..S####.
 | 
			
		||||
.##..#...#.
 | 
			
		||||
.......##..
 | 
			
		||||
.##.#.####.
 | 
			
		||||
.##..##.##.
 | 
			
		||||
...........
 | 
			
		||||
							
								
								
									
										106
									
								
								src/bin/21.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/bin/21.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
use std::{collections::HashSet, usize};
 | 
			
		||||
 | 
			
		||||
fn parse_input(input: &str) -> (Vec<Vec<u8>>, (isize, isize)) {
 | 
			
		||||
    let mut grid: Vec<_> = input.lines().map(|x| x.as_bytes().to_vec()).collect();
 | 
			
		||||
 | 
			
		||||
    let start = grid
 | 
			
		||||
        .iter()
 | 
			
		||||
        .enumerate()
 | 
			
		||||
        .flat_map(|(y, item)| item.iter().enumerate().map(move |(x, item)| (x, y, *item)))
 | 
			
		||||
        .find_map(|(x, y, s)| if s == b'S' { Some((y, x)) } else { None })
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    grid[start.0][start.1] = b'.';
 | 
			
		||||
 | 
			
		||||
    (grid, (start.0 as isize, start.1 as isize))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn walk_return_at(
 | 
			
		||||
    grid: &[Vec<u8>],
 | 
			
		||||
    start: (isize, isize),
 | 
			
		||||
    mut returns: Vec<usize>,
 | 
			
		||||
    can_cycle: bool,
 | 
			
		||||
) -> Vec<usize> {
 | 
			
		||||
    returns.sort_by(|a, b| b.cmp(a));
 | 
			
		||||
 | 
			
		||||
    let h = grid.len() as isize;
 | 
			
		||||
    let w = grid[0].len() as isize;
 | 
			
		||||
 | 
			
		||||
    let invalid_indexing = |y, x| y < 0 || y >= h || x < 0 || x >= w;
 | 
			
		||||
 | 
			
		||||
    let mut results = Vec::new();
 | 
			
		||||
    let length = returns[0];
 | 
			
		||||
    let mut next = returns.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
    let mut visited = HashSet::new();
 | 
			
		||||
    visited.insert(start);
 | 
			
		||||
 | 
			
		||||
    for i in 1..=length {
 | 
			
		||||
        let mut new_visited = HashSet::new();
 | 
			
		||||
 | 
			
		||||
        for (y, x) in visited.iter() {
 | 
			
		||||
            for (dy, dx) in [(1, 0), (0, 1), (-1, 0), (0, -1)] {
 | 
			
		||||
                let (ny, nx) = (y + dy, x + dx);
 | 
			
		||||
 | 
			
		||||
                if !can_cycle && invalid_indexing(ny, nx) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let (cy, cx) = (ny.rem_euclid(h) as usize, nx.rem_euclid(w) as usize);
 | 
			
		||||
 | 
			
		||||
                if grid[cy][cx] == b'.' {
 | 
			
		||||
                    new_visited.insert((ny, nx));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        visited = new_visited;
 | 
			
		||||
 | 
			
		||||
        if i == next {
 | 
			
		||||
            results.push(visited.len());
 | 
			
		||||
            if !returns.is_empty() {
 | 
			
		||||
                next = returns.pop().unwrap();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    results
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn part_one(input: &str) -> Option<usize> {
 | 
			
		||||
    let (grid, start) = parse_input(input);
 | 
			
		||||
    let result = walk_return_at(&grid, start, vec![64], false);
 | 
			
		||||
 | 
			
		||||
    Some(result[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn part_two(input: &str) -> Option<usize> {
 | 
			
		||||
    let (grid, start) = parse_input(input);
 | 
			
		||||
 | 
			
		||||
    let h = grid.len();
 | 
			
		||||
    let s = start.0 as usize;
 | 
			
		||||
 | 
			
		||||
    let result = walk_return_at(&grid, start, vec![s, s + h, s + 2 * h], true);
 | 
			
		||||
 | 
			
		||||
    let a = (result[2] - 2 * result[1] + result[0]) / 2;
 | 
			
		||||
    let b = (result[1] - result[0]) - a;
 | 
			
		||||
    let c = result[0];
 | 
			
		||||
 | 
			
		||||
    let x = 26501365 / h;
 | 
			
		||||
 | 
			
		||||
    Some(a * x * x + b * x + c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
aoc::solution!(21);
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_part_one() {
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            part_one(&aoc::template::read_file("examples", 21)),
 | 
			
		||||
            Some(42)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user