From cc4ccca94377acbf7cdcc7638a11cabee28de9df Mon Sep 17 00:00:00 2001 From: Maciej Jur Date: Sat, 24 Dec 2022 11:33:58 +0100 Subject: [PATCH] 2022 day 24 part 1 --- 2022/rust/inputs/day24.txt | 27 +++++++++ 2022/rust/src/main.rs | 3 +- 2022/rust/src/solutions/day24.rs | 95 +++++++++++++++++++++++++------- 3 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 2022/rust/inputs/day24.txt diff --git a/2022/rust/inputs/day24.txt b/2022/rust/inputs/day24.txt new file mode 100644 index 0000000..b56e90c --- /dev/null +++ b/2022/rust/inputs/day24.txt @@ -0,0 +1,27 @@ +#.######################################################################################################################## +#>v<^v>v^.^>v^v^<^v^^v.><^v^v<><>><^>^>>>vv..>.^<<>><^^vv<>^vv>.<><<<><>>v..v<^^vv^^vv.^v^^>^^^.^v^vv<<^v.# +#><^vvv^^vv>v>^<^v^^<^<.^<^v><>>^>^^^.>^v>>..<<>>^>><^^v<^<<^^>^><<>vvv^.>^vv^>^>vv>vv>.><<>^<^.>vv.<<.^^v<<<# +#<^v>v>v^>^<.>^^vv<^^vv^v>^><^^^^^.^<>>><><>^>>^><^<.v<>v<.v>.>v<^^vv.<<<^^^>>^^>v<.^vv^># +#>^<<.>^<>>v.>^..v<>^vv^v>>^v>v.>.v>vvv.v.>^^>><<>>v>.v>.>^>^<>^<<<^>^v^v^.^v^v>>><>v^^^><>>v>.^<^.vv<# +#..><.>v<^v<.^^<^>^v<><<>.>>v<^<><>v^<.<<^>v^.>v^<^>vv^<<^>^.>..>.<<<<^<<<^>>^<<>v>^^^<^^<>^^><^.<>vv>^.v.^^^.^v<<.^>>><<.<>.^^v<>^<^v<<^>vvv>.^>^<^^>vv^^>>^.<>>>vv<<<.v>^<<>># +#>v<.v^>^^v..>>.^>.>>v><><><^>^>>.>v>><<.>.<>.v^^>v^><<><>^>^<>v^>v>^^>^><<.>>v<>v.<^v^^..v.>.^.<^v>v^v.>>>.><^>>>^>vv.^<.^v>v<.><>^>>>>.<<>><>^<.<.^>><>^^.>.>^^v>.^<<# +#>v><<<>v>.>.^>><<^<.^^^<.<>.>vv>.>v.^>v>^v>.v^^.vv^^<>v<><^^<^><^.^^>^v>>>^^<.>.><# +#<<>v>>>^<<<>^.v>v^><>^<^^.<>>>><><>^>v^<^vv^>^.<.v<^v.>>>^v.v>>>v<^^>>.>^v>.vv>><<>v^>.v^<>v<# +#>^>><^<.>>>>.>.v.>vvv^^^v^<>^<><^>.>^.v^>.<^v<^v>^..v^^>><.^^>.vv>>>>vvv.^<>>v<>>v>vv^v<>><# +#>^^>v^^>..<.>^^<.>v<.><^<>>.<<<^v<>v>^<.^^>^<>>v.>v^v>.<>vv<>.v^>v.v>>><.>v>v^v<>>v<# +#<^v.v>>^^^<^^<^>><>^>><<><^.<^v<.>^^>v<^^^^.>>^v.><..>.>v><>^>v.v>^v<^v.vv<><><<^v^vv<<^<^>^<.<<>>.# +#>^v<^^v>vv^.^.>>.v>>.^.^.v^>^><>v>>^>>.v.vvvv.vv><<<>vv>v<<<^<>.^^.<<..v>^^<<^^<<>><>>v^^v.<<>v^^<^^v>>v><^v^<<>.>>>>^.v>^^^<..^>>>>.><^^^<^^>>^>vv>^<^<<^<<<<>>>.v^<.^^^^<.v^^^v<<^v<^^<^v<^>.^<<<>>^<.<<<^^># +#v^.v>>><.<<>^.v<<<^^<.^^>>v>>v<^^^<.>vv..>^>>><.v^v^v^<>^>vvv>vvv.^>>.^^<# +#><<.^>>^><<>>>v<>v^>^^^<^><>^>>^v^^^<.>>^vv<^v><>>^<>^^^>^>^>v^vv^<>.^.^^v^.vv^^^>^v>^v.>^>v><<^.v^.<>v^>^^v<><# +#>v>^..<^^>^<^^^^.vv<^v<^<..^^>v^>^^^>.v><..>vvv<<^.^<^v<<<<>^v^>.vv^<<<<>^v><>>># +#>>>><<><<<>vvv^>^>..v^<<<><.>><<><^vvvv<<>><^>^>.>v>v^v>.<^vvv>..v>v<<^><>v>>^># +#>^v<<^^vv^>v^><^^^^>v^v^>>.>vv<>v>^<<vvv>v^^^^<^^.v>>><^v>v^<^<><^v>><<^<<^<^.vv<^<<><>># +#><^>>vv<<^v<<^^<><>>^^>><><^>><<^>.vv^><>>v>v^>>vvv>>v..>^<.^<.v.<<^>>^^>v>>.>^v<<<# +#><<<^.v^^>.v>>v>>^<>v>>>..^v>.^<>^v..vv^<>^..^<^^.vv<<>.^.<<^v^<^>>v^>^v<><>.>v^^vv><^^># +#<.^v^<^v<<^<>^>.v<^>>vv<^v<.<>^^>><>.>vv^>>^<.>>v^v.vvvv<^v.^>><<<><>>^><^v>v<>>^^>v<# +#>>.^<.^>^.<^<.<<<><<v<..^^<.v^<>^>^<><^<<^.>>vv><<<^^v>^>v.<<<^^.>>.^v>>>># +#>^.^<<<<..^>>.v<<<^.v>^<<<>>.^.^><>>v>^>>v^v<<<^^><>>>.>>^>^.v.><^^^vv<^<><^<.vv><<^<.>>vv^vv><# +########################################################################################################################.# diff --git a/2022/rust/src/main.rs b/2022/rust/src/main.rs index 46b2b13..aea977e 100644 --- a/2022/rust/src/main.rs +++ b/2022/rust/src/main.rs @@ -25,5 +25,6 @@ fn main() { // solutions::day20::run(); // solutions::day21::run(); // solutions::day22::run(); - solutions::day23::run(); + // solutions::day23::run(); + solutions::day24::run(); } diff --git a/2022/rust/src/solutions/day24.rs b/2022/rust/src/solutions/day24.rs index aedca7c..acd3890 100644 --- a/2022/rust/src/solutions/day24.rs +++ b/2022/rust/src/solutions/day24.rs @@ -1,4 +1,5 @@ -use std::collections::HashSet; +use std::cmp::Ordering; +use std::collections::{BinaryHeap, HashMap, HashSet}; use crate::utils; @@ -11,6 +12,8 @@ pub fn run() -> () { } +type Pos = (isize, isize); + #[derive(Copy, Clone, Debug)] enum Dir { U, D, L, R @@ -19,11 +22,11 @@ enum Dir { #[derive(Copy, Clone, Debug)] struct Blizzard { dir: Dir, - pos: (isize, isize), + pos: Pos, } -fn offset_blizzards(blizzards: &[Blizzard], (rows, cols): (isize, isize), offset: isize) -> HashSet<(isize, isize)> { +fn offset_blizzards(blizzards: &[Blizzard], (rows, cols): (isize, isize), offset: isize) -> HashSet { blizzards.iter() .map(|&Blizzard { dir, pos: (row, col) }| match dir { Dir::U => ((row - offset).rem_euclid(rows), col), @@ -35,10 +38,62 @@ fn offset_blizzards(blizzards: &[Blizzard], (rows, cols): (isize, isize), offset } -fn solve1((dims, blizzards): &((isize, isize), Vec)) -> i32 { - let o = offset_blizzards(blizzards, *dims, 5); - println!("{o:?}"); - 1 +#[derive(Copy, Clone, Eq, PartialEq)] +struct State { + cost: isize, + position: (isize, Pos), +} + +impl Ord for State { + fn cmp(&self, other: &Self) -> Ordering { + other.cost.cmp(&self.cost).then_with(|| self.position.cmp(&other.position)) + } +} + +impl PartialOrd for State { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +fn neighbours((row, col): Pos, (rows, cols): (isize, isize)) -> impl Iterator { + [(row, col), (row+1, col), (row-1, col), (row, col+1), (row, col-1)].into_iter().filter(move |&(n_row, n_col)| + 0 <= n_row && (n_row < rows || n_col == cols - 1) && 0 <= n_col && n_col < cols) +} + +fn manhattan(start: Pos, goal: Pos) -> isize { + (start.0.abs_diff(goal.0) + start.1.abs_diff(goal.1)) as isize +} + +fn a_star(start: Pos, goal: Pos, dims: (isize, isize), blizzards: &[Blizzard]) -> Option { + let mut frontier: BinaryHeap = BinaryHeap::new(); + let mut parent: HashMap<(isize, Pos), (isize, Pos)> = HashMap::new(); + let mut cost: HashMap<(isize, Pos), isize> = HashMap::from([((0, start), 0)]); + + frontier.push(State { cost: 0, position: (0, start) }); + while let Some(State { position: (cur_t, cur_pos), .. }) = frontier.pop() { + if cur_pos == goal { return Some(cur_t) }; + let next_t = cur_t + 1; + let blizzards = offset_blizzards(blizzards, dims, next_t); + + for neighbour in neighbours(cur_pos, dims).filter(|p| !blizzards.contains(p)) { + let new_cost = cost.get(&(cur_t, cur_pos)).unwrap() + 1; + if !cost.contains_key(&(next_t, neighbour)) || new_cost < cost[&(next_t, neighbour)] { + cost.insert((next_t, neighbour), new_cost); + parent.insert((next_t, neighbour), (cur_t, cur_pos)); + frontier.push(State { + cost: new_cost + manhattan(neighbour, goal), + position: (next_t, neighbour), + }); + } + } + } + None +} + +fn solve1((dims, blizzards): &((isize, isize), Vec)) -> isize { + let (start, goal) = ((-1_isize, 0_isize), (dims.0, dims.1 - 1)); + a_star(start, goal, *dims, blizzards).unwrap() } fn solve2(data: &((isize, isize), Vec)) -> i32 { @@ -52,9 +107,10 @@ fn parse_data>(data: &[T]) -> ((isize, isize), Vec) { let blizzards = data.iter() .skip(1) .enumerate() - .flat_map(|(row, line)| { - let line = line.as_ref(); - line.chars().skip(1).enumerate().filter_map(move |(col, char)| { + .flat_map(|(row, line)| line.as_ref().chars() + .skip(1) + .enumerate() + .filter_map(move |(col, char)| { let pos = (row as isize, col as isize); match char { '^' => Some(Blizzard { dir: Dir::U, pos }), @@ -62,9 +118,7 @@ fn parse_data>(data: &[T]) -> ((isize, isize), Vec) { '<' => Some(Blizzard { dir: Dir::L, pos }), '>' => Some(Blizzard { dir: Dir::R, pos }), _ => None, - } - }) - }) + }})) .collect(); ((rows, cols), blizzards) } @@ -75,19 +129,18 @@ mod tests { use super::*; static DATA: &[&str] = &[ - "#.#####", - "#.....#", - "#>....#", - "#.....#", - "#...v.#", - "#.....#", - "#####.#", + "#.######", + "#>>.<^<#", + "#.<..<<#", + "#>v.><>#", + "#<^v^^>#", + "######.#", ]; #[test] fn part1() { let data = parse_data(DATA); - assert_eq!(1, solve1(&data)); + assert_eq!(18, solve1(&data)); } #[test]