day6 fast
This commit is contained in:
parent
586dbbfe17
commit
02fe9aea97
|
@ -47,10 +47,42 @@ dependencies = [
|
||||||
"aoc-runner",
|
"aoc-runner",
|
||||||
"aoc-runner-derive",
|
"aoc-runner-derive",
|
||||||
"nom",
|
"nom",
|
||||||
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
"topological-sort",
|
"topological-sort",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
|
@ -97,6 +129,26 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
|
|
@ -7,5 +7,6 @@ edition = "2021"
|
||||||
aoc-runner = "0.3.0"
|
aoc-runner = "0.3.0"
|
||||||
aoc-runner-derive = "0.3.0"
|
aoc-runner-derive = "0.3.0"
|
||||||
nom = "7.1.3"
|
nom = "7.1.3"
|
||||||
|
rayon = "1.10.0"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
topological-sort = "0.2.2"
|
topological-sort = "0.2.2"
|
||||||
|
|
242
src/day6.rs
242
src/day6.rs
|
@ -1,29 +1,72 @@
|
||||||
type Input = ((usize, usize), Vec<Vec<u8>>);
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
type Input = ((usize, usize), Vec<Vec<u8>>);
|
||||||
|
// type Input = ((usize, usize), Vec<Vec<u8>>, Vec<Vec<[u8; 5]>>);
|
||||||
|
|
||||||
|
const UP: u8 = 0;
|
||||||
|
const DOWN: u8 = 1;
|
||||||
|
const LEFT: u8 = 2;
|
||||||
|
const RIGHT: u8 = 4;
|
||||||
|
const EMPTY: u8 = 8;
|
||||||
|
const WALL: u8 = 16;
|
||||||
|
const PASSED: u8 = 32;
|
||||||
|
|
||||||
|
const DIR: [(isize, isize); 5] = [(0, -1), (0, 1), (-1, 0), (0, 0), (1, 0)];
|
||||||
|
const NEXT_DIR: [usize; 5] = [RIGHT as usize, LEFT as usize, UP as usize, 0, DOWN as usize];
|
||||||
|
|
||||||
#[aoc_generator(day6)]
|
#[aoc_generator(day6)]
|
||||||
fn parse(input: &str) -> Input {
|
fn parse(input: &str) -> Input {
|
||||||
let lines = input.split("\n");
|
let lines = input.split("\n");
|
||||||
let mut pos = (0, 0);
|
let mut pos = (0, 0);
|
||||||
let map = lines
|
let mut stones = VecDeque::new();
|
||||||
|
|
||||||
|
let map: Vec<Vec<u8>> = lines
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(y, line)| {
|
.map(|(y, line)| {
|
||||||
line.chars()
|
line.chars()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(x, c)| match c {
|
.map(|(x, c)| match c {
|
||||||
'.' => 0,
|
'.' => EMPTY,
|
||||||
'#' => 1,
|
'#' => {
|
||||||
|
stones.push_back((x, y));
|
||||||
|
WALL
|
||||||
|
}
|
||||||
'^' => {
|
'^' => {
|
||||||
pos = (x, y);
|
pos = (x, y);
|
||||||
0
|
EMPTY
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// let mut jumps = vec![vec![[u8::MAX; 5]; map[0].len()]; map.len()];
|
||||||
|
|
||||||
|
// while let Some((x, y)) = stones.pop_front() {
|
||||||
|
// for dir in NEXT_DIR {
|
||||||
|
// let mut d = 1;
|
||||||
|
// loop {
|
||||||
|
// let pos = (x as isize - d * DIR[dir].0, y as isize - d * DIR[dir].1);
|
||||||
|
// if pos.0 < 0
|
||||||
|
// || pos.0 >= map[0].len() as isize
|
||||||
|
// || pos.1 < 0
|
||||||
|
// || pos.1 >= map.len() as isize
|
||||||
|
// || map[pos.1 as usize][pos.0 as usize] == WALL
|
||||||
|
// {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// jumps[pos.1 as usize][pos.0 as usize][dir] = (d - 1) as u8;
|
||||||
|
|
||||||
|
// d += 1;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// (pos, map, jumps)
|
||||||
(pos, map)
|
(pos, map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,161 +74,128 @@ fn parse(input: &str) -> Input {
|
||||||
fn part1(input: &Input) -> u64 {
|
fn part1(input: &Input) -> u64 {
|
||||||
let h = input.1.len();
|
let h = input.1.len();
|
||||||
let w = input.1[0].len();
|
let w = input.1[0].len();
|
||||||
|
|
||||||
let mut map = input.1.clone();
|
let mut map = input.1.clone();
|
||||||
let mut pos = input.0;
|
// let mut jumps = input.2.clone();
|
||||||
let mut dir = (0, -1);
|
|
||||||
|
let mut pos = ((input.0).0 as isize, (input.0).1 as isize);
|
||||||
|
let mut dir = UP as usize;
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if map[pos.1][pos.0] == 0 {
|
if map[pos.1 as usize][pos.0 as usize] == EMPTY {
|
||||||
map[pos.1][pos.0] = 2;
|
|
||||||
count += 1;
|
count += 1;
|
||||||
};
|
map[pos.1 as usize][pos.0 as usize] = PASSED;
|
||||||
if pos.0 as isize + dir.0 < 0
|
}
|
||||||
|| pos.0 as isize + dir.0 >= w as isize
|
|
||||||
|| pos.1 as isize + dir.1 < 0
|
if pos.0 + DIR[dir].0 < 0
|
||||||
|| pos.1 as isize + dir.1 >= h as isize
|
|| pos.0 + DIR[dir].0 >= w as isize
|
||||||
|
|| pos.1 + DIR[dir].1 < 0
|
||||||
|
|| pos.1 + DIR[dir].1 >= h as isize
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while map[(pos.1 as isize + dir.1) as usize][(pos.0 as isize + dir.0) as usize] == 1 {
|
|
||||||
if dir.0 == 1 {
|
while map[(pos.1 + DIR[dir].1) as usize][(pos.0 + DIR[dir].0) as usize] == WALL {
|
||||||
dir = (0, 1);
|
dir = NEXT_DIR[dir];
|
||||||
} else if dir.0 == -1 {
|
|
||||||
dir = (0, -1);
|
|
||||||
} else if dir.1 == 1 {
|
|
||||||
dir = (-1, 0);
|
|
||||||
} else if dir.1 == -1 {
|
|
||||||
dir = (1, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pos = (
|
|
||||||
(pos.0 as isize + dir.0) as usize,
|
let next_pos = (pos.0 + DIR[dir].0, pos.1 + DIR[dir].1);
|
||||||
(pos.1 as isize + dir.1) as usize,
|
pos = next_pos;
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day6, part2)]
|
#[aoc(day6, part2)]
|
||||||
|
|
||||||
fn part2(input: &Input) -> u64 {
|
fn part2(input: &Input) -> u64 {
|
||||||
let initial = input.0;
|
|
||||||
let h = input.1.len();
|
let h = input.1.len();
|
||||||
let w = input.1[0].len();
|
let w = input.1[0].len();
|
||||||
|
|
||||||
|
let initial = ((input.0).0 as isize, (input.0).1 as isize);
|
||||||
|
|
||||||
let mut map = input.1.clone();
|
let mut map = input.1.clone();
|
||||||
let mut pos = input.0;
|
|
||||||
let mut dir = (0, -1);
|
let mut pos = initial;
|
||||||
let mut loops = vec![];
|
let mut dir = UP as usize;
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if pos.0 as isize + dir.0 < 0
|
if pos.0 + DIR[dir].0 < 0
|
||||||
|| pos.0 as isize + dir.0 >= w as isize
|
|| pos.0 + DIR[dir].0 >= w as isize
|
||||||
|| pos.1 as isize + dir.1 < 0
|
|| pos.1 + DIR[dir].1 < 0
|
||||||
|| pos.1 as isize + dir.1 >= h as isize
|
|| pos.1 + DIR[dir].1 >= h as isize
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while map[(pos.1 as isize + dir.1) as usize][(pos.0 as isize + dir.0) as usize] == 1 {
|
|
||||||
if dir.0 == 1 {
|
while map[(pos.1 + DIR[dir].1) as usize][(pos.0 + DIR[dir].0) as usize] == WALL {
|
||||||
dir = (0, 1);
|
dir = NEXT_DIR[dir];
|
||||||
} else if dir.0 == -1 {
|
|
||||||
dir = (0, -1);
|
|
||||||
} else if dir.1 == 1 {
|
|
||||||
dir = (-1, 0);
|
|
||||||
} else if dir.1 == -1 {
|
|
||||||
dir = (1, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let next_pos = (
|
|
||||||
(pos.0 as isize + dir.0) as usize,
|
let next_pos = (pos.0 + DIR[dir].0, pos.1 + DIR[dir].1);
|
||||||
(pos.1 as isize + dir.1) as usize,
|
|
||||||
);
|
if next_pos != initial && map[next_pos.1 as usize][next_pos.0 as usize] == EMPTY {
|
||||||
if map[next_pos.1][next_pos.0] != 1 {
|
map[next_pos.1 as usize][next_pos.0 as usize] = WALL;
|
||||||
map[next_pos.1][next_pos.0] = 1;
|
if check_loop(pos, dir, &mut map) {
|
||||||
if check_loop(pos, dir, &map) {
|
count += 1;
|
||||||
// count += 1;
|
|
||||||
if !(loops.contains(&next_pos)) && next_pos != initial {
|
|
||||||
loops.push(next_pos);
|
|
||||||
}
|
|
||||||
// println!("{} {}", nexts_pos.0 + 1, next_pos.1 + 1);
|
|
||||||
}
|
}
|
||||||
map[next_pos.1][next_pos.0] = 0;
|
map[next_pos.1 as usize][next_pos.0 as usize] = PASSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = next_pos;
|
pos = next_pos;
|
||||||
}
|
}
|
||||||
loops.len() as u64
|
|
||||||
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut VISITED: [[[bool; 4]; 130]; 130] = [[[false; 4]; 130]; 130];
|
fn check_loop(mut pos: (isize, isize), mut dir: usize, map: &mut [Vec<u8>]) -> bool {
|
||||||
static mut VISITED_VEC: Vec<(usize, usize, usize)> = vec![];
|
|
||||||
|
|
||||||
fn check_loop(pos: (usize, usize), dir: (isize, isize), map: &[Vec<u8>]) -> bool {
|
|
||||||
let h = map.len();
|
let h = map.len();
|
||||||
let w = map[0].len();
|
let w = map[0].len();
|
||||||
|
|
||||||
unsafe {
|
let mut changed = Vec::with_capacity(w * h * 4);
|
||||||
VISITED_VEC.clear();
|
|
||||||
VISITED_VEC.reserve(w * h * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// let mut visited = [[[false; 4]; 130]; 130];
|
|
||||||
// let mut visited = HashSet::with_capacity(h * w * 4);
|
|
||||||
// let mut visited = 0;
|
|
||||||
|
|
||||||
let mut dir = dir;
|
|
||||||
let mut pos = pos;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if pos.0 as isize + dir.0 < 0
|
if pos.0 + DIR[dir].0 < 0
|
||||||
|| pos.0 as isize + dir.0 >= w as isize
|
|| pos.0 + DIR[dir].0 >= w as isize
|
||||||
|| pos.1 as isize + dir.1 < 0
|
|| pos.1 + DIR[dir].1 < 0
|
||||||
|| pos.1 as isize + dir.1 >= h as isize
|
|| pos.1 + DIR[dir].1 >= h as isize
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let mut turns = 0;
|
|
||||||
while map[(pos.1 as isize + dir.1) as usize][(pos.0 as isize + dir.0) as usize] == 1 {
|
|
||||||
if dir.0 == 1 {
|
|
||||||
dir = (0, 1);
|
|
||||||
} else if dir.0 == -1 {
|
|
||||||
dir = (0, -1);
|
|
||||||
} else if dir.1 == 1 {
|
|
||||||
dir = (-1, 0);
|
|
||||||
} else if dir.1 == -1 {
|
|
||||||
dir = (1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
turns += 1;
|
let mut turn = false;
|
||||||
|
while map[(pos.1 + DIR[dir].1) as usize][(pos.0 + DIR[dir].0) as usize] == WALL {
|
||||||
|
dir = NEXT_DIR[dir];
|
||||||
|
turn = true;
|
||||||
}
|
}
|
||||||
if turns == 2 {
|
|
||||||
break;
|
let next_pos = (pos.0 + DIR[dir].0, pos.1 + DIR[dir].1);
|
||||||
}
|
|
||||||
pos = (
|
if turn {
|
||||||
(pos.0 as isize + dir.0) as usize,
|
if map[next_pos.1 as usize][next_pos.0 as usize] & dir as u8 != 0 {
|
||||||
(pos.1 as isize + dir.1) as usize,
|
changed.into_iter().for_each(|pos: (isize, isize)| {
|
||||||
);
|
map[pos.1 as usize][pos.0 as usize] &= PASSED | WALL | EMPTY;
|
||||||
let dirnum = ((dir.1 + 1) >> 2) as usize + (dir.0 + 1) as usize;
|
});
|
||||||
unsafe {
|
|
||||||
if VISITED[pos.1][pos.0][dirnum] {
|
|
||||||
clear_visited();
|
|
||||||
return true;
|
return true;
|
||||||
} else if turns > 0 {
|
} else {
|
||||||
VISITED[pos.1][pos.0][dirnum] = true;
|
map[next_pos.1 as usize][next_pos.0 as usize] |= dir as u8;
|
||||||
VISITED_VEC.push((pos.0, pos.1, dirnum));
|
changed.push(next_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos = next_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
changed.into_iter().for_each(|pos: (isize, isize)| {
|
||||||
clear_visited();
|
map[pos.1 as usize][pos.0 as usize] &= PASSED | WALL | EMPTY;
|
||||||
}
|
});
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn clear_visited() {
|
|
||||||
VISITED_VEC
|
|
||||||
.iter()
|
|
||||||
.for_each(|(a, b, c)| VISITED[*b][*a][*c] = false);
|
|
||||||
}
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -193,10 +203,12 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn part1_example() {
|
fn part1_example() {
|
||||||
assert_eq!(part1(&parse("....#.....\n.........#\n..........\n..#.......\n.......#..\n..........\n.#..^.....\n........#.\n#.........\n......#...")), 41);
|
assert_eq!(part1(&parse("....#.....\n.........#\n..........\n..#.......\n.......#..\n..........\n.#..^.....\n........#.\n#.........\n......#...")), 41);
|
||||||
|
assert_eq!(part1(&parse(include_str!("../input/2024/day6.txt"))), 4977);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part2_example() {
|
fn part2_example() {
|
||||||
assert_eq!(part2(&parse("....#.....\n.........#\n..........\n..#.......\n.......#..\n..........\n.#..^.....\n........#.\n#.........\n......#...")), 6);
|
assert_eq!(part2(&parse("....#.....\n.........#\n..........\n..#.......\n.......#..\n..........\n.#..^.....\n........#.\n#.........\n......#...")), 6);
|
||||||
|
assert_eq!(part2(&parse(include_str!("../input/2024/day6.txt"))), 1729);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue