Video version
This commit is contained in:
Generated
-21
@@ -43,7 +43,6 @@ dependencies = [
|
|||||||
"colornamer",
|
"colornamer",
|
||||||
"itertools",
|
"itertools",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -141,26 +140,6 @@ dependencies = [
|
|||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.219"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
|
||||||
dependencies = [
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.219"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.100"
|
||||||
|
|||||||
@@ -7,4 +7,3 @@ edition = "2021"
|
|||||||
colornamer = "1.0.1"
|
colornamer = "1.0.1"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
rand = "0.9.1"
|
rand = "0.9.1"
|
||||||
serde = {version = "1.0.219", features=["derive"]}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use rand::{rng, seq::IndexedRandom, Rng};
|
use rand::{rng, seq::IndexedRandom};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ChoiceFunction {
|
pub enum ChoiceFunction {
|
||||||
@@ -9,6 +9,9 @@ pub enum ChoiceFunction {
|
|||||||
|
|
||||||
impl ChoiceFunction {
|
impl ChoiceFunction {
|
||||||
pub fn choose<'a, T>(&self, xs: &'a [T]) -> &'a T {
|
pub fn choose<'a, T>(&self, xs: &'a [T]) -> &'a T {
|
||||||
|
if xs.len() == 0 {
|
||||||
|
panic!("requires at least one item")
|
||||||
|
}
|
||||||
match self {
|
match self {
|
||||||
ChoiceFunction::First => &xs[0],
|
ChoiceFunction::First => &xs[0],
|
||||||
ChoiceFunction::Last => &xs[xs.len() - 1],
|
ChoiceFunction::Last => &xs[xs.len() - 1],
|
||||||
|
|||||||
+14
-10
@@ -27,12 +27,12 @@ impl Genetic for Coloration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
pub r: Stat<'.', '!', 0, 8>,
|
pub r: Stat<'.', '!', 0, 8>,
|
||||||
pub g: Stat<'.', '!', 0, 8>,
|
pub g: Stat<'.', '!', 0, 8>,
|
||||||
pub b: Stat<'.', '!', 0, 8>,
|
pub b: Stat<'.', '!', 0, 8>,
|
||||||
pub pallor: Stat<'.', '!', 0, 8>,
|
pub p: Stat<'.', '!', 0, 8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Genetic for Color {
|
impl Genetic for Color {
|
||||||
@@ -40,21 +40,25 @@ impl Genetic for Color {
|
|||||||
self.r.transcribe(t.nest("r"));
|
self.r.transcribe(t.nest("r"));
|
||||||
self.g.transcribe(t.nest("g"));
|
self.g.transcribe(t.nest("g"));
|
||||||
self.b.transcribe(t.nest("b"));
|
self.b.transcribe(t.nest("b"));
|
||||||
self.pallor.transcribe(t.nest("pallor"));
|
self.p.transcribe(t.nest("p"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
fn to_name(&self) -> String {
|
pub fn to_rgb(&self) -> (u8, u8, u8) {
|
||||||
let mut r = self.r.value() * 255 / 8;
|
let mut r = self.r.value() * 255 / 8;
|
||||||
let mut g = self.g.value() * 255 / 8;
|
let mut g = self.g.value() * 255 / 8;
|
||||||
let mut b = self.b.value() * 255 / 8;
|
let mut b = self.b.value() * 255 / 8;
|
||||||
let pallor_amt = self.pallor.value() * 255 / 8;
|
let p = self.p.value() * 255 / 8;
|
||||||
r = (r * (255 - pallor_amt) + 255 * pallor_amt) / 255;
|
|
||||||
g = (g * (255 - pallor_amt) + 255 * pallor_amt) / 255;
|
r = (r * (255 - p) + 0xd0 * p) / 255;
|
||||||
b = (b * (255 - pallor_amt) + 255 * pallor_amt) / 255;
|
g = (g * (255 - p) + 0xd0 * p) / 255;
|
||||||
// let colornamer = ColorNamer::new(Colors::NTC);
|
b = (b * (255 - p) + 0xd8 * p) / 255;
|
||||||
let colornamer = ColorNamer::new(Colors::X11);
|
return (r as u8, g as u8, b as u8);
|
||||||
|
}
|
||||||
|
pub fn to_name(&self) -> String {
|
||||||
|
let colornamer = ColorNamer::new(Colors::NTC);
|
||||||
|
let (r, g, b) = self.to_rgb();
|
||||||
let hex_color = format!("#{:02x}{:02x}{:02x}", r, g, b);
|
let hex_color = format!("#{:02x}{:02x}{:02x}", r, g, b);
|
||||||
return format!(
|
return format!(
|
||||||
"{} ({})",
|
"{} ({})",
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
use crate::genetics::{Genetic, Transcriber};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub enum Gender {
|
||||||
|
Male,
|
||||||
|
Female,
|
||||||
|
#[default]
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Genetic for Gender {
|
||||||
|
fn transcribe(&mut self, mut t: Transcriber) {
|
||||||
|
t.express(
|
||||||
|
self,
|
||||||
|
&[
|
||||||
|
('m', Gender::Male),
|
||||||
|
('f', Gender::Female),
|
||||||
|
('O', Gender::Other),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gender {
|
||||||
|
pub fn profile(&self) -> String {
|
||||||
|
format!("Gender: {:?}\n", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
-47
@@ -1,62 +1,47 @@
|
|||||||
mod coloration;
|
mod coloration;
|
||||||
|
mod gender;
|
||||||
|
mod phenotype;
|
||||||
mod species;
|
mod species;
|
||||||
mod stats;
|
mod stats;
|
||||||
|
|
||||||
use coloration::Coloration;
|
use phenotype::Phenotype;
|
||||||
use species::Parts;
|
|
||||||
use stats::Stats;
|
|
||||||
|
|
||||||
use crate::genetics::{Genetic, Genotype, Transcriber};
|
use crate::{choice_function::ChoiceFunction, genetics::Genotype};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct Creature {
|
pub struct Creature {
|
||||||
// pub name: String,
|
genotype: Genotype,
|
||||||
pub genotype: Genotype,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Creature {
|
impl Creature {
|
||||||
pub fn profile(&self) -> String {
|
pub fn generate(choice_function: ChoiceFunction) -> Self {
|
||||||
let phenotype: Phenotype = self.genotype.load();
|
Creature {
|
||||||
|
genotype: Genotype::generate::<Phenotype>(choice_function),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut profile = phenotype.profile(); // format!("Name: {}\n{}", self.name, phenotype.profile());
|
pub fn breed(&self, choice_function: ChoiceFunction, other: &Creature) -> Creature {
|
||||||
profile.push_str("\nGenome:\n");
|
return Creature {
|
||||||
for (chromosome, (lhs, rhs)) in self.genotype.chromosomes.iter() {
|
genotype: self.genotype.breed(choice_function, &other.genotype),
|
||||||
profile.push_str(&format!(" {}[l]: {}\n", chromosome, lhs));
|
};
|
||||||
profile.push_str(&format!(" {}[r]: {}\n", chromosome, rhs));
|
}
|
||||||
|
|
||||||
|
pub fn phenotype(&self) -> Phenotype {
|
||||||
|
let phenotype: Phenotype = self.genotype.load();
|
||||||
|
return phenotype;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn profile(&self) -> String {
|
||||||
|
let phenotype: Phenotype = self.phenotype();
|
||||||
|
let mut profile = phenotype.profile();
|
||||||
|
if true {
|
||||||
|
profile.push_str("\nGenome:\n");
|
||||||
|
|
||||||
|
for (chromosome, (lhs, rhs)) in self.genotype.chromosomes.iter() {
|
||||||
|
profile.push_str(&format!(" {}[l]: {}\n", chromosome, lhs));
|
||||||
|
profile.push_str(&format!(" {}[r]: {}\n", chromosome, rhs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn breed(&self, other: &Creature) -> Creature {
|
|
||||||
return Creature {
|
|
||||||
// name: String::from("Pyrex"),
|
|
||||||
genotype: self.genotype.breed(&other.genotype),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Phenotype {
|
|
||||||
pub stats: Stats,
|
|
||||||
pub coloration: Coloration,
|
|
||||||
pub parts: Parts,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Phenotype {
|
|
||||||
pub fn profile(&self) -> String {
|
|
||||||
format!(
|
|
||||||
"{}{}{}",
|
|
||||||
self.stats.profile(),
|
|
||||||
self.coloration.profile(),
|
|
||||||
self.parts.profile()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Genetic for Phenotype {
|
|
||||||
fn transcribe(&mut self, t: Transcriber) {
|
|
||||||
self.stats.transcribe(t.nest("stats"));
|
|
||||||
self.coloration.transcribe(t.nest("coloration"));
|
|
||||||
self.parts.transcribe(t.nest("parts"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
use crate::genetics::{Genetic, Transcriber};
|
||||||
|
|
||||||
|
use super::{coloration::Coloration, gender::Gender, species::Parts, stats::Stats};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Phenotype {
|
||||||
|
pub gender: Gender,
|
||||||
|
pub parts: Parts,
|
||||||
|
pub stats: Stats,
|
||||||
|
pub coloration: Coloration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Phenotype {
|
||||||
|
pub fn profile(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"{}{}{}{}",
|
||||||
|
self.gender.profile(),
|
||||||
|
self.parts.profile(),
|
||||||
|
self.stats.profile(),
|
||||||
|
self.coloration.profile()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Genetic for Phenotype {
|
||||||
|
fn transcribe(&mut self, t: Transcriber) {
|
||||||
|
self.gender.transcribe(t.nest("gender"));
|
||||||
|
self.parts.transcribe(t.nest("parts"));
|
||||||
|
self.stats.transcribe(t.nest("stats"));
|
||||||
|
self.coloration.transcribe(t.nest("coloration"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,14 +43,6 @@ impl Parts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Genetic for Parts {
|
|
||||||
fn transcribe(&mut self, t: Transcriber) {
|
|
||||||
self.stare.transcribe(t.nest("stare"));
|
|
||||||
self.fangs.transcribe(t.nest("fangs"));
|
|
||||||
self.wings.transcribe(t.nest("wings"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum Species {
|
pub enum Species {
|
||||||
Bunny,
|
Bunny,
|
||||||
@@ -62,3 +54,11 @@ pub enum Species {
|
|||||||
Snake,
|
Snake,
|
||||||
Bat,
|
Bat,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Genetic for Parts {
|
||||||
|
fn transcribe(&mut self, t: Transcriber) {
|
||||||
|
self.stare.transcribe(t.nest("stare"));
|
||||||
|
self.fangs.transcribe(t.nest("fangs"));
|
||||||
|
self.wings.transcribe(t.nest("wings"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ impl<const OFF: char, const ON: char, const MIN: usize, const RANGE: usize> Gene
|
|||||||
{
|
{
|
||||||
fn transcribe(&mut self, mut t: Transcriber) {
|
fn transcribe(&mut self, mut t: Transcriber) {
|
||||||
for v in self.values.iter_mut() {
|
for v in self.values.iter_mut() {
|
||||||
t.express(v, &[(OFF, false), (ON, true)]);
|
t.express(v, &[(OFF, false), (ON, true)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
mod transcriber;
|
||||||
|
|
||||||
|
use std::collections::{BTreeMap, HashSet};
|
||||||
|
|
||||||
|
use itertools::{EitherOrBoth, Itertools};
|
||||||
|
pub use transcriber::Transcriber;
|
||||||
|
|
||||||
|
use crate::choice_function::{self, ChoiceFunction};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Genotype {
|
||||||
|
pub chromosomes: BTreeMap<String, Chromosomes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Chromosomes = (String, String);
|
||||||
|
|
||||||
|
pub trait Genetic: Default {
|
||||||
|
fn transcribe(&mut self, t: Transcriber);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge(choice_function: ChoiceFunction, one: &str, two: &str) -> String {
|
||||||
|
let mut results = String::new();
|
||||||
|
for pair in one.chars().zip_longest(two.chars()) {
|
||||||
|
results.push(match pair {
|
||||||
|
EitherOrBoth::Both(l, r) => *choice_function.choose(&[l, r]),
|
||||||
|
EitherOrBoth::Left(l) => l,
|
||||||
|
EitherOrBoth::Right(r) => r,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Genotype {
|
||||||
|
pub fn breed(&self, choice_function: ChoiceFunction, other: &Genotype) -> Genotype {
|
||||||
|
let mut chromosomes: HashSet<String> = HashSet::new();
|
||||||
|
chromosomes.extend(self.chromosomes.keys().cloned());
|
||||||
|
chromosomes.extend(other.chromosomes.keys().cloned());
|
||||||
|
|
||||||
|
let mut result: BTreeMap<String, Chromosomes> = BTreeMap::new();
|
||||||
|
let placeholder = (String::new(), String::new());
|
||||||
|
|
||||||
|
for k in chromosomes {
|
||||||
|
let mine = self.chromosomes.get(&k).unwrap_or(&placeholder);
|
||||||
|
let theirs = self.chromosomes.get(&k).unwrap_or(&placeholder);
|
||||||
|
|
||||||
|
/*
|
||||||
|
let mine_merged = merge(choice_function, &mine.0, &mine.1);
|
||||||
|
let theirs_merged = merge(choice_function, &theirs.0, &theirs.1);
|
||||||
|
result.insert(k, (mine_merged, theirs_merged));
|
||||||
|
*/
|
||||||
|
let my_choice = (*choice_function.choose(&[&mine.0, &mine.1])).clone();
|
||||||
|
let their_choice = (*choice_function.choose(&[&theirs.0, &theirs.1])).clone();
|
||||||
|
result.insert(k, (my_choice, their_choice));
|
||||||
|
}
|
||||||
|
return Genotype {
|
||||||
|
chromosomes: result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,74 +1,29 @@
|
|||||||
use std::{
|
use std::{cell::RefCell, collections::BTreeMap};
|
||||||
cell::RefCell,
|
|
||||||
collections::{BTreeMap, HashSet},
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use itertools::{EitherOrBoth, Itertools};
|
|
||||||
use rand::{seq::IndexedRandom, RngCore};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::choice_function::ChoiceFunction;
|
use crate::choice_function::ChoiceFunction;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize, Debug)]
|
use super::{Chromosomes, Genetic, Genotype};
|
||||||
pub struct Genotype {
|
|
||||||
pub chromosomes: BTreeMap<String, Chromosomes>,
|
|
||||||
}
|
|
||||||
type Chromosomes = (String, String);
|
|
||||||
|
|
||||||
fn merge(rng: &mut impl RngCore, one: &str, two: &str) -> String {
|
|
||||||
let mut results = String::new();
|
|
||||||
for pair in one.chars().zip_longest(two.chars()) {
|
|
||||||
results.push(match pair {
|
|
||||||
EitherOrBoth::Both(l, r) => *[l, r].choose(rng).unwrap(),
|
|
||||||
EitherOrBoth::Left(l) => l,
|
|
||||||
EitherOrBoth::Right(r) => r,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Genotype {
|
impl Genotype {
|
||||||
pub fn breed(&self, other: &Genotype) -> Genotype {
|
|
||||||
let mut rng = rand::rng();
|
|
||||||
let mut chromosomes: HashSet<String> = HashSet::new();
|
|
||||||
chromosomes.extend(self.chromosomes.keys().cloned());
|
|
||||||
chromosomes.extend(other.chromosomes.keys().cloned());
|
|
||||||
|
|
||||||
let mut result: BTreeMap<String, Chromosomes> = BTreeMap::new();
|
|
||||||
let placeholder = (String::new(), String::new());
|
|
||||||
for k in chromosomes {
|
|
||||||
let mine = self.chromosomes.get(&k).unwrap_or(&placeholder);
|
|
||||||
let theirs = self.chromosomes.get(&k).unwrap_or(&placeholder);
|
|
||||||
|
|
||||||
let mine_merged = merge(&mut rng, &mine.0, &mine.1);
|
|
||||||
let theirs_merged = merge(&mut rng, &theirs.0, &theirs.1);
|
|
||||||
result.insert(k, (mine_merged, theirs_merged));
|
|
||||||
}
|
|
||||||
return Genotype {
|
|
||||||
chromosomes: result,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate<T: Genetic>(choice_function: ChoiceFunction) -> Self {
|
pub fn generate<T: Genetic>(choice_function: ChoiceFunction) -> Self {
|
||||||
let root = RootTranscriber::Generator(Generator {
|
let root = RootTranscriber::Generator(Generator {
|
||||||
choice_function,
|
choice_function,
|
||||||
progress: BTreeMap::new(),
|
progress: BTreeMap::new(),
|
||||||
});
|
});
|
||||||
let root_cell = Rc::new(RefCell::new(root));
|
let root_cell = RefCell::new(root);
|
||||||
let transcriber = Transcriber {
|
let transcriber = Transcriber {
|
||||||
root: root_cell.clone(),
|
root: &root_cell,
|
||||||
chromosome: String::from("base"),
|
chromosome: String::from("base"),
|
||||||
};
|
};
|
||||||
let mut base = T::default();
|
let mut base = T::default();
|
||||||
base.transcribe(transcriber);
|
base.transcribe(transcriber);
|
||||||
match &*root_cell.borrow() {
|
match root_cell.into_inner() {
|
||||||
RootTranscriber::Generator(generator) => {
|
RootTranscriber::Generator(generator) => {
|
||||||
let chromosomes = generator.progress.clone();
|
let chromosomes = generator.progress;
|
||||||
return Genotype { chromosomes };
|
return Genotype { chromosomes };
|
||||||
}
|
}
|
||||||
_ => panic!("a generator should not able to turn into a loader"),
|
_ => panic!("a generator should not be able to turn into anything else"),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load<T: Genetic>(&self) -> T {
|
pub fn load<T: Genetic>(&self) -> T {
|
||||||
@@ -76,13 +31,14 @@ impl Genotype {
|
|||||||
for (key, (lhs, rhs)) in self.chromosomes.iter() {
|
for (key, (lhs, rhs)) in self.chromosomes.iter() {
|
||||||
progress.insert(
|
progress.insert(
|
||||||
key.clone(),
|
key.clone(),
|
||||||
|
// as a note: we could just store the character iterator!
|
||||||
(0, Vec::from_iter(lhs.chars()), Vec::from_iter(rhs.chars())),
|
(0, Vec::from_iter(lhs.chars()), Vec::from_iter(rhs.chars())),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let root = RootTranscriber::Loader(Loader { progress });
|
let root = RootTranscriber::Loader(Loader { progress });
|
||||||
let root_cell = Rc::new(RefCell::new(root));
|
let root_cell = RefCell::new(root);
|
||||||
let transcriber = Transcriber {
|
let transcriber = Transcriber {
|
||||||
root: root_cell.clone(),
|
root: &root_cell,
|
||||||
chromosome: String::from("base"),
|
chromosome: String::from("base"),
|
||||||
};
|
};
|
||||||
let mut base = T::default();
|
let mut base = T::default();
|
||||||
@@ -104,21 +60,20 @@ impl RootTranscriber {
|
|||||||
possibilities: &[(char, T)],
|
possibilities: &[(char, T)],
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
RootTranscriber::Generator(generator) => {
|
RootTranscriber::Generator(generator) => generator.express(chromosome, possibilities),
|
||||||
generator.express(chromosome, field, possibilities)
|
RootTranscriber::Loader(loader) => {
|
||||||
|
loader.express(chromosome, field, possibilities);
|
||||||
}
|
}
|
||||||
RootTranscriber::Loader(loader) => loader.express(chromosome, field, possibilities),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub struct Transcriber<'r> {
|
||||||
pub struct Transcriber {
|
root: &'r RefCell<RootTranscriber>,
|
||||||
root: Rc<RefCell<RootTranscriber>>,
|
|
||||||
chromosome: String,
|
chromosome: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transcriber {
|
impl Transcriber<'_> {
|
||||||
pub fn express<T: Clone>(&mut self, field: &mut T, possibilities: &[(char, T)]) {
|
pub fn express<T: Clone>(&mut self, field: &mut T, possibilities: &[(char, T)]) {
|
||||||
self.root
|
self.root
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
@@ -127,33 +82,28 @@ impl Transcriber {
|
|||||||
|
|
||||||
pub fn nest(&self, suffix: &str) -> Transcriber {
|
pub fn nest(&self, suffix: &str) -> Transcriber {
|
||||||
return Transcriber {
|
return Transcriber {
|
||||||
root: self.root.clone(),
|
root: self.root,
|
||||||
chromosome: format!("{}.{}", self.chromosome, suffix),
|
chromosome: format!("{}.{}", self.chromosome, suffix),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Genetic: Default {
|
|
||||||
fn transcribe(&mut self, t: Transcriber);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Generator {
|
struct Generator {
|
||||||
choice_function: ChoiceFunction,
|
choice_function: ChoiceFunction,
|
||||||
progress: BTreeMap<String, Chromosomes>,
|
progress: BTreeMap<String, Chromosomes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Generator {
|
impl Generator {
|
||||||
pub fn express<T>(&mut self, chromosome: &str, _field: &mut T, possibilities: &[(char, T)]) {
|
pub fn express<T>(&mut self, chromosome: &str, possibilities: &[(char, T)]) {
|
||||||
let lhs = self.choice_function.choose(possibilities).0;
|
let lhs = self.choice_function.choose(possibilities);
|
||||||
let rhs = self.choice_function.choose(possibilities).0;
|
let rhs = self.choice_function.choose(possibilities);
|
||||||
|
|
||||||
let progress = self
|
let progress = self
|
||||||
.progress
|
.progress
|
||||||
.entry(chromosome.to_string())
|
.entry(chromosome.to_string()) // SLOW!
|
||||||
.or_insert((String::new(), String::new()));
|
.or_insert((String::new(), String::new()));
|
||||||
|
|
||||||
progress.0.push(lhs);
|
progress.0.push(lhs.0);
|
||||||
progress.1.push(rhs);
|
progress.1.push(rhs.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +125,7 @@ impl Loader {
|
|||||||
*ix += 1;
|
*ix += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut expressed = lhs; // lhs wins if not dominated
|
let mut expressed = lhs;
|
||||||
if dominance(rhs) > dominance(lhs) {
|
if dominance(rhs) > dominance(lhs) {
|
||||||
expressed = rhs;
|
expressed = rhs;
|
||||||
}
|
}
|
||||||
+15
-23
@@ -1,53 +1,48 @@
|
|||||||
use choice_function::ChoiceFunction;
|
use choice_function::ChoiceFunction;
|
||||||
use creature::{Creature, Phenotype};
|
use creature::Creature;
|
||||||
use genetics::Genotype;
|
|
||||||
use rand::{rng, seq::SliceRandom};
|
use rand::{rng, seq::SliceRandom};
|
||||||
|
|
||||||
mod choice_function;
|
mod choice_function;
|
||||||
mod creature;
|
mod creature;
|
||||||
mod genetics;
|
mod genetics;
|
||||||
|
|
||||||
fn generate_creature() -> Creature {
|
|
||||||
let genotype: Genotype = Genotype::generate::<Phenotype>(ChoiceFunction::Random);
|
|
||||||
let creature = Creature {
|
|
||||||
// name: String::from("Pyrex"),
|
|
||||||
genotype,
|
|
||||||
};
|
|
||||||
return creature;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn evolve() {
|
fn evolve() {
|
||||||
|
let cf = ChoiceFunction::Random;
|
||||||
const N_ITERATIONS: usize = 200;
|
const N_ITERATIONS: usize = 200;
|
||||||
const N_CREATURES: usize = 100;
|
const N_CREATURES: usize = 100;
|
||||||
const N_SURVIVORS: usize = 90;
|
const N_RANDOMS: usize = 50;
|
||||||
|
const N_SURVIVORS: usize = 40;
|
||||||
|
|
||||||
let mut pool = vec![];
|
let mut pool = vec![];
|
||||||
for _ in 0..N_CREATURES {
|
for _ in 0..N_CREATURES {
|
||||||
pool.push(generate_creature());
|
pool.push(Creature::generate(cf));
|
||||||
}
|
}
|
||||||
|
|
||||||
for iteration in 0..N_ITERATIONS {
|
for iteration in 0..N_ITERATIONS {
|
||||||
report(iteration, &pool);
|
report(iteration, &pool);
|
||||||
|
|
||||||
// kill N creatures
|
let mut survivors = pool;
|
||||||
let mut survivors = pool.clone();
|
|
||||||
survivors.sort_by(|x, y| fitness(x).partial_cmp(&fitness(y)).unwrap());
|
survivors.sort_by(|x, y| fitness(x).partial_cmp(&fitness(y)).unwrap());
|
||||||
survivors.reverse();
|
survivors.reverse();
|
||||||
survivors.drain(N_SURVIVORS..N_CREATURES);
|
survivors.drain(N_SURVIVORS..N_CREATURES);
|
||||||
|
|
||||||
let mut pool2 = vec![];
|
for _ in 0..N_RANDOMS {
|
||||||
|
survivors.push(Creature::generate(cf));
|
||||||
|
}
|
||||||
|
|
||||||
let mut survivors_queue = vec![];
|
let mut survivors_queue = vec![];
|
||||||
while survivors_queue.len() < N_CREATURES * 2 {
|
while survivors_queue.len() < N_CREATURES * 2 {
|
||||||
survivors_queue.extend(survivors.clone());
|
survivors_queue.extend(survivors.clone());
|
||||||
}
|
}
|
||||||
survivors_queue.shuffle(&mut rng());
|
survivors_queue.shuffle(&mut rng());
|
||||||
|
|
||||||
|
let mut offspring = vec![];
|
||||||
for _ in 0..N_CREATURES {
|
for _ in 0..N_CREATURES {
|
||||||
let lhs = survivors_queue.pop().unwrap();
|
let lhs = survivors_queue.pop().unwrap();
|
||||||
let rhs = survivors_queue.pop().unwrap();
|
let rhs = survivors_queue.pop().unwrap();
|
||||||
pool2.push(lhs.breed(&rhs));
|
offspring.push(lhs.breed(cf, &rhs));
|
||||||
}
|
}
|
||||||
pool = pool2;
|
pool = offspring;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,13 +53,10 @@ fn report(iteration: usize, pool: &[Creature]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fitness(creature: &Creature) -> f64 {
|
fn fitness(creature: &Creature) -> f64 {
|
||||||
let phenotype: Phenotype = creature.genotype.load();
|
let phenotype = creature.phenotype();
|
||||||
let mut value = 0.0;
|
let mut value = 0.0;
|
||||||
if phenotype.parts.has_wings() {
|
|
||||||
value += 0.5;
|
|
||||||
}
|
|
||||||
value -= phenotype.coloration.body.r.value() as f64 / 4.0;
|
|
||||||
value += (phenotype.stats.iq.value() as f64) / 10.0;
|
value += (phenotype.stats.iq.value() as f64) / 10.0;
|
||||||
|
value += (phenotype.stats.eq.value() as f64) / 10.0;
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 280 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 238 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 425 KiB |
Binary file not shown.
Reference in New Issue
Block a user