Gene, flow and manipulations
This commit is contained in:
parent
6be5d415ab
commit
4ed86fda31
7 changed files with 119 additions and 48 deletions
18
rust-pvz-genetics/src/genetics/flow.rs
Normal file
18
rust-pvz-genetics/src/genetics/flow.rs
Normal 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![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 Display for Gene {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f,"({}) {}",self.plant_name,self.place);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GeneType {
|
impl GeneType {
|
||||||
pub fn pure_producer(flow_function: fn()) -> Self {
|
/// Creates pure producer with create function.
|
||||||
|
pub fn pure_producer(flow_function: fn(GeneContext) -> Flow) -> Self {
|
||||||
Self::PureProducer { create_flow: flow_function }
|
Self::PureProducer { create_flow: flow_function }
|
||||||
}
|
}
|
||||||
|
/// Creates transport with random distribution.
|
||||||
pub fn random_distribution() -> Self {
|
pub fn random_distribution() -> Self {
|
||||||
Self::Transport { distribute_between_children: ||{} }
|
Self::Transport { distribute_between_children: Self::distribute_between_random }
|
||||||
}
|
}
|
||||||
|
/// Creates transport with distribution between all children.
|
||||||
pub fn fill_all() -> Self {
|
pub fn fill_all() -> Self {
|
||||||
Self::Transport { distribute_between_children: ||{} }
|
Self::Transport { distribute_between_children: Self::distribute_between_all }
|
||||||
}
|
}
|
||||||
pub fn consumer(consumer_function: fn()) -> Self {
|
/// Creates consumer with consumer function.
|
||||||
|
pub fn consumer(consumer_function: fn(GeneContext)) -> Self {
|
||||||
Self::Consumer { consume: consumer_function }
|
Self::Consumer { consume: consumer_function }
|
||||||
}
|
}
|
||||||
pub fn modifier(modifier_function: fn()) -> Self {
|
/// Creates modifier with modifier function.
|
||||||
|
pub fn modifier(modifier_function: fn(GeneContext) -> Option<Flow>) -> Self {
|
||||||
Self::Modifier { modify_flow: modifier_function }
|
Self::Modifier { modify_flow: modifier_function }
|
||||||
}
|
}
|
||||||
pub fn trigger(trigger_function: fn()) -> Self {
|
/// Creates trigger with distribution between all children.
|
||||||
Self::Trigger { check_trigger: trigger_function }
|
pub fn trigger_all(trigger_function: fn(GeneContext) -> bool) -> Self {
|
||||||
|
Self::Trigger { check_trigger: trigger_function, distribute_between_children: Self::distribute_between_all }
|
||||||
}
|
}
|
||||||
pub fn observer(observer_function: fn()) -> Self {
|
/// Creates observer with distribution between all children.
|
||||||
Self::Observer { observe: observer_function }
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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::*;
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
use crate::genetics::plant_templates::peashooter_template;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let peashooter = peashooter_template();
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue