lifegame 0.3.18

A simple implementation of the classic cellular automaton, Conway's Game of Life.
use super::Filter;
use crate::biosquare::Cell;
use rand::RngExt;

const DEAD_SYMBOLS: &str = "🀒πŸ₯ΆπŸ₯΅πŸ˜‘πŸ€¬πŸ˜ˆπŸ‘ΏπŸ€‘πŸ‘»";
const ALIVE_SYMBOLS: &str = "🀣😊πŸ₯°πŸ˜πŸ€—πŸ€­πŸ˜‹πŸ€€πŸ˜€";

#[derive(Debug, PartialEq, Eq)]
pub struct Emoji {
    dead: &'static str,
    alive: &'static str,
}

impl Emoji {
    pub fn random() -> Self {
        let mut rng = rand::rng();
        let dead = Self::random_char(DEAD_SYMBOLS, &mut rng);
        let alive = Self::random_char(ALIVE_SYMBOLS, &mut rng);
        Self { dead, alive }
    }

    fn random_char<'a, R>(slice: &'a str, rng: &mut R) -> &'a str
    where
        R: RngExt,
    {
        let len = slice.chars().count();
        let index = rng.random_range(..len);
        let mut iter = slice.char_indices().skip(index).map(|(index, _)| index);
        let lower = iter.next().unwrap_or_else(|| unreachable!());
        let upper = iter.next().unwrap_or(slice.len());
        &slice[lower..upper]
    }
}

impl Filter for Emoji {
    fn filter(&self, cell: Cell) -> &str {
        match cell {
            Cell::Dead => self.dead,
            Cell::Alive => self.alive,
        }
    }
}