+use crate::{Map, Mask, Point};
use ndarray::Array2;
use rand::{thread_rng, Rng};
-use std::{cell::Cell, fmt::Display, ops::Deref};
+use std::{cell::Cell, ops::Deref};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum State {
Alive,
}
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct Map {
- pub map: Array2<Cell<State>>,
- pub rows: usize,
- pub cols: usize,
+#[derive(Clone, Debug)]
+pub struct World {
+ pub map: Mask<Cell<State>>,
}
-impl Map {
+impl World {
pub fn new(x: usize, y: usize) -> Self {
- let map = Array2::from_elem((y, x), Cell::new(State::Dead));
- Self {
- map,
- cols: x,
- rows: y,
+ let map = Mask::new(x, y, Cell::from(State::Dead));
+ Self { map }
+ }
+
+ pub fn randomize(&mut self, val: f64) {
+ let mut rng = thread_rng();
+ for cell in self.map.iter() {
+ if rng.gen::<f64>() > val {
+ cell.set(State::Alive)
+ } else {
+ cell.set(State::Dead)
+ }
+ }
+ }
+
+ fn wrap_walls(&mut self) {
+ for (bottom, top) in self.row(self.y_size() - 1).iter().zip(self.row(0).iter()) {
+ bottom.set(State::Dead);
+ top.set(State::Dead);
+ }
+
+ for (right, left) in self
+ .column(self.x_size() - 1)
+ .iter()
+ .zip(self.column(0).iter())
+ {
+ right.set(State::Dead);
+ left.set(State::Dead);
}
}
+}
- pub fn update(&mut self) {
+impl Map<Cell<State>> for World {
+ fn update(&mut self) {
let mut previous = self.clone();
previous.wrap_walls();
for (next, prev) in self
}
}
- pub fn randomize(&mut self, val: f64) {
- let mut rng = thread_rng();
- for cell in self.map.iter() {
- if rng.gen::<f64>() > val {
- cell.set(State::Alive)
- } else {
- cell.set(State::Dead)
- }
- }
+ fn x_size(&self) -> usize {
+ self.ncols()
}
- fn wrap_walls(&mut self) {
- for (bottom, top) in self.row(self.rows - 1).iter().zip(self.row(0).iter()) {
- bottom.set(State::Dead);
- top.set(State::Dead);
- }
+ fn y_size(&self) -> usize {
+ self.nrows()
+ }
- for (right, left) in self.column(self.cols - 1).iter().zip(self.column(0).iter()) {
- right.set(State::Dead);
- left.set(State::Dead);
+ fn graphics(&self) -> (char, char) {
+ ('●', '◌')
+ }
+
+ fn try_point(&self, point: Point) -> bool {
+ if let Some(cell) = self.get((point.y, point.x)) {
+ if cell.get() == State::Alive {
+ return true;
+ }
}
+ false
+ }
+ fn get_point(&self, point: Point) -> Option<Cell<State>> {
+ self.get((point.y, point.x)).cloned()
}
}
-impl Deref for Map {
+impl Deref for World {
type Target = Array2<Cell<State>>;
fn deref(&self) -> &Self::Target {
&self.map
+++ /dev/null
-use crate::{Map, State};
-use crossterm::{
- cursor,
- event::{self, read, Event},
- execute, queue,
- style::{self, Stylize},
- terminal, Result,
-};
-use ndarray::Array2;
-use std::{
- io::{stdout, Write},
- ops::Deref,
- thread,
- time::Duration,
-};
-
-pub type Origin = (usize, usize);
-
-#[derive(Clone, Debug)]
-pub struct Mask<T: Clone> {
- pub cols: usize,
- pub rows: usize,
- pub mask: Array2<Option<T>>,
-}
-
-impl<T: Clone> Mask<T> {
- pub fn new(x: usize, y: usize) -> Self {
- let mask = Array2::from_elem((y, x), None);
- Self {
- cols: x,
- rows: y,
- mask,
- }
- }
-}
-
-impl<T: Clone> Deref for Mask<T> {
- type Target = Array2<Option<T>>;
- fn deref(&self) -> &Self::Target {
- &self.mask
- }
-}
-
-pub fn edit_mask<T: Clone>(mask: &Mask<T>, origin: Origin) -> Result<()> {
- todo!()
-}
-
-pub fn draw_mask<T: Clone>(mask: &Mask<T>, origin: Origin) -> Result<()> {
- execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
- for x in 1..(mask.cols - 1) {
- for y in 1..(mask.rows - 1) {
- let x_off: u16 = (x + origin.0).try_into().unwrap();
- let y_off: u16 = (y + origin.1).try_into().unwrap();
- if mask.get((y, x)).unwrap().is_some() {
- queue!(
- stdout(),
- cursor::Hide,
- cursor::MoveTo(x_off, y_off),
- style::PrintStyledContent("■".green())
- )?;
- } else {
- queue!(
- stdout(),
- cursor::Hide,
- cursor::MoveTo(x_off, y_off),
- style::PrintStyledContent("□".grey())
- )?;
- }
- }
- }
- stdout().flush()
-}
-
-pub fn draw_frame(map: &Map, origin: Origin) -> Result<()> {
- for x in 1..(map.cols - 1) {
- for y in 1..(map.rows - 1) {
- let x_off: u16 = (x + origin.0).try_into().unwrap();
- let y_off: u16 = (y + origin.1).try_into().unwrap();
- if map.get((y, x)).unwrap().get() == State::Alive {
- queue!(
- stdout(),
- cursor::Hide,
- cursor::MoveTo(x_off, y_off),
- style::PrintStyledContent("●".green())
- )?;
- } else {
- queue!(
- stdout(),
- cursor::Hide,
- cursor::MoveTo(x_off, y_off),
- style::PrintStyledContent("◌".grey())
- )?;
- }
- }
- }
- stdout().flush()
-}
-
-pub fn run_map(map: &mut Map, origin: Origin, time: Duration) -> Result<()> {
- loop {
- map.update();
-
- execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
-
- draw_frame(&map, origin)?;
-
- thread::sleep(time);
- }
-}
-
-pub fn loop_map(map: &mut Map, origin: (usize, usize), time: Duration, steps: usize) -> Result<()> {
- loop {
- let mut tmp = map.clone();
- for _ in 0..steps {
- execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
- draw_frame(&tmp, origin)?;
- tmp.update();
- thread::sleep(time);
- }
- }
-}
--- /dev/null
+mod map;
+mod point;
+
+pub use map::*;
+pub use point::*;
+
+use crossterm::{
+ cursor, execute, queue,
+ style::{self, Stylize},
+ terminal, Result,
+};
+use std::{
+ io::{stdout, Write},
+ thread,
+ time::Duration,
+};
+
+pub struct Cursor {}
+
+pub fn draw_frame<T>(map: &mut impl Map<T>, offset: Point) -> Result<()> {
+ let (on, off) = map.graphics();
+ for x in 1..(map.x_size() - 1) {
+ for y in 1..(map.y_size() - 1) {
+ let point = Point::new(x, y);
+ let offset = point + offset;
+ let x_off: u16 = offset.x.try_into().unwrap();
+ let y_off: u16 = offset.y.try_into().unwrap();
+ if map.try_point(point) {
+ queue!(
+ stdout(),
+ cursor::Hide,
+ cursor::MoveTo(x_off, y_off),
+ style::PrintStyledContent(on.green())
+ )?;
+ } else {
+ queue!(
+ stdout(),
+ cursor::Hide,
+ cursor::MoveTo(x_off, y_off),
+ style::PrintStyledContent(off.grey())
+ )?;
+ }
+ }
+ }
+ stdout().flush()
+}
+
+pub fn run_map<T>(map: &mut impl Map<T>, offset: Point, time: Duration) -> Result<()> {
+ loop {
+ map.update();
+
+ execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
+
+ draw_frame(map, offset)?;
+
+ thread::sleep(time);
+ }
+}
+
+pub fn loop_map<T>(
+ map: &mut (impl Map<T> + Clone),
+ offset: Point,
+ time: Duration,
+ steps: usize,
+) -> Result<()> {
+ loop {
+ let mut tmp = map.clone();
+ for _ in 0..steps {
+ execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
+ draw_frame(&mut tmp, offset)?;
+ tmp.update();
+ thread::sleep(time);
+ }
+ }
+}
--- /dev/null
+use crate::Point;
+use ndarray::Array2;
+use std::ops::Deref;
+
+pub trait Map<T> {
+ fn try_point(&self, point: Point) -> bool;
+ fn get_point(&self, point: Point) -> Option<T>;
+ fn x_size(&self) -> usize;
+ fn y_size(&self) -> usize;
+ fn graphics(&self) -> (char, char);
+ fn update(&mut self);
+}
+
+#[derive(Debug, Clone)]
+pub struct Mask<T: Clone> {
+ pub mask: Array2<T>,
+}
+
+impl<T: Clone> Mask<T> {
+ pub fn new(x: usize, y: usize, default: T) -> Self {
+ let mask = Array2::from_elem((y, x), default);
+ Self { mask }
+ }
+}
+
+impl<T: Clone> Deref for Mask<T> {
+ type Target = Array2<T>;
+ fn deref(&self) -> &Self::Target {
+ &self.mask
+ }
+}
+
+impl<T: Clone> Map<T> for Mask<T> {
+ fn x_size(&self) -> usize {
+ self.ncols()
+ }
+
+ fn y_size(&self) -> usize {
+ self.nrows()
+ }
+
+ fn try_point(&self, point: Point) -> bool {
+ self.get((point.y, point.x)).is_some()
+ }
+
+ fn get_point(&self, point: Point) -> Option<T> {
+ self.get((point.y, point.x)).cloned()
+ }
+
+ fn graphics(&self) -> (char, char) {
+ ('■', '□')
+ }
+
+ fn update(&mut self) {}
+}
--- /dev/null
+use crossterm::style::{Attribute, Color};
+use std::ops::{Add, Div, Mul, Sub};
+
+pub struct Pixel {
+ pub location: Point,
+ pub value: char,
+ pub fg: Color,
+ pub bg: Color,
+ pub style: Attribute,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct Point {
+ pub x: usize,
+ pub y: usize,
+}
+
+impl Point {
+ pub fn new(x: usize, y: usize) -> Self {
+ Self { x, y }
+ }
+}
+
+impl Add for Point {
+ type Output = Self;
+ fn add(self, rhs: Self) -> Self::Output {
+ Self {
+ x: self.x + rhs.x,
+ y: self.y + rhs.y,
+ }
+ }
+}
+
+impl Sub for Point {
+ type Output = Self;
+ fn sub(self, rhs: Self) -> Self::Output {
+ Self {
+ x: self.x - rhs.x,
+ y: self.y - rhs.y,
+ }
+ }
+}
+
+impl Mul for Point {
+ type Output = Self;
+ fn mul(self, rhs: Self) -> Self::Output {
+ Self {
+ x: self.x * rhs.x,
+ y: self.y * rhs.y,
+ }
+ }
+}
+
+impl Div for Point {
+ type Output = Self;
+ fn div(self, rhs: Self) -> Self::Output {
+ Self {
+ x: self.x / rhs.x,
+ y: self.y / rhs.y,
+ }
+ }
+}
mod cells;
-mod cli;
+mod graphics;
mod music;
pub use cells::*;
-pub use cli::*;
+pub use graphics::*;
pub use music::*;
+
+use std::time::Duration;
+
+pub fn bpm_to_ms(bpm: usize) -> Duration {
+ let ms = 60000 / bpm;
+ Duration::from_millis(ms.try_into().unwrap())
+}
use eyre::Result;
fn main() -> Result<()> {
- let mut mask: Mask<bool> = Mask::new(48, 24);
- let mut map = Map::new(48, 24);
+ let mut mask: Mask<bool> = Mask::new(48, 24, false);
+ let mut map = World::new(48, 24);
map.randomize(0.75);
- // loop_map(&mut map, (10, 5), std::time::Duration::from_millis(250), 32)?;
- // draw_mask::<bool>(&mask, (10, 5))?;
- edit_mask(&mask, (10, 5))?;
+ let time = bpm_to_ms(120);
+
+ loop_map(&mut map, Point::new(10, 5), time, 32)?;
+ // edit_mask(&mask, (10, 5))?;
Ok(())
}