Skip to content

Commit

Permalink
Split code
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanLT authored Mar 11, 2024
1 parent 3f54d45 commit fcc3494
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 212 deletions.
41 changes: 36 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,47 @@
# Creature
# Game of Life

## Description
## Matrix

### Description
The `Matrix` struct represents a grid with size. It provides methods for matrix a new matrix, updating current matrix with reference and print current matrix.

### Usage
You can use the `Matrix` struct to simulate Conway's Game of Life.

```rust
use Creature;

// Example usage
let mut matrix: Matrix = Matrix {
size: 2,
grid: vec![
vec![Creature::new(0, 0, 2), Creature::new(0, 1, 2)],
vec![Creature::new(1, 0, 2), Creature::new(1, 1, 1)],
],
};
let ref_mat: Matrix = matrix.clone();
matrix.update_matrix(&ref_mat);
assert_eq!(
matrix.grid,
vec![
vec![Creature::new(0, 0, 2), Creature::new(0, 1, 2)],
vec![Creature::new(1, 0, 2), Creature::new(1, 1, 2)],
]
);
```
## Creature

### Description
The `Creature` struct represents a creature with coordinates and an alive state. It provides methods for creating a new creature, setting its alive state, checking its neighboring creatures, and counting the number of alive neighbors.

## Usage
### Usage
You can use the `Creature` struct to simulate and manipulate creatures within a game matrix.

