text_content))); if (empty($tokens)) return; $tokens [] = ''; foreach ($tokens as $num => $token) { if ($num === 0) { $this->addStart($token); } else if ($num === 1) { $this->addOne($tokens[0], $token); } else if ($num === 2) { $this->addOne($tokens[1], $token); $this->addTwo($tokens[0], $tokens[1], $token); } else { $this->addOne($tokens[$num - 1], $token); $this->addTwo($tokens[$num - 2], $tokens[$num - 1], $token); $this->addThree($tokens[$num - 3], $tokens[$num - 2], $tokens[$num - 1], $token); } } } public function compile() { $this->start = $this->index($this->start); foreach ($this->one as $key => $value) { $this->one[$key] = $this->index($this->one[$key]); } foreach ($this->two as $key => $value) { $this->two[$key] = $this->index($this->two[$key]); } foreach ($this->three as $key => $value) { $this->three[$key] = $this->index($this->three[$key]); } } public function generate($limit = 50) { $tokens = []; $start = $this->randomStart(); $tokens[] = $start; $generated = $start; while (strlen($generated) < $limit) { $next = $this->randomNext($tokens); if (empty($next)) break; $tokens[] = $next; $generated .= $next; } return $generated; } private function index($arr) { $result = []; $sum = 0; asort($arr); foreach ($arr as $key => $weight) { $lower = $sum; $sum += $weight; $result[] = [$key, $lower, $sum]; } return $result; } private function randomStart() { return $this->pick($this->start); } private function randomNext($tokens) { $cnt = count($tokens); if ($cnt >= 3) { $cmb = $tokens[$cnt - 3].$tokens[$cnt - 2].$tokens[$cnt - 1]; if (isset($this->three[$cmb])) { return $this->pick($this->three[$cmb]); } } if ($cnt >= 2) { $cmb = $tokens[$cnt - 2].$tokens[$cnt - 1]; if (isset($this->two[$cmb])) { return $this->pick($this->two[$cmb]); } } if ($cnt >= 1) { $cmb = $tokens[$cnt - 1]; if (isset($this->one[$cmb])) { return $this->pick($this->one[$cmb]); } } return ''; } private function pick($options) { $max = end($options)[2]; $num = random_int(0, $max); $min_index = 0; $max_index = count($options) - 1; while ($min_index < $max_index) { $cur_index = intval(($min_index + $max_index) / 2); $cur_low = $options[$cur_index][1]; $cur_high = $options[$cur_index][2]; if ($cur_low > $num) { $max_index = $cur_index; } else if ($cur_high < $num) { $min_index = $cur_index + 1; } else { $min_index = $cur_index; break; } } return $options[$min_index][0]; } private function addStart($token) { if (empty($token)) return; if (!isset($this->start[$token])) { $this->start[$token] = 1; } else { ++$this->start[$token]; } } private function addOne($one, $token) { if (!isset($this->one[$one])) { $this->one[$one] = []; } if (!isset($this->one[$one][$token])) { $this->one[$one][$token] = 1; } else { ++$this->one[$one][$token]; } } private function addTwo($one, $two, $token) { $cmb = $one.$two; if (!isset($this->two[$cmb])) { $this->two[$cmb] = []; } if (!isset($this->two[$cmb][$token])) { $this->two[$cmb][$token] = 1; } else { ++$this->two[$cmb][$token]; } } private function addThree($one, $two, $three, $token) { $cmb = $one.$two.$three; if (!isset($this->three[$cmb])) { $this->three[$cmb] = []; } if (!isset($this->three[$cmb][$token])) { $this->three[$cmb][$token] = 1; } else { ++$this->three[$cmb][$token]; } } private $start = []; private $one = []; private $two = []; private $three = []; }