267 lines
6.5 KiB
Rust
267 lines
6.5 KiB
Rust
use std::io::Read;
|
|
use std::collections::VecDeque;
|
|
use std::str::FromStr;
|
|
use std::fs::File;
|
|
use std::fmt::{Display, Formatter};
|
|
use std::ops::{Index, IndexMut};
|
|
|
|
use color_eyre::{eyre};
|
|
use eyre::eyre;
|
|
|
|
|
|
pub fn load(filename: &str) -> eyre::Result<String> {
|
|
let mut file = File::open(filename)?;
|
|
let mut data = String::new();
|
|
file.read_to_string(&mut data)?;
|
|
Ok(data)
|
|
}
|
|
|
|
|
|
pub struct LineParser<'a, T: FromStr> {
|
|
it: std::str::Lines<'a>,
|
|
convert: fn(&str) -> Result<T, <T as FromStr>::Err>
|
|
}
|
|
|
|
|
|
impl<'a, T: FromStr> Iterator for LineParser<'a, T> {
|
|
type Item = Result<T, <T as FromStr>::Err>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.it.next().map(|s|
|
|
(self.convert)(s)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
// define a trait so that we can attach it to String
|
|
pub trait ParseLines {
|
|
fn parse_lines<T: FromStr>(&self) -> LineParser<'_, T>;
|
|
}
|
|
|
|
|
|
impl ParseLines for str {
|
|
fn parse_lines<T: FromStr>(&self) -> LineParser<'_, T> {
|
|
LineParser {
|
|
it: self.lines(),
|
|
convert: str::parse::<T>
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl ParseLines for String {
|
|
fn parse_lines<T: FromStr>(&self) -> LineParser<'_, T> {
|
|
self[..].parse_lines::<T>()
|
|
}
|
|
}
|
|
|
|
|
|
pub trait IterExt: Iterator {
|
|
fn take_pair(&mut self) -> eyre::Result<(Self::Item, Self::Item)> {
|
|
let a = match self.next() {
|
|
Some(v) => v,
|
|
None => return Err(eyre!("Not enough values to unpack")),
|
|
};
|
|
let b = match self.next() {
|
|
Some(v) => v,
|
|
None => return Err(eyre!("Not enough values to unpack")),
|
|
};
|
|
Ok((a, b))
|
|
}
|
|
|
|
fn max_n(&mut self, n: usize) -> eyre::Result<VecDeque<Self::Item>>
|
|
where Self: Sized, Self::Item: Ord,
|
|
{
|
|
let mut items = VecDeque::with_capacity(n);
|
|
while let Some(item) = self.next() {
|
|
for i in 0..=items.len() {
|
|
if i < items.len() && item > items[i] {
|
|
if items.len() == n {
|
|
items.pop_back();
|
|
}
|
|
items.insert(i, item);
|
|
break;
|
|
}
|
|
else if i == items.len() && i < n {
|
|
items.push_back(item);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if items.len() < n {
|
|
Err(eyre!("Not enough values to take the maximum {}", n))
|
|
}
|
|
else {
|
|
Ok(items)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<I: Iterator> IterExt for I {}
|
|
|
|
|
|
// 2d container, functions kind of like a "vec of vecs" but all data is stored in a single vec for memory contiguity
|
|
pub struct Vec2<T> {
|
|
data: Vec<T>,
|
|
columns: usize,
|
|
}
|
|
|
|
|
|
pub struct NeighborCoords {
|
|
num_rows: usize,
|
|
num_cols: usize,
|
|
start_row: usize,
|
|
start_col: usize,
|
|
i: usize,
|
|
}
|
|
|
|
impl Iterator for NeighborCoords {
|
|
type Item = (usize, usize);
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.i > 8 {
|
|
return None;
|
|
}
|
|
|
|
let (rel_row, rel_col) = (self.i / 3, self.i % 3);
|
|
self.i += 1;
|
|
if rel_row == 1 && rel_col == 1 {
|
|
return self.next();
|
|
}
|
|
|
|
let row_offset = self.start_row + rel_row;
|
|
let col_offset = self.start_col + rel_col;
|
|
// the "neighbor window" is off by 1, so we make the comparisons off by 1 as well
|
|
if row_offset > 0 && row_offset <= self.num_rows
|
|
&& col_offset > 0 && col_offset <= self.num_cols
|
|
{
|
|
Some((row_offset - 1, col_offset - 1))
|
|
}
|
|
else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#[allow(dead_code)]
|
|
impl<T> Vec2<T> {
|
|
pub fn new(columns: usize) -> Vec2<T> {
|
|
Vec2 {data: Vec::<T>::new(), columns}
|
|
}
|
|
|
|
pub fn with_capacity(rows: usize, columns: usize) -> Vec2<T> {
|
|
Vec2 {data: Vec::<T>::with_capacity(rows * columns), columns}
|
|
}
|
|
|
|
pub fn push<S: IntoIterator<Item=T>>(&mut self, row: S) {
|
|
self.data.extend(row.into_iter());
|
|
}
|
|
|
|
pub fn row_count(&self) -> usize {
|
|
self.data.len() / self.columns
|
|
}
|
|
|
|
pub fn col_count(&self) -> usize {
|
|
self.columns
|
|
}
|
|
|
|
pub fn coords(&self, i: usize) -> (usize, usize) {
|
|
// convert underlying index into 2d coordinates
|
|
(i / self.columns, i % self.columns)
|
|
}
|
|
|
|
pub fn offset(&self, row: usize, col: usize) -> usize {
|
|
// and the reverse
|
|
self.columns * row + col
|
|
}
|
|
|
|
pub fn rows(&self) -> impl Iterator<Item=&[T]> {
|
|
self.data.chunks_exact(self.columns)
|
|
}
|
|
|
|
pub fn rows_mut(&mut self) -> impl Iterator<Item=&mut [T]> {
|
|
self.data.chunks_exact_mut(self.columns)
|
|
}
|
|
|
|
pub fn values(&self) -> impl Iterator<Item=&T> {
|
|
self.data.iter()
|
|
}
|
|
|
|
pub fn values_mut(&mut self) -> impl Iterator<Item=&mut T> {
|
|
self.data.iter_mut()
|
|
}
|
|
|
|
pub fn neighbor_coords(&self, row: usize, col: usize) -> NeighborCoords {
|
|
NeighborCoords {
|
|
num_rows: self.row_count(),
|
|
num_cols: self.col_count(),
|
|
start_row: row,
|
|
start_col: col,
|
|
i: 0,
|
|
}
|
|
}
|
|
|
|
pub fn get(&self, row: usize, col: usize) -> &T {
|
|
&self.data[self.offset(row, col)]
|
|
}
|
|
|
|
pub fn get_mut(&mut self, row: usize, col: usize) -> &mut T {
|
|
self.data.index_mut(self.offset(row, col))
|
|
}
|
|
|
|
pub fn set(&mut self, row: usize, col: usize, val: T) {
|
|
let existing = self.data.index_mut(self.offset(row, col));
|
|
*existing = val;
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
impl<T: Copy> Vec2<T> {
|
|
pub fn fill(&mut self, value: T) {
|
|
for i in 0..self.data.len() {
|
|
self.data[i] = value;
|
|
}
|
|
}
|
|
|
|
pub fn fill_to_cap(&mut self, value: T) {
|
|
self.fill(value);
|
|
for _i in self.data.len()..self.data.capacity() {
|
|
self.data.push(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl<T> Index<usize> for Vec2<T> {
|
|
type Output = [T];
|
|
fn index(&self, index: usize) -> &Self::Output {
|
|
let start = self.columns * index;
|
|
&self.data[start..(start + self.columns)]
|
|
}
|
|
}
|
|
|
|
|
|
impl<T> IndexMut<usize> for Vec2<T> {
|
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
let start = self.columns * index;
|
|
&mut self.data[start..(start + self.columns)]
|
|
}
|
|
}
|
|
|
|
|
|
impl<T: Display> Display for Vec2<T> {
|
|
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
|
for row in self.rows() {
|
|
write!(f, "[")?;
|
|
for (i, v) in row.iter().enumerate() {
|
|
if i > 0 {write!(f, ", ")?;}
|
|
write!(f, "{}", v)?;
|
|
}
|
|
write!(f, "]\n")?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|