~athorp96/conway.rs

bf091e801b8a9bad1f600f64ac7a29b4b06d546f — Andrew Thorp 2 years ago
Initial commit
7 files changed, 304 insertions(+), 0 deletions(-)

A .gitignore
A Cargo.lock
A Cargo.toml
A src/conway/board.rs
A src/conway/conway.rs
A src/conway/mod.rs
A src/main.rs
A  => .gitignore +1 -0
@@ 1,1 @@
/target

A  => Cargo.lock +83 -0
@@ 1,83 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "conway"
version = "0.1.0"
dependencies = [
 "rand",
]

[[package]]
name = "getrandom"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
dependencies = [
 "cfg-if",
 "libc",
 "wasi",
]

[[package]]
name = "libc"
version = "0.2.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"

[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"

[[package]]
name = "rand"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [
 "libc",
 "rand_chacha",
 "rand_core",
 "rand_hc",
]

[[package]]
name = "rand_chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
 "ppv-lite86",
 "rand_core",
]

[[package]]
name = "rand_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
dependencies = [
 "getrandom",
]

[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
 "rand_core",
]

[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

A  => Cargo.toml +10 -0
@@ 1,10 @@
[package]
name = "conway"
version = "0.1.0"
authors = ["Andrew Thorp <andrew.thorp.dev@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.8.3"

A  => src/conway/board.rs +103 -0
@@ 1,103 @@
use rand::prelude::*;
use std::fmt;

use crate::conway::conway::{Cell, CellState, Coordinate, SimpleCell};

pub struct Board {
    width: usize,
    height: usize,
    cells: Vec<Vec<SimpleCell>>,
}

impl Board {
    pub fn new(width: usize, height: usize) -> Self {
        let mut cells: Vec<Vec<SimpleCell>> = Vec::with_capacity(height);

        // Initialize vectors
        for i in 0..height {
            let mut row = Vec::with_capacity(width);
            for j in 0..width {
                row.push(SimpleCell::new(Coordinate::new(i as i32, j as i32)));
            }
            cells.push(row);
        }

        Board {
            width,
            height,
            cells: cells,
        }
    }

    pub fn get(&self, x: usize, y: usize) -> Option<SimpleCell> {
        if x < self.width && x >= 0 && y < self.height && y >= 0 {
            Some(self.cells[x][y].clone())
        } else {
            None
        }
    }

    pub fn set(&mut self, x: usize, y: usize, state: CellState) {
        self.cells[x][y].set_state(state);
    }

    pub fn step(&mut self) {
        let mut cells = self.cells.clone();
        let mut display = String::new();
        for i in 0..cells.len() {
            for j in 0..cells[i].len() {
                let cell = cells[i][j].clone();
                cells[i][j].set_state(self.next_cell_step(cell));
            }
        }
        self.cells = cells;
    }

    fn next_cell_step(&self, cell: SimpleCell) -> CellState {
        let adj = cell.get_adjecent();
        let neighbors = self.get_cells(adj);
        let live_neighbors = neighbors.iter().filter(|c| c.is_alive()).count();

        // birth
        if !cell.is_alive() && live_neighbors == 3 {
            CellState::Alive
            // Starvation
        } else if cell.is_alive() && live_neighbors > 3 {
            CellState::Dead
            // Isolation
        } else if cell.is_alive() && live_neighbors <= 1 {
            CellState::Dead
            // Survival
        } else {
            cell.state
        }
    }

    fn get_cells(&self, coordinates: Vec<Coordinate>) -> Vec<SimpleCell> {
        let mut cells = Vec::new();
        for c in coordinates {
            if let Some(cell) = self.get(c.x as usize, c.y as usize) {
                cells.push(cell);
            }
        }
        cells
    }
}

impl fmt::Display for Board {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let cells = self.cells.clone();
        let mut display = String::new();
        for row in cells {
            for cell in row {
                if cell.is_alive() {
                    display.push_str("()");
                } else {
                    display.push_str("__");
                }
            }
            display.push('\n');
        }
        write!(f, "{}", display)
    }
}

A  => src/conway/conway.rs +78 -0
@@ 1,78 @@
use std::fmt;

#[derive(Clone, Debug)]
pub struct Coordinate {
    pub x: i32,
    pub y: i32,
}

impl Coordinate {
    pub fn new(x: i32, y: i32) -> Self {
        Coordinate { x: x, y: y }
    }
    pub fn calculate_adjecents(&self) -> Vec<Coordinate> {
        let x_sub1 = self.x - 1;
        let y_sub1 = self.y - 1;
        let mut adj: Vec<Coordinate> = Vec::new();
        for i in x_sub1..=x_sub1 + 2 {
            for j in y_sub1..=y_sub1 + 2 {
                if !(i == self.x && j == self.y) && i >= 0 && j >= 0 {
                    adj.push(Coordinate { x: i, y: j });
                }
            }
        }
        adj
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CellState {
    Dead,
    Alive,
}

pub trait Cell {
    fn new(location: Coordinate) -> Self;
    fn is_alive(&self) -> bool;
    fn set_state(&mut self, state: CellState);
    fn get_adjecent(&self) -> Vec<Coordinate>;
}

#[derive(Clone, Debug)]
pub struct SimpleCell {
    pub state: CellState,
    pub location: Coordinate,
    adjecent: Vec<Coordinate>,
}

impl SimpleCell {}

impl Cell for SimpleCell {
    fn new(location: Coordinate) -> Self {
        let adjecent = location.calculate_adjecents();
        Self {
            state: CellState::Dead,
            location: location,
            adjecent: adjecent,
        }
    }
    fn is_alive(&self) -> bool {
        self.state == CellState::Alive
    }
    fn set_state(&mut self, state: CellState) {
        self.state = state;
    }
    fn get_adjecent(&self) -> Vec<Coordinate> {
        self.adjecent.clone()
    }
}

impl fmt::Display for SimpleCell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Cell ({}, {}): {:?}",
            self.location.x, self.location.y, self.state
        )
    }
}

A  => src/conway/mod.rs +2 -0
@@ 1,2 @@
pub mod board;
pub mod conway;

A  => src/main.rs +27 -0
@@ 1,27 @@
use std::{thread, time};

mod conway;

use conway::board::Board;
use conway::conway::CellState;

fn sleep(time_ms: usize) {
    let sleep_time = time::Duration::from_millis(time_ms as u64);
    thread::sleep(sleep_time);
}

fn main() {
    let mut b = Board::new(10, 10);

    b.set(0, 0, CellState::Alive);
    b.set(1, 1, CellState::Alive);
    b.set(1, 2, CellState::Alive);
    b.set(2, 0, CellState::Alive);
    b.set(2, 1, CellState::Alive);

    for i in 0..50 {
        println!("Board:\n{}", b);
        b.step();
        sleep(100);
    }
}