]> git.huck.website - cellseq.git/commitdiff
refactored: made maps into a trait and genericized masks
authorHuck Boles <huck@huck.website>
Sun, 28 May 2023 21:58:44 +0000 (16:58 -0500)
committerHuck Boles <huck@huck.website>
Sun, 28 May 2023 21:58:44 +0000 (16:58 -0500)
src/cells.rs
src/cli.rs [deleted file]
src/graphics.rs [new file with mode: 0644]
src/graphics/map.rs [new file with mode: 0644]
src/graphics/point.rs [new file with mode: 0644]
src/lib.rs
src/main.rs

index ca92d4871b690dbc91f455f5e7fd0cdc4698a400..c0fceb8fd588195771d88d2afb5a972c25860fef 100644 (file)
@@ -1,6 +1,7 @@
+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 {
@@ -8,24 +9,47 @@ 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
@@ -52,31 +76,32 @@ impl 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 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
diff --git a/src/cli.rs b/src/cli.rs
deleted file mode 100644 (file)
index 0ef0a8f..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-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);
-        }
-    }
-}
diff --git a/src/graphics.rs b/src/graphics.rs
new file mode 100644 (file)
index 0000000..44fc0dd
--- /dev/null
@@ -0,0 +1,75 @@
+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);
+        }
+    }
+}
diff --git a/src/graphics/map.rs b/src/graphics/map.rs
new file mode 100644 (file)
index 0000000..a003edc
--- /dev/null
@@ -0,0 +1,55 @@
+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) {}
+}
diff --git a/src/graphics/point.rs b/src/graphics/point.rs
new file mode 100644 (file)
index 0000000..2585d35
--- /dev/null
@@ -0,0 +1,62 @@
+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,
+        }
+    }
+}
index 6f19c4e073bd61ed784ba2d9509458cc1989ff56..f5e7525e6e21248207591c11dde31b603d59f845 100644 (file)
@@ -1,7 +1,14 @@
 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())
+}
index c5a7442b49020633663ab488b1cd42b38487267f..fe995fb8a3675e13226b8d764b168aebf8435110 100644 (file)
@@ -2,12 +2,13 @@ use cellseq::*;
 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(())
 }