Популярное
Свежее
Моя лента
Сообщения
Рейтинг
Пополнить Steam
Низкая комиссия
Темы
Игры
Офтоп
Гайды
Творчество
Ночной музпостинг
Кино и сериалы
Вопросы
Музыка
Милые животные
Видео
Показать все
DTF
О проекте
Правила
Реклама
Приложения
Аккаунт удален
Офтоп
28.07.2020

Статья удалена

Статья удалена

Не знаю, что взбрело мне в голову, но решил я вдруг написать программу, которая могла бы генерировать несуществующие имена.

Ну и как любой уважающий себя человек, который пишет программы для себя, я отправился нет, не учить основы программирования, а сразу писать программу

Начало

Начиналось всё безобидно. Я скачал python и открыл стандартное IDLE. Затем написал маленький файл, который обозвал gen.txt и сохранил его в ту же папку, в которую у меня сохранён и сам файл с кодом питона. Содержимое этого файла выглядело так:

a;0.1 b;0.1 c;0.1

По задумке, программа должна брать из файла букву и вероятность того, что именно эта буква будет сгенерирована.

Сначал я открыл сам файл с буквами, затем добавил цикл, в котором три прохода (По числу строк во внешнем файле, которые начинаются с нулевой). В этом цикле было решено разместить считывание строки, и дальнейшее её разделение на две части, или две переменные «n» и «m»

with open("C:/Users/Admin/Documents/namegen/gen2.txt") as f: for i in range (2): s = f.readline() n = s[0:1] m = s[3:5]

Можно было конечно использовать метод split, который просто отделяет всё что стоит до указанного знака и после, но у меня он отказался работать в дальнейшем, потому что в конце каждой строки есть так же невидимые символы «/n», которые означают, что строка переносится. Я их не вижу, а вот программа видит. Из-за чего преобразовать строку в числе будет невозможно.

Дальше сложнее. Я добавил несколько переменных

char=[] ver=[] i=0 ran1=[0] ran2=[] for i in range (2): s = f.readline() n = s[0:2] m = s[3:5] char.append(n) ver.append(m)

«char» это список всех букв, в нашем файле. Методом «Append» мы добавляем новый пункт к нашему списку «char»

«ver» это список вероятностей того, что та или иная буква выпадет. Здесь тоже используется метод «Append»

У каждого из этих списков есть индекс. Так, если мы например, напишем это:

print(ver[0]) print(char[0])

То в выводе получим следующее:

a 0,1

Что полностью соответствует первой строке

Но как сделать так, чтобы буквы ещё и генерировались с определённой вероятностью? В английском языке, например буква «E» встречается в 13% случаев. Тогда как «Z» всего в 0,1% (Данные разумеется не абсолютные, и постоянно меняются)

Для этого я изобрёл костыль, и решил прикрутить такую вещь как диапазоны. И моя пародия на код стала выглядеть вот так

with open("C:/Users/Admin/Documents/namegen/gen2.txt") as f: char=[] ver=[] i=0 ran1=[0] ran2=[] for i in range (2): s = f.readline() n = s[0:2] m = s[3:5] char.append(n) ver.append(m) if i == 0: ran2.append(int(ver[i])) else: ran1.append(ran2[i-1]+0,001) ran2.append(float(ran1[i]+float(ver[i])))

Список «ran1» Это список начальных диапазонов

Список «ran2» Это список конечных диапазонов.

Ничего не поняли? Не расстраивайтесь. Я тоже не с первого раза понял, что за хрень я написал.

Давайте разберём всё тот же файл gen.txt

При помощи этого костыля, мы сможем используя один и тот же индекс (циферка, которая стоит в квадратных скобочках) вытащить из переменной «ran1» начальное число, при котором будет начинаться генерация символа с таким же индексом из списка «char». А «ran2» это число, которым оно будет заканчиваться. Таким образом, при первом заходе мы получим, что буква «a» будет генерироваться если наш рандомайзер выдаст число от 0 до 0,1

При втором заходе мы получим, что буква «b» будет генерироваться если наш рандомайзер выдаст число от 0,1 до 0,2.

Но... это всё в теории. На практике же случилось то же самое, что кот думает при виде работающего экскаватора: «Ничего не понятно, но очень интересно»

