genetics-vs-zombies/rust-pvz-genetics/src/genetics/genome.rs

74 lines
1.8 KiB
Rust

use petgraph::graph::{Graph, NodeIndex};
use crate::genetics::gene::Gene;
#[derive(Default,Clone)]
pub struct Genome {
pub(crate) graph: Graph<Gene,()>,
}
impl Genome {
pub fn new() -> Self {
Self {
graph: Graph::<Gene,()>::new()
}
}
pub fn from_edges(nodes: Vec<Gene>,edges: Vec<(usize,usize)>) -> Result<Self,PlantCreationError> {
if nodes.len() == 0 {
return Err(PlantCreationError::EmptyNodes);
}
if edges.len() == 0 {
return Err(PlantCreationError::EmptyEdges);
}
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
});
}
}
// Vibecoded
use std::fmt::{self, Display};
impl Display for Genome {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let graph = &self.graph;
if graph.node_count() == 0 {
return Ok(());
}
let root = NodeIndex::new(0);
let mut stack: Vec<(NodeIndex, usize)> = vec![(root, 0)];
while let Some((node, depth)) = stack.pop() {
let indent = "\t".repeat(depth);
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(())
}
}
#[derive(Debug)]
pub enum PlantCreationError {
EmptyNodes,
EmptyEdges,
}