added grid utility and used it to speed up day 6
This commit is contained in:
29
src/day06.rs
29
src/day06.rs
@@ -3,6 +3,8 @@ use std::{
|
|||||||
fs::read_to_string,
|
fs::read_to_string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::utils::grid::Grid;
|
||||||
|
|
||||||
pub fn day_main() {
|
pub fn day_main() {
|
||||||
let input = read_to_string("input/day06.txt").unwrap();
|
let input = read_to_string("input/day06.txt").unwrap();
|
||||||
let input = input.trim();
|
let input = input.trim();
|
||||||
@@ -11,7 +13,7 @@ pub fn day_main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RiddleResult = usize;
|
type RiddleResult = usize;
|
||||||
type Point = (i32, i32);
|
type Point = (i64, i64);
|
||||||
|
|
||||||
fn part1(input: &str) -> RiddleResult {
|
fn part1(input: &str) -> RiddleResult {
|
||||||
let (m, pos) = parse(input);
|
let (m, pos) = parse(input);
|
||||||
@@ -21,13 +23,9 @@ fn part1(input: &str) -> RiddleResult {
|
|||||||
visited.len()
|
visited.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_visited(
|
fn get_visited(m: &Grid<char>, mut pos: Point, mut dir: char) -> HashSet<Point> {
|
||||||
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;
|
||||||
visited.insert(pos);
|
visited.insert(pos);
|
||||||
let next = match dir {
|
let next = match dir {
|
||||||
@@ -37,7 +35,7 @@ fn get_visited(
|
|||||||
'>' => (x + 1, y),
|
'>' => (x + 1, y),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
if let Some('#') = m.get(&next) {
|
if m.contains_key(next) && '#' == m[next] {
|
||||||
dir = match dir {
|
dir = match dir {
|
||||||
'^' => '>',
|
'^' => '>',
|
||||||
'v' => '<',
|
'v' => '<',
|
||||||
@@ -62,13 +60,13 @@ fn part2(input: &str) -> RiddleResult {
|
|||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(input: &str) -> (HashMap<Point, char>, Point) {
|
fn parse(input: &str) -> (Grid<char>, Point) {
|
||||||
let mut m = HashMap::new();
|
let mut m = HashMap::new();
|
||||||
let mut pos = None;
|
let mut pos = None;
|
||||||
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 i64;
|
||||||
let y = y as i32;
|
let y = y as i64;
|
||||||
if c == '^' {
|
if c == '^' {
|
||||||
pos = Some((x, y));
|
pos = Some((x, y));
|
||||||
m.insert((x, y), '.');
|
m.insert((x, y), '.');
|
||||||
@@ -77,10 +75,10 @@ fn parse(input: &str) -> (HashMap<Point, char>, Point) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
(m, pos.unwrap())
|
(Grid::from(m), pos.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_loop(m: &HashMap<Point, char>, block: Point, mut pos: Point, mut dir: char) -> bool {
|
fn is_loop(m: &Grid<char>, block: Point, mut pos: Point, mut dir: char) -> bool {
|
||||||
let mut visited = HashSet::new();
|
let mut visited = HashSet::new();
|
||||||
loop {
|
loop {
|
||||||
let (x, y) = pos;
|
let (x, y) = pos;
|
||||||
@@ -92,10 +90,9 @@ fn is_loop(m: &HashMap<Point, char>, block: Point, mut pos: Point, mut dir: char
|
|||||||
'>' => (x + 1, y),
|
'>' => (x + 1, y),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let next_tile = m.get(&next);
|
if !m.contains_key(next) {
|
||||||
if None == next_tile {
|
|
||||||
return false;
|
return false;
|
||||||
} else if next == block || Some(&'#') == next_tile {
|
} else if next == block || '#' == m[next] {
|
||||||
// we only check for loops on a collision to speed things up
|
// we only check for loops on a collision to speed things up
|
||||||
if visited.contains(&(pos, dir)) {
|
if visited.contains(&(pos, dir)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ pub mod day03;
|
|||||||
pub mod day04;
|
pub mod day04;
|
||||||
pub mod day05;
|
pub mod day05;
|
||||||
pub mod day06;
|
pub mod day06;
|
||||||
|
pub mod utils;
|
||||||
|
|||||||
109
src/utils/grid.rs
Normal file
109
src/utils/grid.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
ops::{Index, IndexMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A grid structure, indexed by (x, y) tuples. The top-left coordinate is (0, 0).
|
||||||
|
pub struct Grid<T> {
|
||||||
|
content_width: i64,
|
||||||
|
content_height: i64,
|
||||||
|
content: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Coord = (i64, i64);
|
||||||
|
|
||||||
|
impl<T> Grid<T> {
|
||||||
|
pub fn from(mut source: HashMap<Coord, T>) -> Grid<T> {
|
||||||
|
let x_max = source.keys().max_by_key(|c| c.0).unwrap().0;
|
||||||
|
let y_max = source.keys().max_by_key(|c| c.1).unwrap().1;
|
||||||
|
let content_width = x_max + 1;
|
||||||
|
let content_height = y_max + 1;
|
||||||
|
let mut content = Vec::with_capacity((content_width * content_height) as usize);
|
||||||
|
for y in 0..content_height {
|
||||||
|
for x in 0..content_width {
|
||||||
|
let v = source
|
||||||
|
.remove(&(x, y))
|
||||||
|
.unwrap_or_else(|| panic!("no entry for {x}, {y}"));
|
||||||
|
content.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Grid {
|
||||||
|
content_width,
|
||||||
|
content_height,
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index_of(&self, c: Coord) -> usize {
|
||||||
|
(c.1 * self.content_width + c.0) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, c: Coord) -> &T {
|
||||||
|
&self.content[self.index_of(c)]
|
||||||
|
}
|
||||||
|
pub fn get_mut(&mut self, c: Coord) -> &mut T {
|
||||||
|
let index_of = self.index_of(c);
|
||||||
|
&mut self.content[index_of]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, c: Coord, value: T) {
|
||||||
|
let index_of = self.index_of(c);
|
||||||
|
self.content[index_of] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains_key(&self, c: Coord) -> bool {
|
||||||
|
0 <= c.0 && c.0 < self.content_width && 0 <= c.1 && c.1 < self.content_height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Index<Coord> for Grid<T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: Coord) -> &Self::Output {
|
||||||
|
self.get(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IndexMut<Coord> for Grid<T> {
|
||||||
|
fn index_mut(&mut self, index: Coord) -> &mut Self::Output {
|
||||||
|
self.get_mut(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::Grid;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_and_read() {
|
||||||
|
let grid: Grid<char> = Grid::from(HashMap::from_iter([
|
||||||
|
((0, 0), '.'),
|
||||||
|
((0, 1), '.'),
|
||||||
|
((1, 0), '.'),
|
||||||
|
((1, 1), '#'),
|
||||||
|
]));
|
||||||
|
assert_eq!(&'.', grid.get((0, 0)));
|
||||||
|
assert_eq!(&'.', grid.get((0, 1)));
|
||||||
|
assert_eq!(&'.', grid.get((1, 0)));
|
||||||
|
assert_eq!(&'#', grid.get((1, 1)));
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn mutate_by_index() {
|
||||||
|
let mut grid = generate();
|
||||||
|
grid[(0, 1)] = 'x';
|
||||||
|
assert_eq!(&'x', grid.get((0, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate() -> Grid<char> {
|
||||||
|
let grid: Grid<char> = Grid::from(HashMap::from_iter([
|
||||||
|
((0, 0), '.'),
|
||||||
|
((0, 1), '.'),
|
||||||
|
((1, 0), '.'),
|
||||||
|
((1, 1), '.'),
|
||||||
|
]));
|
||||||
|
grid
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/utils/mod.rs
Normal file
1
src/utils/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod grid;
|
||||||
Reference in New Issue
Block a user