Короче, рандомайзер "random.random()" не захотел работать адекватно. Потому что для того, чтобы разграничить диапазоны мне пришлось прибавлять какое-то маленькое число. Но при добавлении этого маленького числа всё равно оставался малюсенький диапазончик, в которое рандомайзер может выстрелить, и при этом ни одна буква не сгенерируется вообще. Плюс происходила неизвестная магия, и помимо того маленького числа которое я прибавлял — добавлялось ещё и непонятно откуда взявшееся очень маленькое число. Что-то порядка 0,00000005. Короче я забил, и решил проводить все операции в формате целых чисел. Для этого я переписал таблицу, ну и заодно добавил недостающих букв. Частоту использования букв брал из интернета

a;073 b;009 c;030 d;044 e;130 f;028 g;016 h;035 i;074 j;002 k;003 l;035 m;025 n;078 o;074 p;027 q;003 r;077 s;063 t;093 u;027 v;013 w;016 x;005 y;019 z;005 `;118

Получилось примерно следующее. Я конечно не особо сильно искал, но тем не менее не нашёл, насколько часто встречается апостроф. Поэтому число взял из головы. Впринципе, если взять 500 или 800, то получится вообще какой-нибудь язык орков

Ну и подумал я, что в файл я по своему усмотрению буду добавлять и убирать разные символы. К тому же, возможно когда-нибудь залью туда японскую Хирагану. Поэтому мне надо сделать автоматический счётчик строк. Его я пытался сделать ещё в самом начале, но столкнулся с такой проблемой, что при использовании метода readline, читается каждая следующая строка. С одной стороны это конечно фича. Но с другой стороны, если я при помощи этого метода буду в основном цикле считать строки, то прочитать их и вынести в переменные уже не получится, т.к после окончания подсчёта, невидимый курсор программы будет в самом конце файла (А как его сместить я не нашёл)

Но проблема была решена. Где-то в интернете я откопал вот такой код

def count_lines(file): try: with open(file) as fl: return len(fl.readlines()) except Exception: return 0

Его преимущество, как я понял в том, что он каждый раз открывает и закрывает файл. Ну и невидимый курсор прыгает с точки зрения программы по совершенно другому тексту.

def count_lines(file): try: with open(file) as fl: return len(fl.readlines()) except Exception: return 0 with open("C:/Users/Admin/Documents/namegen/gen.txt") as f: char=[] ver=[] i=0 ran1=[0] ran2=[] for i in range (count_lines("C:/Users/Admin/Documents/namegen/gen.txt")): s = f.readline() n = s[0:1] m = s[2:5] char.append(n) ver.append(m) if i == 0: ran2.append(int(ver[i])) else: ran1.append(ran2[i-1]+1) ran2.append(int(ran1[i]+int(ver[i])))

Сам генератор

И так, диапазоны сгенерированы. Их можно проверить. Для этого в конце цикла можем вывести print (char[i, ran1[i], ran2[i]) и полюбоваться на то, какие мы умные

Статья удалена

Для генератора случайных чисел надо подключить модуль random. Просто пишем в самом начале файла

import random

Теперь пишем то, что будет генерировать число и преобразовывать это в букву

x = random.randrange(0,ran2[(count_lines("C:/Users/Admin/Documents/namegen/gen.txt"))-1],1) for q in range (count_lines("C:/Users/Admin/Documents/namegen/gen.txt")): if (x>=minrange[q])and(x<=maxrange[q]): print char[q]

Написать написал, теперь переведу с эльфийского.

x = random.randrange(0,ran2[(count_lines("C:/Users/Admin/Documents/namegen/gen.txt"))-1],1)

Разберём эту строчку.

Random.randrange означает, что мы генерируем число в заданном диапазоне. В скобках у нас стоит ноль (То есть генерировать число мы будем от нуля), и какая-то непонятная фигня "ran2[(count_lines("C:/Users/Admin/Documents/namegen/gen.txt"))-1]"

ran2 это уже знакомый нам список. Из этого списка мы хотим взять последний элемент, т.к именно он будет конечным числом, в пределах которого должна происходить генерация. В квадратных скобках идёт индекс элемента. Но как узнать, какой индекс будет у нашего последнего элемента? Очень просто! Нужно всего лишь посчитать количество строк в файле, что мы и делаем функцией count_lines с полным путём к нашему фуйлу. После чего вычитаем один, ведь количество строк считается с единицы, а индексы нумеруются с нуля.

for q in range (count_lines("C:/Users/Admin/Documents/namegen/gen.txt")): if (x>=minrange[q])and(x<=maxrange[q]): print char[q]

Теперь рассмотрим вот это.

Мы хотим узнать, какой букве из наших диапазонов соответствует число, которое мы сгенерировали. Для этого мы запускаем цикл, который будет тикать ровно столько раз, сколько строк в файле. И в каждом тике будет запускаться проверка. Если число больше либо равно ran1 с индексом данного "тика", и меньше/равно ran2 с индексом данного тика то проверка проходится, и мы печатаем букву. В дальнейшем мы не будем просто печатать, а будем выводить в переменную, но пока нам этого зватит, чтобы побаловаться с результатом.

for q in range 10: x = random.randrange(0,ran2[(count_lines("C:/Users/Admin/Documents/namegen/gen.txt"))-1],1) for q in range (count_lines("C:/Users/Admin/Documents/namegen/gen.txt")): if (x>=minrange[q])and(x<=maxrange[q]): print char[q]

Однако сгенерировав таким образом несколько имён мы видим, что они получаются какими-то странными. Всему виной то, что на генерацию не наложено ни каких ограничений. Мы можем получить хоть одинаковые буквы.

Для этого нам надо сделать ограничитель на несколько гласных и согласных букв подряд.

Я не хочу, чтобы подряд встречалось больше 2 гласных/согласных. Поэтому выносим наш генератор в отдельную функцию

def gen_char(minrange,maxrange,table): x = random.randrange(0,maxrange[(count_lines("C:/Users/Admin/Documents/namegen/gen.txt"))-1],1) for q in range (count_lines("C:/Users/Admin/Documents/namegen/gen.txt")): if (x>=minrange[q])and(x<=maxrange[q]): return table[q]

И делаем цикл while

while q < d: p = gen_char(ran1,ran2,char)

и помещаем в переменную "p" то, что нам выдаст наш генератор

Следующие строчки будут определять - гласная это буква или согласная

if p in 'aeiouy': type.append(1) else: type.append(0)

соответственно цифра 1 означает, что буква гласная, а 0 - согласная. "type" это список. И если нам например будет сгенерировано слово ghyalta, то если мы выведем список все элементов "type" то получим 0011001, то "маску" гласности/согласности букв

if q<2: if (q==1)and(p == '`'): pass else: name = name + p q = q + 1 else: if ((type[q-2] == 1) and (type[q-1] == 1) and (type[q] == 1)) or ((type[q-2] == 0) and (type[q-1] == 0) and (type[q] == 0)): pass else: name = name + p q = q + 1

