diff --git a/Cargo.toml b/Cargo.toml index 1793912..9bf2a58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -rand = "0.9.0" +rand = "0.9.1" paste = "1.0.15" rust_decimal = { version = "1.37", features = ["macros", "maths"] } rush_macro = { path = "rush_macro" } \ No newline at end of file diff --git a/src/gp/genome.rs b/src/gp/genome.rs new file mode 100644 index 0000000..8238da1 --- /dev/null +++ b/src/gp/genome.rs @@ -0,0 +1,115 @@ +use crate::instructions::code::{ + exec_do_count, exec_do_range, exec_do_times, exec_do_while, exec_if, exec_when, exec_while, +}; +use crate::instructions::common::{ + exec_dup, exec_dup_times, exec_pop, exec_rotate, exec_shove, exec_swap, +}; +use crate::instructions::vector::{ + string_iterate, vector_boolean_iterate, vector_char_iterate, vector_float_iterate, + vector_int_iterate, vector_string_iterate, +}; +use crate::push::state::Gene; +use crate::push::state::Gene::StateFunc; +use rand::prelude::*; +use std::collections::HashMap; +use std::sync::LazyLock; + +/// Generates a random plushy. +pub fn make_random_plushy( + genes: Vec, + max_init_plushy_size: usize, + mut rng: impl Rng, +) -> Vec { + let plushy_size = rng.random_range(0..=max_init_plushy_size); + let mut plushy = Vec::with_capacity(plushy_size); + for _ in 0..plushy_size { + plushy.push(genes[rng.random_range(0..genes.len())].clone()); + } + plushy +} + +/// A map of genes to their number of blocks they open. +static OPEN_MAP: LazyLock> = LazyLock::new(|| { + let mut temp_map = HashMap::default(); + temp_map.insert(StateFunc(exec_dup), 1u8); + temp_map.insert(StateFunc(exec_dup_times), 1u8); + temp_map.insert(StateFunc(exec_pop), 1u8); + temp_map.insert(StateFunc(exec_rotate), 3u8); + temp_map.insert(StateFunc(exec_shove), 1u8); + temp_map.insert(StateFunc(exec_swap), 2u8); + temp_map.insert(StateFunc(exec_if), 2u8); + temp_map.insert(StateFunc(exec_when), 1u8); + temp_map.insert(StateFunc(exec_while), 1u8); + temp_map.insert(StateFunc(exec_do_while), 1u8); + temp_map.insert(StateFunc(exec_do_range), 1u8); + temp_map.insert(StateFunc(exec_do_count), 1u8); + temp_map.insert(StateFunc(exec_do_times), 1u8); + //exec_k, 2 + //exec_s 3 + //exec_y 1 + temp_map.insert(StateFunc(string_iterate), 1u8); + temp_map.insert(StateFunc(vector_int_iterate), 1u8); + temp_map.insert(StateFunc(vector_float_iterate), 1u8); + temp_map.insert(StateFunc(vector_string_iterate), 1u8); + temp_map.insert(StateFunc(vector_boolean_iterate), 1u8); + temp_map.insert(StateFunc(vector_char_iterate), 1u8); + temp_map +}); + +fn has_openers(genes: &[Gene]) -> bool { + for gene in genes { + match gene { + Gene::Open(_) => return true, + _ => (), + }; + } + false +} + +/// Converts a plushy to a push program. +pub fn plushy_to_push(genes: Vec) -> Vec { + let mut plushy_buffer: Vec = Vec::with_capacity(genes.len() * 2); + for gene in genes.into_iter() { + let open = OPEN_MAP.get(&gene); + plushy_buffer.push(gene); + if let Some(amt) = open { + plushy_buffer.push(Gene::Open(*amt)) + } + } + let mut push_buffer = Vec::with_capacity(plushy_buffer.len()); + loop { + // recur with one more close if there are openers + if plushy_buffer.is_empty() && has_openers(&push_buffer) { + plushy_buffer.push(Gene::Close); + } else if plushy_buffer.is_empty() { + return plushy_buffer; + } else { + let first_gene = plushy_buffer.pop().unwrap(); + match &first_gene { + Gene::Close => if has_openers(&push_buffer) { + let ndx: usize; + let opener + }, + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::instructions::vector::{string_iterate, vector_float_maximum}; + use crate::push::interpreter::interpret_program; + use crate::push::state::Gene::StateFunc; + use crate::push::state::{EMPTY_STATE, PushState}; + use crate::push::utils::most_genes; + use rand::SeedableRng; + + #[test] + fn make_random_plushy_test() { + let rng = StdRng::seed_from_u64(42); + let rand_plushy = make_random_plushy(most_genes(), 15, rng); + let fin_result = vec![StateFunc(string_iterate), StateFunc(vector_float_maximum)]; + assert_eq!(fin_result, rand_plushy); + } +} diff --git a/src/gp/mod.rs b/src/gp/mod.rs new file mode 100644 index 0000000..d2ccc73 --- /dev/null +++ b/src/gp/mod.rs @@ -0,0 +1 @@ +pub mod genome; diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 7961762..1528be1 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -666,6 +666,23 @@ pub fn exec_instructions() -> Vec { ] } +pub fn all_instructions() -> Vec { + let mut instructions = vec![]; + instructions.append(&mut int_instructions()); + instructions.append(&mut float_instructions()); + instructions.append(&mut string_instructions()); + instructions.append(&mut boolean_instructions()); + instructions.append(&mut char_instructions()); + instructions.append(&mut vector_int_instructions()); + instructions.append(&mut vector_float_instructions()); + instructions.append(&mut vector_string_instructions()); + instructions.append(&mut vector_boolean_instructions()); + instructions.append(&mut vector_char_instructions()); + instructions.append(&mut code_instructions()); + instructions.append(&mut exec_instructions()); + instructions +} + #[cfg(test)] mod tests { //use super::*; diff --git a/src/lib.rs b/src/lib.rs index 15e8271..eee298f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ +pub mod gp; pub mod instructions; pub mod push; diff --git a/src/push/mod.rs b/src/push/mod.rs index 7181eca..00d9418 100644 --- a/src/push/mod.rs +++ b/src/push/mod.rs @@ -1,2 +1,3 @@ pub mod interpreter; pub mod state; +pub mod utils; diff --git a/src/push/state.rs b/src/push/state.rs index 99117c7..8feba32 100644 --- a/src/push/state.rs +++ b/src/push/state.rs @@ -35,7 +35,7 @@ pub const EMPTY_STATE: PushState = PushState { code: vec![], }; -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone, Hash)] #[allow(dead_code)] // remove this later. Is here bc Close, Skip, CrossoverPadding pub enum Gene { GeneInt(i128), @@ -129,16 +129,13 @@ impl Gene { val.insert(n, gene.clone()); return true; } - match el { - iblock @ Gene::Block(_) => { - // This line has side effects on iblock if inserts properly. - let success = iblock.attempt_code_insert(gene.clone(), idx - 1); - if success { - return true; - } - idx -= iblock.rec_len() + 1 + if let iblock @ Gene::Block(_) = el { + // This line has side effects on iblock if inserts properly. + let success = iblock.attempt_code_insert(gene.clone(), idx - 1); + if success { + return true; } - _ => (), + idx -= iblock.rec_len() + 1 } idx -= 1; } diff --git a/src/push/utils.rs b/src/push/utils.rs new file mode 100644 index 0000000..b4e6972 --- /dev/null +++ b/src/push/utils.rs @@ -0,0 +1,12 @@ +use crate::instructions::all_instructions; +use crate::push::state::Gene; + +pub fn most_genes() -> Vec { + let mut instructions: Vec = all_instructions() + .into_iter() + .map(|x| Gene::StateFunc(x)) + .collect(); + instructions.push(Gene::Close); + instructions.push(Gene::Skip); + instructions +}