Skip to content

Commit

Permalink
Adding test cases and updating readme with test documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
reecewayt committed Jan 19, 2025
1 parent 26c259e commit 9fb7745
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 20 deletions.
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Rust-Rule110
Author: Reece Wayt
Contact: [email protected]
Date: 1/18/2025
Date: 1/18/2025
GitHub Repo: https://github.com/reecewayt/rust-rule110
---
## Algorithm Description
A simple rust application for assignment 1 of CS 523.
Expand All @@ -11,9 +12,23 @@ Rule 110 is a elementary cellular automata which means each cell is binary 0 or
![Rule 110 Pattern](./docs/images/rule-110-wolfram-ref.png)
*Image source: [Wolfram MathWorld - Rule 110](https://mathworld.wolfram.com/Rule110.html)*

Here I'm using **u8** method for encapsulating generational data. Another method could use an array instead.
## Implementation Notes
- Uses `u8` ddata type to store each cellular automata generation
- Includes unit tests for corner cases to test wrap around behavior and base case from assignment requirements

## Building and running the application
## Running application, tests, and rustdoc
```bash
#run application main() entry
cargo run
```
# run #[test] cases
cargo test
# run rustdoc
cargo doc --no-deps --open
```
**Note**: I'm running wsl which requires some additional steps to natively launch the rustdoc html in a browser. If you're also on wsl follow this guide to run browsers from wsl. [Run Linux Gui Apps from WSL](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps)

### Sources
- Algorithm Reference: [Wolfram MathWorld - Rule 110](https://mathworld.wolfram.com/Rule110.html)
- Development Tools:
- Rustdoc boilerplate and documentation formatting assistance provided by [Claude.ai](https://claude.ai)
- rust-analyzer (vs-code extension)
89 changes: 73 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,109 @@


/// Implements Rule 110 cellular automaton for a single generation of 8 bits
///
/// Rule 110 is an elementary cellular automaton where each cell's next state is determined by its
/// current state and its two neighbors. The rules are:
/// - 111 -> 0 - 011 -> 1
/// - 110 -> 1 - 010 -> 1
/// - 101 -> 1 - 001 -> 1
/// - 100 -> 0 - 000 -> 0
///
/// # Arguments
///
/// * `bits` - An 8-bit unsigned integer representing the current generation
///
/// # Returns
///
/// * An 8-bit unsigned integer representing the next generation
///
/// # Examples
///
/// ```
/// let current = 0b1010_0100;
/// let next = rule110(current);
/// assert_eq!(next, 0b1110_1101);
/// ```
fn rule110(bits: u8) -> u8 {
let mut next_gen = 0;
let mut next_gen: u8 = 0;

for i in 0..8 {
// Get the left bit
let left = if i == 7 {
let left: u8 = if i == 7 {
bits & 0b0000_0001 // mask all but the lsb
} else {
(bits >> (i + 1)) & 0b0000_0001
};

// Get the center bit
let center = (bits >> i) & 0b0000_0001;
let center: u8 = (bits >> i) & 0b0000_0001;

// Get the right bit
let right = if i == 0 {
let right: u8 = if i == 0 {
(bits & 0b1000_0000) >> 7 // mask all but the msb
} else {
(bits >> (i - 1)) & 0b0000_0001
};

// Apply rule 110 pattern
let pattern = (left << 2) | (center << 1) | right;
let temp_bit = match pattern {
let pattern: u8 = (left << 2) | (center << 1) | right;
let temp_bit: u8 = match pattern {
0b111 => 0,
0b110 => 1,
0b110 => 1,
0b101 => 1,
0b100 => 0,
0b011 => 1,
0b010 => 1,
0b001 => 1,
0b000 => 0,
_ => unreachable!(),
};
};
// Set the next generation bit
next_gen |= temp_bit << i;
};
}
next_gen
}

fn main() {
// Test with some initial pattern
let mut current = 0b1010_0100u8;
// Print several generations
for _ in 0..8 {
let mut current: u8 = 0b1010_0100u8;

// Print 10 generations
for _ in 0..10 {
println!("{:08b}", current);
current = rule110(current);
}
}

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

#[test]
fn test_corner_case_bit_0() {
// Test bit 0's right neighbor wrapping
let input: u8 = 0b0000_0001;
let result: u8 = rule110(input);
// Rule 110 pattern: 010 -> 1
// Bit 0 should be 1, and rest should be 0
assert_eq!((result & 0b0000_0001), 1);
}

#[test]
fn test_corner_case_bit_7() {
// Test bit 7's left neighbor wrapping
let input: u8 = 0b1000_0000;
let result: u8 = rule110(input);
// Rule 110 pattern: 010 -> 1
// Bit 7 should be 1, and rest should be 0
assert_eq!((result & 0b1000_0000), 1 << 7);
}

#[test]
fn test_assignment_base_case() {
// Test the base case from the assignment
// 1010_0100 -> 1101_0110
let input: u8 = 0b1010_0100;
let result: u8 = rule110(input);

assert_eq!(result, 0b1110_1101);
}
}

0 comments on commit 9fb7745

Please sign in to comment.