Теперь генерируем первые две буквы. На них правила генерации распространятся, кроме тех, что я не хочу чтобы первая буква бывала апострофом, не будут. Соответственно проверили - если q меньше двух, значит это первые две буквы. Если q = 1 и буква которая сгенерировалась это апостров, то не делаем ничего. А если нет, то просто добавляем к строке "name" ту бвукву, которая у нас сгенерировалась, и увеличиваем счётчик q на единицу

Если же q у нас больше двух, то снова запускаем проверку. Если в списке type предыдущая, пред-предыдущая и нынешняя буквы гласные (type с каким-то индексом равен 1) или те же самые буквы согласные, то не делаем ничего. Иначе добавляем наш символ к строке "name". Ну и увеличиваем счётчик на 1

Далее я добавил несколько проверяльщиков, и вынес проверялщикнескольких согласных подряд в отдельную функцию. А так же назначил апострофу отдельную цифру - 2

Полный код

import random def count_lines(file): try: with open(file) as fl: return len(fl.readlines()) except Exception: return 0 def gen_char(minrange,maxrange,table): x = random.randrange(0,maxrange[(count_lines("C:/Users/Admin/Documents/namegen/gen.txt"))-1],1) for q in range (count_lines("C:/Users/Admin/Documents/namegen/gen.txt")): if (x>=minrange[q])and(x<=maxrange[q]): return table[q] def chck_buk(ty,nu,bo1,bo2,bo3): if ((ty[nu-2] == bo1) and (ty[nu-1] == bo2) and (ty[nu] == bo3)): return True else: return False def chck_chr(ch,nu,snu,sch): if snu == nu: if (ch == sch): return True else: return False else: return False def chck_ap(ty,nu): if (ty[nu-1] == 2) and (ty[nu] == 2): return True else: if (ty[nu-1] == 1) and (ty[nu] == 2): return True else: return False with open("C:/Users/Admin/Documents/namegen/gen.txt") as f: char=[] ver=[] i=0 ran1=[0] ran2=[] q=0 e=0 name="" nn = 0 d = 7 type = [] for i in range (count_lines("C:/Users/Admin/Documents/namegen/gen.txt")): s = f.readline() n = s[0:1] m = s[2:5] char.append(n) ver.append(m) if i == 0: ran2.append(int(ver[i])) else: ran1.append(ran2[i-1]+1) ran2.append(int(ran1[i]+int(ver[i]))) while q < d: print (q) p = gen_char(ran1,ran2,char) print (p) if (p in 'aeiouy'): type.append(1) else: if (p == '`'): type.append(2) else: type.append(0) if q<2: if (q==0)and(p == '`'): type.pop(q) else: name = name + p q = q + 1 else: if ((chck_buk(type,q,1,1,1)) or (chck_buk(type,q,0,0,0)) or (chck_buk(type,q,0,2,1)) or (chck_buk(type,q,0,0,0))): type.pop(q) else: if chck_chr(p,q,d-1,'`'): type.pop(q) else: if chck_ap(type,q): type.pop(q) else: name = name + p q = q + 1 print (name)

