This commit is contained in:
sepia 2024-12-12 15:14:17 -06:00
parent 78f7f2db49
commit 04f4adc410
4 changed files with 243 additions and 1 deletions

108
src/util/maps.rs Normal file
View file

@ -0,0 +1,108 @@
use itertools::Itertools;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Direction {
North,
South,
East,
West,
}
impl Direction {
pub fn all_variants() -> Vec<Self> {
vec![Self::North, Self::East, Self::West, Self::South]
}
}
#[derive(Clone)]
pub struct Map<T>
where
T: Copy,
{
pub map: Vec<Vec<T>>,
}
impl Map<char> {
pub fn from_string(string: &str) -> Self {
Map::from_2d_vec(
string
.lines()
.filter(|line| !line.is_empty())
.map(|line| line.chars().collect())
.collect(),
)
}
}
impl<T> Map<T>
where
T: Copy,
{
pub fn from_2d_vec(map: Vec<Vec<T>>) -> Self {
Self { map }
}
pub fn from_dimensions(width: usize, height: usize, default: T) -> Self {
Self {
map: vec![vec![default; width]; height],
}
}
pub fn travel(&self, x: usize, y: usize, direction: Direction) -> Option<(usize, usize)> {
match direction {
Direction::North => Some((x, y.checked_sub(1)?)),
Direction::South => {
if y + 1 < self.height() {
Some((x, y + 1))
} else {
None
}
}
Direction::West => Some((x.checked_sub(1)?, y)),
Direction::East => {
if x + 1 < self.width() {
Some((x + 1, y))
} else {
None
}
}
}
}
pub fn travel_get(&self, x: usize, y: usize, direction: Direction) -> Option<T> {
let (nx, ny) = self.travel(x, y, direction)?;
self.get(nx, ny)
}
pub fn get(&self, x: usize, y: usize) -> Option<T> {
Some(*self.map.get(y)?.get(x)?)
}
pub fn set(&mut self, x: usize, y: usize, value: T) {
self.map[y][x] = value
}
pub fn height(&self) -> usize {
self.map.len()
}
pub fn width(&self) -> usize {
self.map[0].len()
}
pub fn in_bounds(&self, x: usize, y: usize) -> bool {
x < self.width() && y < self.height()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.map.iter().flat_map(|row| row.iter())
}
pub fn coordinates(&self) -> impl Iterator<Item = (usize, usize)> {
(0..self.width()).cartesian_product(0..self.height())
}
pub fn enumerate(&self) -> impl Iterator<Item = (usize, usize, &T)> {
self.coordinates().map(|(x, y)| (x, y, &self.map[y][x]))
}
}