Skip to content

Commit

Permalink
Refactoring lookup table struct
Browse files Browse the repository at this point in the history
  • Loading branch information
be-next committed Dec 24, 2023
1 parent e7582d1 commit fc073b2
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 66 deletions.
20 changes: 10 additions & 10 deletions src/core/cellular_automaton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@ use crate::core::lookup_table::M1DLookupTable;

#[allow(dead_code)]
pub struct CA1D {
pub current_world: Box<Vec<u8>>,
pub next_world: Box<Vec<u8>>,
pub current_world: Box<Vec<i8>>,
pub next_world: Box<Vec<i8>>,
pub lookup_table: M1DLookupTable,
pub num_states: u8,
pub num_cells: usize,
}

macro_rules! get_left {
($self:ident, $i:ident) => {
$self.current_world[$i - 1] as usize
$self.current_world[$i - 1]
};
}

macro_rules! get_center {
($self:ident, $i:ident) => {
$self.current_world[$i] as usize
$self.current_world[$i]
};
}

macro_rules! get_right {
($self:ident, $i:ident) => {
$self.current_world[$i + 1] as usize
$self.current_world[$i + 1]
};
}

Expand Down Expand Up @@ -56,11 +56,11 @@ impl CA1D {
}
}

pub fn get_current_world(&self) -> &Vec<u8> {
pub fn get_current_world(&self) -> &Vec<i8> {
&self.current_world
}

pub fn get_next_world(&self) -> &Vec<u8> {
pub fn get_next_world(&self) -> &Vec<i8> {
&self.next_world
}

Expand All @@ -76,11 +76,11 @@ impl CA1D {
&self.lookup_table
}

pub fn set_current_world(&mut self, current_world: Vec<u8>) {
pub fn set_current_world(&mut self, current_world: Vec<i8>) {
self.current_world = Box::new(current_world);
}

pub fn set_next_world(&mut self, next_world: Vec<u8>) {
pub fn set_next_world(&mut self, next_world: Vec<i8>) {
self.next_world = Box::new(next_world);
}

Expand All @@ -102,7 +102,7 @@ impl CA1D {
get_left!(self, i),
get_center!(self, i),
get_right!(self, i));
self.next_world[i] = *next_state.unwrap() as u8;
self.next_world[i] = *next_state.unwrap();
}
std::mem::swap(&mut self.current_world, &mut self.next_world);
}
Expand Down
50 changes: 22 additions & 28 deletions src/core/lookup_table.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use std as sdt;
use serde::{Deserialize, Serialize};

// This lookup table is used to map the neighborhood of a cell to its next state.
// The neighborhood is represented by a tuple of three values: (left, center, right).
// The next state is represented by a single value.

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct M1DLookupTable {
data: Vec<i8>,
left: usize,
center: usize,
right: usize,
num_states: i8,
}

#[derive(Debug, PartialEq)]
Expand All @@ -15,7 +17,7 @@ pub enum M1DLookupTableError {
}

macro_rules! get_index_or_err {
($self:ident, $left:expr, $center:expr, $right:expr) => {
($self:ident, $left:ident, $center:ident, $right:ident) => {
match $self.index($left, $center, $right) {
Some(i) => i,
None => return Err(M1DLookupTableError::IndexOutOfBounds),
Expand All @@ -35,37 +37,29 @@ impl sdt::fmt::Display for M1DLookupTable {
}

impl M1DLookupTable {
pub fn new(left: usize, center: usize, right: usize, default_value: i8) -> Self {
pub fn new(num_states: i8, default_value: i8) -> Self {
Self {
data: vec![default_value; left * center * right],
left,
center,
right,
data: vec![default_value; (num_states * num_states * num_states) as usize],
num_states,
}
}

pub fn set(
&mut self,
left: usize,
center: usize,
right: usize,
value: i8,
) -> Result<&mut Self, M1DLookupTableError> {
pub fn set(&mut self, left: i8, center: i8, right: i8, value: i8) -> Result<&mut Self, M1DLookupTableError> {
let index = get_index_or_err!(self, left, center, right);
self.data[index] = value;
self.data[index as usize] = value;
Ok(self)
}

pub fn get(&self, left: usize, center: usize, right: usize) -> Result<&i8, M1DLookupTableError> {
pub fn get(&self, left: i8, center: i8, right: i8) -> Result<&i8, M1DLookupTableError> {
let index = get_index_or_err!(self, left, center, right);
Ok(self.data.get(index).unwrap())
Ok(self.data.get(index as usize).unwrap())
}

fn index(&self, left: usize, center: usize, right: usize) -> Option<usize> {
return if left >= self.left || center >= self.center || right >= self.right {
fn index(&self, left: i8, center: i8, right: i8) -> Option<i8> {
return if left >= self.num_states || center >= self.num_states || right >= self.num_states {
None
} else {
let index = left + center * self.left + right * self.left * self.center;
let index = left + center * self.num_states + right * self.num_states * self.num_states;
Some(index)
};
}
Expand All @@ -74,10 +68,10 @@ impl M1DLookupTable {
self.data.len()
}

pub fn iter_indices(&self) -> impl Iterator<Item = (usize, usize, usize)> {
let left = self.left;
let center = self.center;
let right = self.right;
pub fn iter_indices(&self) -> impl Iterator<Item = (i8, i8, i8)> {
let left = self.num_states;
let center = self.num_states;
let right = self.num_states;

(0..left)
.flat_map(move |r| (0..center)
Expand All @@ -95,13 +89,13 @@ impl M1DLookupTable {
}

pub fn finalize(&mut self, value_to_replace: i8) -> &mut Self {
let indices_to_modify: Vec<(usize, usize, usize)> = self
let indices_to_modify: Vec<(i8, i8, i8)> = self
.iter_indices()
.filter(|(r, c, l)| self.get(*r, *c, *l).unwrap() == &value_to_replace)
.collect();

for (r, c, l) in indices_to_modify {
let _ = self.set(r, c, l, c as i8).unwrap();
let _ = self.set(r, c, l, c).unwrap();
}

self
Expand Down
12 changes: 5 additions & 7 deletions src/core/lookup_table_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ impl LookupTableBuilder {
let transition_rules = TransitionRules::new_from_json_file(rules_file_name)?;

let mut lookup_table = M1DLookupTable::new(
transition_rules.get_num_states() as usize,
transition_rules.get_num_states() as usize,
transition_rules.get_num_states() as usize,
transition_rules.get_num_states(),
Self::DEFAULT_INITIAL_VALUE,
);

Expand All @@ -34,10 +32,10 @@ impl LookupTableBuilder {
.for_each(|(neighborhood, next_state)| {
lookup_table
.set(
neighborhood[0] as usize,
neighborhood[1] as usize,
neighborhood[2] as usize,
next_state as i8,
neighborhood[0],
neighborhood[1],
neighborhood[2],
next_state,
)
.unwrap();
});
Expand Down
12 changes: 6 additions & 6 deletions src/core/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct TransitionRule {
neighborhood: [u8; 3],
pub next_state: u8,
neighborhood: [i8; 3],
pub next_state: i8,
}

#[derive(Serialize, Deserialize)]
pub struct TransitionRules {
name: String,
num_states: u8,
num_states: i8,
pub rules: Vec<TransitionRule>,
}

Expand Down Expand Up @@ -42,7 +42,7 @@ impl TransitionRules {
Self::new_from_json_string(&json_string)
}

pub fn get_num_states(&self) -> u8 {
pub fn get_num_states(&self) -> i8 {
self.num_states
}
}
Expand All @@ -54,7 +54,7 @@ pub struct TransitionRulesIter<'a> {
}

impl<'a> IntoIterator for &'a TransitionRules {
type Item = ([u8; 3], u8);
type Item = ([i8; 3], i8);
type IntoIter = TransitionRulesIter<'a>;

fn into_iter(self) -> Self::IntoIter {
Expand All @@ -66,7 +66,7 @@ impl<'a> IntoIterator for &'a TransitionRules {
}

impl<'a> Iterator for TransitionRulesIter<'a> {
type Item = ([u8; 3], u8);
type Item = ([i8; 3], i8);

fn next(&mut self) -> Option<Self::Item> {
if self.index < self.transition_rules.rules.len() {
Expand Down
20 changes: 10 additions & 10 deletions tests/test_lookup_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ use mono_axis::core::lookup_table::M1DLookupTableError;

#[test]
fn it_works() {
let lt = M1DLookupTable::new(3, 3, 3, 0);
let lt = M1DLookupTable::new(3,0);
let result = lt.get(2, 2, 2).unwrap();
assert_eq!(*result, 0);
}

#[test]
fn it_returns_index_out_of_bounds_on_get_call() {
let lt = M1DLookupTable::new(3, 3, 3, 0);
let lt = M1DLookupTable::new(3,0);
let result = lt.get(3, 3, 3);
assert_eq!(result, Err(M1DLookupTableError::IndexOutOfBounds));
}

#[test]
fn it_returns_index_out_of_bounds_on_set_call() {
let mut lt = M1DLookupTable::new(3, 3, 3, 0);
let mut lt = M1DLookupTable::new(3, 0);
let result = lt.set(3, 3, 3, 1);
assert_eq!(result, Err(M1DLookupTableError::IndexOutOfBounds));
}

#[test]
fn it_returns_index_out_of_bounds_on_set_call_with_correct_index() {
let mut lt = M1DLookupTable::new(3, 3, 3, 0);
let mut lt = M1DLookupTable::new(3, 0);
let lt_address_before = &lt as *const _;
let result = lt.set(2, 2, 2, 1);
assert!(result.is_ok());
Expand All @@ -36,23 +36,23 @@ fn it_returns_index_out_of_bounds_on_set_call_with_correct_index() {

#[test]
fn it_returns_correct_value_on_get_call() {
let mut lt = M1DLookupTable::new(3, 3, 3, 0);
let mut lt = M1DLookupTable::new(3, 0);
_ = lt.set(2, 2, 2, 1);
let result = lt.get(2, 2, 2);
assert_eq!(result, Ok(&1));
}

#[test]
fn it_returns_correct_collection_size() {
let lt = M1DLookupTable::new(3, 3, 3, 0);
let lt = M1DLookupTable::new(3, 0);
let result = lt.collection_size();
assert_eq!(result, 27);
}

#[test]
fn it_returns_correct_indices() {
let lt = M1DLookupTable::new(3, 3, 3, 0);
let result = lt.iter_indices().collect::<Vec<(usize, usize, usize)>>();
let lt = M1DLookupTable::new(3, 0);
let result = lt.iter_indices().collect::<Vec<(i8, i8, i8)>>();
assert_eq!(
result,
vec![
Expand Down Expand Up @@ -89,7 +89,7 @@ fn it_returns_correct_indices() {

#[test]
fn it_replaces_values_with_replace_values() {
let mut lt = M1DLookupTable::new(3, 3, 3, 0);
let mut lt = M1DLookupTable::new(3, 0);
_ = lt.set(2, 2, 2, 1);
_ = lt.replace_values(1, 2);
let result = lt.get(2, 2, 2).unwrap();
Expand All @@ -98,7 +98,7 @@ fn it_replaces_values_with_replace_values() {

#[test]
fn it_finalizes() {
let mut lt = M1DLookupTable::new(3, 3, 3, 0);
let mut lt = M1DLookupTable::new(3, 0);
_ = lt.set(2, 2, 2, 1);
_ = lt.finalize(0);
let result = lt.get(2, 2, 2).unwrap();
Expand Down
4 changes: 1 addition & 3 deletions tests/test_lookup_table_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ use mono_axis::core::lookup_table_builder::LookupTableBuilder;
const LOOKUP_TABLE_EX1: &str = r#"
{
"data": [0,0,0,1,1,2,2,0,2,0,2,0,1,1,2,2,1,2,0,0,0,1,1,1,2,2,2],
"left": 3,
"center": 3,
"right": 3
"num_states": 3
}
"#;

Expand Down
4 changes: 2 additions & 2 deletions tests/test_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const JSON_DATA: &str = r#"
fn it_deserializes() {
let rules: TransitionRules = serde_json::from_str(JSON_DATA).unwrap();
let result = rules.rules[0].next_state;
assert_eq!(result, 2u8);
assert_eq!(result, 2i8);
}

#[test]
Expand Down Expand Up @@ -50,7 +50,7 @@ fn it_returns_error_on_invalid_file() {
#[test]
fn it_iterates_correctly() {
let rules: TransitionRules = serde_json::from_str(JSON_DATA).unwrap();
let result = rules.into_iter().collect::<Vec<([u8; 3], u8)>>();
let result = rules.into_iter().collect::<Vec<([i8; 3], i8)>>();
assert_eq!(
result,
vec![
Expand Down

0 comments on commit fc073b2

Please sign in to comment.