7 public function addMessage($msg) {
8 $tokens = array_values(array_filter(preg_split('/\s+/u', $msg->text_content)));
9 if (empty($tokens)) return;
11 foreach ($tokens as $num => $token) {
13 $this->addStart($token);
16 $this->addOne($tokens[$num - 1], $token);
19 $this->addTwo($tokens[$num - 2], $tokens[$num - 1], $token);
22 $this->addThree($tokens[$num - 3], $tokens[$num - 2], $tokens[$num - 1], $token);
25 $this->addFour($tokens[$num - 4], $tokens[$num - 3], $tokens[$num - 2], $tokens[$num - 1], $token);
28 $this->addFive($tokens[$num - 5], $tokens[$num - 4], $tokens[$num - 3], $tokens[$num - 2], $tokens[$num - 1], $token);
33 public function compile() {
34 $this->start = $this->index($this->start);
35 foreach ($this->one as $key => $value) {
36 $this->one[$key] = $this->index($this->one[$key]);
37 if (empty($this->one[$key])) {
38 unset($this->one[$key]);
41 foreach ($this->two as $key => $value) {
42 $this->two[$key] = $this->index($this->two[$key]);
43 if (empty($this->two[$key])) {
44 unset($this->two[$key]);
47 foreach ($this->three as $key => $value) {
48 $this->three[$key] = $this->index($this->three[$key]);
49 if (empty($this->three[$key])) {
50 unset($this->three[$key]);
53 foreach ($this->four as $key => $value) {
54 $this->four[$key] = $this->index($this->four[$key]);
55 if (empty($this->four[$key])) {
56 unset($this->four[$key]);
59 foreach ($this->five as $key => $value) {
60 $this->five[$key] = $this->index($this->five[$key]);
61 if (empty($this->five[$key])) {
62 unset($this->five[$key]);
67 public function generate($limit = 75) {
69 $start = $this->randomStart();
72 while (strlen($generated) < $limit) {
73 $next = $this->randomNext($tokens);
74 if (empty($next)) break;
76 $generated .= ' '.$next;
81 private function index($arr) {
84 foreach ($arr as $key => $entry) {
85 $weight = $entry['count'];
86 if ($weight == 1) continue;
88 $sum += intval(pow($weight, 1.4));
90 if (is_array(end($entry['examples']))) {
92 $examples = $entry['examples'];
95 foreach ($entry['examples'] as $example => $subweight) {
97 $subsum += $subweight * $subweight;
98 $examples[] = [$example, $sublower, $subsum];
101 $result[] = [$key, $lower, $sum, $examples];
106 private function randomStart() {
107 $pick = $this->pick($this->start);
108 if (is_null($pick)) return '';
109 return $this->exampleOf($pick);
112 private function randomNext($tokens) {
113 $cnt = count($tokens);
116 $cmb = $this->generalize(array_slice($tokens, $cnt - 5, 5));
117 if (isset($this->five[$cmb])) {
118 $pick = $this->pick($this->five[$cmb]);
119 if (!is_null($pick)) {
122 'examples' => $pick[3],
128 $cmb = $this->generalize(array_slice($tokens, $cnt - 4, 4));
129 if (isset($this->four[$cmb])) {
130 $pick = $this->pick($this->four[$cmb]);
131 if (!is_null($pick)) {
134 'examples' => $pick[3],
140 $cmb = $this->generalize(array_slice($tokens, $cnt - 3, 3));
141 if (isset($this->three[$cmb])) {
142 $pick = $this->pick($this->three[$cmb]);
143 if (!is_null($pick)) {
146 'examples' => $pick[3],
152 $cmb = $this->generalize(array_slice($tokens, $cnt - 2, 2));
153 if (isset($this->two[$cmb])) {
154 $pick = $this->pick($this->two[$cmb]);
155 if (!is_null($pick)) {
158 'examples' => $pick[3],
164 $cmb = $this->generalize(array_slice($tokens, $cnt - 1, 1));
165 if (isset($this->one[$cmb])) {
166 $pick = $this->pick($this->one[$cmb]);
167 if (!is_null($pick)) {
170 'examples' => $pick[3],
175 if (empty($picks)) return '';
176 $picks = $this->index($picks);
177 $pick = $this->pick($picks);
178 return $this->exampleOf($pick);
181 private function pick($options) {
182 if (empty($options)) return null;
183 $max = end($options)[2];
184 $num = random_int(0, $max);
186 $max_index = count($options) - 1;
187 while ($min_index < $max_index) {
188 $cur_index = intval(($min_index + $max_index) / 2);
189 $cur_low = $options[$cur_index][1];
190 $cur_high = $options[$cur_index][2];
191 if ($cur_low > $num) {
192 $max_index = $cur_index;
193 } else if ($cur_high < $num) {
194 $min_index = $cur_index + 1;
196 $min_index = $cur_index;
200 return $options[$min_index];
203 private function addStart($token) {
204 if (empty($token)) return;
205 $this->increment($this->start, $token);
208 private function addOne($one, $token) {
209 $cmb = $this->generalize([$one]);
210 if (!isset($this->one[$cmb])) {
211 $this->one[$cmb] = [];
213 $this->increment($this->one[$cmb], $token);
216 private function addTwo($one, $two, $token) {
217 $cmb = $this->generalize([$one, $two]);
218 if (!isset($this->two[$cmb])) {
219 $this->two[$cmb] = [];
221 $this->increment($this->two[$cmb], $token);
224 private function addThree($one, $two, $three, $token) {
225 $cmb = $this->generalize([$one, $two, $three]);
226 if (!isset($this->three[$cmb])) {
227 $this->three[$cmb] = [];
229 $this->increment($this->three[$cmb], $token);
232 private function addFour($one, $two, $three, $four, $token) {
233 $cmb = $this->generalize([$one, $two, $three, $four]);
234 if (!isset($this->four[$cmb])) {
235 $this->four[$cmb] = [];
237 $this->increment($this->four[$cmb], $token);
240 private function addFive($one, $two, $three, $four, $five, $token) {
241 $cmb = $this->generalize([$one, $two, $three, $four, $five]);
242 if (!isset($this->five[$cmb])) {
243 $this->five[$cmb] = [];
245 $this->increment($this->five[$cmb], $token);
248 private function increment(&$which, $token) {
249 $generalized = $this->generalize([$token]);
250 if (!isset($which[$generalized])) {
251 $which[$generalized] = [
255 $which[$generalized]['examples'][$token] = 1;
257 ++$which[$generalized]['count'];
258 if (!isset($which[$generalized]['examples'][$token])) {
259 $which[$generalized]['examples'][$token] = 1;
261 ++$which[$generalized]['examples'][$token];
266 private function generalize($tokens) {
268 foreach ($tokens as $token) {
269 $replaced = preg_replace('/\W/u', '', $token);
270 $replaced = preg_replace('/\d+/', '0', $replaced);
271 $replaced = strtolower(trim($replaced));
272 $str .= empty($replaced) ? $token : $replaced;
277 private function exampleOf($pick) {
278 $example = $this->pick($pick[3]);