#[macro_use]
extern crate failure;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate packed_simd;
mod life;
pub mod node;
pub mod parse;
pub use crate::life::Life;
use crate::{node::Quadrant, parse::rle::RleError};
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "IO error: {}", io)]
Io { io: std::io::Error },
#[fail(display = "RLE pattern error: {}", rle)]
Rle { rle: RleError },
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Cell {
Alive,
Dead,
}
impl Cell {
pub fn new(alive: bool) -> Self {
if alive {
Cell::Alive
} else {
Cell::Dead
}
}
pub fn is_alive(self) -> bool {
match self {
Cell::Alive => true,
Cell::Dead => false,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Position {
pub x: i64,
pub y: i64,
}
impl Position {
pub fn new(x: i64, y: i64) -> Self {
Self { x, y }
}
pub fn offset(&self, x_offset: i64, y_offset: i64) -> Self {
Self {
x: self.x + x_offset,
y: self.y + y_offset,
}
}
pub fn quadrant(&self) -> Quadrant {
match (self.x < 0, self.y < 0) {
(true, true) => Quadrant::Northwest,
(false, true) => Quadrant::Northeast,
(true, false) => Quadrant::Southwest,
(false, false) => Quadrant::Southeast,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BoundingBox {
upper_left: Position,
lower_right: Position,
}
impl BoundingBox {
pub fn new(upper_left: Position, lower_right: Position) -> Self {
assert!(upper_left.x <= lower_right.x);
assert!(upper_left.y <= lower_right.y);
Self {
upper_left,
lower_right,
}
}
pub fn upper_left(&self) -> Position {
self.upper_left
}
pub fn lower_right(&self) -> Position {
self.lower_right
}
pub fn combine(&self, other: BoundingBox) -> Self {
let min_x = Ord::min(self.upper_left.x, other.upper_left.x);
let min_y = Ord::min(self.upper_left.y, other.upper_left.y);
let max_x = Ord::max(self.lower_right.x, other.lower_right.x);
let max_y = Ord::max(self.lower_right.y, other.lower_right.y);
Self::new(Position::new(min_x, min_y), Position::new(max_x, max_y))
}
pub fn intersect(&self, other: BoundingBox) -> Option<Self> {
let min_x = Ord::max(self.upper_left.x, other.upper_left.x);
let min_y = Ord::max(self.upper_left.y, other.upper_left.y);
let max_x = Ord::min(self.lower_right.x, other.lower_right.x);
let max_y = Ord::min(self.lower_right.y, other.lower_right.y);
if min_x > max_x || min_y > max_y {
None
} else {
Some(Self::new(
Position::new(min_x, min_y),
Position::new(max_x, max_y),
))
}
}
pub fn offset(&self, x_offset: i64, y_offset: i64) -> Self {
Self::new(
self.upper_left.offset(x_offset, y_offset),
self.lower_right.offset(x_offset, y_offset),
)
}
pub fn pad(&self, amount: i64) -> Self {
assert!(amount >= 0);
Self {
upper_left: self.upper_left.offset(-amount, -amount),
lower_right: self.lower_right.offset(amount, amount),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cell() {
let alive = Cell::new(true);
let dead = Cell::new(false);
assert!(alive.is_alive());
assert!(!dead.is_alive());
}
}