------art_32547_16008079.1144636541192
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Here is my first ruby quiz solution submission. Thanks for posting
this one, it provided a fun break from my school projects.

I tried to make the code as general as possible, with variable order
of both words and letters. It uses a hash of arrays for storage. I was
planning on unifying the MarkovWords and MarkovLetters classes into
one, but decided against it, mostly to keep them simpler. These
examples use an english translation of The Odyssey to derive the text.


  Usage...

[brian / spica] [~/rubyquiz]
$ ruby markov.rb -h
Usage: ruby markov.rb [options] <filename>
  -h, --help         show this usage message
  -o, --order        set markov chain order
  -s, --sentences    set number of sentences to print
  -w, --words        set number of words to print
  -l, --letters      use letters as the basic unit


  Print 5 sentences of order 2, using words as the base unit...

[brian / spica] [~/rubyquiz]
$ ruby markov.rb -s 5 -o 2 ../etext/dyssy10.txt
My men came out of your wits? If Apollo and the whole world, neither
rich nor poor, who is handsome and clean built, whereas I am so lost
in a beautiful golden ewer, and poured it over with a lie; 'Neptune,'
said I, 'of escaping Charybdis, and at the base of her maids brought
the heifer down with my tears during the darkness of death itself. A
poor unfortunate tramp has come to pass." And Penelope answered,
"Stranger, you must have gone off to bring the contest to an end."
Melanthius lit the fire for her, but she wishes to hear the enchanting
sweetness of their grey hair.


  Print 1 sentence of order 1, using words as the base unit...

[brian / spica] [~/rubyquiz]
$ ruby markov.rb -s 1 -o 1 ../etext/dyssy10.txt
Proserpine had got into a mission to be scandalised at last of them,
and lay a hard task, no more fond of wind blew a man talked and will
leave their sport known that stalks about his wife, and the store for
he stretched out their own house, which I shall be willing to the
house to you, Telemachus.


  Print 50 words of order 3, using letters as the base unit...

[brian / spica] [~/rubyquiz]
$ ruby markov.rb -w 50 -o 3 -l ../etext/dyssy10.txt
the of it into beautiful nose kill as did ther people the wood and him
all the meanthrountry stilltrese ffere peak the the the eleide oly
with blooked ent back the himself over s his hey glarge tood welcomind
where and mannot been spoke aloud valitterince one of his


  Print 50 words of order 2, using letters as the base unit, with text
  from The Aeneid (latin version)...

[brian / spica] [~/rubyquiz]
$ ruby markov.rb -w 50 -o 2 -l ../etext/anidl10.txt
quora desi aras ta acerummarmallenstos es mihinus vade imurbethinc
plia caum turnit que re et sum fuit ade re restaeteri invicaviam
ceuctitur hos aectalisubsillo parmeis suntereffunc meo que
clachilliaeque mul rut moropula sonitotuspiumque terrequebraherautras
nos ad la ciem atque part dubstra repononibus comet ad num undo cisque
retrangeneferat simas obla




[brian / spica] [~/rubyquiz]
$ cat markov.rb
#!/usr/bin/ruby

