304 lines
5.4 KiB
PHP
304 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace alveolata\random;
|
|
|
|
|
|
/**
|
|
* @return float in interval [0,1[
|
|
*/
|
|
function generate_unit(
|
|
) : float
|
|
{
|
|
$max = \getrandmax();
|
|
return (rand(0, $max) / $max);
|
|
}
|
|
|
|
|
|
/**
|
|
* generate an integer value
|
|
*
|
|
* @param float $probability the probability with which the result is "true"
|
|
* @return bool
|
|
*/
|
|
function generate_boolean(
|
|
$probability = 0.5
|
|
) : bool
|
|
{
|
|
return (generate_unit() < $probability);
|
|
}
|
|
|
|
|
|
/**
|
|
* generate an integer value
|
|
*
|
|
* @param int $min the lowest possible generated value
|
|
* @param int $max the highest possible generated value
|
|
* @return int
|
|
*/
|
|
function generate_integer(
|
|
int $min,
|
|
int $max
|
|
) : int
|
|
{
|
|
$t = generate_unit();
|
|
return \intval(\floor($min + ($t * ($max - $min + 1))));
|
|
}
|
|
|
|
|
|
/**
|
|
* generate a string value
|
|
*
|
|
* @return string
|
|
*/
|
|
function generate_string(
|
|
int $length = 16
|
|
) : string
|
|
{
|
|
$string = '';
|
|
for ($index = 0; $index < $length; $index += 1) {
|
|
$string .= sprintf("%X", generate_integer(0, 15));
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
|
|
/**
|
|
* choose an element from a list with equal probabilities for all elements
|
|
*
|
|
* @template type_element
|
|
* @param array $list {list<§type_element>}
|
|
* @return type_element
|
|
*/
|
|
function choose_uniformly(
|
|
array $list
|
|
)
|
|
{
|
|
$index = generate_integer(0, count($list)-1);
|
|
return $list[$index];
|
|
}
|
|
|
|
|
|
/**
|
|
* chooses a value randomly from a list of values with weights (a higher weight means a higher probability to be chosen)
|
|
*
|
|
* @template type_element
|
|
* @param array $list {list<record<element:§type_element,weight:float>>}
|
|
* @return type_element
|
|
*/
|
|
function choose_weighted(
|
|
array $sets
|
|
)
|
|
{
|
|
$sum = array_reduce(
|
|
$sets,
|
|
function (float $sum, array $entry) : float {return ($sum + $entry['weight']);},
|
|
0
|
|
);
|
|
if ($sum === 0) {
|
|
throw (new \Exception('weights sum up to zero; are all zero or are negative weights included?'));
|
|
}
|
|
else {
|
|
$position = generate_unit();
|
|
return array_reduce(
|
|
$sets,
|
|
function ($current, $set) use ($sum, $position) {
|
|
$next = ['index' => null, 'value' => null];
|
|
$next['index'] = ($current['index'] + ($set['weight'] / $sum));
|
|
$next['value'] = (
|
|
(($current['index'] <= $position) && ($position < $next['index']))
|
|
? $set['value']
|
|
: $current['value']
|
|
);
|
|
return $next;
|
|
},
|
|
['index' => 0, 'value' => null]
|
|
)['value'];
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_vowel(
|
|
) : string
|
|
{
|
|
return choose_weighted([
|
|
['value' => 'i', 'weight' => 1],
|
|
['value' => 'e', 'weight' => 2],
|
|
['value' => 'a', 'weight' => 3],
|
|
['value' => 'o', 'weight' => 2],
|
|
['value' => 'u', 'weight' => 1],
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_semivowel(
|
|
) : string
|
|
{
|
|
return choose_weighted([
|
|
['value' => 'y', 'weight' => 2],
|
|
['value' => 'w', 'weight' => 1],
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_lateral_approximant(
|
|
) : string
|
|
{
|
|
return choose_weighted([
|
|
['value' => 'l', 'weight' => 1],
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_nasal(
|
|
) : string
|
|
{
|
|
return choose_weighted([
|
|
['value' => 'n', 'weight' => 4],
|
|
['value' => 'm', 'weight' => 2],
|
|
['value' => 'q', 'weight' => 1],
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_plosive(
|
|
) : string
|
|
{
|
|
return choose_weighted([
|
|
['value' => 'b', 'weight' => 1],
|
|
['value' => 'p', 'weight' => 2],
|
|
['value' => 'd', 'weight' => 1],
|
|
['value' => 't', 'weight' => 2],
|
|
['value' => 'g', 'weight' => 1],
|
|
['value' => 'k', 'weight' => 2],
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_fricative(
|
|
) : string
|
|
{
|
|
return choose_weighted([
|
|
['value' => 'r', 'weight' => 2],
|
|
['value' => 'h', 'weight' => 1],
|
|
['value' => 'x', 'weight' => 1],
|
|
['value' => 'j', 'weight' => 1],
|
|
['value' => 'c', 'weight' => 1],
|
|
['value' => 'v', 'weight' => 2],
|
|
['value' => 'f', 'weight' => 2],
|
|
['value' => 's', 'weight' => 2],
|
|
['value' => 'z', 'weight' => 2],
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_consonant(
|
|
) : string
|
|
{
|
|
return choose_weighted([
|
|
['value' => generate_lateral_approximant(), 'weight' => 1],
|
|
['value' => generate_nasal(), 'weight' => 1],
|
|
['value' => generate_plosive(), 'weight' => 1],
|
|
['value' => generate_fricative(), 'weight' => 1],
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_syllable(
|
|
) : string
|
|
{
|
|
/*
|
|
+---+---+---+---+---+---+---+
|
|
| | L | N | P | F | S | V |
|
|
+---+---+---+---+---+---+---+
|
|
| L | | o | x | x | o | x |
|
|
+---+---+---+---+---+---+---+
|
|
| N | | | o | x | | x |
|
|
+---+---+---+---+---+---+---+
|
|
| P | x | o | o | x | x | x |
|
|
+---+---+---+---+---+---+---+
|
|
| F | x | o | | o | x | x |
|
|
+---+---+---+---+---+---+---+
|
|
| S | x | x | x | x | | x |
|
|
+---+---+---+---+---+---+---+
|
|
| V | x | x | x | x | x | o |
|
|
+---+---+---+---+---+---+---+
|
|
|
|
{L,N,P,F}
|
|
{LP,LF,NF,NP,PL,PF,FL}
|
|
{LPF,NPL,NPF,PFL}
|
|
|
|
pflantze
|
|
glas
|
|
crayb-tic
|
|
|
|
|
|
*/
|
|
$length1 = choose_weighted([
|
|
['value' => 1, 'weight' => 3],
|
|
['value' => 2, 'weight' => 4],
|
|
['value' => 3, 'weight' => 1],
|
|
]);
|
|
|
|
return sprintf(
|
|
'%s%s%s',
|
|
generate_consonant(),
|
|
generate_vowel(),
|
|
(generate_boolean(0.125) ? generate_semivowel() : '')
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_word(
|
|
) : string
|
|
{
|
|
$length = generate_integer(1, 4);
|
|
$syllables = [];
|
|
for ($index = 0; $index < $length; $index += 1) {
|
|
$syllables[] = generate_syllable();
|
|
}
|
|
return implode('', $syllables);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
function generate_text(
|
|
) : string
|
|
{
|
|
$length = generate_integer(8, 32);
|
|
$words = [];
|
|
for ($index = 0; $index < $length; $index += 1) {
|
|
$words[] = generate_word();
|
|
}
|
|
return implode(' ', $words);
|
|
}
|
|
|
|
?>
|