Gene, flow and manipulations

This commit is contained in:
rendo 2026-03-30 11:36:42 +05:00
commit 4ed86fda31
7 changed files with 119 additions and 48 deletions

View file

@ -0,0 +1,18 @@
pub struct Flow {
pub projectiles: Vec<ProjectilePlaceholder>
}
pub struct ProjectilePlaceholder;
impl Flow {
pub fn new(projectiles: Vec<ProjectilePlaceholder>) -> Self {
Self {
projectiles,
}
}
pub fn empty() -> Self {
Self {
projectiles: vec![],
}
}
}

View file

@ -1,61 +1,123 @@
use std::fmt::Display;
use crate::genetics::flow::Flow;
#[derive(PartialEq,Eq,Clone)] #[derive(PartialEq,Eq,Clone)]
pub struct Gene { pub struct Gene {
pub plant_name: String,
pub place: String, pub place: String,
pub kind: GeneType pub kind: GeneType
} }
pub struct GeneContext {
pub flow: Flow
}
/// GeneType is an enum that defines behaviour of gene.
#[derive(PartialEq,Eq,Clone)] #[derive(PartialEq,Eq,Clone)]
pub enum GeneType { pub enum GeneType {
/// Without functional behaviour. Doesn't pass through flow.
Dummy, Dummy,
/// Only creates flow. Can be set up to not create flow if flow isn't empty.
PureProducer { 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 { Transport {
distribute_between_children: fn() distribute_between_children: fn(GeneContext) -> ChildDistribution
}, },
/// Consumes flow, destroying it in process.
Consumer { Consumer {
consume: fn() consume: fn(GeneContext)
}, },
/// Modifies flow
Modifier { Modifier {
modify_flow: fn() modify_flow: fn(GeneContext) -> Option<Flow>
}, },
/// Conditionally passes through flow. Acts like transport.
Trigger { Trigger {
check_trigger: fn() check_trigger: fn(GeneContext) -> bool,
distribute_between_children: fn(GeneContext) -> ChildDistribution
}, },
/// Observes flow. Acts like transport.
Observer { Observer {
observe: fn() observe: fn(GeneContext),
distribute_between_children: fn(GeneContext) -> ChildDistribution
}, },
} }
pub enum ChildDistribution{
Single,
Multiple{amount: usize},
All,
Custom{child_indicies: Vec<usize>}
}
pub enum ProduceDecision {
Create,
ModifyAll,
ModifySingle,
}
impl Gene { impl Gene {
pub fn new(place_str: impl Into<String>, kind: GeneType) -> Self { pub fn new(plant_str: impl Into<String>, place_str: impl Into<String>, kind: GeneType) -> Self {
Self { Self {
plant_name: plant_str.into(),
place: place_str.into(), place: place_str.into(),
kind, kind,
} }
} }
} }
impl GeneType { impl Display for Gene {
pub fn pure_producer(flow_function: fn()) -> Self { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Self::PureProducer { create_flow: flow_function } write!(f,"({}) {}",self.plant_name,self.place);
} Ok(())
pub fn random_distribution() -> Self { }
Self::Transport { distribute_between_children: ||{} } }
}
pub fn fill_all() -> Self { impl GeneType {
Self::Transport { distribute_between_children: ||{} } /// Creates pure producer with create function.
} pub fn pure_producer(flow_function: fn(GeneContext) -> Flow) -> Self {
pub fn consumer(consumer_function: fn()) -> Self { Self::PureProducer { create_flow: flow_function }
Self::Consumer { consume: consumer_function } }
} /// Creates transport with random distribution.
pub fn modifier(modifier_function: fn()) -> Self { pub fn random_distribution() -> Self {
Self::Modifier { modify_flow: modifier_function } Self::Transport { distribute_between_children: Self::distribute_between_random }
} }
pub fn trigger(trigger_function: fn()) -> Self { /// Creates transport with distribution between all children.
Self::Trigger { check_trigger: trigger_function } pub fn fill_all() -> Self {
} Self::Transport { distribute_between_children: Self::distribute_between_all }
pub fn observer(observer_function: fn()) -> Self { }
Self::Observer { observe: observer_function } /// 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<Flow>) -> 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
} }
} }

View file

