From: Boris Prinz Date: 2006-10-02T04:51:30+09:00 Subject: [Solution][QUIZ] Story Generator (#96) Little Red-Cap revisited Once upon a time little red-cap opened the stomach of the huntsman. The huntsman thought to himself "what a tender young creature". Soon he gave a pair of scissors to grandmother. Little red-cap went into the wood. And so the huntsman swallowed up the wolf. Grandmother gave a piece of cake to the wolf. Mother ran straight to grandmother's house. And so grandmother was on her guard although the wolf was not afraid of grandmother until mother swallowed up the wolf. Grandmother was not afraid of herself. The wolf gave a pair of scissors to the huntsman. Little red-cap fell asleep. She said: "oh, the huntsman, what big ears you have". The End. ### stories.rb require 'enumerator' class Base def self.constructor *args attr_accessor(*args) define_method :initialize do |*values| (0...args.size).each do |i| self.instance_variable_set("@#{args[i]}", values[i]) end end end def to_s @name end end class Character < Base constructor :name, :gender end class Action < Base constructor :name, :objects_or_types end class Item < Base constructor :name end class Place < Base constructor :name end class PronounBase < Base constructor :gender class << self attr_accessor :cases end def to_s cases = self.class.cases @gender == :female ? cases[0] : cases[1] end end class PossessiveAdjective < PronounBase self.cases = ['her', 'his'] end class Pronoun < PronounBase self.cases = ['she', 'he'] end class ReflexivePronoun < PronounBase self.cases = ['herself', 'himself'] end class Bridge < Base constructor :name end class Entities def initialize klass @entities = [] @klass = klass yield(self) end def create *args @entities << @klass.new(*args) end def pick @entities[rand(@entities.size)] end end CAST = Entities.new(Character) do |c| c.create 'little red-cap', :female c.create 'mother', :female c.create 'grandmother', :female c.create 'the wolf', :male c.create 'the huntsman', :male end ACTIONS = Entities.new(Action) do |a| a.create 'met', [Character] a.create 'gave', [Item, 'to', Character] a.create 'took', [Item] a.create 'ate', [Item] a.create 'saw', [Item] a.create 'told', [Character, 'to be careful'] a.create 'lived in', [Place] a.create 'lied in', [Place] a.create 'went into', [Place] a.create 'ran straight to', [Place] a.create 'raised', [PossessiveAdjective, 'eyes'] a.create 'was on', [PossessiveAdjective, 'guard'] a.create 'thought to', [ReflexivePronoun, '"what a tender young creature"'] a.create 'swallowed up', [Character] a.create 'opened the stomach of', [Character] a.create 'looked very strange', [] a.create 'was delighted', [] a.create 'fell asleep', [] a.create 'snored very loud', [] a.create 'said: "oh,', [Character, ', what big ears you have"'] a.create 'was not afraid of', [Character] a.create 'walked for a short time by the side of', [Character] a.create 'got deeper and deeper into', [Place] end ITEMS = Entities.new(Item) do |i| i.create 'a piece of cake' i.create 'a bottle of wine' i.create 'pretty flowers' i.create 'a pair of scissors' end PLACES = Entities.new(Place) do |p| p.create 'the wood' p.create 'the village' p.create 'bed' p.create "grandmother's house" p.create 'the room' end BRIDGES = Entities.new(Bridge) do |b| 5.times{b.create '.'} b.create ', because' b.create ', while' b.create '. Later' b.create '. Then' b.create '. The next day' b.create '. And so' b.create ', but' b.create '. Soon' b.create ', and' b.create ' until' b.create ' although' end ALL = { Character => CAST, Action => ACTIONS, Place => PLACES, Item => ITEMS } class Sentence attr_accessor :subject def initialize @subject = CAST.pick @verb = ACTIONS.pick @objects = [] @verb.objects_or_types.each do |obj_or_type| if String === obj_or_type @objects << obj_or_type else if obj_or_type == PossessiveAdjective or obj_or_type == ReflexivePronoun @objects << obj_or_type.new(@subject.gender) else thingy = ALL[obj_or_type].pick thingy = ReflexivePronoun.new(thingy.gender) if thingy == @subject @objects << thingy end end end end def to_s [@subject, @verb, @objects].flatten.map{|e| e.to_s}.join(' ') end end class Story def initialize @sentences = [] 1.upto(rand(10)+10) do @sentences << Sentence.new end combine_subjects end # When the last sentence had the same subject, replace subject with 'he' or 'she': def combine_subjects @sentences.each_cons(2) do |s1, s2| if s1.subject == s2.subject s2.subject = Pronoun.new(s1.subject.gender) end end end # Combine sentences to a story: def to_s text = 'Once upon a time ' + @sentences[0].to_s @sentences[1..-1].each do |sentence| bridge = BRIDGES.pick.to_s text += bridge + ' ' + (bridge[-1,1] == '.' ? sentence.to_s.capitalize : sentence.to_s) end text.gsub!(/ ,/, ',') # a little clean-up text.gsub!(/(.{70,80}) /, "\\1\n") text + ".\nThe End.\n" end end puts Story.new.to_s