RPG Maker VX Ace
TriNameGenRMVXA

Back when I was still a Minecraft modder I wanted to create something that would be very useful to content creators, both Minecraft modders and regular Java programmers. I originally created a name generator which was pretty complicated.

A year or two later I decided to simplify the script a little, and decided to just start from scratch. When creating the first name generator, I had already heard something about Markov Chains, so I decided to just do whatever the hell I wanted (I don't need no stinkin' Markov Chains). Well, turns out that this name generator might be more Markov Chain-y than I thought.

So yeah, here's my very simple name generator. Mind you, it's simple in its design. It doesn't mean the process of creating your own name set is.

Download (16.44 kB, 42 times downloaded)

Demo (1.33 MB, 4 times downloaded)

You basically need one thing, and that is a list of names. This list can be anything from human names to even cities and animals. You can even use five letter words if you wanted to. You can create this list in two ways, either as an array or as a text file, where each name is separated by a new line.

Now, you'll need to first create a dictionary object.

dictionary = TNG_Dictionary.new

Alternatively you could use optional parameters.

dictionary = TNG_Dictionary.new(min_length, max_length, start_min, dict...)

min_length and max_length define the minimum and maximum search length. What it basically does is stitch two name parts that originally followed eah other together. What the name generator does is splice each name in groups of any amount of characters between min_length and max_length, and for each name part stores what other name parts have followed.

start_min determines the minimum length of the first name part. When set to -1, this value would be min_length - 1.

If you have previously created dictionaries and want to easily merge the two name lists, you can also supply other dictionaries at the end. Do note that name parts are not being merged with the dictionary.

Next, add the names, using either method or both.

dictionary.add_names(array)
dictionary.add_file(filename)

After the names are added, the names need to be processed.

dictionary.process_names

Even after you've processed the names, though, you can still add names to be processed. You do still need to process the names again though, although it will skip over those that already have been processed.

Finally, to generate names, you could call the next method. All parameters are optional.

dictionary.generate_name(max_namelength, min_namelength, rng, names_list)

max_namelength and min_namelength define the minimum and maximum length of the name. They default to 10 and 3 respectively. rng is a Random object. If set to nil, it will create a new instance of Random. names_list is an array where the generated name will be stored. When left empty, it will use the generated names list inside the dictionary. This list can be retrieved and cleared.

dictionary.generated_names
dictionary.clear_generated
#==============================================================================
# 
# GaryCXJk - TriNameGenVXA v1.00
# * Last Updated: 2013.06.30
# * Level: Medium
# * Requires: N/A
# 
#==============================================================================

$imported = {} if $imported.nil?
$imported["CXJ-TriNameGenVXA"] = true

#==============================================================================
#
# Changelog:
#
#------------------------------------------------------------------------------
# 2013.06.30 - v1.00
#
# * Initial release
#
#==============================================================================
#
# Back when I was still a Minecraft modder I wanted to create something that
# would be very useful to content creators, both Minecraft modders and regular
# Java programmers. I originally created a name generator which was pretty
# complicated.
#
# A year or two later I decided to simplify the script a little, and decided
# to just start from scratch. When creating the first name generator, I had
# already heard something about Markov Chains, so I decided to just do whatever
# the hell I wanted (I don't need no stinkin' Markov Chains). Well, turns out
# that this name generator might be more Markov Chain-y than I thought.
#
# So yeah, here's my very simple name generator. Mind you, it's simple in its
# design. It doesn't mean the process of creating your own name set is.
#
#==============================================================================
#
# Installation:
#
# Make sure to put this below Materials, but above Main Process.
#
#==============================================================================
#
# Usage:
#
# You basically need one thing, and that is a list of names. This list can be
# anything from human names to even cities and animals. You can even use
# five letter words if you wanted to. You can create this list in two ways,
# either as an array or as a text file, where each name is separated by a new
# line.
#
# Now, you'll need to first create a dictionary object.
#
# dictionary = TNG_Dictionary.new
#
# Alternatively you could use optional parameters.
#
# dictionary = TNG_Dictionary.new(min_length, max_length, start_min, dict...)
#
# min_length and max_length define the minimum and maximum search length.
# What it basically does is stitch two name parts that originally followed
# eah other together. What the name generator does is splice each name in
# groups of any amount of characters between min_length and max_length, and
# for each name part stores what other name parts have followed.
#
# start_min determines the minimum length of the first name part. When set to
# -1, this value would be min_length - 1.
#
# If you have previously created dictionaries and want to easily merge the two
# name lists, you can also supply other dictionaries at the end. Do note that
# name parts are not being merged with the dictionary.
#
# Next, add the names, using either method or both.
#
# dictionary.add_names(array)
# dictionary.add_file(filename)
#
# After the names are added, the names need to be processed.
#
# dictionary.process_names
#
# Even after you've processed the names, though, you can still add names to be
# processed. You do still need to process the names again though, although it
# will skip over those that already have been processed.
#
# Finally, to generate names, you could call the next method. All parameters
# are optional.
#
# dictionary.generate_name(max_namelength, min_namelength, rng, names_list)
#
# max_namelength and min_namelength define the minimum and maximum length of
# the name. They default to 10 and 3 respectively. rng is a Random object.
# If set to nil, it will create a new instance of Random. names_list is an
# array where the generated name will be stored. When left empty, it will
# use the generated names list inside the dictionary. This list can be
# retrieved and cleared.
#
# dictionary.generated_names
# dictionary.clear_generated
#
#==============================================================================
#
# License:
#
#            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
#                    Version 2, December 2004
#
# Copyright (C) 2013 Sam Hocevar <sam@hocevar.net>
#
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
#            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
#   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
#  0. You just DO WHAT THE FUCK YOU WANT TO.
#
# See http://www.wtfpl.net/ for more details.
#
#------------------------------------------------------------------------------
# Extra notes:
#
# This license was picked due to the fact that in my opinion this script
# shouldn't be restricted by the creative commons license, which mostly still
# requires you to attribute the content to the original creator. I also feel
# like this script could help others understand certain mechanics and can
# learn from it without the fear of violating a license due to similar coding.
#
# You can still give credits if you want though, and are free to pick the
# following names when you give credit:
#
# * GaryCXJk
# * Gary A.M. Kertopermono
# * G.A.M. Kertopermono
# * GARYCXJK
#
# To make it clear, this license allows you to DO WHAT THE FUCK YOU WANT TO,
# which means you can use it in commercial as well as non-commercial products,
# you can modify it, redistribute it, make toilet paper out of it, sell it on
# eBay and win a presidential election with it. But it's mostly for making
# games. There are no restrictions, no need to attribute regardless of the
# aount of modifications made, you are allowed to remove all references to me,
# you are allowed to change the license, although that's pretty much a dick
# move (actually, I'm not sure if you can change the license or not, but let's
# just not be dicks here, mmm'kay?), you are allowed to directly sell this
# script or monetize on it on your own site.
#
# This script was originally hosted on:
# http://area91.multiverseworks.com
#
#==============================================================================
#
# The code below should not be altered unless you know what you're doing.
#
#==============================================================================

