Статья удалена
Не знаю, что взбрело мне в голову, но решил я вдруг написать программу, которая могла бы генерировать несуществующие имена.
Ну и как любой уважающий себя человек, который пишет программы для себя, я отправился нет, не учить основы программирования, а сразу писать программу
Начало
Начиналось всё безобидно. Я скачал python и открыл стандартное IDLE. Затем написал маленький файл, который обозвал gen.txt и сохранил его в ту же папку, в которую у меня сохранён и сам файл с кодом питона. Содержимое этого файла выглядело так:
По задумке, программа должна брать из файла букву и вероятность того, что именно эта буква будет сгенерирована.
Сначал я открыл сам файл с буквами, затем добавил цикл, в котором три прохода (По числу строк во внешнем файле, которые начинаются с нулевой). В этом цикле было решено разместить считывание строки, и дальнейшее её разделение на две части, или две переменные «n» и «m»
Можно было конечно использовать метод split, который просто отделяет всё что стоит до указанного знака и после, но у меня он отказался работать в дальнейшем, потому что в конце каждой строки есть так же невидимые символы «/n», которые означают, что строка переносится. Я их не вижу, а вот программа видит. Из-за чего преобразовать строку в числе будет невозможно.
Дальше сложнее. Я добавил несколько переменных
«char» это список всех букв, в нашем файле. Методом «Append» мы добавляем новый пункт к нашему списку «char»
«ver» это список вероятностей того, что та или иная буква выпадет. Здесь тоже используется метод «Append»
У каждого из этих списков есть индекс. Так, если мы например, напишем это:
То в выводе получим следующее:
Что полностью соответствует первой строке
Но как сделать так, чтобы буквы ещё и генерировались с определённой вероятностью? В английском языке, например буква «E» встречается в 13% случаев. Тогда как «Z» всего в 0,1% (Данные разумеется не абсолютные, и постоянно меняются)
Для этого я изобрёл костыль, и решил прикрутить такую вещь как диапазоны. И моя пародия на код стала выглядеть вот так
Список «ran1» Это список начальных диапазонов
Список «ran2» Это список конечных диапазонов.
Ничего не поняли? Не расстраивайтесь. Я тоже не с первого раза понял, что за хрень я написал.
Давайте разберём всё тот же файл gen.txt
При помощи этого костыля, мы сможем используя один и тот же индекс (циферка, которая стоит в квадратных скобочках) вытащить из переменной «ran1» начальное число, при котором будет начинаться генерация символа с таким же индексом из списка «char». А «ran2» это число, которым оно будет заканчиваться. Таким образом, при первом заходе мы получим, что буква «a» будет генерироваться если наш рандомайзер выдаст число от 0 до 0,1
При втором заходе мы получим, что буква «b» будет генерироваться если наш рандомайзер выдаст число от 0,1 до 0,2.
Но... это всё в теории. На практике же случилось то же самое, что кот думает при виде работающего экскаватора: «Ничего не понятно, но очень интересно»
Короче, рандомайзер "random.random()" не захотел работать адекватно. Потому что для того, чтобы разграничить диапазоны мне пришлось прибавлять какое-то маленькое число. Но при добавлении этого маленького числа всё равно оставался малюсенький диапазончик, в которое рандомайзер может выстрелить, и при этом ни одна буква не сгенерируется вообще. Плюс происходила неизвестная магия, и помимо того маленького числа которое я прибавлял — добавлялось ещё и непонятно откуда взявшееся очень маленькое число. Что-то порядка 0,00000005. Короче я забил, и решил проводить все операции в формате целых чисел. Для этого я переписал таблицу, ну и заодно добавил недостающих букв. Частоту использования букв брал из интернета
Получилось примерно следующее. Я конечно не особо сильно искал, но тем не менее не нашёл, насколько часто встречается апостроф. Поэтому число взял из головы. Впринципе, если взять 500 или 800, то получится вообще какой-нибудь язык орков
Ну и подумал я, что в файл я по своему усмотрению буду добавлять и убирать разные символы. К тому же, возможно когда-нибудь залью туда японскую Хирагану. Поэтому мне надо сделать автоматический счётчик строк. Его я пытался сделать ещё в самом начале, но столкнулся с такой проблемой, что при использовании метода readline, читается каждая следующая строка. С одной стороны это конечно фича. Но с другой стороны, если я при помощи этого метода буду в основном цикле считать строки, то прочитать их и вынести в переменные уже не получится, т.к после окончания подсчёта, невидимый курсор программы будет в самом конце файла (А как его сместить я не нашёл)
Но проблема была решена. Где-то в интернете я откопал вот такой код
Его преимущество, как я понял в том, что он каждый раз открывает и закрывает файл. Ну и невидимый курсор прыгает с точки зрения программы по совершенно другому тексту.
Сам генератор
И так, диапазоны сгенерированы. Их можно проверить. Для этого в конце цикла можем вывести print (char[i, ran1[i], ran2[i]) и полюбоваться на то, какие мы умные
Для генератора случайных чисел надо подключить модуль random. Просто пишем в самом начале файла
Теперь пишем то, что будет генерировать число и преобразовывать это в букву
Написать написал, теперь переведу с эльфийского.
Разберём эту строчку.
Random.randrange означает, что мы генерируем число в заданном диапазоне. В скобках у нас стоит ноль (То есть генерировать число мы будем от нуля), и какая-то непонятная фигня "ran2[(count_lines("C:/Users/Admin/Documents/namegen/gen.txt"))-1]"
ran2 это уже знакомый нам список. Из этого списка мы хотим взять последний элемент, т.к именно он будет конечным числом, в пределах которого должна происходить генерация. В квадратных скобках идёт индекс элемента. Но как узнать, какой индекс будет у нашего последнего элемента? Очень просто! Нужно всего лишь посчитать количество строк в файле, что мы и делаем функцией count_lines с полным путём к нашему фуйлу. После чего вычитаем один, ведь количество строк считается с единицы, а индексы нумеруются с нуля.
Теперь рассмотрим вот это.
Мы хотим узнать, какой букве из наших диапазонов соответствует число, которое мы сгенерировали. Для этого мы запускаем цикл, который будет тикать ровно столько раз, сколько строк в файле. И в каждом тике будет запускаться проверка. Если число больше либо равно ran1 с индексом данного "тика", и меньше/равно ran2 с индексом данного тика то проверка проходится, и мы печатаем букву. В дальнейшем мы не будем просто печатать, а будем выводить в переменную, но пока нам этого зватит, чтобы побаловаться с результатом.
Однако сгенерировав таким образом несколько имён мы видим, что они получаются какими-то странными. Всему виной то, что на генерацию не наложено ни каких ограничений. Мы можем получить хоть одинаковые буквы.
Для этого нам надо сделать ограничитель на несколько гласных и согласных букв подряд.
Я не хочу, чтобы подряд встречалось больше 2 гласных/согласных. Поэтому выносим наш генератор в отдельную функцию
И делаем цикл while
и помещаем в переменную "p" то, что нам выдаст наш генератор
Следующие строчки будут определять - гласная это буква или согласная
соответственно цифра 1 означает, что буква гласная, а 0 - согласная. "type" это список. И если нам например будет сгенерировано слово ghyalta, то если мы выведем список все элементов "type" то получим 0011001, то "маску" гласности/согласности букв
Теперь генерируем первые две буквы. На них правила генерации распространятся, кроме тех, что я не хочу чтобы первая буква бывала апострофом, не будут. Соответственно проверили - если q меньше двух, значит это первые две буквы. Если q = 1 и буква которая сгенерировалась это апостров, то не делаем ничего. А если нет, то просто добавляем к строке "name" ту бвукву, которая у нас сгенерировалась, и увеличиваем счётчик q на единицу
Если же q у нас больше двух, то снова запускаем проверку. Если в списке type предыдущая, пред-предыдущая и нынешняя буквы гласные (type с каким-то индексом равен 1) или те же самые буквы согласные, то не делаем ничего. Иначе добавляем наш символ к строке "name". Ну и увеличиваем счётчик на 1
Далее я добавил несколько проверяльщиков, и вынес проверялщикнескольких согласных подряд в отдельную функцию. А так же назначил апострофу отдельную цифру - 2
Полный код
Побалуемся с генератором
Такие "Имена" получились у меня при генерацииlteruan
hedzeed
lie`oen
iulianf
peggata
pcetgey
eishisp
nroadeo
hirhopa
be`neun
hedzeed
bseslee
ffitpeo
ehmoela
Побалуемся с набором букв
Попробуем сделать какой-нибудь язык орков. Много старшных согласных и апострофов. Ниже я написал только то, что изменил. Остальное оставил по как было
ehwehwe
hdeh`dq
ehfyt`h
rh`derd
ech`dar
tsog`cr
dd`dsos
gm`wrav
ghiegse
dcels`l
hgeatre
Многое из этого прочитать практически невозможно, но это ж язык орков! Зато звучит страшно.
Попробуем теперь сделать наоборот какой-нибудь эльфийский язык
С ним пришлось повозиться и подумать, поэтому выкладываю полную табличку
cuyszeo
fzizaax
uwizxiq
xoezafv
aoquxmo
msimaow
cobciex
oizoizw
eymeoms
Ну и давайте сделаем какой-нибудь язык котиков. Для этого сократим табличку
uymoomy
uimamuu
eummeul
eimomio
moomoim
oemieme
imoimuy
immeemo
mumaima
oomoemo
Заключение
Как мне кажется у меня получилось сделать гибкую и интересную систему, которую можно будет интегрировать под свои задачи наверное каждому человеку, который создаёт контент.
Ей можно прикрутить к какой-нибудь игре, и делать динамически генерируемые имена для неписей (Ну или гораздо проще создать список имён из которых будет происходить генерация), можно придумывать имена в своих книгах, когда стандартные Вани, Джоны и Марии уже режут слух. Можно даже сгенерировать целый язык. Просто взять какой-нибудь словарь, и для каждой позиции в словаре сгенерировать слово. Так что в итоге получится действительно неузнаваемая фигня, которую даже расшифровать без словаря не получится.
(Если в комментариях будут умные програмисты, то не стесняйтесь исправлять костыли. Всё-таки опыт у меня в программировании крайне скромный. Это школьный курс информатики на паскале, и пожалуй всё, за исключением пары других, аналогичных попыток что-то написать)
Спасибки всем кто прочитал. Добра вам и котиков :3