Побалуемся с генератором

Такие "Имена" получились у меня при генерацииlteruan
hedzeed
lie`oen
iulianf
peggata
pcetgey
eishisp
nroadeo
hirhopa
be`neun
hedzeed
bseslee
ffitpeo
ehmoela

Побалуемся с набором букв

Попробуем сделать какой-нибудь язык орков. Много старшных согласных и апострофов. Ниже я написал только то, что изменил. Остальное оставил по как было

d;220 h;214 r;205 t;178 `;215 y;007 u;005 o;040 i;020

ehwehwe
hdeh`dq
ehfyt`h
rh`derd
ech`dar
tsog`cr
dd`dsos
gm`wrav
ghiegse
dcels`l
hgeatre

Многое из этого прочитать практически невозможно, но это ж язык орков! Зато звучит страшно.

Попробуем теперь сделать наоборот какой-нибудь эльфийский язык

a;140 b;009 c;030 d;044 e;190 f;028 g;016 h;035 i;215 j;002 k;003 l;018 m;109 n;020 o;178 p;007 q;085 r;009 s;120 t;020 u;180 v;048 w;072 x;120 y;100 z;130 `;005

С ним пришлось повозиться и подумать, поэтому выкладываю полную табличку
cuyszeo
fzizaax
uwizxiq
xoezafv
aoquxmo
msimaow
cobciex
oizoizw
eymeoms

Ну и давайте сделаем какой-нибудь язык котиков. Для этого сократим табличку

a;140 e;190 i;215 l;018 m;109 n;020 o;178 u;180 y;100

uymoomy
uimamuu
eummeul
eimomio
moomoim
oemieme
imoimuy
immeemo
mumaima
oomoemo

Заключение

Как мне кажется у меня получилось сделать гибкую и интересную систему, которую можно будет интегрировать под свои задачи наверное каждому человеку, который создаёт контент.

Ей можно прикрутить к какой-нибудь игре, и делать динамически генерируемые имена для неписей (Ну или гораздо проще создать список имён из которых будет происходить генерация), можно придумывать имена в своих книгах, когда стандартные Вани, Джоны и Марии уже режут слух. Можно даже сгенерировать целый язык. Просто взять какой-нибудь словарь, и для каждой позиции в словаре сгенерировать слово. Так что в итоге получится действительно неузнаваемая фигня, которую даже расшифровать без словаря не получится.

(Если в комментариях будут умные програмисты, то не стесняйтесь исправлять костыли. Всё-таки опыт у меня в программировании крайне скромный. Это школьный курс информатики на паскале, и пожалуй всё, за исключением пары других, аналогичных попыток что-то написать)

Спасибки всем кто прочитал. Добра вам и котиков :3