------art_1873_20978574.1189296067069
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Here is my solution for both the number puzzle and the letter one.  I didn't
realize that the numbers wouldn't converge until I watched it take a looong
time and followed the wikepedia link.  In any case, the code handles both
count_and_say and look_and_say.  As others have said, the Fixnum.say method
was more work than the rest of the puzzle.

# Expect a block that takes a first argument of 'count' or 'reorder'
depending on what
# we need to do with the current string.
# In hindsight, this could have taken two Proc objects instead: count_proc
and reorder_proc
def find_cycle string
  puts "Finding a cycle for #{string}"
  sequence  }
  until sequence[string]
    sequence[string]  equence.length
    string.gsub!(/ /,'')  # we ignore all spaces
    #STDOUT.write "#{string.length}:#{string[0..50]} "  #progress feedback
    string  ield( 'reorder', string )
    previous_char, count  tring[0..0], 1
    counts  tring.split('')[1..-1].inject([]) do |memo,obj|
      if previous_char obj
        count + 
      else
        memo << [yield('count',count),previous_char]
        previous_char, count  bj, 1
      end
      memo
    end
    counts << [yield('count',count),string[-1..-1]]
    string  ounts.flatten.join(' ')
  end
  "Cycle found at position #{sequence.length}, duplicating position
#{sequence[string]}: #{string}"
end

def count_and_say string  1"
  find_cycle string do |operation, value|
    # in the numerical mode, each operation is a null operation
    case operation
    when 'reorder'
      value  # no need to re-order the string
    when 'count'
      value.to_s  # just make sure it is a string
    end
  end
end

def look_and_say string  LOOK AND SAY"
  find_cycle string do |operation, value|
    case operation
    when 'reorder'
      value.split('').sort.join
    when 'count'
      value.to_i.say
    end
  end
end

class Fixnum
  NUMBERS  w[zero one two three four five six seven eight nine ten
          eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen
nineteen twenty]
  TENS  w[zero ten twenty thirty forty fifty sixty seventy eighty ninety]
  BIG_DIGITS  w[zero ten hundred thousand]
  def ones_digit; (self % 10); end
  def tens_digit; ((self / 10) % 10); end
  def say
    result  ]
    if NUMBERS[self % 100]
      result << NUMBERS[self % 100] if self 0 or (self % 100) ! 
    else
      result << NUMBERS[self.ones_digit] if self.ones_digit > 0
      result << TENS[self.tens_digit]
    end
    str  elf.to_s
    str[0..-3].reverse.split('').each_with_index do |char,idx|
      result << BIG_DIGITS[idx+2]
      result << NUMBERS[char.to_i] if char.to_i > 0
    end
    result.reverse.collect {|i| i.upcase }.join(' ')
  end
end

I found this to be a lot of fun - just the right amount of work for a lazy
Saturday.
"Cycle found at position 607, duplicating position 178: ONE A ONE D
EIGHTEEN E FIVE F TWO G THREE H EIGHT I ONE K TWO L ELEVEN N TEN O THREE R
TWO S TEN T TWO U FIVE V SIX W TWO X ONE Y"

(I hope this is actually correct!)
JB


On 9/8/07, Brad Ediger <brad / bradediger.com> wrote:
>
> Here's my solution. Coincidentally, it uses the same
> Integer#to_english method that JEG2 posted from quiz 25 (not
> included, as integer_to_english.rb).
>
> --Usage:
> $ ./138_count_and_say.rb LOOK AND SAY
> Took 179 cycles to enter a cycle of length 429
>
> --
>
> #!/usr/bin/env ruby -rubygems
>
> # integer_to_english.rb -> http://blade.nagaokaut.ac.jp/cgi-bin/
> scat.rb/ruby/ruby-talk/135449
> %w(facet/string/chars facet/enumerable/injecting facet/symbol/to_proc
> integer_to_english).each(&method(:require))
>
> class String
>    def letter_histogram
>      upcase.gsub(/[^A-Z]/,'').chars.injecting(Hash.new(0)){|h, l| h
> [l] + }
>    end
>
>    def count_and_say
>      letter_histogram.sort_by{|l,n| l}.map{|(l, n)| "#
> {n.to_english.upcase} #{l}"}.join(" ")
>    end
> end
>
> class Object
>    def detect_cycles
>      ary  self]
>      loop do
>        val  ield(ary.last)
>        if ary.include? val
>          return [ary.index(val)+1, ary.length - ary.index(val)]
>        end
>        ary << val
>      end
>    end
> end
>
> if __FILE__ $PROGRAM_NAME
>    tail, cycle_length  RGV.join.detect_cycles(&:count_and_say)
>    puts "Took #{tail} cycles to enter a cycle of length #{cycle_length}"
> end
>
>


-- 
Random useless thoughts:
http://www.johnbaylor.org/

------art_1873_20978574.1189296067069--