day6: complete solution + grid lib (used in solution)
This commit is contained in:
7
libs/grid/Cargo.lock
generated
Normal file
7
libs/grid/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "grid"
|
||||
version = "0.1.0"
|
6
libs/grid/Cargo.toml
Normal file
6
libs/grid/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "grid"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
188
libs/grid/src/lib.rs
Normal file
188
libs/grid/src/lib.rs
Normal file
@ -0,0 +1,188 @@
|
||||
use std::{
|
||||
fmt::{self, Debug, Display, Formatter, Write},
|
||||
io::{BufRead, Cursor, Lines},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Grid<T> {
|
||||
data: Vec<T>,
|
||||
width: i64,
|
||||
}
|
||||
|
||||
impl<T: Copy + Eq + PartialEq + Display + Debug> Grid<T> {
|
||||
pub fn new(width: i64) -> Self {
|
||||
Self {
|
||||
data: Vec::new(),
|
||||
width,
|
||||
}
|
||||
}
|
||||
pub fn width(&self) -> usize {
|
||||
return self.width as usize;
|
||||
}
|
||||
pub fn height(&self) -> usize {
|
||||
return self.data.len() / self.width();
|
||||
}
|
||||
fn pos(&self, x: i64, y: i64) -> i64 {
|
||||
y * self.width + x
|
||||
}
|
||||
fn coord(&self, pos: i64) -> Option<(i64, i64)> {
|
||||
if pos < 0 || pos >= self.data.len() as i64 {
|
||||
None
|
||||
} else {
|
||||
Some((pos % self.width, pos / self.width))
|
||||
}
|
||||
}
|
||||
fn valid_pos(&self, x: i64, y: i64) -> Option<usize> {
|
||||
if x < 0 || x >= self.width {
|
||||
return None;
|
||||
}
|
||||
if y < 0 || y >= self.data.len() as i64 / self.width {
|
||||
return None;
|
||||
}
|
||||
let pos = self.pos(x, y);
|
||||
if pos < 0 || pos as usize >= self.data.len() {
|
||||
return None;
|
||||
}
|
||||
self.pos(x, y).try_into().ok()
|
||||
}
|
||||
pub fn get(&self, x: i64, y: i64) -> Option<T> {
|
||||
match self.valid_pos(x, y) {
|
||||
Some(pos) => Some(self.data[pos]),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
pub fn set(&mut self, x: i64, y: i64, val: T) -> bool {
|
||||
match self.valid_pos(x, y) {
|
||||
Some(pos) => {
|
||||
self.data[pos] = val;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
pub fn row(&self, y: i64) -> Option<&[T]> {
|
||||
if y < self.height() as i64 {
|
||||
Some(&self.data[self.pos(0, y) as usize..self.pos(self.width, y) as usize])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find(&self, haystack: T) -> Option<(i64, i64)> {
|
||||
self.coord(
|
||||
self.data
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(pos, val)| if *val == haystack { Some(pos as i64) } else { None })
|
||||
.unwrap_or(-1),
|
||||
)
|
||||
}
|
||||
pub fn count(&self, haystack: T) -> usize {
|
||||
self.data.iter().filter(|item| **item == haystack).count()
|
||||
}
|
||||
|
||||
pub fn forward_slice(&self, x: i64, y: i64, len: i64) -> Option<&[T]> {
|
||||
let pos = (self.valid_pos(x, y), self.valid_pos(x + len - 1, y));
|
||||
match pos {
|
||||
(Some(pos1), Some(pos2)) => Some(&self.data[pos1..pos2 + 1]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// fn window_compare_impl<const REV: bool>(&self, needle: &[T]) -> Vec<(i64, i64)> {
|
||||
// if (self.width as usize) < needle.len() {
|
||||
// return Vec::new();
|
||||
// }
|
||||
// let mut res = Vec::new();
|
||||
// for y in 0..self.height() as i64 {
|
||||
// let mut windows_tmp = self.row(y).unwrap().windows(needle.len());
|
||||
// let windows = if REV {
|
||||
// windows_tmp.rev()
|
||||
// } else {
|
||||
// windows_tmp
|
||||
// };
|
||||
|
||||
// res.extend(
|
||||
// windows
|
||||
// .enumerate()
|
||||
// .filter_map(|(x, w)| if w == needle { Some((x as i64, y)) } else { None }),
|
||||
// );
|
||||
// }
|
||||
// res
|
||||
// }
|
||||
}
|
||||
|
||||
impl<T: BufRead> From<Lines<T>> for Grid<u8> {
|
||||
fn from(input: Lines<T>) -> Grid<u8> {
|
||||
let mut data = Vec::new();
|
||||
let mut width = 0;
|
||||
for line in input.map(|i| i.unwrap()) {
|
||||
if width == 0 {
|
||||
width = line.len() as i64
|
||||
} else if line.len() as i64 != width {
|
||||
panic!("Grids must have fixed length rows")
|
||||
}
|
||||
data.extend_from_slice(line.as_bytes());
|
||||
}
|
||||
Grid { data, width }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Eq + PartialEq + Display + Debug> Display for Grid<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
for y in 0..self.height() {
|
||||
for x in 0..self.width() {
|
||||
self.get(x as i64, y as i64).fmt(f);
|
||||
}
|
||||
}
|
||||
f.write_char('\n')
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
static TEST_VECTOR: &str = &"ABCD
|
||||
EFGH
|
||||
IJKL
|
||||
FBCG";
|
||||
|
||||
fn unchecked_load() -> Grid<u8> {
|
||||
Grid::from(Cursor::new(TEST_VECTOR).lines())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_string() {
|
||||
let grid = unchecked_load();
|
||||
assert_eq!(grid.data, "ABCDEFGHIJKLFBCG".as_bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexing() {
|
||||
let grid = unchecked_load();
|
||||
assert_eq!(grid.get(0, 0), Some(b'A'));
|
||||
assert_eq!(grid.get(3, 3), Some(b'G'));
|
||||
assert_eq!(grid.get(-1, 0), None);
|
||||
assert_eq!(grid.get(0, -1), None);
|
||||
assert_eq!(grid.get(5, 0), None);
|
||||
assert_eq!(grid.get(0, 5), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn forward_slice() {
|
||||
let grid = unchecked_load();
|
||||
assert_eq!(grid.forward_slice(0, 0, 2), Some(b"AB".as_slice()));
|
||||
assert_eq!(grid.forward_slice(2, 0, 2), Some(b"CD".as_slice()));
|
||||
assert_eq!(grid.forward_slice(2, 0, 3), None);
|
||||
assert_eq!(grid.forward_slice(0, 2, 4), Some(b"IJKL".as_slice()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_compare() {
|
||||
let grid = unchecked_load();
|
||||
assert_eq!(grid.window_compare(b"IJKL"), &[(0, 2)]);
|
||||
assert_eq!(grid.window_compare(b"BC"), &[(1, 0), (1, 3)]);
|
||||
assert_eq!(grid.window_compare(b"LF").len(), 0);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user