diff --git a/rust-pvz-genetics/src/genetics/genome.rs b/rust-pvz-genetics/src/genetics/genome.rs index ad2c183..d5bc3ae 100644 --- a/rust-pvz-genetics/src/genetics/genome.rs +++ b/rust-pvz-genetics/src/genetics/genome.rs @@ -1,16 +1,16 @@ -use std::fmt::Display; +use petgraph::graph::{Graph, NodeIndex}; use crate::genetics::gene::Gene; -#[derive(Default,Clone,PartialEq,Eq)] +#[derive(Default,Clone)] pub struct Genome { - pub(crate) graph: Vec<(Gene,Vec)>, + pub(crate) graph: Graph, } impl Genome { pub fn new() -> Self { Self { - graph: Vec::new() + graph: Graph::::new() } } pub fn from_edges(nodes: Vec,edges: Vec<(usize,usize)>) -> Result { @@ -22,13 +22,9 @@ impl Genome { return Err(PlantCreationError::EmptyEdges); } - let mut graph: Vec<(Gene,Vec)> = Vec::new(); - for gene in nodes { - graph.push((gene,Vec::new())); - } - for edge in edges { - graph[edge.0].1.push(edge.1); - } + let mut graph = Graph::::new(); + let gene_indicies = nodes.into_iter().map(|gene|{graph.add_node(gene)}).collect::>(); + edges.into_iter().map(|(node_a,node_b)|graph.add_edge(gene_indicies[node_a], gene_indicies[node_b], ())); return Ok(Self { graph @@ -36,27 +32,34 @@ impl Genome { } } +// Vibecoded +use std::fmt::{self, Display}; + impl Display for Genome { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let indents = { - let mut result: Vec<(usize, Gene)> = Vec::new(); - let mut stack: Vec<(usize, usize)> = vec![(0, 0)]; // (node_index, depth) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let graph = &self.graph; - while let Some((node, depth)) = stack.pop() { - result.push((depth, self.graph[node].0.clone())); + if graph.node_count() == 0 { + return Ok(()); + } - // push in reverse so left-most child is processed first - for &child in self.graph[node].1.iter().rev() { - stack.push((child, depth + 1)); - } - } + let root = NodeIndex::new(0); + let mut stack: Vec<(NodeIndex, usize)> = vec![(root, 0)]; - result - }; - - for (depth,gene) in indents { + while let Some((node, depth)) = stack.pop() { let indent = "\t".repeat(depth); - writeln!(f,"{}{}",indent,gene)?; + writeln!(f, "{}{}", indent, graph[node])?; + + // push in reverse to preserve child order + let mut children: Vec = graph + .neighbors(node) + .filter(|&n| n != node) // skip self-loops + .collect(); + + children.reverse(); + for child in children { + stack.push((child, depth + 1)); + } } Ok(()) @@ -68,3 +71,4 @@ pub enum PlantCreationError { EmptyNodes, EmptyEdges, } + diff --git a/rust-pvz-genetics/src/genetics/manipulations.rs b/rust-pvz-genetics/src/genetics/manipulations.rs index 9a844aa..429f9f4 100644 --- a/rust-pvz-genetics/src/genetics/manipulations.rs +++ b/rust-pvz-genetics/src/genetics/manipulations.rs @@ -1,8 +1,9 @@ use std::{collections::HashMap, mem::swap}; +use petgraph::graph::NodeIndex; use rand::{RngExt, SeedableRng, rngs::StdRng}; -use crate::genetics::genome::*; +use crate::genetics::{gene::GenePlace, genome::*}; pub struct PairGenomeModificator { genome_a: Genome, @@ -31,61 +32,53 @@ impl PairGenomeModificator { }; } pub fn allelic_crossingover(&mut self,chance: Option) -> (Genome, Genome) { - let amount: usize = *[self.genome_a.graph.len(),self.genome_b.graph.len()].iter().min().unwrap_or(&0); + let amount: usize = *[self.genome_a.graph.node_count(),self.genome_b.graph.node_count()].iter().min().unwrap_or(&0); for i in 0..amount { let computed = self.generator.random_range(0..chance.unwrap_or(2).max(2)); if computed != 0 {continue;} - swap(&mut self.genome_a.graph[i].0, &mut self.genome_b.graph[i].0); + let idx: NodeIndex = (i as u32).into(); + swap(&mut self.genome_a.graph[idx], &mut self.genome_b.graph[idx]); } (self.genome_a.clone(),self.genome_b.clone()) } pub fn categoric_crossingover(&mut self, chance: Option,broad: Option) -> (Genome,Genome) { let threshold = chance.unwrap_or(2).max(2); - - let mut categories_a: HashMap> = HashMap::new(); - let mut categories_b: HashMap> = HashMap::new(); - - for (i, (gene, _)) in self.genome_a.graph.iter().enumerate() { - if broad.unwrap_or(false){ - categories_a.entry(gene.place.broad().to_string()).or_default().push(i); - } else { - categories_a.entry(gene.place.to_string()).or_default().push(i); + let mut categories = HashMap::,Vec)>::new(); + + if broad.unwrap_or(false) { + for i in self.genome_a.graph.node_indices() { + categories.entry(self.genome_a.graph[i].place.broad().to_string()).or_default().0.push(i); } - } - for (i, (gene, _)) in self.genome_b.graph.iter().enumerate() { - if broad.unwrap_or(false){ - categories_b.entry(gene.place.broad().to_string()).or_default().push(i); - } else { - categories_b.entry(gene.place.to_string()).or_default().push(i); + for i in self.genome_b.graph.node_indices() { + categories.entry(self.genome_b.graph[i].place.broad().to_string()).or_default().1.push(i); + } + } else { + for i in self.genome_a.graph.node_indices() { + categories.entry(self.genome_a.graph[i].place.to_string()).or_default().0.push(i); + } + for i in self.genome_b.graph.node_indices() { + categories.entry(self.genome_b.graph[i].place.to_string()).or_default().1.push(i); } } - for (category, indices_a) in &categories_a { - let Some(indices_b) = categories_b.get(category) else { continue; }; - - let computed = self.generator.random_range(0..threshold); - if computed != 0 { continue; } - - let fi = indices_a[self.generator.random_range(0..indices_a.len())]; - let si = indices_b[self.generator.random_range(0..indices_b.len())]; - - let gene_a = self.genome_a.graph[fi].0.clone(); - let gene_b = self.genome_b.graph[si].0.clone(); - self.genome_a.graph[fi].0 = gene_b; - self.genome_b.graph[si].0 = gene_a; + for (_,(genes_a,genes_b)) in categories { + if self.generator.random_range(0..threshold) != 0 {continue;} + swap(&mut self.genome_a.graph[genes_a[self.generator.random_range(0..genes_a.len())]],&mut self.genome_b.graph[genes_b[self.generator.random_range(0..genes_b.len())]]); } + + (self.genome_a.clone(),self.genome_b.clone()) } pub fn combine(&mut self) -> (Genome,Genome){ - let donor_gene: usize = self.generator.random_range(0..self.genome_a.graph.len()); +/* let donor_gene: usize = self.generator.random_range(0..self.genome_a.graph.len()); let mut extracted = vec![self.genome_a.graph.remove(donor_gene)]; let mut idx = 0; while idx < extracted.len() { for child_idx idx += 1; - } + }*/ (self.genome_a.clone(),self.genome_b.clone()) } pub fn cancel(&self) -> (Genome,Genome) { diff --git a/rust-pvz-genetics/src/godot_wrapper/godot_genome.rs b/rust-pvz-genetics/src/godot_wrapper/godot_genome.rs index ffcfd58..f8e2d37 100644 --- a/rust-pvz-genetics/src/godot_wrapper/godot_genome.rs +++ b/rust-pvz-genetics/src/godot_wrapper/godot_genome.rs @@ -39,6 +39,10 @@ impl INode for GodotGenome { PlantType::Sunflower => Some(sunflower_template()), PlantType::CherryBomb => Some(peashooter_template()), _ => None, + }; + + if let Some(genome) = self.genome.as_ref() { + godot_print!("{}",genome); } } diff --git a/rust-pvz-genetics/src/godot_wrapper/plant.rs b/rust-pvz-genetics/src/godot_wrapper/plant.rs index ef2306d..a0f7856 100644 --- a/rust-pvz-genetics/src/godot_wrapper/plant.rs +++ b/rust-pvz-genetics/src/godot_wrapper/plant.rs @@ -1,5 +1,8 @@ +use std::collections::HashMap; + use godot::prelude::*; use godot::classes::{INode2D, Node2D, Sprite2D, Texture2D}; +use petgraph::graph::NodeIndex; use crate::godot_wrapper::godot_genome::GodotGenome; @@ -19,33 +22,37 @@ impl INode2D for Plant { godot_genome.signals().genome_updated().connect_other(&*self, Self::restructure); let Some(genome)= godot_genome.bind().get_genome() else { return; }; + let mut root_index = NodeIndex::new(0); - let mut children = { - let mut result = Vec::new(); - for i in 0..genome.graph.len() { - result.push((Sprite2D::new_alloc(),&genome.graph[i])); + let mut nodes = { + let mut result = HashMap::new(); + for i in genome.graph.node_indices() { + if result.len() == 0 { + root_index = i; + } + result.insert(i, Sprite2D::new_alloc()); } result }; - - for i in 0..genome.graph.len() { - children[i].0.set_name(&genome.graph[i].0.place.to_string()); + for idx in nodes.keys().map(|k|*k).collect::>() { + nodes.get_mut(&idx).unwrap().set_name(&genome.graph[idx].place.to_string()); // Setting up genes - if let Some(sprite) = genome.graph[i].0.sprite.clone() { - children[i].0.set_texture(&load::(&("res://assets/sprites/".to_string() + &sprite))); + if let Some(sprite) = genome.graph[idx].sprite.clone() { + nodes.get_mut(&idx).unwrap().set_texture(&load::(&("res://assets/sprites/".to_string() + &sprite))); } // Setting up children - for edge in &genome.graph[i].1 { - let mut gene_sprite = children[*edge].0.clone(); + for child_idx in genome.graph.neighbors(idx) { + let mut gene_sprite = nodes.get(&child_idx).unwrap().clone(); + - gene_sprite.set_position((children[i].1.0.get_child_position)(children[*edge].1.0.place.clone())); + gene_sprite.set_position((genome.graph[idx].get_child_position)(genome.graph[child_idx].place.clone())); - children[i].0.add_child(&gene_sprite); + nodes.get_mut(&idx).unwrap().add_child(&gene_sprite); } } - self.base_mut().add_child(&children[0].0); + self.base_mut().add_child(&nodes[&root_index]); } } @@ -59,34 +66,40 @@ impl Plant { } let Some(godot_genome) = self.genome.clone() else { return; }; + + godot_genome.signals().genome_updated().connect_other(&*self, Self::restructure); let Some(genome)= godot_genome.bind().get_genome() else { return; }; + let mut root_index = NodeIndex::new(0); - let mut children = { - let mut result = Vec::new(); - for i in 0..genome.graph.len() { - result.push((Sprite2D::new_alloc(),&genome.graph[i])); + let mut nodes = { + let mut result = HashMap::new(); + for i in genome.graph.node_indices() { + if result.len() == 0 { + root_index = i; + } + result.insert(i, Sprite2D::new_alloc()); } result }; - - for i in 0..genome.graph.len() { - children[i].0.set_name(&genome.graph[i].0.place.to_string()); + for idx in nodes.keys().map(|k|*k).collect::>() { + nodes.get_mut(&idx).unwrap().set_name(&genome.graph[idx].place.to_string()); // Setting up genes - if let Some(sprite) = genome.graph[i].0.sprite.clone() { - children[i].0.set_texture(&load::(&("res://assets/sprites/".to_string() + &sprite))); + if let Some(sprite) = genome.graph[idx].sprite.clone() { + nodes.get_mut(&idx).unwrap().set_texture(&load::(&("res://assets/sprites/".to_string() + &sprite))); } // Setting up children - for edge in &genome.graph[i].1 { - let mut gene_sprite = children[*edge].0.clone(); + for child_idx in genome.graph.neighbors(idx) { + let mut gene_sprite = nodes.get(&child_idx).unwrap().clone(); + - gene_sprite.set_position((children[i].1.0.get_child_position)(children[*edge].1.0.place.clone())); + gene_sprite.set_position((genome.graph[idx].get_child_position)(genome.graph[child_idx].place.clone())); - children[i].0.add_child(&gene_sprite); + nodes.get_mut(&idx).unwrap().add_child(&gene_sprite); } } - self.base_mut().add_child(&children[0].0); + self.base_mut().add_child(&nodes[&root_index]); } }