#==============================================================================
# ** TNG_Part
#------------------------------------------------------------------------------
#  This defines a name part for TriNameGen.
#==============================================================================

class TNG_Part
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize(part_string)
    @part_string = part_string
  end

  #--------------------------------------------------------------------------
  # * Define if this name part can end the name
  #--------------------------------------------------------------------------
  def set_can_end(can_end)
    @can_end = can_end
  end
  
  #--------------------------------------------------------------------------
  # * Determine if this name part can end the name
  #--------------------------------------------------------------------------
  def can_end?
    @can_end = false if @can_end.nil?
    return @can_end
  end
  
  #--------------------------------------------------------------------------
  # * Add a name part as a possible follow-up
  #--------------------------------------------------------------------------
  def add_part(part)
    @next_parts||= []
    @next_parts.push(part) unless @next_parts.include?(part)
  end
  
  #--------------------------------------------------------------------------
  # * Gets the amount of name parts that can follow
  #--------------------------------------------------------------------------
  def length
    return @next_parts.size
  end
  
  #--------------------------------------------------------------------------
  # * Returns a copy of the list of follow-up parts
  #--------------------------------------------------------------------------
  def get_parts
    @next_parts||= []
    return Array.new(@next_parts)
  end
  
  #--------------------------------------------------------------------------
  # * Gets a copy of the part string
  #--------------------------------------------------------------------------
  def part_string
    return String.new(@part_string)
  end
end

#==============================================================================
# ** TNG_Dictionary
#------------------------------------------------------------------------------
#  This defines a dictionary for TriNameGen. This is basically the main class
#  you'll be working with.
#==============================================================================

