Switched to petgraph as graph representation. Initialization doesn't work yet

This commit is contained in:
rendo 2026-04-07 11:21:28 +05:00
commit 0eaa9d04b8
4 changed files with 103 additions and 89 deletions

View file

@ -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<usize>)>,
pub(crate) graph: Graph<Gene,()>,
}
impl Genome {
pub fn new() -> Self {
Self {
graph: Vec::new()
graph: Graph::<Gene,()>::new()
}
}
pub fn from_edges(nodes: Vec<Gene>,edges: Vec<(usize,usize)>) -> Result<Self,PlantCreationError> {
@ -22,13 +22,9 @@ impl Genome {
return Err(PlantCreationError::EmptyEdges);
}
let mut graph: Vec<(Gene,Vec<usize>)> = 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::<Gene,()>::new();
let gene_indicies = nodes.into_iter().map(|gene|{graph.add_node(gene)}).collect::<Vec<NodeIndex>>();
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<NodeIndex> = 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,
}

View file

@ -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<u8>) -> (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<u8>,broad: Option<bool>) -> (Genome,Genome) {
let threshold = chance.unwrap_or(2).max(2);
let mut categories_a: HashMap<String, Vec<usize>> = HashMap::new();
let mut categories_b: HashMap<String, Vec<usize>> = 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::<String,(Vec<NodeIndex>,Vec<NodeIndex>)>::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) {

View file

@ -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);
}
}

View file

@ -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::<Vec<NodeIndex>>() {
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::<Texture2D>(&("res://assets/sprites/".to_string() + &sprite)));
if let Some(sprite) = genome.graph[idx].sprite.clone() {
nodes.get_mut(&idx).unwrap().set_texture(&load::<Texture2D>(&("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::<Vec<NodeIndex>>() {
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::<Texture2D>(&("res://assets/sprites/".to_string() + &sprite)));
if let Some(sprite) = genome.graph[idx].sprite.clone() {
nodes.get_mut(&idx).unwrap().set_texture(&load::<Texture2D>(&("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]);
}
}