Ruby Fnord Generator - Part Two
In Part 1, I took you through the beginnings of the Fnord generator up to the point we could create Fnords using random words and optional parts of speech. This gave us a class Fnord which contained the following functions.
require "fnord_words.rb" #Arrays of NOUNS, ADJECTIVES, PLACES etc.
class Fnord
def self.true?(chance) (chance==0 or rand(chance)<1) end
def self.build(string_array,chance=0) true?(chance) ? string_array[rand(string_array.length)] : "" end
def self.in_place(chance=0) true?(chance) ? "in #{build(PLACES)}" : "" end
def self.adjective(chance=0) build(ADJECTIVES, chance) end
def self.name(chance=0) build(NAMES, chance) end
def self.place(chance=0) build(PLACES, chance) end
def self.preposition(chance=0) build(PREPOSITIONS, chance) end
def self.action(chance=0) build(ACTIONS, chance) end
def self.pronoun(chance=0) build(PRONOUNS, chance) end
def self.intro(chance=0) build(INTROS, chance) end
def self.noun(chance=0) build(NOUNS, chance) end
end
I moved the word lists into their own file “fnord_words.rb”. Since these are separately generated and updated by SJ Games, it made sense to have them as separate files. I thought of writing a quick Perl->Ruby conversion to allow for the files to be dropped in, but since manually updating requires making only small changes to the file, I decided to leave this as an exercise for a later date.
I was using the normal
msg=case rand(14) #Return generated Fnord as a string
when 0: "The #{adjective(2)} #{noun} #{in_place(5)} is #{adjective}."
when 1: "#{name} #{action} the #{adjective} #{noun} and the #{adjective} #{noun}."
when 2: "The #{noun} from #{place} will go to #{place}."
when 3: "#{name} must take the #{adjective} #{noun} from #{place}."
when 4: "#{place} is #{adjective} and the #{noun} is #{adjective}."
.
.
.
when 13: "A #{noun} from #{place} #{action} the #{adjective(2)} #{adjective(5)} #{noun}."
end
and I figured I could move all of the data including the SENTENCES into a template to make it even easier to update. This required two things to happen.
- All of the parts of speech required are embedded in the string.
- The parts of speech can only be evaluated at runtime when the method is called.
We’d already achieved the first, and in order to have the second all that was needed was to move the SENTENCE strings into single quotes, such as
'#{intro(5)} the #{adjective(2)} #{adjective(2)} #{noun} #{action} the #{adjective(2)} #{adjective(2)} #{noun} #{in_place(2)}.'
In order to execute this later, you use the eval function to perform substitutions. Ignore normalize for now, it’s only to remove extra spaces and fixup capitalization.
def self.sentence(chance=0)
normalize(eval('"'+build(SENTENCES,chance)+'"'))
end
private
def self.normalize(msg)
while msg.include?(" ")
msg.gsub!(/ /," ")
end
msg.gsub!(/^ /,"")
msg.gsub!(/ ./,".")
msg.gsub!(/[s^]([aA])s([aeiouhy])/,' 1n 2')
msg[0]=msg[0,1].upcase
while msg[/([^A-Z][.!?:])s+([a-z])/]
msg[/([^A-Z][.!?:])s+([a-z])/]="#{$1} #{$2.upcase}"
end
msg
end
and voila. Sentences can be constructed by calling
print Fnord.sentence
We are still missing the word lists. You can grab the latest updated Perl version from SJ Games, or, if you are feeling really lazy, download my updated Ruby code from my website and grab my personalized Rubyised word lists from here. They aren’t strictly the Fnords word list, so you may prefer the SJ Games ones, but they are in the correct format.
If you’ve gone down the Perl wordlist route, you won’t have found the SENTENCES array, which you need for my code to work. You can either modify my oroginal code, or use the expanded versions below.
#Note. Parts of speech are coded in the main application and MUST NOT be expanded here. Hence only ' rather then " can be used.
SENTENCES=[
'#{intro(5)} #{name} #{action} #{name} and #{pronoun} #{adjective(2)} #{adjective(2)} #{noun}.',
'#{intro(5)} #{name} #{action} the #{adjective(2)} #{adjective(2)} #{noun} and the #{adjective(2)} #{adjective(2)} #{noun} #{in_place(2)}.',
'#{intro(5)} #{name} #{action} the #{adjective(2)} #{adjective(2)} #{noun} of #{place}.',
'#{intro(5)} #{name} #{preposition} #{place} and #{action} the #{adjective(2)} #{adjective(2)} #{noun}.',
'#{intro(5)} #{name} #{preposition} #{place} for the #{adjective(2)} #{adjective} #{noun}.',
'#{intro(5)} #{name} is the #{adjective(2)} #{adjective(2)} #{noun}; #{name} #{preposition} #{place}.',
'#{intro(5)} #{name} must take the #{adjective(2)} #{adjective(2)} #{noun} from #{place}.',
'#{intro(5)} #{name} takes #{pronoun} #{adjective(2)} #{adjective(2)} #{noun} and #{preposition} #{place}.',
'#{intro(5)} #{place} is #{adjective} and the #{noun} is #{adjective}.',
'#{intro(5)} a #{adjective(2)} #{adjective(2)} #{noun} from #{place} #{action} the #{adjective(2)} #{adjective(2)} #{noun}.',
'#{intro(5)} the #{adjective(2)} #{adjective(2)} #{noun} #{action} the #{adjective(2)} #{adjective(2)} #{noun} #{in_place(2)}.',
'#{intro(5)} the #{adjective(2)} #{adjective(2)} #{noun} #{in_place(2)} is #{adjective}.',
'#{intro(5)} the #{adjective(2)} #{adjective(2)} #{noun} from #{place} will go to #{place}.',
'#{intro(5)} you must meet #{name} at #{place} and get the #{adjective(2)} #{adjective(2)} #{noun}.'
]
Enjoy
Trackbacks
Use this link to trackback from your own site.
Comments
You must be logged in to leave a response.