--- /dev/null
+<?php
+
+namespace App\Models;
+
+class ChatLib {
+
+ public function addMessage($msg) {
+ $tokens = array_values(array_filter(preg_split('/\b/', $msg->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 = [];
+
+}