1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use crate::engines::genome::chromosome::Chromosome;
use crate::engines::genome::genes::gene::Gene;
use crate::engines::genome::genotype::Genotype;
use crate::engines::genome::phenotype::Phenotype;
use crate::engines::genome::population::Population;

pub trait Crossover<G: Gene<G, A>, A> {

    fn cross_rate(&self) -> f32;
    
    fn cross(&self, population: &mut Population<G, A>, parent_indexes: &[i32], generation: i32) {
        let index_one = parent_indexes[0] as usize;
        let index_two = parent_indexes[1] as usize;

        let mut geno_one = population.get(index_one).genotype().clone();
        let mut geno_two = population.get(index_two).genotype().clone();

        let cross_count = self.cross_genotypes(&mut geno_one, &mut geno_two);

        if cross_count > 0 {
            population.set(index_one, Phenotype::from_genotype(geno_one, generation));
            population.set(index_two, Phenotype::from_genotype(geno_two, generation));
        }
    }

    fn cross_genotypes(
        &self,
        geno_one: &mut Genotype<G, A>,
        geno_two: &mut Genotype<G, A>,
    ) -> i32 {
        let min_index = std::cmp::min(geno_one.len(), geno_two.len());
        let chromosome_index = rand::random::<usize>() % min_index;

        let mut chrom_one = geno_one.get_chromosome_mut(chromosome_index);
        let mut chrom_two = geno_two.get_chromosome_mut(chromosome_index);

        self.cross_chromosomes(&mut chrom_one, &mut chrom_two)
    }

    fn cross_chromosomes(
        &self,
        chrom_one: &mut Chromosome<G, A>,
        chrom_two: &mut Chromosome<G, A>
    ) -> i32 {
        let rate = self.cross_rate();
        let mut cross_count = 0;

        for i in 0..std::cmp::min(chrom_one.len(), chrom_two.len()) {
            if rand::random::<f32>() < rate {
                let gene_one = chrom_one.get_gene(i);
                let gene_two = chrom_two.get_gene(i);

                let new_gene_one = gene_one.from_allele(&gene_two.allele());
                let new_gene_two = gene_two.from_allele(&gene_one.allele());

                chrom_one.set_gene(i, new_gene_one);
                chrom_two.set_gene(i, new_gene_two);

                cross_count += 1;
            }
        }

        cross_count
    }
}