get something working

main
annieversary 2021-08-26 14:04:31 +02:00
commit a0666b94a0
4 changed files with 146 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
Cargo.lock
.DS_Store

15
Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "incantata"
version = "0.1.0"
edition = "2018"
[lib]
name = "incantata"
path = "src/lib.rs"
[[bin]]
name = "incantata"
path = "src/bin.rs"
[dependencies]
rand = "0.8.4"

24
src/bin.rs Normal file
View File

@ -0,0 +1,24 @@
use incantata::*;
fn main() {
let s = Structure {
onset: 1,
onset_dict: CONSONANTS.chars().collect(),
nucleus: 1,
nucleus_dict: VOCALS
.chars()
.cycle()
.take(VOCALS.len() * 5)
.chain(VOCALS_ACCENTS.chars())
.collect(),
coda: 0,
coda_dict: CONSONANTS.chars().collect(),
min_len: 4,
suggested_len: 15,
};
for _ in 0..10 {
println!("{}", incantata(&s));
}
}

104
src/lib.rs Normal file
View File

@ -0,0 +1,104 @@
use rand::{thread_rng, Rng};
pub const CONSONANTS: &'static str = "bcdfghjklmnpqrstvwxyz";
pub const VOCALS: &'static str = "aeiou";
pub const VOCALS_ACCENTS: &'static str = "aeiouàèìòùáéíóúäëïöü";
// TODO replace Vec<char> with HashMap<char, f32>, where the value is the probability
pub struct Structure {
pub onset: usize,
pub onset_dict: Vec<char>,
pub nucleus: usize,
pub nucleus_dict: Vec<char>,
pub coda: usize,
pub coda_dict: Vec<char>,
pub min_len: usize,
pub suggested_len: usize,
}
pub fn incantata(structure: &Structure) -> String {
let mut rng = thread_rng();
let len = rng.gen_range(structure.min_len..structure.suggested_len);
let mut s = String::new();
while s.len() < len {
let syl = syllable(structure);
s.push_str(&syl);
}
s
}
enum State {
Onset(usize),
Nucleus(usize),
Coda(usize),
}
fn syllable(structure: &Structure) -> String {
let mut rng = thread_rng();
let mut state = State::Onset(0);
let mut s = String::new();
'syl: loop {
match state {
State::Onset(n) => {
if n >= structure.onset || rng.gen_bool(0.3) {
state = State::Nucleus(0);
} else {
state = State::Onset(n + 1);
s.push(structure.onset_dict[rng.gen_range(0..structure.onset_dict.len())]);
}
}
State::Nucleus(n) => {
// nucleus is one or more
if n >= structure.nucleus || (n > 0 && rng.gen_bool(0.3)) {
state = State::Coda(0);
} else {
state = State::Nucleus(n + 1);
s.push(structure.nucleus_dict[rng.gen_range(0..structure.nucleus_dict.len())]);
}
}
State::Coda(n) => {
if n >= structure.coda || rng.gen_bool(0.3) {
break 'syl;
} else {
state = State::Coda(n + 1);
s.push(structure.coda_dict[rng.gen_range(0..structure.coda_dict.len())]);
}
}
}
}
s
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let s = Structure {
onset: 1,
onset_dict: CONSONANTS.chars().collect(),
nucleus: 1,
nucleus_dict: VOCALS.chars().collect(),
coda: 1,
coda_dict: CONSONANTS.chars().collect(),
min_len: 4,
suggested_len: 10,
};
for _ in 0..100 {
let r = incantata(&s);
assert!(r.len() >= 4);
}
}
}