Générateur de nom d’heroic fantasy en Python


Les générateurs de noms d’heroic fantasy sont légions sur internet. Mais autant j’ai trouvé des générateurs de noms normaux en Python (dont je me sers d’ailleurs pour créer des comptes bidons automatiquement pour les démos), autant je n’ai rien trouvé pour pythonement printer l’en-tête d’une feuille de personnage de DDA.

Et comme c’est fun, voilà le nonos du Sam du jour:

from random import randint, choice
 
class FantasyNameGenerator(object):
    """
        Random fantasy name generator
    """
 
    # on déclare les lettres, leurs positions voulues dans le nom
    # et un poids de fréquence d'apparition
 
    # voyelles
    VOWELS = (
        (('start', 'middle', 'end'), (
                (5, ("a", "e", "i", "o", "u")),
                (1, ("ae", "ai", "ao", "au", "aa", "ea", "eo", "eu", "ee", "ia",
                     "io", "iu", "ii", "oa", "oe", "oi", "ou", "oo", "eau", "y"))
        )),
        (('middle'), (
            (1, ("'",)),
        ))
    )
 
    # consonnes
    CONSONANTS = (
        (('start', 'middle', 'end'), (
                (3, ("b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p",
                     "r", "s", "t", "v", "w")),
                (1, ("x", "y", "z", "sc", "ch", "gh", "ph", "sh", "th", "sk", "wk", "st"))
        )),
        (('middle', 'end'), (
                (1, ("ck", "nk", "rk", "ss")),
        )),
        (('start', 'middle'), (
                (2, ("br", "dr", "fr", "gr", "kr", )),
                (1, ("cr", "pr", "sr", "tr", "qu", "wh", "cl", "fl", "gl", "kl",
                     "ll", "pl", "sl", "str"))
        )),
    )
 
    # on génère deux listes de type ((lettre, position), (lettre, position)...)
    # pour pouvoir piocher au hasard dedans
    SYLLABLES_POOL = [[], []]
 
    for i, group in enumerate((VOWELS, CONSONANTS)):
        pool = SYLLABLES_POOL[i]
        for place, pack in group:
            for frequency, letters in pack:
                for letter in letters:
                    pool.extend(((letter, set(place)),) * frequency)
 
 
    def __init__(self, min_syllable=2, max_syllable=None):
        self.min_syllable = min_syllable
        self.max_syllable = max_syllable or (min_syllable + 2)
 
    def __iter__(self):
        # juste pour le plaisir d'avoir le générateur itérable
        while True:
            yield self.get_new_name()
 
    # générer un nom avec les réglages de l'instance
    def get_new_name(self):
        return self.generate_name(self.min_syllable, self.max_syllable)
 
    @classmethod
    def generate_name(cls, min_syllable, max_syllable, base=""):
 
        # méthode pour générer un nom à indépendament de l'instance
 
        # on génère aléatoirement la taille du mot et le son de départ
        length, pool = randint(min_syllable, max_syllable), randint(0, 1)
 
        # pour chaque syllabe, on en choppe une au hasard et on change de pool
        # si la syllable n'est pas à la bonne place, on tire à nouveau
        for i in xrange(1, length + 1):
 
            while True:
 
                letter, place = choice(cls.SYLLABLES_POOL[pool])
 
                if i == 1:
                    if 'start' not in place:
                        continue
                elif i == length:
                    if 'end' not in place:
                        continue
                else:
                    if 'middle' not in place:
                        continue
 
                base += letter
                pool = abs(pool - 1)
                break
 
        return base.title()

Et ça s’utilise comme ça:

import itertools
 
for name in itertools.islice(FantasyNameGenerator(max_syllable=5), 5):
    print name

Et ça affiche ça:

Oislaex
Feasroap
Kab
Uthi
Iin

Ok, ok, ça sert à rien. Mais c’est marrant !

7 thoughts on “Générateur de nom d’heroic fantasy en Python

  • Laurent

    Ça pourrait bien me servir pour la création de personnages à Guild Wars 2. Je vais transformer mon raspberry pi en générateur de nom inutile donc indispensable.

    Quelques questions du gros noob que je suis.
    La méthode __iter__ elle permet de rendre l’instance de classe itérable c’est ça ?
    à quoi sert le @classmethod ? C’est un décorateur ?

    Merci

  • Sam Post author

    Oui, la méthode __iter__ permet de faire un for directement sur l’instance et récupérer des noms.

    @classmethode est un décorateur (voir l’article sur le bloc à ce sujet) qui permet de transformer une méthode en une méthode de classe (qui n’a pas besoin d’instance pour fonctionner, et qui se voit passer la classe en premier paramètre).

  • Bronco

    Haha ! J’adore ! J’avais fait un générateur de ce genre avec des styles de noms an AMOS à l’époque de l’amiga !
    souvestalgie ^^

  • JEEK

    Inutile ou pas, je pense que je vais en avoir l’utilité (même si ça fait un paquet d’années que je ne joue plus aux JDR)…
    …merci du partage !
    ;-)

  • stephane

    Au cas où quelqu’un tombe sur cet article pour générer des noms en français :

    Faker permet de le faire en choisissant la langue donc avoir Bernard Duplantier plutôt que John Smith (contrairement à namegen cité dans l’article). C’est compatible python2 et 3.

    https://pypi.python.org/pypi/Faker

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.