class MarkovWords

  def initialize(filename, order)
    @order = order
    @words = Hash.new
    @state = Array.new(@order)
    previous = Array.new(@order)
    File.foreach(filename) do |line|
      line.split(/\s+/).each do |word|
        unless previous.include?(nil)
          p = previous.join(' ')
          unless @words.has_key?(p)
            @words[p] = Array.new
          end
          @words[p] << word
        end
        previous.shift
        previous.push(word)
      end
    end
  end

  def print_words(n = 50)
    word = next_word(true)
    1.upto(n) do |i|
      print word, i == n ? "\n" : " "
      word = next_word()
    end
    print "\n"
  end

  # sentences start with a capital or quoted capital and end with
  # punctuation or quoted punctuation
  def print_sentences(n = 5)
    sentences = 0
    word = next_word(true)
    while word !~ /^['"`]?[A-Z]/
      word = next_word()
    end
    begin
      print word
      if word =~ /[?!.]['"`]?$/
        sentences += 1
        if sentences == n
          print "\n"
        else
          print " "
        end
      else
        print " "
      end
      word = next_word()
    end until sentences == n
  end

  def next_word(restart = false)
    if restart or @state.include?(nil)
      key = @words.keys[rand(@words.length)]
      @state = key.split(/\s+/)
    end
    key ||= @state.join(' ')
    # restart if we hit a dead end, rare unless text is small
    if @words[key].nil?
      next_word(true)
    else
      word = @words[key][rand(@words[key].length)]
      @state.shift
      @state.push(word)
      word
    end
  end

end

class MarkovLetters

  def initialize(filename, order)
    @order = order
    @letters = Hash.new
    @state = Array.new(@order)
    previous = Array.new(@order)
    File.foreach(filename) do |line|
      line.strip!
      line << ' ' unless line.length == 0
      line.gsub!(/\s+/, ' ')
      line.gsub!(/[^a-z ]/, '')
      line.split(//).each do |letter|
        unless previous.include?(nil)
          p = previous.join('')
          unless @letters.has_key?(p)
            @letters[p] = Array.new
          end
          @letters[p] << letter
        end
        previous.shift
        previous.push(letter)
      end
    end
  end

  # words begin after a space and end before a space
  def print_words(n = 50)
    letter = next_letter(true)
    while letter != ' '
      letter = next_letter()
    end
    letter = next_letter()
    words = 0
    while words < n
      words += 1 if letter == ' '
      print letter
      letter = next_letter()
    end
    print "\n"
  end

  def next_letter(restart = false)
    if restart or @state.include?(nil)
      key = @letters.keys[rand(@letters.length)]
      @state = key.split(//)
    end
    key ||= @state.join('')
    # restart if we hit a dead end, rare unless text is small
    if @letters[key].nil?
      next_letter(true)
    else
      word = @letters[key][rand(@letters[key].length)]
      @state.shift
      @state.push(word)
      word
    end
  end

end

if $0 == __FILE__
  require 'getoptlong'

  def usage()
    $stderr.puts "Usage: ruby #{$0} [options] <filename>",
                 "  -h, --help         show this usage message",
                 "  -o, --order        set markov chain order",
                 "  -s, --sentences    set number of sentences to print",
                 "  -w, --words        set number of words to print",
                 "  -l, --letters      use letters as the basic unit"
  end

  order = 2
  sentences = 5
  words = nil
  letters = false

  opts = GetoptLong.new(["--help",      "-h", GetoptLong::NO_ARGUMENT],
                        ["--order",     "-o", GetoptLong::REQUIRED_ARGUMENT],
                        ["--sentences", "-s", GetoptLong::REQUIRED_ARGUMENT],
                        ["--words",     "-w", GetoptLong::REQUIRED_ARGUMENT],
                        ["--letters",   "-l", GetoptLong::NO_ARGUMENT])

  opts.each do |opt, arg|
    case opt
    when "--help"
      usage
      exit 0
    when "--order"
      order = arg.to_i
    when "--sentences"
      sentences = arg.to_i
      words = nil
    when "--words"
      words = arg.to_i
      sentences = nil
    when "--letters"
      letters = true
      words = 50 if words.nil?
    end
  end

  if ARGV.length < 1
    usage
    exit 1
  end

  ARGV.each do |arg|
    begin
      if letters
        m = MarkovLetters.new(arg, order)
        m.print_words(words)
      else
        m = MarkovWords.new(arg, order)
        m.print_words(words) unless words.nil?
        m.print_sentences(sentences) unless sentences.nil?
      end
    rescue
      $stderr.puts $!
    end
  end
end

------art_32547_16008079.1144636541192
Content-Type: application/octet-stream; name=markov.rb
Content-Transfer-Encoding: 7bit
X-Attachment-Id: 0.1
Content-Disposition: attachment; filename="markov.rb"

#!/usr/bin/ruby

class MarkovWords

  def initialize(filename, order)
    @order  rder
    @words  ash.new
    @state  rray.new(@order)
    previous  rray.new(@order)
    File.foreach(filename) do |line|
      line.split(/\s+/).each do |word|
        unless previous.include?(nil)
          p  revious.join(' ')
          unless @words.has_key?(p)
            @words[p]  rray.new
          end
          @words[p] << word
        end
        previous.shift
        previous.push(word)
      end
    end
  end

  def print_words(n  0)
    word  ext_word(true)
    1.upto(n) do |i|
      print word, i n ? "\n" : " "
      word  ext_word()
    end
    print "\n"
  end

  # sentences start with a capital or quoted capital and end with
  # punctuation or quoted punctuation
  def print_sentences(n  )
    sentences  
    word  ext_word(true)
    while word !~ /^['"`]?[A-Z]/
      word  ext_word()
    end
    begin
      print word
      if word /[?!.]['"`]?$/
        sentences + 
        if sentences n
          print "\n"
        else
          print " "
        end
      else
        print " "
      end
      word  ext_word()
    end until sentences n
  end

  def next_word(restart  alse)
    if restart or @state.include?(nil)
      key  words.keys[rand(@words.length)]
      @state  ey.split(/\s+/)
    end
    key || state.join(' ')
    # restart if we hit a dead end, rare unless text is small
    if @words[key].nil?
      next_word(true)
    else
      word  words[key][rand(@words[key].length)]
      @state.shift
      @state.push(word)
      word
    end
  end

end

class MarkovLetters

  def initialize(filename, order)
    @order  rder
    @letters  ash.new
    @state  rray.new(@order)
    previous  rray.new(@order)
    File.foreach(filename) do |line|
      line.strip!
      line << ' ' unless line.length 0
      line.gsub!(/\s+/, ' ')
      line.gsub!(/[^a-z ]/, '')
      line.split(//).each do |letter|
        unless previous.include?(nil)
          p  revious.join('')
          unless @letters.has_key?(p)
            @letters[p]  rray.new
          end
          @letters[p] << letter
        end
        previous.shift
        previous.push(letter)
      end
    end
  end

  # words begin after a space and end before a space
  def print_words(n  0)
    letter  ext_letter(true)
    while letter !  '
      letter  ext_letter()
    end
    letter  ext_letter()
    words  
    while words < n
      words +  if letter ' '
      print letter
      letter  ext_letter()
    end
    print "\n"
  end

  def next_letter(restart  alse)
    if restart or @state.include?(nil)
      key  letters.keys[rand(@letters.length)]
      @state  ey.split(//)
    end
    key || state.join('')
    # restart if we hit a dead end, rare unless text is small
    if @letters[key].nil?
      next_letter(true)
    else
      word  letters[key][rand(@letters[key].length)]
      @state.shift
      @state.push(word)
      word
    end
  end

end

if $0 __FILE__
  require 'getoptlong'

  def usage()
    $stderr.puts "Usage: ruby #{$0} [options] <filename>",
                 "  -h, --help         show this usage message",
                 "  -o, --order        set markov chain order",
                 "  -s, --sentences    set number of sentences to print",
                 "  -w, --words        set number of words to print",
                 "  -l, --letters      use letters as the basic unit"
  end

  order  
  sentences  
  words  il
  letters  alse

  opts  etoptLong.new(["--help",      "-h", GetoptLong::NO_ARGUMENT],
                        ["--order",     "-o", GetoptLong::REQUIRED_ARGUMENT],
                        ["--sentences", "-s", GetoptLong::REQUIRED_ARGUMENT],
                        ["--words",     "-w", GetoptLong::REQUIRED_ARGUMENT],
                        ["--letters",   "-l", GetoptLong::NO_ARGUMENT])

  opts.each do |opt, arg|
    case opt
    when "--help"
      usage
      exit 0
    when "--order"
      order  rg.to_i
    when "--sentences"
      sentences  rg.to_i
      words  il
    when "--words"
      words  rg.to_i
      sentences  il
    when "--letters"
      letters  rue
      words  0 if words.nil?
    end
  end

  if ARGV.length < 1
    usage
    exit 1
  end

  ARGV.each do |arg|
    begin
      if letters
        m  arkovLetters.new(arg, order)
        m.print_words(words)
      else
        m  arkovWords.new(arg, order)
        m.print_words(words) unless words.nil?
        m.print_sentences(sentences) unless sentences.nil?
      end
    rescue
      $stderr.puts $!
    end
  end
end


------art_32547_16008079.1144636541192--