Video version
This commit is contained in:
parent
b323eef0e2
commit
4df78304d0
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -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],
|
||||||
|
@ -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!(
|
||||||
"{} ({})",
|
"{} ({})",
|
||||||
|
28
src/creature/gender.rs
Normal file
28
src/creature/gender.rs
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
32
src/creature/phenotype.rs
Normal file
32
src/creature/phenotype.rs
Normal file
@ -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)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
src/genetics/mod.rs
Normal file
59
src/genetics/mod.rs
Normal file
@ -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;
|
||||||
}
|
}
|
38
src/main.rs
38
src/main.rs
@ -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;
|
||||||
}
|
}
|
||||||
|
BIN
thumbnail.png
Normal file
BIN
thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 280 KiB |
BIN
thumbnail.xcf
Normal file
BIN
thumbnail.xcf
Normal file
Binary file not shown.
BIN
thumbnail2.png
Normal file
BIN
thumbnail2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 238 KiB |
BIN
thumbnail2.xcf
Normal file
BIN
thumbnail2.xcf
Normal file
Binary file not shown.
BIN
thumbnail3.xcf
Normal file
BIN
thumbnail3.xcf
Normal file
Binary file not shown.
BIN
thumbnail4.png
Normal file
BIN
thumbnail4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 425 KiB |
BIN
thumbnail4.xcf
Normal file
BIN
thumbnail4.xcf
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user