package robot // Robot display names are composed, not hand-listed. Per language there is a pool of // 32 full first names and a paired pool of 32 colloquial forms (William/Bill, // Анастасия/Настя), a surname pool, and three rendering forms: first name only; // first name plus a surname initial; first name plus full surname. Because robots are // durable accounts whose name must stay stable across restarts (a player's opponent // must not rename itself on every deploy, nor mid-game), the composition is // deterministic per pool slot — seeded by the slot index through mix — rather than // re-randomised each boot. Russian surnames are gender-agreed with the first name. // robotPoolSize is the number of robot accounts provisioned per language. It equals // the first-name pool size, so each slot draws a distinct person. const robotPoolSize = 32 // latinShareInRussian is the approximate percentage of Russian-variant games that // draw a Latin-named robot rather than a Russian-named one (the owner's "≤20%"). const latinShareInRussian = 20 // name composition forms. const ( nameFormFirstOnly = iota // "Anna" nameFormInitial // "Anna C." nameFormFull // "Anna Carter" ) // genderedName is a Russian first name tagged by grammatical gender so the surname // form (masculine vs feminine) can agree with it. type genderedName struct { name string female bool } // surnamePair holds a Russian surname's masculine and feminine forms. type surnamePair struct{ m, f string } // firstNamesFullEN and firstNamesShortEN are paired by index: the same person's // official and colloquial English first name (William/Bill). var firstNamesFullEN = []string{ "William", "Robert", "Thomas", "Nicholas", "Joseph", "Edward", "Charles", "Margaret", "Elizabeth", "Katherine", "Alexander", "Samuel", "Andrew", "Christopher", "Benjamin", "Daniel", "Matthew", "Anthony", "Michael", "Richard", "Jonathan", "Patricia", "Jennifer", "Jessica", "Stephanie", "Victoria", "Theodore", "Frederick", "Gabriel", "Vincent", "Eleanor", "Josephine", } var firstNamesShortEN = []string{ "Will", "Bob", "Tom", "Nick", "Joe", "Eddie", "Charlie", "Maggie", "Liz", "Kate", "Alex", "Sam", "Drew", "Chris", "Ben", "Dan", "Matt", "Tony", "Mike", "Rick", "Jon", "Pat", "Jen", "Jess", "Steph", "Vicky", "Ted", "Fred", "Gabe", "Vince", "Ellie", "Josie", } // surnamesEN is a pool of gender-neutral English surnames. var surnamesEN = []string{ "Carter", "Hayes", "Brooks", "Reed", "Cole", "Lane", "Bishop", "Hart", "Shaw", "Wells", "Pierce", "Wade", "Frost", "Doyle", "Boyd", "Marsh", "Hale", "Nash", "Webb", "Dale", "Park", "Lyon", "Snow", "Cross", "Vance", "Knox", "Page", "Ford", "Banks", "Foster", "Greer", "Mills", } // firstNamesFullRU and firstNamesShortRU are paired by index: the same person's // official and colloquial Russian first name (Анастасия/Настя), gender-tagged. var firstNamesFullRU = []genderedName{ {"Александр", false}, {"Дмитрий", false}, {"Сергей", false}, {"Алексей", false}, {"Михаил", false}, {"Николай", false}, {"Владимир", false}, {"Константин", false}, {"Павел", false}, {"Григорий", false}, {"Андрей", false}, {"Иван", false}, {"Пётр", false}, {"Роман", false}, {"Антон", false}, {"Евгений", false}, {"Анна", true}, {"Мария", true}, {"Анастасия", true}, {"Наталья", true}, {"Татьяна", true}, {"Екатерина", true}, {"Юлия", true}, {"Ольга", true}, {"Елена", true}, {"Ирина", true}, {"Светлана", true}, {"Полина", true}, {"Дарья", true}, {"София", true}, {"Алина", true}, {"Вера", true}, } var firstNamesShortRU = []genderedName{ {"Саша", false}, {"Дима", false}, {"Серёжа", false}, {"Лёша", false}, {"Миша", false}, {"Коля", false}, {"Володя", false}, {"Костя", false}, {"Паша", false}, {"Гриша", false}, {"Андрюша", false}, {"Ваня", false}, {"Петя", false}, {"Рома", false}, {"Антоша", false}, {"Женя", false}, {"Аня", true}, {"Маша", true}, {"Настя", true}, {"Наташа", true}, {"Таня", true}, {"Катя", true}, {"Юля", true}, {"Оля", true}, {"Лена", true}, {"Ира", true}, {"Света", true}, {"Поля", true}, {"Даша", true}, {"Соня", true}, {"Аля", true}, {"Верочка", true}, } // surnamesRU is a pool of common Russian surnames in masculine and feminine forms. var surnamesRU = []surnamePair{ {"Иванов", "Иванова"}, {"Смирнов", "Смирнова"}, {"Кузнецов", "Кузнецова"}, {"Соколов", "Соколова"}, {"Попов", "Попова"}, {"Лебедев", "Лебедева"}, {"Новиков", "Новикова"}, {"Морозов", "Морозова"}, {"Волков", "Волкова"}, {"Зайцев", "Зайцева"}, {"Павлов", "Павлова"}, {"Беляев", "Беляева"}, {"Орлов", "Орлова"}, {"Громов", "Громова"}, {"Суханов", "Суханова"}, {"Киселёв", "Киселёва"}, {"Макаров", "Макарова"}, {"Фёдоров", "Фёдорова"}, {"Никитин", "Никитина"}, {"Захаров", "Захарова"}, {"Борисов", "Борисова"}, {"Королёв", "Королёва"}, {"Герасимов", "Герасимова"}, {"Пономарёв", "Пономарёва"}, {"Григорьев", "Григорьева"}, {"Романов", "Романова"}, {"Виноградов", "Виноградова"}, {"Богданов", "Богданова"}, {"Воробьёв", "Воробьёва"}, {"Сергеев", "Сергеева"}, {"Кузьмин", "Кузьмина"}, {"Соловьёв", "Соловьёва"}, } // robotDisplayNamesEN builds the English robot display-name pool, one per slot. Each // slot draws its paired full or colloquial first name, a surname, and a form. func robotDisplayNamesEN() []string { out := make([]string, robotPoolSize) for i := range out { h := mix(int64(i), "robot-en") first := firstNamesFullEN[i%len(firstNamesFullEN)] if (h>>16)&1 == 1 { first = firstNamesShortEN[i%len(firstNamesShortEN)] } surname := surnamesEN[h%uint64(len(surnamesEN))] out[i] = composeName(first, surname, int((h>>8)%3)) } return out } // robotDisplayNamesRU builds the Russian robot display-name pool, one per slot, with // the surname form agreeing with the first name's gender. func robotDisplayNamesRU() []string { out := make([]string, robotPoolSize) for i := range out { h := mix(int64(i), "robot-ru") fn := firstNamesFullRU[i%len(firstNamesFullRU)] if (h>>16)&1 == 1 { fn = firstNamesShortRU[i%len(firstNamesShortRU)] } sp := surnamesRU[h%uint64(len(surnamesRU))] surname := sp.m if fn.female { surname = sp.f } out[i] = composeName(fn.name, surname, int((h>>8)%3)) } return out } // composeName renders one of the three name forms from a first name and a surname. func composeName(first, surname string, form int) string { switch form { case nameFormInitial: return first + " " + string([]rune(surname)[:1]) + "." case nameFormFull: return first + " " + surname default: return first } }