```rust
// Example usage
let matrix: Vec<Vec<Creature>> = vec![
vec![Creature::new(0, 0, 1), Creature::new(0, 0, 2)],
vec![Creature::new(0, 0, 1), Creature::new(0, 0, 1)]
vec![Creature::new(0, 0, 1), Creature::new(0, 1, 2)],
vec![Creature::new(1, 0, 1), Creature::new(1, 1, 1)]
];
let mut c_0 = matrix[0][0].clone();
c_0.check_still_alive(matrix);
Expand Down
2 changes: 2 additions & 0 deletions src/classes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod creature;
pub mod matrix;
161 changes: 161 additions & 0 deletions src/classes/creature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/// Struct representing a creature in the game of life.
///
/// # Fields
///
/// - `alive`: A boolean indicating whether the creature is alive or not.
/// - `x`: The x-coordinate of the creature.
/// - `y`: The y-coordinate of the creature.
#[derive(Debug, Clone, PartialEq)]
pub struct Creature {
alive: bool,
x: usize,
y: usize,
}

impl Creature {
/// Creates a new creature with the given coordinates and alive state.
///
/// # Arguments
///
/// - `x`: The x-coordinate of the creature.
/// - `y`: The y-coordinate of the creature.
/// - `alive`: The alive state of the creature, represented as an i8.
/// 0 or 2 represents a live creature, while any other value represents a dead creature.
#[must_use]
pub fn new(x: usize, y: usize, alive: i8) -> Creature {
Creature {
alive: match alive {
0 | 2 => true,
_ => false,
},
x,
y,
}
}

/// Sets the alive state of the creature.
///
/// # Arguments
///
/// - `alive`: The new alive state of the creature.
pub fn set_alive(&mut self, alive: bool) {
self.alive = alive;
}

/// Checks the neighboring creatures of the current creature and updates its alive state accordingly.
///
/// # Arguments
///
/// - `matrix`: The game matrix containing all the creatures.
pub fn check_still_alive(&mut self, matrix: Vec<Vec<Creature>>) {
match self.check_neighbors(matrix) {
2 => {
if self.alive {
self.set_alive(true)
}
}
3 => {
if !self.alive {
self.set_alive(true)
}
}
_ => self.set_alive(false),
};
}

/// Counts the number of alive neighbors of the current creature.
///
/// # Arguments
///
/// - `matrix`: The game matrix containing all the creatures.
///
/// # Returns
///
/// The number of alive neighbors of the current creature, represented as a u8.
#[must_use]
pub fn check_neighbors(&self, matrix: Vec<Vec<Creature>>) -> u8 {
let max_i = matrix.len() - 1;
let max_j = matrix[0].len() - 1;

let mut count: u8 = 0;
for x in (self.x.saturating_sub(1))..=(self.x + 1).min(max_i) {
for y in (self.y.saturating_sub(1))..=(self.y + 1).min(max_j) {
if x != self.x || y != self.y {
count += matrix[x][y].alive as u8;
}
}
}
count
}
}

/// This struct implements the `Display` trait, which allows us to
/// print the `Creature` struct in a nice format.
impl std::fmt::Display for Creature {
/// Formats the `Creature` struct into a string, which is then
/// returned as a `Result` of type `std::fmt::Result`. The formatted
/// string represents the state of the creature, whether it is alive
/// or not, and is enclosed in square brackets.
///
/// # Arguments
///
/// * `f`: A formatter struct, which allows us to specify how to
/// format the data.
///
/// # Returns
///
/// A formatted string, representing the state of the creature.
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Format the string, representing the state of the creature.
write!(f, "[{}]", self.alive as u8)
}
}

#[cfg(test)]
mod tests {
use super::Creature;

#[test]
fn test_new_creature() {
let creature = Creature::new(0, 0, 2);
assert_eq!(creature.alive, true);
assert_eq!(creature.x, 0);
assert_eq!(creature.y, 0);
}

#[test]
fn test_set_alive() {
let mut creature = Creature::new(0, 0, 2);
creature.set_alive(false);
assert_eq!(creature.alive, false);
}

#[test]
fn test_check_neighbors() {
let matrix = vec![
vec![Creature::new(0, 0, 2), Creature::new(0, 0, 2)],
vec![Creature::new(0, 0, 2), Creature::new(0, 0, 1)],
];
let c = matrix[0][0].clone();
assert_eq!(c.check_neighbors(matrix), 2);
}

#[test]
fn test_check_still_alive() {
let matrix: Vec<Vec<Creature>> = vec![
vec![Creature::new(0, 0, 2), Creature::new(0, 0, 2)],
vec![Creature::new(0, 0, 2), Creature::new(0, 0, 1)],
];
let mut c_0 = matrix[0][0].clone();
c_0.check_still_alive(matrix);
assert_eq!(c_0.alive, true);

let matrix: Vec<Vec<Creature>> = vec![
vec![Creature::new(0, 0, 1), Creature::new(0, 0, 2)],
vec![Creature::new(0, 0, 1), Creature::new(0, 0, 1)],
];
let mut c_0 = matrix[0][0].clone();
c_0.check_still_alive(matrix);
assert_eq!(c_0.alive, false);
}
}
88 changes: 88 additions & 0 deletions src/classes/matrix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use rand::Rng;

use crate::classes::creature::Creature;

/// Struct representing a matrix in the game of life.
///
/// # Fields
///
/// - `size`: Size of the matrix.
#[derive(Debug, Clone, PartialEq)]
pub struct Matrix {
size: usize,
grid: Vec<Vec<Creature>>,
}

impl Matrix {
/// Creates a new square matrix with the given x and y size.
///
/// # Arguments
///
/// - `size`: Size.
#[must_use]
pub fn new(size: usize) -> Matrix {
// Create a new RNG for random number generation
let mut rng: rand::rngs::ThreadRng = rand::thread_rng();

Matrix {
size,
grid: (0..size)
.map(|x| {
(0..size)
.map(|y| Creature::new(x, y, rng.gen_range(0..=4)))
.collect()
})
.collect(),
}
}

/// Prints the matrix to the console.
pub fn print_matrix(&self) {
for row in self.grid.iter() {
for c in row.iter() {
print!("{}", c);
}
println!();
}
}

/// Updates the matrix by calling with ref_mat the check_still_alive
/// function on each creature.
///
/// # Arguments
///
/// - `ref_mat`: The cloned matrix to reference.
pub fn update_matrix(&mut self, ref_mat: &Matrix) {
for row in self.grid.iter_mut() {
for c in row.iter_mut() {
c.check_still_alive(ref_mat.grid.clone());
}
}
}
}

#[cfg(test)]
mod tests {
use super::Creature;
use super::Matrix;

#[test]
fn test_update_matrix() {
let mut matrix = Matrix {
size: 2,
grid: vec![
vec![Creature::new(0, 0, 2), Creature::new(0, 1, 2)],
vec![Creature::new(1, 0, 2), Creature::new(1, 1, 1)],
],
};
let ref_mat: Matrix = matrix.clone();
matrix.update_matrix(&ref_mat);
assert_eq!(
matrix.grid,
vec![
vec![Creature::new(0, 0, 2), Creature::new(0, 1, 2)],
vec![Creature::new(1, 0, 2), Creature::new(1, 1, 2)],
]
);
}
}
Loading

0 comments on commit fcc3494

Please sign in to comment.