From a90aef46f27956718d352d4c4bde843241499872 Mon Sep 17 00:00:00 2001
From: bernd32 <phreolol@gmail.com>
Date: Sat, 16 Apr 2022 18:15:19 +0500
Subject: [PATCH] addition to README

---
 README.md | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 89 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index d8c97b6..ec0c894 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,10 @@
 # nickname-generator
 Данный скрипт является примером использования на практике алгоритма случайного выбора элементов массива с учётом веса. 
-Nickname-generator генерирует случайные слова (никнеймы) на основе случайных букв английского (латинского) алфавита. 
-Если мы просто будем брать случайные буквы и составлять их них слова, то они будут выглядеть неестественно и неприглядно. 
+
+В данном случае практикой будет являться генерирование случайных слов (никнеймов) на основе букв английского (латинского) алфавита. 
+
+
+Начнём для начала с самого простого подхода. Если мы просто будем брать случайные буквы и составлять их них слова, то они будут выглядеть неестественно и неприглядно. 
 Примеры: 
 
 - srjxdq
@@ -12,10 +15,10 @@ Nickname-generator генерирует случайные слова (никн
 
 и т.д. 
 
-Как видим, такой подход не позволяет нам генерировать слова, которые хотя бы отдалённо напоминали обычные - получается просто набор бысмысленных букв. 
-Чтобы придать словам натуральность и "человечность", нам нужно сделать как минимум две вещи:
+Как видим, такой подход не позволяет нам генерировать слова, которые хотя бы отдалённо напоминали обычные - получается просто набор бысмысленных букв, который больше походит на пароли. 
+Чтобы придать словам натуральность и "человечность", нам нужно сделать как минимум две вещи (на мой взгляд):
 
-1) Исключить появление более двух гласных/согласных при генерировании слова. Данная задача является тривиальной и ее не имеет смысла рассматривать. 
+1) Исключить появления более двух гласных/согласных при генерировании слова. Данная задача является тривиальной и ее не имеет смысла рассматривать. 
 2) Подбирать случайные буквы для слова с учётом их веса. Весами в данном случае будут являться частотность букв в английском языке. 
 Таким образом мы должны уменьшить/увеличить шанс того, что определенная буква попадёт в наше генерируемое слово, и таких редко используемых 
 букв, как, например, Q, Z и X будут встречаться в наших словах гораздо реже, чем E, T, A, O, I, которые по статистике являются самыми частыми в английских словах. 
@@ -37,4 +40,84 @@ Nickname-generator генерирует случайные слова (никн
 Относительно простой имплементацией подобного алгоритма является преобразование ряда рациональных чисел s1 (массива), являющимися весами для элементов, в ряд чисел s2, который
 получается посредством кумулятивного сложения чисел: 
 
-![equation](https://latex.codecogs.com/svg.image?S_{n}\Rightarrow&space;S_{cumulative}&space;=&space;\sum_{i=0}^{n}a_{i}&plus;(a_{i-1}\vee&space;0))
\ No newline at end of file
+![equation](https://latex.codecogs.com/gif.image?\dpi{110}\bg{white}S_{n}\Rightarrow&space;S_{cumulative}&space;=&space;\sum_{i=1}^{n}a_{i}&plus;(a_{i-1}\vee&space;0))
+
+где `Sn` - это массив со значениями весов, `ai` - элементы этого массива. 
+
+Разберём алгоритм по шагам в JS:
+1) Создаём в качестве примера два массива ``items`` и ``weights``, где ``items`` - это элементы, которые будут выбираться случайно, а ``weights`` - это весы этих элементов:
+
+`const items =   [ '🍌', '🍎', '🥕' ];`
+
+`const weights = [  3,    7,    1  ];`
+
+2) Подготавливаем массив весов посредством кумулятивного сложения (то есть список ``cumulativeWeights``, который будет иметь то же количество элементов, что и исходный список весов ``weights``). 
+В нашем случае такой массив будет выглядеть следующим образом: 
+
+` cumulativeWeights = [3, 3 + 7, 3 + 7 + 1] = [3, 10, 11] `
+
+3) Генерируем случайное число `randomNumber` от `0` до самого высокого кумулятивного значения веса. В нашем случае случайное число будет находиться в диапазоне `[0..11]`. Допустим, что `randomNumber = 8`.
+
+4) Проходим с помощью цикла по массиву `cumulativeWeights` слева направо и выбираем первый элемент, который больше или равен `randomNumber`. 
+Индекс такого элемента мы будем использовать для выбора элемента из массива элементов.
+
+Идея этого подхода заключается в том, что более высокие веса будут "занимать" больше числового пространства. Следовательно, существует более высокая вероятность того, что случайное число попадет в "числовое ведро" с более высоким весом.
+
+Попробую наглядно показать это на нашем примере:
+
+
+     const weights =           [3, 7,  1 ]; 
+
+     const cumulativeWeights = [3, 10, 11]; 
+
+     // В псевдопредставлении мы можем представить cumulativeWeights следующим образом: 
+
+     const pseudoCumulativeWeights = [ 
+
+       1, 2, 3,               // <-- [3] числа 
+
+       4, 5, 6, 7, 8, 9, 10,  // <-- [7] чисел 
+    
+     11,                    // <-- [1] число 
+
+     ]; 
+
+Как видим, более тяжёлые весы занимают более высокое числовое пространство, а следовательно, имеют более высокий шанс быть случайно выбранными. Процентное соотношение шанса выбора для элементо `weights` будет таким:
+
+Элемент `3`: ≈ 27%, 
+
+Элемент `7`: ≈ 64%, 
+
+Элемент `1`: ≈ 9%
+
+## Как можно еще лучше алгоритм генерации слов?
+
+Данный скрипт является больше примером использования алгоритма выбора случайного элемента массива на основе их веса, поэтому я не 
+стал сильно углубляться в лингвистику и алгоритмы искусственного интеллекта. Но навскидку сразу бросаются в глаза неприглядные комбинации некоторых гласных и согласных пар, которые выглядят неестественно и не встречаются в настоящих словах:
+- satlenl
+- tohhi
+- tiowh
+- aahepw
+
+и т.д. 
+
+Самым простым решением этого вопроса является ограничение на чередование более двух гласных/согласных слов:
+
+    if (vowelCounter >= maxVowelsInRow) {
+        i -= 1;
+        continue;
+    }
+
+и
+
+    if (consonantCounter >= maxConsonantsInRow) {
+        i -= 1;
+        continue;
+    }
+
+Пусть значения maxConsonantsInRow = 1 и maxVowelsInRow = 1, тогда сгенерированые слова будут выглядеть примерно так:
+
+
+Отметим, что th и ae являются диграмами, и считаются как одна буква. 
+
+Очевидной минус данного подхода заключается в том, что сгенерированные слова получаются более однотипными и с гораздо меньшим вариативным потенциалом. 
\ No newline at end of file