@ -15,11 +15,6 @@ impl PlantGenome {
} }
} }
pub fn from_edges(nodes: Vec<Gene>,edges: Vec<(usize,usize)>) -> Result<Self,PlantCreationError> { pub fn from_edges(nodes: Vec<Gene>,edges: Vec<(usize,usize)>) -> Result<Self,PlantCreationError> {
// Check for nodes amount and edges amount mismatch
if nodes.len() != edges.len() {
return Err(PlantCreationError::AmountMismatch);
}
if nodes.len() == 0 { if nodes.len() == 0 {
return Err(PlantCreationError::EmptyNodes); return Err(PlantCreationError::EmptyNodes);
} }
@ -56,7 +51,7 @@ impl Display for PlantGenome {
visited[0] = true; visited[0] = true;
while let Some((node, depth)) = queue.pop_front() { 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] { for &next in &adj[node] {
if !visited[next] { if !visited[next] {
@ -69,9 +64,9 @@ impl Display for PlantGenome {
result result
}; };
for (depth,name) in indents { for (depth,gene) in indents {
let indent = "____".repeat(depth); let indent = "____".repeat(depth);
writeln!(f,"{}{}",indent,name)?; writeln!(f,"{}{}",indent,gene)?;
} }
Ok(()) Ok(())
@ -82,5 +77,4 @@ impl Display for PlantGenome {
pub enum PlantCreationError { pub enum PlantCreationError {
EmptyNodes, EmptyNodes,
EmptyEdges, EmptyEdges,
AmountMismatch,
} }

View file

@ -1,6 +1,6 @@
use std::mem::swap; use std::mem::swap;
use rand::random_range; use rand::RngExt;
use crate::genetics::genome::*; use crate::genetics::genome::*;
@ -11,11 +11,12 @@ impl<'a> GenomeModificator<'a> {
return Self(genome_a,genome_b); return Self(genome_a,genome_b);
} }
pub fn allelic_crossingover(&mut self,chance: Option<u8>) { pub fn allelic_crossingover(&mut self,chance: Option<u8>) {
let mut generator = rand::rng();
let amount: usize = *[self.0.genes.len(),self.1.genes.len()].iter().min().unwrap_or(&0); let amount: usize = *[self.0.genes.len(),self.1.genes.len()].iter().min().unwrap_or(&0);
for i in 0..amount { for i in 0..amount {
let computed = random_range(1..chance.unwrap_or(2).max(2)); let computed = generator.random_range(0..chance.unwrap_or(2).max(2));
if computed != 1 {continue;} if computed != 0 {continue;}
swap(&mut self.0.genes[i], &mut self.1.genes[i]); swap(&mut self.0.genes[i], &mut self.1.genes[i]);
} }
} }

View file

@ -5,6 +5,7 @@ pub mod gene;
pub mod genome; pub mod genome;
pub mod arguments; pub mod arguments;
pub mod manipulations; pub mod manipulations;
pub mod flow;
pub mod prelude { pub mod prelude {
pub use crate::genetics::genome::*; pub use crate::genetics::genome::*;

View file

@ -1,12 +1,12 @@
use crate::genetics::prelude::*; use crate::genetics::{flow::Flow, prelude::*};
pub fn peashooter_template() -> PlantGenome { pub fn peashooter_template() -> PlantGenome {
PlantGenome::from_edges(vec![ PlantGenome::from_edges(vec![
Gene::new("root", GeneType::pure_producer(||{})), Gene::new("Peashooter","root", GeneType::pure_producer(|_|{Flow::empty()})),
Gene::new("stem", GeneType::fill_all()), Gene::new("Peashooter","stem", GeneType::fill_all()),
Gene::new("head",GeneType::random_distribution()), Gene::new("Peashooter","head",GeneType::random_distribution()),
Gene::new("leaf",GeneType::modifier(||{})), Gene::new("Peashooter","leaf",GeneType::modifier(|_|{None})),
Gene::new("face",GeneType::consumer(||{})) Gene::new("Peashooter","face",GeneType::consumer(|_|{}))
],vec![ ],vec![
(0,1), (0,1),
(1,2), (1,2),
@ -17,10 +17,10 @@ pub fn peashooter_template() -> PlantGenome {
pub fn sunflower_template() -> PlantGenome { pub fn sunflower_template() -> PlantGenome {
PlantGenome::from_edges(vec![ PlantGenome::from_edges(vec![
Gene::new("root", GeneType::Dummy), Gene::new("Sunflower","root", GeneType::Dummy),
Gene::new("stem", GeneType::Dummy), Gene::new("Sunflower","stem", GeneType::Dummy),
Gene::new("head", GeneType::modifier(||{})), Gene::new("Sunflower","head", GeneType::modifier(|_|{None})),
Gene::new("face", GeneType::consumer(||{})), Gene::new("Sunflower","face", GeneType::consumer(|_|{})),
], vec![ ], vec![
(0,1), (0,1),
(1,2), (1,2),
@ -30,11 +30,11 @@ pub fn sunflower_template() -> PlantGenome {
pub fn cherry_bomb_template() -> PlantGenome { pub fn cherry_bomb_template() -> PlantGenome {
PlantGenome::from_edges(vec![ PlantGenome::from_edges(vec![
Gene::new("root", GeneType::modifier(||{})), Gene::new("Cherry bomb","root", GeneType::modifier(|_|{None})),
Gene::new("head", GeneType::consumer(||{})), Gene::new("Cherry bomb","head", GeneType::consumer(|_|{})),
Gene::new("head", GeneType::consumer(||{})), Gene::new("Cherry bomb","head", GeneType::consumer(|_|{})),
Gene::new("face", GeneType::Dummy), Gene::new("Cherry bomb","face", GeneType::Dummy),
Gene::new("face", GeneType::Dummy), Gene::new("Cherry bomb","face", GeneType::Dummy),
], vec![ ], vec![
(0,1), (0,1),
(0,2), (0,2),

View file

@ -1,5 +0,0 @@
use crate::genetics::plant_templates::peashooter_template;
fn main() {
let peashooter = peashooter_template();
}