From edb5ed4b1e725cdd925c21bbcb900a2853d75191 Mon Sep 17 00:00:00 2001 From: rendo Date: Tue, 31 Mar 2026 16:19:44 +0500 Subject: [PATCH] Pair manipulations --- rust-pvz-genetics/src/genetics/genome.rs | 8 +-- .../src/genetics/manipulations.rs | 61 ++++++++++++++----- .../src/genetics/plant_templates.rs | 12 ++-- rust-pvz-genetics/src/genetics/tests.rs | 8 +-- 4 files changed, 59 insertions(+), 30 deletions(-) diff --git a/rust-pvz-genetics/src/genetics/genome.rs b/rust-pvz-genetics/src/genetics/genome.rs index 2bc63a8..90ba3ea 100644 --- a/rust-pvz-genetics/src/genetics/genome.rs +++ b/rust-pvz-genetics/src/genetics/genome.rs @@ -2,12 +2,12 @@ use std::{collections::VecDeque, fmt::Display}; use crate::genetics::gene::Gene; -#[derive(PartialEq,Eq)] -pub struct PlantGenome { +#[derive(Clone,PartialEq,Eq)] +pub struct Genome { pub(crate) graph: Vec<(Gene,Vec)>, } -impl PlantGenome { +impl Genome { pub fn new() -> Self { Self { graph: Vec::new() @@ -33,7 +33,7 @@ impl PlantGenome { } } -impl Display for PlantGenome { +impl Display for Genome { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let indents = { let mut result: Vec<(usize,Gene)> = vec![(0,self.graph[0].0.clone())]; diff --git a/rust-pvz-genetics/src/genetics/manipulations.rs b/rust-pvz-genetics/src/genetics/manipulations.rs index e140ab7..3151a5f 100644 --- a/rust-pvz-genetics/src/genetics/manipulations.rs +++ b/rust-pvz-genetics/src/genetics/manipulations.rs @@ -1,26 +1,26 @@ -use std::mem::swap; +use std::{collections::HashMap, mem::swap}; use rand::{RngExt, SeedableRng, rngs::StdRng}; -use crate::genetics::genome::*; +use crate::genetics::{gene::Gene, genome::*}; -pub struct GenomeModificator<'a> { - genome_a: &'a mut PlantGenome, - genome_b: &'a mut PlantGenome, +pub struct PairGenomeModificator { + genome_a: Genome, + genome_b: Genome, generator: StdRng } -impl<'a> GenomeModificator<'a> { - pub fn new(genome_a: &'a mut PlantGenome,genome_b: &'a mut PlantGenome) -> Self { +impl PairGenomeModificator { + pub fn new(genome_a: &Genome,genome_b: &Genome) -> Self { return Self { - genome_a, - genome_b, + genome_a: genome_a.clone(), + genome_b: genome_b.clone(), generator: rand::make_rng(), }; } - pub fn with_seed(genome_a: &'a mut PlantGenome, genome_b: &'a mut PlantGenome, seed: u64) -> Self { + pub fn with_seed(genome_a: &Genome, genome_b: &Genome, seed: u64) -> Self { return Self { - genome_a, - genome_b, + genome_a: genome_a.clone(), + genome_b: genome_b.clone(), generator: StdRng::seed_from_u64(seed) }; } @@ -33,9 +33,38 @@ impl<'a> GenomeModificator<'a> { swap(&mut self.genome_a.graph[i].0, &mut self.genome_b.graph[i].0); } } - /*pub fn categoric_crossingover(&mut self,chance: Option) { - helper(self.genome_a.graph.iter().map(|mut gene|(gene.place.clone(),&mut gene)).collect::>().append(&mut self.genome_b.graph.iter().map(|mut gene|(gene.place.clone(),&mut gene)).collect::>()),chance); + pub fn categoric_crossingover(&mut self, chance: Option) { + 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() { + categories_a.entry(gene.place.clone()).or_default().push(i); + } + for (i, (gene, _)) in self.genome_b.graph.iter().enumerate() { + categories_b.entry(gene.place.clone()).or_default().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; + } + } + pub fn finish(self) -> (Genome,Genome) { + (self.genome_a,self.genome_b) } - fn helper(test: HashMap>,chance: Option) { - }*/ } diff --git a/rust-pvz-genetics/src/genetics/plant_templates.rs b/rust-pvz-genetics/src/genetics/plant_templates.rs index ba0c980..7f95fe5 100644 --- a/rust-pvz-genetics/src/genetics/plant_templates.rs +++ b/rust-pvz-genetics/src/genetics/plant_templates.rs @@ -1,7 +1,7 @@ use crate::genetics::{flow::Flow, prelude::*}; -pub fn peashooter_template() -> PlantGenome { - PlantGenome::from_edges(vec![ +pub fn peashooter_template() -> Genome { + Genome::from_edges(vec![ Gene::new("Peashooter","root", GeneType::pure_producer(|_|{Flow::empty()})), Gene::new("Peashooter","stem", GeneType::fill_all()), Gene::new("Peashooter","head",GeneType::random_distribution()), @@ -15,8 +15,8 @@ pub fn peashooter_template() -> PlantGenome { ]).unwrap() } -pub fn sunflower_template() -> PlantGenome { - PlantGenome::from_edges(vec![ +pub fn sunflower_template() -> Genome { + Genome::from_edges(vec![ Gene::new("Sunflower","root", GeneType::Dummy), Gene::new("Sunflower","stem", GeneType::Dummy), Gene::new("Sunflower","head", GeneType::modifier(|_|{None})), @@ -28,8 +28,8 @@ pub fn sunflower_template() -> PlantGenome { ]).unwrap() } -pub fn cherry_bomb_template() -> PlantGenome { - PlantGenome::from_edges(vec![ +pub fn cherry_bomb_template() -> Genome { + Genome::from_edges(vec![ Gene::new("Cherry bomb","root", GeneType::modifier(|_|{None})), Gene::new("Cherry bomb","head", GeneType::consumer(|_|{})), Gene::new("Cherry bomb","head", GeneType::consumer(|_|{})), diff --git a/rust-pvz-genetics/src/genetics/tests.rs b/rust-pvz-genetics/src/genetics/tests.rs index bbe4717..c7b0cf9 100644 --- a/rust-pvz-genetics/src/genetics/tests.rs +++ b/rust-pvz-genetics/src/genetics/tests.rs @@ -1,4 +1,4 @@ -use crate::genetics::{flow::Flow, gene::{Gene, GeneType}, genome::PlantGenome, manipulations::GenomeModificator, plant_templates::{peashooter_template, sunflower_template}}; +use crate::genetics::{flow::Flow, gene::{Gene, GeneType}, genome::Genome, manipulations::PairGenomeModificator, plant_templates::{peashooter_template, sunflower_template}}; #[test] fn test_display() { @@ -9,8 +9,8 @@ fn test_display() { fn test_allelic_crossingover() { let mut peashooter = peashooter_template(); let mut sunflower = sunflower_template(); - GenomeModificator::with_seed(&mut peashooter, &mut sunflower,3996684975687038250u64).allelic_crossingover(None); - assert!(peashooter.to_string() == PlantGenome::from_edges(vec![ + PairGenomeModificator::with_seed(&mut peashooter, &mut sunflower,3996684975687038250u64).allelic_crossingover(None); + assert!(peashooter.to_string() == Genome::from_edges(vec![ Gene::new("Sunflower","root", GeneType::Dummy), Gene::new("Peashooter","stem", GeneType::fill_all()), Gene::new("Peashooter","head",GeneType::random_distribution()), @@ -22,7 +22,7 @@ fn test_allelic_crossingover() { (2,3), (2,4) ]).unwrap().to_string()); - assert!(sunflower.to_string() == PlantGenome::from_edges(vec![ + assert!(sunflower.to_string() == Genome::from_edges(vec![ Gene::new("Peashooter","root", GeneType::pure_producer(|_|{Flow::empty()})), Gene::new("Sunflower","stem", GeneType::Dummy), Gene::new("Sunflower","head", GeneType::modifier(|_|{None})),