diff --git a/src/bin/predprey/main.rs b/src/bin/predprey/main.rs index ed83642..2ba9fbe 100644 --- a/src/bin/predprey/main.rs +++ b/src/bin/predprey/main.rs @@ -11,6 +11,7 @@ use rand::Rng; use pixelfoo::color::Color; use pixelfoo::point2d::Point2d; use pixelfoo::rect2d::Rect2d; +use pixelfoo::v2; use pixelfoo::vec2d::Vec2d; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -21,10 +22,39 @@ enum Square { Fox, } -type Board = Vec>; +struct Board(Vec>); + +impl Board { + pub fn new(size: Vec2d, mut f: impl FnMut() -> Square) -> Board { + Board( + repeat_with(|| { + repeat_with(&mut f) + .take(size.x as usize) + .collect::>() + }) + .take(size.y as usize) + .collect::>(), + ) + } + pub fn size(&self) -> Vec2d { + let x_size = self.0[0].len() as i32; + let y_size = self.0.len() as i32; + v2!(x_size, y_size) + } + pub fn rect(&self) -> Rect2d { + Rect2d::new(0, self.size().x, 0, self.size().y) + } + pub fn get(&self, pos: Point2d) -> Square { + self.0[pos.y as usize][pos.x as usize] + } + pub fn set(&mut self, pos: Point2d, sq: Square) { + self.0[pos.y as usize][pos.x as usize] = sq; + } +} fn send(w: &mut T, board: &Board) -> std::io::Result<()> { - for line in board { + let Board(lines) = board; + for line in lines { for square in line { let c = match square { Square::Empty => Color::blue(), @@ -41,12 +71,10 @@ fn send(w: &mut T, board: &Board) -> std::io::Result<()> { const DEFAULT_ARG: usize = 10; fn grow(board: &Board, pos: Point2d, grow: Square, die: Square) -> Square { - let x_size = board[0].len() as i32; - let y_size = board.len() as i32; for dir in Vec2d::directions() { let pos1 = pos + dir; - if 0 <= pos1.x && pos1.x < x_size && 0 <= pos1.y && pos1.y < y_size { - let neigh_sq = board[pos1.y as usize][pos1.x as usize]; + if board.rect().contains(pos1) { + let neigh_sq = board.get(pos); if neigh_sq == grow { return grow; } @@ -65,35 +93,28 @@ fn main() -> std::io::Result<()> { eprintln!("screen size {}x{}, arg {}", x_size, y_size, arg); let mut rng = thread_rng(); + let size = v2!(x_size as i32, y_size as i32); let p_empty = 0.25; let p_grass = 0.25; let p_rabbit = 0.25; // p_fox = 0.05 - let mut board = repeat_with(|| { - repeat_with(|| { - let p = rng.gen::(); - if p < p_empty { - Square::Empty - } else if p < p_empty + p_grass { - Square::Grass - } else if p < p_empty + p_grass + p_rabbit { - Square::Rabbit - } else { - Square::Fox - } - }) - .take(x_size) - .collect::>() - }) - .take(y_size) - .collect::>(); + let mut board = Board::new(size, || { + let p = rng.gen::(); + if p < p_empty { + Square::Empty + } else if p < p_empty + p_grass { + Square::Grass + } else if p < p_empty + p_grass + p_rabbit { + Square::Rabbit + } else { + Square::Fox + } + }); let t_frame = 0.040; // s let delay = Duration::new(0, (1_000_000_000.0 * t_frame) as u32); - let board_rect = Rect2d::new(0, x_size as i32, 0, y_size as i32); - // mid point of the board let x_mid = (x_size - 1) as f64 / 2.0; let y_mid = (y_size - 1) as f64 / 2.0; @@ -103,8 +124,8 @@ fn main() -> std::io::Result<()> { loop { for _ in 0..arg { - let pos = board_rect.random_point(&mut rng); - let sq = board[pos.y as usize][pos.x as usize]; + let pos = board.rect().random_point(&mut rng); + let sq = board.get(pos); let dx = (pos.x as f64 - x_mid as f64) / r as f64; let dy = (pos.y as f64 - y_mid as f64) / r as f64; let p0 = (dx * dx + dy * dy).min(1.0); @@ -119,12 +140,15 @@ fn main() -> std::io::Result<()> { } else { Square::Empty }; - board[pos.y as usize][pos.x as usize] = match sq { - Square::Empty => grow(&board, pos, Square::Grass, new_sq), - Square::Grass => grow(&board, pos, Square::Rabbit, new_sq), - Square::Rabbit => grow(&board, pos, Square::Fox, new_sq), - Square::Fox => new_sq, - }; + board.set( + pos, + match sq { + Square::Empty => grow(&board, pos, Square::Grass, new_sq), + Square::Grass => grow(&board, pos, Square::Rabbit, new_sq), + Square::Rabbit => grow(&board, pos, Square::Fox, new_sq), + Square::Fox => new_sq, + }, + ); } let mut buf = Vec::with_capacity(x_size * y_size * 3);