Re: Story Generator (#96)

My submission might have been scrubbed because I included a ZIP file,
so here it is again…

On 10/1/06, James Edward G. II [email protected] wrote:

Wow, I can’t wait to see that generator!

James Edward G. II

Ok!

It’s a bit long and not particularly smart, but here it is. The idea
was to make a sort of Ruby Choose-Your-Own adventure book, where the
computer chooses the adventure. By using variable names which made
sense in the context of the story, I could get the generator to
substitute random alternatives for nouns etc. while leaving the story
failrly easy to follow in code.

Reopening the Array class made multiple decisions very easy to program

  • man I love Ruby! In the interim testing I see my
    unique-item-from-array
    helper is not working because the arrays are not static. This makes for
    some stories with duplicate names, which isn’t nice.

I had some trouble coming up with good names for individual paragraphs
in the story tree, if you look you may see what I mean.

You have to run “story_generator.rb”.

Les

------------------ Another run --------------------------------

A long time ago in the land of Middle-Earth there was a loyal Knight
named
Sweetcheeks. Sweetcheeks lived there with her interesting Eyebrow
Derick, and the two were pals.

Middle-Earth was in uproar because the Necronomicon, the book of the
dead, had been stolen
by the smelly witch Smythe. Smythe had hidden the book in the Batpoo
Cave and it’s presence there
would raise the dastardly Armies of Darkness at midnight!

Sweetcheeks’s plan was to recover the book of the dead and outwit the
Armies of Darkness, with Derick serving as her navigator.
While Derick memorized the layout of the Batpoo Cave, Sweetcheeks
memorized the magical words needed to safely
retrieve the Necronomicon.

Sweetcheeks and Derick spent days exploring the Batpoo Cave, stumbling
through the damp undergrowth and biting insects.
When they finally found the Necronomicon, Sweetcheeks prepared to say
the secret phrase - but could not remember it!
‘Flitzen!’ she said, pretending to remember. With a shudder the earth
split open and the Armies of Darkness rose!

Sweetcheeks and Derick beat a hasty retreat through the Batpoo Cave,
but the elders of Middle-Earth were not interested in their
excuses and drove them out to face the enemy!
In a final desperate standoff the friends remembered the magic words
and used the secret powers of the Necronomicon to defeat the Armies of
Darkness!

THE END.

--------------------------- THE CODE ----------------------------------

require 'helper' require 'phrase_generator' require 'character'

class StoryGenerator
def initialize(phraseGenerator, mainCharacter, subCharacter)
@pg = phraseGenerator
@mc = mainCharacter
@sc = subCharacter

getWords

end

def introPhrase
[“A long time ago”, “In a parallel universe”, “On the planet of
Albanara”].any
end

def getWords
@once = introPhrase
@nod = @pg.landName
@brave = @pg.goodAdjective
@loyal = @pg.goodAdjective
@knight = @pg.title
@friends = @pg.bondingPhrase

  @john_old = @mc.name
  @his = @mc.hisHer
  @him = @mc.himHer
  @he = @mc.heShe

  @dog = @sc.species
  @skip = @sc.name

  @consternation = @pg.consternation
  @evil = @pg.evilAdjective
  @scary = @pg.evilAdjective

  @dragon = @pg.evilSpecies
  @smarg = @pg.evilName

  @clever = @pg.clever
  @rent, @ribbons = @pg.outcome
  @sword = @pg.cuttingWeapon
  @whirling = @pg.distraction

  @armies = @pg.evilArmy
  @forest = @pg.hidingPlace
  @necronomicon, @magicalBook = @pg.mysteriousArtifact
  @abracadabra = @pg.magicWord

  @scardyPants = [@john_old, @skip].any
  @braveSirRobin = ([@john_old, @skip] - [@scardyPants]).to_s

  @mummydesc, @mummy = @pg.magicalRescuer

end

def story
“#{@once} in the land of #{@nod} there was a #{@brave} #{@knight}
named\n” +
"#{@john_old}. #{@john_old} lived there with #{@his} #{@loyal} #{@dog}
#{@skip}, " +
“and the two were #{@friends}.\n\n” +
[premiseBattle, premiseNecro].any
end

def premiseBattle
“The land of #{@nod} was in #{@consternation} because of the
#{@evil}\n” +
“influence of a #{@scary} #{@dragon} named #{@smarg}.\n\n” +
[distactPlanBattle, catapultPlanBattle].any
end

def distactPlanBattle
“#{@john_old} and #{@skip} came up with a #{@clever} plan - #{@skip}
would\n” +
“distract the #{@dragon}, giving #{@john_old} the opportunity to
attack unseen.\n\n” +
executionBattle
end

def catapultPlanBattle
“#{@john_old} and #{@skip} came up with a #{@clever} plan - #{@skip}
would lure the\n” +
“#{@dragon} from it’s lair while #{@john_old} would use one of
#{@nod}'s catapults to blast\n” +
“it from a safe distance.\n\n” +
catapultPlanOutcome
end

def catapultPlanOutcome
“#{@skip} bravely taunted the #{@dragon} and when it was in range,
#{@john_old} fired the catapult.\n” +
[“The ball of flaming pitch struck the side of the #{@dragon} and
enveloped it in flames! Before\n” +
"long, nothing was left og the #{@scary} #{@dragon} was a pile of
cinders. " + returnToNod1,

 "The ball of flaming pitch struck #{@skip} squarely between the

eyes! Before anyone could react,\n" +
“#{@skip} had disappeared in a ball of flame. #{@john_old} stared in
stunned silence, but the #{@dragon},\n” +
“sensing an opportunity, blasted #{@john_old} with it’s magic.\n\n” +
failedCatapult,
].any
end

def failedCatapult
“#{@john_old} was crumpled by the blast, and that was the tragic end
of the two friends. The #{@dragon}'s\n” +
“reign of terror continued unabated over the unfortunate land of
#{@nod} for many years thereafter.\n\n”
end

def executionBattle
“They rode bravely into battle and #{@john_old} #{@rent} the #{@scary}
#{@dragon} in\n” +
“#{@ribbons} with #{@his} #{@sword} while #{@skip} created a
diversion by #{@whirling}!\n” +
resultBattle
end

def resultBattle
[“#{@john_old} and #{@skip} became the heroes of #{@nod} and lived
happily ever after.\n\n”,
“#{@john_old} and #{@skip} became well-reknowned in #{@nod} and lived
to be old and wise.\n\n”,
“The wise friends were the heroes of the day but were soon
forgotten by the ungrateful citizens of #{@nod}.\n\n”,
“#{@john_old} and #{@skip} left the land of #{@nod} to seek fame and
fortune and great pizza!\n\n”].any
end

def premiseNecro
“#{@nod} was in #{@consternation} because the #{@necronomicon},
the #{@magicalBook}, had been stolen\n” +
“by the #{@scary} #{@dragon} #{@smarg}. #{@smarg} had hidden the
book in the #{@forest} and it’s presence there\n” +
“would raise the #{@evil} #{@armies} at midnight!\n\n” +
planNecro
end

def planNecro
“#{@john_old}'s plan was to recover the #{@magicalBook} and outwit the
#{@armies}, with #{@skip} serving as #{@his} navigator.\n” +
“While #{@skip} memorized the layout of the #{@forest}, #{@john_old}
memorized the magical words needed to safely\n” +
“retrieve the #{@necronomicon}.\n\n” +
[executionNecro1, executionNecro2].any
end

def executionNecro1
“The two friends set off to the #{@forest} to find the
#{@necronomicon}. They searched for many hours, fighting\n” +
“through the tangled vegetation and being scratched by long thorns
and briars. Deep in the darkest part of #{@forest}\n” +
“they finally found the #{@necronomicon}. #{@john_old} spoke the magic
phrase perfectly and the #{@magicalBook} flashed\n” +
“into #{@his} hands… \n\n” +
[resultNecro1, resultNecro2].any
end

def resultNecro1
“#{@john_old} was instantly subverted by the dark power of the magical
device! #{@he.capitalize} rose as the leader of the #{@armies}\n” +
“in siege against the land of #{@nod}, burning it to the
ground.\n\n”
end

def resultNecro2
“#{@john_old}'s personality was instantly joined with the magical
device, moulding it’s power for good. #{@he.capitalize} rose in great
power\n” +
“and with trusty #{@skip} by #{@his} side, #{@he} singlehandedly
destroyed the #{@armies}!\n\n” +
[returnToNod1, returnToNod2].any
end

def returnToNod1
“Returning to #{@nod}, #{@john_old} and #{@skip} were hailed as heroes
and crowned rulers of the land. They ruled justly\n” +
“for many years in the future.\n\n”
end

def returnToNod2
“Returning to #{@nod} however, #{@john_old} was subverted by #{@his}
newfound power. When the city elders would not crown #{@him} ruler,\n”
+
“#{@he} tried to take power from them. After a bitter war, #{@he}
was overcome and killed by the people of #{@nod}, led by #{@his}\n” +
“old friend #{@skip}.\n\n”
end

def executionNecro2
“#{@john_old} and #{@skip} spent hours exploring the #{@forest},
stumbling through the damp undergrowth and biting insects (sic).\n” +
“When they finally found the #{@necronomicon}, #{@john_old} prepared
to say the secret phrase - but could not remember it!\n” +
“‘#{@abracadabra}!’ #{@he} said, pretending to remember. With a
shudder the earth split open and the #{@armies} rose!\n\n” +
resultNecro3
end

def resultNecro3
[“#{@john_old} and #{@skip} beat a hasty retreat through the
#{@forest}, but the elders of #{@nod} were not interested in their\n”
+
“excuses and drove them out to face the enemy!\n” +
"In a final desperate standoff the friends " + outcomeNecro,

  "#{@john_old} and #{@skip} ran themselves ragged through the

brambles but the #{@armies} were gaining on them. Eventually\n" +
"they tumbled down an embankment and stumbled on " +
salvationNecro
].any
end

def salvationNecro
“a #{@mummydesc}!\n” +
“#{@scardyPants} cowered in fear, but #{@braveSirRobin} quickly
started flattering their potential ally.\n\n” +
salvationOutcomeNecro
end

def salvationOutcomeNecro
[
“The #{@mummy} was so grateful to have found friends after so
many lonely years in the #{@forest} that he accepted their request\n”
+
“and rose in their defense. He singlehandedly crushed the
#{@armies} with powerful magic. For years the friends lived on
together\n” +
“in the #{@forest}, the #{@mummy} learning to adapt to #{@skip}
and #{@john_old} and them learning to love the #{@forest}.\n\n”,

  "The #{@mummy} was touched but not fooled. Annoyed by their

pleading, he blasted the two friends with his magic and then\n" +
“joined the evil #{@armies} to bring devastation to the whole
land of #{@nod}.\n\n”
].any
end

def outcomeNecro
[“were crushed by the evil minions as they marched unopposed over
the whole land of #{@nod}.\n\n”,
“remembered the magic words and used the secret powers of the
#{@necronomicon} to defeat the #{@armies}!\n\n”,
“turned tail and ran.\n” +
“Skirting the land of #{@nod} they escaped to the kingdom of
Darrel, leaving #{@nod} to fend for itself.\n\n”
].any
end

def generate
response = story
response << “THE END.\n\n”
end
end

pg = PhraseGenerator.new

characters = []
2.times do
name, hisHer, heShe, himHer = pg.goodName
characters << Character.new(name, hisHer, heShe, himHer,
pg.goodAdjective, pg.goodSpecies)
end

sg = StoryGenerator.new(pg, characters[0], characters[1])
puts sg.generate

</story_generator.rb>

<character.rb>
class Character
attr_reader :name, :hisHer, :heShe, :himHer, :adjective, :species

def initialize(name, hisHer, heShe, himHer, adjective, species)
@name = name
@hisHer = hisHer
@heShe = heShe
@himHer = himHer
@adjective = adjective
@species = species
end
end
</character.rb>

<helper.rb>
class Array
#Try to get a unique response
def any
@anylist = [] if !@anylist
response = nil
(self.length*3).times do
response = self[rand(length)]
break if !(@anylist.include? response)
end
@anylist << response
response
end
end
</helper.rb>

<phrase_generator.rb>
require ‘helper’

class PhraseGenerator
def goodName
response = []
if (rand(2)==1)
response << %W[Skip Derick Brian Kevin Brightbritches
Lightleaves].any
response << “his”
response << “he”
response << “him”
else
response << %W[Goldilocks Cindy Sweetcheeks Barbara Liselle].any
response << “her”
response << “she”
response << “her”
end
response
end

def landName
  %W[Dwenthym Narnia Atlantis Middle-Earth].any
end

def goodAdjective
  %W[brave hardcore dedicated loyal honest tireless cool 

interesting].any
end

def title
  %W[Knight Accountant Duke Stable-keep Botanist].any
end

def goodSpecies
  %W[Aunt Eyebrow Donkey Armadillo Jellyfish Dog Page Friend].any
end

def consternation
  (%W[consternation uproar mayhem] + ["a bind"]).any
end

def evilName
  %W[Smarg Argonagas Bel Smythe Zoot].any
end

def evilAdjective
  %W[dastardly despicable evil smelly repulsive scary terrifying

horrific].any
end

def evilSpecies
  %W[dragon morgawr witch troll].any
end

def clever
  %W[clever daring brave smile smart diabolical].any
end

def outcome
  [
    %W[rent ribbons],
    %W[sliced strips],
    ["stabbed", "the knees"],
  ].any
end

def cuttingWeapon
  ["powerful magic sword", "portable angle-grinder"].any
end

def distraction
  ["whirling like a Dervish", "prancing like a poodle",
    "rolling in the dirt", "screaming synonyms"].any
end

def princessName
  %W[Leia Arabella Liselle Diana Linda Jenna].any
end

def hidingPlace
  ["Dark Forest", "Stinky Swamp", "Batpoo Cave"].any
end

def evilArmy
  ["Armies of Darkness", "Hordes of Hell"].any
end

def mysteriousArtifact
  [
    ["Necronomicon", "book of the dead"],
    ["Sceptara", "magical Sceptre of Ra"]
  ].any
end

def magicWord
  %W[Flitzen Bratwurst Alacazam Avrocadavra].any
end

def magicalRescuer
  [
    ["massive stone Giant", "giant"],
    ["powerful magical Unicorn", "unicorn"],
    ["Mummy Lord", "mummy"]
  ].any
end

def bondingPhrase
  ["thick as thieves", "never apart", "always together", "secretly

lovers", “pals”].any
end
end
</phrase_generator.rb>

<test_helper.rb>
require ‘test/unit’ unless defined? $ZENTEST and $ZENTEST
require ‘helper’

class TestArray < Test::Unit::TestCase
def test_any
a = [1, 2, 3, 4, 5]

outOfBounds = false
100.times do
  any = a.any
  outOfBounds = true if !(a.include? any)
end
assert(!outOfBounds, "Item returned is not in the array")

end

def test_any_coverage
a = [1, 2, 3, 4, 5]

coverage = {}
count = 0
loop do
  any = a.any
  coverage[any] = 0
  break if coverage.keys.length == 5

  count += 1
  if count > 100
    assert(false, message="Possible random number problem,

coverage not achieved after 100 iterations")
return
end
end

assert(coverage.keys.length == 5)
assert(coverage.keys.inject{|a, b| a > b ? a : b} == 5) #max = 5
assert(coverage.keys.inject{|a, b| a < b ? a : b} == 1) #min = 1

end

def test_any_variance
a = [1, 2]
any1 = a.any
any2 = a.any

assert(any2 == 2) if any1 == 1
assert(any2 == 1) if any1 == 2

assert(a.include?(a.any))

end
end
</test_helper.rb>