use rand::Rng;
use crate::gene::Gene;
use super::Mutation;
#[derive(Copy, Clone, Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct Swap {
pub chance: f64,
}
impl<G, const GENES: usize, RNG> Mutation<[G; GENES], RNG> for Swap
where
G: Gene,
RNG: Rng,
{
fn mutate(&self, genotype: &mut [G; GENES], rng: &mut RNG) {
assert!(
self.chance >= 0.0_f64,
"chance of mutation has to be above or equal 0.0, but is {}",
self.chance
);
assert!(
self.chance <= 1.0_f64,
"chance of mutation has to be below or equal 1.0, but is {}",
self.chance
);
if genotype.len() < 2 {
return;
}
if rng.gen_bool(self.chance) {
generic_slice_swap(genotype, rng);
}
}
}
impl<G, RNG> Mutation<Vec<G>, RNG> for Swap
where
G: Gene,
RNG: Rng,
{
fn mutate(&self, genotype: &mut Vec<G>, rng: &mut RNG) {
assert!(
self.chance >= 0.0_f64,
"chance of mutation has to be above or equal 0.0, but is {}",
self.chance
);
assert!(
self.chance <= 1.0_f64,
"chance of mutation has to be below or equal 1.0, but is {}",
self.chance
);
if genotype.len() < 2 {
return;
}
if rng.gen_bool(self.chance) {
generic_slice_swap(genotype, rng);
}
}
}
impl<RNG> Mutation<String, RNG> for Swap
where
RNG: Rng,
{
fn mutate(&self, genotype: &mut String, rng: &mut RNG) {
assert!(
self.chance >= 0.0_f64,
"chance of mutation has to be above or equal 0.0, but is {}",
self.chance
);
assert!(
self.chance <= 1.0_f64,
"chance of mutation has to be below or equal 1.0, but is {}",
self.chance
);
if genotype.len() < 2 {
return;
}
if rng.gen_bool(self.chance) {
let mut chars = genotype.chars().collect::<Vec<_>>();
generic_slice_swap(&mut chars, rng);
*genotype = chars.iter().collect::<String>();
}
}
}
fn generic_slice_swap<G, R>(genotype: &mut [G], rng: &mut R)
where
R: Rng,
{
if genotype.len() < 2 {
return;
}
let slot_a = rng.gen_range(0..genotype.len());
let slot_b = loop {
let potential_slot = rng.gen_range(0..genotype.len());
if potential_slot != slot_a {
break potential_slot;
}
};
genotype.swap(slot_a, slot_b);
}
#[cfg(test)]
mod tests {
use rand::rngs::SmallRng;
use rand::SeedableRng;
use super::{Mutation, Swap};
#[test]
fn array() {
let mutation = Swap { chance: 1.0 };
let mut rng = SmallRng::seed_from_u64(1);
let mut array = [0_u8, 1, 2, 3, 4];
mutation.mutate(&mut array, &mut rng);
assert_eq!(array, [3, 1, 2, 0, 4]);
}
#[test]
fn vector() {
let mutation = Swap { chance: 1.0 };
let mut rng = SmallRng::seed_from_u64(1);
let mut array = vec![0_u8, 1, 2, 3, 4];
mutation.mutate(&mut array, &mut rng);
assert_eq!(array, [3, 1, 2, 0, 4]);
}
#[test]
fn string() {
let mutation = Swap { chance: 1.0 };
let mut rng = SmallRng::seed_from_u64(0);
let mut string = String::from("test");
mutation.mutate(&mut string, &mut rng);
assert_eq!(string, "tets");
}
}