From 4ed86fda31a8948cb7b534e191c7d50b52aba505 Mon Sep 17 00:00:00 2001 From: rendo Date: Mon, 30 Mar 2026 11:36:42 +0500 Subject: [PATCH] Gene, flow and manipulations --- rust-pvz-genetics/src/genetics/flow.rs | 18 +++ rust-pvz-genetics/src/genetics/gene.rs | 118 +++++++++++++----- rust-pvz-genetics/src/genetics/genome.rs | 12 +- .../src/genetics/manipulations.rs | 7 +- rust-pvz-genetics/src/genetics/mod.rs | 1 + .../src/genetics/plant_templates.rs | 30 ++--- rust-pvz-genetics/src/main.rs | 5 - 7 files changed, 131 insertions(+), 60 deletions(-) create mode 100644 rust-pvz-genetics/src/genetics/flow.rs delete mode 100644 rust-pvz-genetics/src/main.rs diff --git a/rust-pvz-genetics/src/genetics/flow.rs b/rust-pvz-genetics/src/genetics/flow.rs new file mode 100644 index 0000000..dd2e493 --- /dev/null +++ b/rust-pvz-genetics/src/genetics/flow.rs @@ -0,0 +1,18 @@ +pub struct Flow { + pub projectiles: Vec +} + +pub struct ProjectilePlaceholder; + +impl Flow { + pub fn new(projectiles: Vec) -> Self { + Self { + projectiles, + } + } + pub fn empty() -> Self { + Self { + projectiles: vec![], + } + } +} diff --git a/rust-pvz-genetics/src/genetics/gene.rs b/rust-pvz-genetics/src/genetics/gene.rs index e1e5d46..7de6272 100644 --- a/rust-pvz-genetics/src/genetics/gene.rs +++ b/rust-pvz-genetics/src/genetics/gene.rs @@ -1,61 +1,123 @@ +use std::fmt::Display; + +use crate::genetics::flow::Flow; + #[derive(PartialEq,Eq,Clone)] pub struct Gene { + pub plant_name: String, pub place: String, pub kind: GeneType } +pub struct GeneContext { + pub flow: Flow +} + +/// GeneType is an enum that defines behaviour of gene. #[derive(PartialEq,Eq,Clone)] pub enum GeneType { + /// Without functional behaviour. Doesn't pass through flow. Dummy, + /// Only creates flow. Can be set up to not create flow if flow isn't empty. PureProducer { - create_flow: fn() + create_flow: fn(GeneContext) -> Flow }, + /// Creates or modifies flow. Needs to decide whether to create or modify flow. + Producer { + create_flow: fn(GeneContext) -> Flow, + modify_single: fn(GeneContext) -> Flow, + modify_all: fn(GeneContext) -> Flow, + decide_modification_type: fn(GeneContext) -> ProduceDecision, + }, + /// Allows flow to pass through. Transport { - distribute_between_children: fn() + distribute_between_children: fn(GeneContext) -> ChildDistribution }, + /// Consumes flow, destroying it in process. Consumer { - consume: fn() + consume: fn(GeneContext) }, + /// Modifies flow Modifier { - modify_flow: fn() + modify_flow: fn(GeneContext) -> Option }, + /// Conditionally passes through flow. Acts like transport. Trigger { - check_trigger: fn() + check_trigger: fn(GeneContext) -> bool, + distribute_between_children: fn(GeneContext) -> ChildDistribution }, + /// Observes flow. Acts like transport. Observer { - observe: fn() + observe: fn(GeneContext), + distribute_between_children: fn(GeneContext) -> ChildDistribution }, } +pub enum ChildDistribution{ + Single, + Multiple{amount: usize}, + All, + Custom{child_indicies: Vec} +} + +pub enum ProduceDecision { + Create, + ModifyAll, + ModifySingle, +} + impl Gene { - pub fn new(place_str: impl Into, kind: GeneType) -> Self { + pub fn new(plant_str: impl Into, place_str: impl Into, kind: GeneType) -> Self { Self { + plant_name: plant_str.into(), place: place_str.into(), kind, } } } -impl GeneType { - pub fn pure_producer(flow_function: fn()) -> Self { - Self::PureProducer { create_flow: flow_function } - } - pub fn random_distribution() -> Self { - Self::Transport { distribute_between_children: ||{} } - } - pub fn fill_all() -> Self { - Self::Transport { distribute_between_children: ||{} } - } - pub fn consumer(consumer_function: fn()) -> Self { - Self::Consumer { consume: consumer_function } - } - pub fn modifier(modifier_function: fn()) -> Self { - Self::Modifier { modify_flow: modifier_function } - } - pub fn trigger(trigger_function: fn()) -> Self { - Self::Trigger { check_trigger: trigger_function } - } - pub fn observer(observer_function: fn()) -> Self { - Self::Observer { observe: observer_function } +impl Display for Gene { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f,"({}) {}",self.plant_name,self.place); + Ok(()) + } +} + +impl GeneType { + /// Creates pure producer with create function. + pub fn pure_producer(flow_function: fn(GeneContext) -> Flow) -> Self { + Self::PureProducer { create_flow: flow_function } + } + /// Creates transport with random distribution. + pub fn random_distribution() -> Self { + Self::Transport { distribute_between_children: Self::distribute_between_random } + } + /// Creates transport with distribution between all children. + pub fn fill_all() -> Self { + Self::Transport { distribute_between_children: Self::distribute_between_all } + } + /// Creates consumer with consumer function. + pub fn consumer(consumer_function: fn(GeneContext)) -> Self { + Self::Consumer { consume: consumer_function } + } + /// Creates modifier with modifier function. + pub fn modifier(modifier_function: fn(GeneContext) -> Option) -> Self { + Self::Modifier { modify_flow: modifier_function } + } + /// Creates trigger with distribution between all children. + pub fn trigger_all(trigger_function: fn(GeneContext) -> bool) -> Self { + Self::Trigger { check_trigger: trigger_function, distribute_between_children: Self::distribute_between_all } + } + /// Creates observer with distribution between all children. + pub fn observer_all(observer_function: fn(GeneContext)) -> Self { + Self::Observer { observe: observer_function, distribute_between_children: Self::distribute_between_all } + } + + + fn distribute_between_random(_: GeneContext) -> ChildDistribution { + ChildDistribution::Single + } + fn distribute_between_all(_: GeneContext) -> ChildDistribution { + ChildDistribution::All } } diff --git a/rust-pvz-genetics/src/genetics/genome.rs b/rust-pvz-genetics/src/genetics/genome.rs index d90e60d..4e433a5 100644 --- a/rust-pvz-genetics/src/genetics/genome.rs +++ b/rust-pvz-genetics/src/genetics/genome.rs @@ -15,11 +15,6 @@ impl PlantGenome { } } pub fn from_edges(nodes: Vec,edges: Vec<(usize,usize)>) -> Result { - // Check for nodes amount and edges amount mismatch - if nodes.len() != edges.len() { - return Err(PlantCreationError::AmountMismatch); - } - if nodes.len() == 0 { return Err(PlantCreationError::EmptyNodes); } @@ -56,7 +51,7 @@ impl Display for PlantGenome { visited[0] = true; while let Some((node, depth)) = queue.pop_front() { - result.push((depth, self.genes[node].place.clone())); + result.push((depth, self.genes[node].clone())); for &next in &adj[node] { if !visited[next] { @@ -69,9 +64,9 @@ impl Display for PlantGenome { result }; - for (depth,name) in indents { + for (depth,gene) in indents { let indent = "____".repeat(depth); - writeln!(f,"{}{}",indent,name)?; + writeln!(f,"{}{}",indent,gene)?; } Ok(()) @@ -82,5 +77,4 @@ impl Display for PlantGenome { pub enum PlantCreationError { EmptyNodes, EmptyEdges, - AmountMismatch, } diff --git a/rust-pvz-genetics/src/genetics/manipulations.rs b/rust-pvz-genetics/src/genetics/manipulations.rs index 03a8561..d8f7717 100644 --- a/rust-pvz-genetics/src/genetics/manipulations.rs +++ b/rust-pvz-genetics/src/genetics/manipulations.rs @@ -1,6 +1,6 @@ use std::mem::swap; -use rand::random_range; +use rand::RngExt; use crate::genetics::genome::*; @@ -11,11 +11,12 @@ impl<'a> GenomeModificator<'a> { return Self(genome_a,genome_b); } pub fn allelic_crossingover(&mut self,chance: Option) { + let mut generator = rand::rng(); let amount: usize = *[self.0.genes.len(),self.1.genes.len()].iter().min().unwrap_or(&0); for i in 0..amount { - let computed = random_range(1..chance.unwrap_or(2).max(2)); - if computed != 1 {continue;} + let computed = generator.random_range(0..chance.unwrap_or(2).max(2)); + if computed != 0 {continue;} swap(&mut self.0.genes[i], &mut self.1.genes[i]); } } diff --git a/rust-pvz-genetics/src/genetics/mod.rs b/rust-pvz-genetics/src/genetics/mod.rs index 0c59c83..c7a92b7 100644 --- a/rust-pvz-genetics/src/genetics/mod.rs +++ b/rust-pvz-genetics/src/genetics/mod.rs @@ -5,6 +5,7 @@ pub mod gene; pub mod genome; pub mod arguments; pub mod manipulations; +pub mod flow; pub mod prelude { pub use crate::genetics::genome::*; diff --git a/rust-pvz-genetics/src/genetics/plant_templates.rs b/rust-pvz-genetics/src/genetics/plant_templates.rs index 1aa3c0c..ba0c980 100644 --- a/rust-pvz-genetics/src/genetics/plant_templates.rs +++ b/rust-pvz-genetics/src/genetics/plant_templates.rs @@ -1,12 +1,12 @@ -use crate::genetics::prelude::*; +use crate::genetics::{flow::Flow, prelude::*}; pub fn peashooter_template() -> PlantGenome { PlantGenome::from_edges(vec![ - Gene::new("root", GeneType::pure_producer(||{})), - Gene::new("stem", GeneType::fill_all()), - Gene::new("head",GeneType::random_distribution()), - Gene::new("leaf",GeneType::modifier(||{})), - Gene::new("face",GeneType::consumer(||{})) + Gene::new("Peashooter","root", GeneType::pure_producer(|_|{Flow::empty()})), + Gene::new("Peashooter","stem", GeneType::fill_all()), + Gene::new("Peashooter","head",GeneType::random_distribution()), + Gene::new("Peashooter","leaf",GeneType::modifier(|_|{None})), + Gene::new("Peashooter","face",GeneType::consumer(|_|{})) ],vec![ (0,1), (1,2), @@ -17,10 +17,10 @@ pub fn peashooter_template() -> PlantGenome { pub fn sunflower_template() -> PlantGenome { PlantGenome::from_edges(vec![ - Gene::new("root", GeneType::Dummy), - Gene::new("stem", GeneType::Dummy), - Gene::new("head", GeneType::modifier(||{})), - Gene::new("face", GeneType::consumer(||{})), + Gene::new("Sunflower","root", GeneType::Dummy), + Gene::new("Sunflower","stem", GeneType::Dummy), + Gene::new("Sunflower","head", GeneType::modifier(|_|{None})), + Gene::new("Sunflower","face", GeneType::consumer(|_|{})), ], vec![ (0,1), (1,2), @@ -30,11 +30,11 @@ pub fn sunflower_template() -> PlantGenome { pub fn cherry_bomb_template() -> PlantGenome { PlantGenome::from_edges(vec![ - Gene::new("root", GeneType::modifier(||{})), - Gene::new("head", GeneType::consumer(||{})), - Gene::new("head", GeneType::consumer(||{})), - Gene::new("face", GeneType::Dummy), - Gene::new("face", GeneType::Dummy), + Gene::new("Cherry bomb","root", GeneType::modifier(|_|{None})), + Gene::new("Cherry bomb","head", GeneType::consumer(|_|{})), + Gene::new("Cherry bomb","head", GeneType::consumer(|_|{})), + Gene::new("Cherry bomb","face", GeneType::Dummy), + Gene::new("Cherry bomb","face", GeneType::Dummy), ], vec![ (0,1), (0,2), diff --git a/rust-pvz-genetics/src/main.rs b/rust-pvz-genetics/src/main.rs deleted file mode 100644 index 1e5690e..0000000 --- a/rust-pvz-genetics/src/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::genetics::plant_templates::peashooter_template; - -fn main() { - let peashooter = peashooter_template(); -}