#![allow(dead_code)]
use std::fmt::Debug;
use std::marker::PhantomData;
pub mod cellular_process;
#[macro_use]
pub mod util;
pub type Printer = Fn(&str) -> ();
pub type Reader = Fn() -> String;
pub trait CellularAutomata<
'a,
CellDataType: Clone + 'static + util::Newable + util::Parseable + util::Encodeable + Debug,
MetaDataType: Clone + 'static + util::Newable + util::Parseable + cellular_process::GridMeta,
>
{
fn run(&self, _: &'a str) -> ();
fn input_handler(
_: &mut cellular_process::Grid<CellDataType, MetaDataType>,
_: &Reader,
_: &Printer,
) -> ();
fn output_handler(_: &cellular_process::Grid<CellDataType, MetaDataType>, _: &Printer) -> ();
}
#[derive(Clone)]
pub struct DummyMetaData {}
#[derive(Clone, Debug)]
pub struct AdaptiveTransitionFunction {
matrix: AdaptiveTransitionFunctionMatrix,
}
#[derive(Clone, Debug, PartialEq)]
pub enum AdaptiveNeighborParserNode {
Relative(Vec<isize>),
Absolute(Vec<usize>),
}
#[derive(Clone, Debug)]
pub struct AdaptiveTransitionFunctionMatrix {
matrix: Vec<Option<util::NanoVec<util::UsizeWrapper>>>,
dimensions: Vec<usize>,
}
#[derive(Clone, Debug)]
pub struct AdaptiveNeighborParser {
addr_matrix: Vec<AdaptiveNeighborParserNode>,
edge_val: util::NanoVec<util::UsizeWrapper>,
}
#[derive(Clone, Debug)]
pub struct AdaptiveMetaData {
dimensions: Vec<usize>,
transition: AdaptiveTransitionFunction,
neighbor_parser: AdaptiveNeighborParser,
}
#[derive(Clone)]
pub struct AdaptiveCellularAutomata<'a> {
meta: AdaptiveMetaData,
initial: Vec<util::UsizeWrapper>,
phantom: PhantomData<&'a str>,
}
impl AdaptiveTransitionFunction {
#[inline]
pub fn apply(
data: &mut util::NanoVec<util::UsizeWrapper>,
neighbor: &cellular_process::NeighborType<util::UsizeWrapper>,
meta: &AdaptiveMetaData,
) {
*data = meta
.get_transition_function()
.get_matrix()
.follow_path(neighbor.get_data().as_slice());
}
#[inline]
pub fn get_matrix(&self) -> &AdaptiveTransitionFunctionMatrix {
&self.matrix
}
}
impl util::Parseable for AdaptiveTransitionFunction {
fn parse(input: &str) -> Self {
Self {
matrix: util::Parseable::parse(input),
}
}
}
impl util::Newable for AdaptiveTransitionFunction {
fn new() -> Self {
Self {
matrix: util::Newable::new(),
}
}
}
impl AdaptiveNeighborParser {
#[inline]
pub fn neighbor_func_parser<'b>(
grid: &'b cellular_process::GridDataType<util::UsizeWrapper>,
meta: &'b AdaptiveMetaData,
address: usize,
) -> cellular_process::NeighborType<'b, util::UsizeWrapper> {
let tmp = meta.get_neighbor_parser();
tmp.apply_neighbors(grid, meta, address)
}
#[inline]
pub fn apply_neighbors<'b>(
&'b self,
grid: &'b cellular_process::GridDataType<util::UsizeWrapper>,
meta: &'b AdaptiveMetaData,
address: usize,
) -> cellular_process::NeighborType<'b, util::UsizeWrapper> {
let dimensions = cellular_process::GridMeta::get_dimensions(meta);
let table = &self.addr_matrix;
let mut to_ret: Vec<&'b util::NanoVec<util::UsizeWrapper>> = Vec::new();
for item in table {
if let AdaptiveNeighborParserNode::Absolute(the_vec) = item {
to_ret.push(util::access_flattened_vec(
grid.get_data_ref(),
&(the_vec.iter().map(|&x| x as isize).collect::<Vec<isize>>()),
&dimensions.to_vec(),
0,
&self.edge_val,
))
} else if let AdaptiveNeighborParserNode::Relative(the_vec) = item {
to_ret.push(util::access_flattened_vec(
grid.get_data_ref(),
&the_vec,
&dimensions.to_vec(),
address,
&self.edge_val,
))
} else {
panic!("This shouldn't happen");
}
}
cellular_process::NeighborType::new(to_ret, dimensions)
}
}
impl util::Newable for AdaptiveNeighborParser {
fn new() -> Self {
Self {
addr_matrix: Vec::new(),
edge_val: util::NanoVec::new(1, util::UsizeWrapper::from(0)),
}
}
}
impl util::Parseable for AdaptiveNeighborParser {
fn parse(input: &str) -> Self {
let mut split = input.split(',');
let mut temp_vec: Vec<AdaptiveNeighborParserNode> = Vec::new();
let edge_case: util::NanoVec<util::UsizeWrapper> = {
let cached = split.next().unwrap();
let mut to_ret: util::NanoVec<util::UsizeWrapper> =
util::NanoVec::new(0, util::UsizeWrapper::from(0));
if cached.starts_with('e') {
to_ret.push(util::Parseable::parse(&cached[1..cached.len()]))
} else {
panic!("Symbol table is invalid");
}
to_ret
};
for item in split {
temp_vec.push(util::Parseable::parse(item));
}
Self {
addr_matrix: temp_vec,
edge_val: edge_case,
}
}
}
impl util::Parseable for AdaptiveNeighborParserNode {
fn parse(input: &str) -> Self {
let collected: Vec<char> = input.chars().collect::<Vec<char>>();
if collected.len() <= 1 {
panic!("Node is invalid");
}
let discrim: char = {
if let Some(d) = collected[0].to_lowercase().nth(0) {
d
} else {
panic!("Character has no lowercase version");
}
};
let the_string = input[1..input.len()].to_string();
let tokenized = {
let tmp = the_string.split(' ');
let mut to_return: Vec<isize> = Vec::new();
for item in tmp {
to_return.push(if let Ok(a) = item.parse::<isize>() {
a
} else {
panic!("Position index is not an integer");
});
}
to_return
};
if discrim == 'a' {
AdaptiveNeighborParserNode::Absolute(
tokenized
.iter()
.map(|x| *x as usize)
.collect::<Vec<usize>>(),
)
} else if discrim == 'r' {
AdaptiveNeighborParserNode::Relative(
tokenized
.iter()
.map(|&x| x as isize)
.collect::<Vec<isize>>(),
)
} else {
panic!("Discriminator is invalid");
}
}
}
impl util::Newable for DummyMetaData {
fn new() -> Self {
Self {}
}
}
impl util::Parseable for DummyMetaData {
fn parse(_data: &str) -> Self {
util::Newable::new()
}
}
impl util::Encodeable for DummyMetaData {
fn encode(&self) -> String {
String::new()
}
}
impl AdaptiveMetaData {
#[inline(always)]
pub fn get_neighbor_parser(&self) -> &AdaptiveNeighborParser {
&self.neighbor_parser
}
#[inline(always)]
pub fn get_transition_function(&self) -> &AdaptiveTransitionFunction {
&self.transition
}
}
impl cellular_process::GridMeta for AdaptiveMetaData {
fn get_dimensions(&self) -> &[usize] {
self.dimensions.as_slice()
}
}
impl util::Parseable for AdaptiveMetaData {
fn parse(input: &str) -> Self {
let split = util::parse_table_sections(input);
if split.len() != 3 {
panic!("Malformed metadata table");
}
Self {
dimensions: util::parse_csv_list_native(&split[0], ','),
neighbor_parser: util::Parseable::parse(&split[1]),
transition: util::Parseable::parse(&split[2]),
}
}
}
impl util::Newable for AdaptiveMetaData {
fn new() -> Self {
Self {
dimensions: Vec::new(),
neighbor_parser: util::Newable::new(),
transition: util::Newable::new(),
}
}
}
impl<'a> util::Parseable for AdaptiveCellularAutomata<'a> {
fn parse(input: &str) -> Self {
let split = util::parse_table_sections(input);
if split.len() != 2 {
panic!("Malformed metadata table")
}
let parsed = util::parse_csv_list(&split[1], ',');
AdaptiveCellularAutomata {
phantom: PhantomData,
meta: util::Parseable::parse(&split[0]),
initial: parsed,
}
}
}
impl<'a> AdaptiveCellularAutomata<'a> {
pub fn test_1() {
let neighbor_str = "e2,a1 1";
let parser_str = "1 2";
let data_str = "1,1,1";
let dim_str = "3,1";
let meta_str = util::encode_table_sections(&[
String::from(dim_str),
String::from(neighbor_str),
String::from(parser_str),
]);
let final_str = util::encode_table_sections(&[meta_str, String::from(data_str)]);
dbg!(&final_str);
let transition: &cellular_process::TransitionFunc<util::UsizeWrapper, AdaptiveMetaData> =
&AdaptiveTransitionFunction::apply;
let neighbor: &cellular_process::NeighborFuncParser<util::UsizeWrapper, AdaptiveMetaData> =
&AdaptiveNeighborParser::neighbor_func_parser;
let mut grid = cellular_process::Grid::<util::UsizeWrapper, AdaptiveMetaData>::decode(
final_str.as_str(),
);
let meta = grid.get_meta().clone();
grid.apply(transition, neighbor, &meta);
dbg!(grid.get_data_read()); }
fn get_meta_data(&self) -> &AdaptiveMetaData {
&self.meta
}
fn get_initial_state(&self) -> &Vec<util::UsizeWrapper> {
&self.initial
}
}
impl<'a> CellularAutomata<'a, util::UsizeWrapper, AdaptiveMetaData>
for AdaptiveCellularAutomata<'a>
{
fn input_handler(
_: &mut cellular_process::Grid<util::UsizeWrapper, AdaptiveMetaData>,
_: &Reader,
_: &Printer,
) {
}
fn output_handler(
_: &cellular_process::Grid<util::UsizeWrapper, AdaptiveMetaData>,
_: &Printer,
) {
}
fn run(&self, input: &str) {
let transition: &cellular_process::TransitionFunc<util::UsizeWrapper, AdaptiveMetaData> =
&AdaptiveTransitionFunction::apply;
let neighbor: &cellular_process::NeighborFuncParser<util::UsizeWrapper, AdaptiveMetaData> =
&AdaptiveNeighborParser::neighbor_func_parser;
let mut grid =
cellular_process::Grid::<util::UsizeWrapper, AdaptiveMetaData>::decode(input);
let meta = grid.get_meta().clone();
grid.apply(transition, neighbor, &meta);
dbg!(grid);
}
}
impl util::Newable for AdaptiveTransitionFunctionMatrix {
fn new() -> Self {
Self {
matrix: Vec::new(),
dimensions: Vec::new(),
}
}
}
impl util::Parseable for AdaptiveTransitionFunctionMatrix {
#[inline]
fn parse(input: &str) -> Self {
let mut to_return_vec: Vec<Option<util::NanoVec<util::UsizeWrapper>>> = Vec::new();
let input_as_string = input.to_string();
let split_input: Vec<&str> = input_as_string.split(';').collect();
let tokens: Vec<Vec<util::NanoVec<util::UsizeWrapper>>> = {
let mut to_return: Vec<Vec<util::NanoVec<util::UsizeWrapper>>> = Vec::new();
let neighbor_count = split_input[0].split(' ').count() - 1;
to_return.resize(neighbor_count + 1, Vec::new());
for (indx1, j) in split_input.iter().enumerate() {
let tmp: Vec<&str> = j.split(' ').collect();
for item in tmp {
to_return[indx1].push({
let parsed = util::split_str(item, ',');
let mut temp_vec: util::NanoVec<util::UsizeWrapper> =
util::NanoVec::new(0, util::UsizeWrapper::from(0));
for itm in parsed {
temp_vec.push(util::Parseable::parse(itm));
}
temp_vec
});
}
}
to_return
};
if split_input.is_empty() {
panic!("ERROR - error reading transition function symbol table - table is empty");
}
let num_neighbors = split_input[0].split(' ').count() - 1; let num_dimensions = tokens[0][0].len();
for rule in &tokens {
if rule.len() - 1 != num_neighbors {
panic!("Inconsistent number of neighbors in rule");
}
for cell in rule {
if cell.len() != num_dimensions {
panic!("Inconsistent number of dimensions in cell");
}
}
}
let dimension_maxima: Vec<util::NanoVec<util::UsizeWrapper>> = {
let mut to_return: Vec<util::NanoVec<util::UsizeWrapper>> = Vec::new();
for _ in 0..num_neighbors {
to_return.push(util::NanoVec::new(
num_dimensions,
util::UsizeWrapper::from(0),
));
}
for rule in &tokens {
for (j, cell) in rule.iter().enumerate() {
debug_emit!("Iteration begin");
debug_val!(&cell);
if j != rule.len() - 1 {
debug_emit!("Here");
for (k, data) in cell.into_iter().enumerate() {
debug_val!(&data);
if data.get_data() > to_return[j].at(k).get_data() {
to_return[j].set_at(k, *data);
}
}
} else {
debug_emit!("Rule discarded");
}
debug_emit!("Iteration end");
}
}
to_return
};
debug_val!(&dimension_maxima);
let to_pass_dim: Vec<&util::NanoVec<util::UsizeWrapper>> = {
let mut to_ret: Vec<&util::NanoVec<util::UsizeWrapper>> = Vec::new();
for item in dimension_maxima.iter() {
to_ret.push(&item);
}
to_ret
};
let flattened_dimension_maxima: Vec<usize> = Self::stitch(to_pass_dim.as_slice())
.iter()
.map(|x| x.get_data())
.collect::<Vec<usize>>();
for _ in 0..(util::addr_normal_to_flattened_usize(
&flattened_dimension_maxima,
&(flattened_dimension_maxima
.iter()
.map(|x| x + 1)
.collect::<Vec<usize>>()),
)) {
to_return_vec.push(None);
}
for rule in &tokens {
let to_pass: Vec<&util::NanoVec<util::UsizeWrapper>> = {
let mut to_ret: Vec<&util::NanoVec<util::UsizeWrapper>> = Vec::new();
for item in (&rule).into_iter() {
to_ret.push(&item);
}
to_ret
};
to_return_vec
[Self::compute_index(&to_pass[0..rule.len() - 1], &flattened_dimension_maxima)] =
Some(rule[rule.len() - 1].clone());
}
Self {
matrix: to_return_vec,
dimensions: flattened_dimension_maxima,
}
}
}
impl AdaptiveTransitionFunctionMatrix {
fn compute_index(input: &[&util::NanoVec<util::UsizeWrapper>], sizes: &[usize]) -> usize {
util::addr_normal_to_flattened_usize_wrapper_ref(&Self::stitch(input), sizes)
}
fn stitch<'a, T: Clone + util::Encodeable + util::Newable + Debug>(
input: &[&'a util::NanoVec<T>],
) -> Vec<&'a T> {
let mut to_return: Vec<&T> = Vec::new();
for item_1 in input {
for item_2 in item_1.into_iter() {
to_return.push(item_2);
}
}
to_return
}
#[inline]
pub fn follow_path(
&self,
path: &[&util::NanoVec<util::UsizeWrapper>],
) -> util::NanoVec<util::UsizeWrapper> {
if let Some(a) = &self.matrix[Self::compute_index(path, &self.dimensions)] {
a.clone()
} else {
panic!("No value associated with given key");
}
}
}