class TNG_Dictionary
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize(min_length = 2, max_length = 3, start_min = 1, *dictionary)
    @unprocessed_names = []
    @processed_names = []
    @generated_names = []
    @start_parts = []
    @part_dictionary = {}

    @min_length = (min_length <= 0 ? 2 : min_length)
    @max_length = (max_length < @min_length ? (@min_length == 2 ? 3 : @min_length) : max_length)
    @start_min = (start_min > 0 ? [start_min, @min_length].min : @min_length - 1)
    
    add_dictionary(dictionary) unless dictionary.nil? || dictionary.empty?
  end
  
  #--------------------------------------------------------------------------
  # * Add the names of other dictionaries into this dictionary
  #--------------------------------------------------------------------------
  def add_dictionary(*dictionaries)
    dictionaries.each do |dictionary|
      add_names(dictionary.base_names)
    end
  end
  
  #--------------------------------------------------------------------------
  # * Add names to the unprocessed names list in this dictionary
  #--------------------------------------------------------------------------
  def add_names(names)
    names.each do |name|
      next if names.empty?
      @unprocessed_names.push(name) unless base_names.include?(name)
    end
  end
  
  #--------------------------------------------------------------------------
  # * Add names to the unprocessed names list in this dictionary from a
  #     plaintext file
  #--------------------------------------------------------------------------
  def add_file(filename)
    File.open(filename, "rb") do |f|
      data = f.read.split(/[\r\n]+/)
    end
    add_names(data)
  end
  
  #--------------------------------------------------------------------------
  # * Get all names used to generate this library (both used and unused)
  #--------------------------------------------------------------------------
  def base_names
    return @unprocessed_names + @processed_names
  end
  
  #--------------------------------------------------------------------------
  # * Process the names list
  #--------------------------------------------------------------------------
  def process_names
    while @unprocessed_names.size > 0
      name = @unprocessed_names.shift
      process_name(name)
      @processed_names.push(name)
    end
  end
  
  #--------------------------------------------------------------------------
  # * Process the current name
  #--------------------------------------------------------------------------
  def process_name(name)
    proc = [[[@start_min, name.size].min, name, nil]]
    while proc.size > 0
      while proc.size > 0 && proc[-1][0] > [proc[-1][1].size, @max_length].min
        proc.pop
      end
      next unless proc.size > 0
      part_string = proc[-1][1][0, proc[-1][0]]
      if @part_dictionary.include?(part_string)
        part = @part_dictionary[part_string]
      else
        part = TNG_Part.new(part_string)
        @part_dictionary[part_string] = part
      end
      if !proc[-1][2].nil?
        proc[-1][2].add_part(part)
      else
        @start_parts.push(part) unless @start_parts.include?(part)
      end
      if proc[-1][1].size == proc[-1][0]
        part.set_can_end(true)
        proc[-1][0]+= 1
      else
        name = proc[-1][1][part_string.size, proc[-1][1].size - part_string.size]
        proc.push([[@min_length, name.size].min, name, part])
        proc[-2][0]+= 1
      end
    end
  end
  
  #--------------------------------------------------------------------------
  # * Get all parts
  #--------------------------------------------------------------------------
  def get_parts
    return Array.new(@part_dictionary.values)
  end
  
  #--------------------------------------------------------------------------
  # * Get all start parts
  #--------------------------------------------------------------------------
  def start_parts
    return Array.new(@start_parts)
  end
  
  #--------------------------------------------------------------------------
  # * Generate all possible names
  #     Only advisable during development or to pre-generate a complete
  #     names list
  #--------------------------------------------------------------------------
  def generate_all_names(max_namelength = 10, min_namelength = 3, names_list = @generated_names)
    min_namelength = 3 if min_namelength < 2
    max_namelength = min_namelength if max_namelength < min_namelength
    proc = [[start_parts, ""]]
    while !proc.empty?
      if proc[-1][0].empty?
        proc.pop
        next
      end
      part = proc[-1][0].shift
      name = proc[-1][1] + part.part_string
      if ((min_namelength)..max_namelength).include?(name.size) && part.can_end? && !names_list.include?(name)
        names_list.push(name)
      end
      next if name.size >= max_namelength
      index = [@min_length, name.size].min
      next_parts = []
      while index <= [@max_length, name.size].min
        unless @part_dictionary.include?(name[-index, index])
          index+= 1
          next
        end
        parts = @part_dictionary[name[-index, index]].get_parts
        index+= 1
        next if parts.empty?
        parts.each do |cpart|
          next if (name + cpart.part_string).size > max_namelength || next_parts.include?(cpart)
          next_parts.push(cpart)
        end
      end
      proc.push([next_parts, name])
    end
  end
  
  #--------------------------------------------------------------------------
  # * Generate name
  #--------------------------------------------------------------------------
  def generate_name(max_namelength = 10, min_namelength = 3, rng = nil, names_list = @generated_names)
    min_namelength = 3 if min_namelength < 2
    max_namelength = min_namelength if max_namelength < min_namelength
    rng = Random.new if rng.nil?
    proc = [[start_parts, ""]]
    while !proc.empty?
      if proc[-1][0].empty?
        proc.pop
        next
      end
      index = rng.rand(proc[-1][0].size)
      part = proc[-1][0].delete_at(index)
      name = proc[-1][1] + part.part_string
      rndn = rng.rand(2)
      if ((min_namelength)..max_namelength).include?(name.size) && part.can_end? && !names_list.include?(name)
        if rndn == 0
          names_list.push(name)
          return name
        end
        proc[-1][0].push(part)
      end
      next if name.size >= max_namelength
      index = [@min_length, name.size].min
      next_parts = []
      while index <= [@max_length, name.size].min
        next unless @part_dictionary.include?(name[-index, index])
        parts = @part_dictionary[name[-index, index]].get_parts
        index+= 1
        next if parts.empty?
        parts.each do |cpart|
          next if (name + cpart.part_string).size > max_namelength || next_parts.include?(cpart)
          next_parts.push(cpart)
        end
      end
      proc.push([next_parts, name])
    end
    return ""
  end
  
  #--------------------------------------------------------------------------
  # * Clear the default list of generated names
  #--------------------------------------------------------------------------
  def clear_generated
    @generated_names.clear
  end
  
  def generated_names
    return Array.new(@generated_names)
  end
end
                                

Creator: GaryCXJk

Release date: 2013-06-30

Downloads: 42

License: DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE