[QUIZ] Count and Say (#138)

A

Adam Shelly

Over on rec.puzzles, Eric A. proposed a variant in which the letters of a
sentence are grouped, then "counted aloud", omitting the "s"s for the plural
form. Thus, seeding the sequence with "LOOK AND SAY", we get:

0. LOOK AND SAY
1. TWO A ONE D ONE K ONE L ONE N TWO O ONE S ONE Y
2. ONE A ONE D SIX E ONE K ONE L SEVEN N NINE O ONE S TWO T TWO W ONE Y
3. ONE A ONE D TEN E TWO I ONE K ONE L TEN N NINE O THREE S THREE T ONE V
THREE W ONE X ONE Y

and so on. (Note the difference between this and the L&S sequence--the letters
are counted rather than read in order). Eric wants to know when the sequence
enters a cycle, and how long that cycle is. Well?


My solution follows. I rolled my own integer to word routine. The
shortest cycle I found starts with letter 'Y':
C:\code\quiz>looksay2.rb y
Y

After 50 iterations, repeated pattern 48:
SIXTEEN E SIX F TWO G THREE H FIVE I TWO L NINE N NINE O SIX R FOUR S
FOUR T FIVE U FIVE V TWO W TWO X ONE Y
Loop length = 2


-Adam

---looksay2.rb---

class Integer
GROUPS =%W{ THOUSAND MILLION BILLION TRILLION QUADRILLION
QUINTILLION SEXILLION SEPTILLION OCTILLION NONILLION}.unshift nil
DIGITS = %W{ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT NINE}.unshift nil
TEENS = %W{TEN ELEVEN TWELVE THIRTEEN FOURTEEN FIFTEEN SIXTEEN
SEVENTEEN EIGHTEEN NINETEEN}
TENS = %W{TEN TWENTY THIRTY FOURTY FIFTY SIXTY SEVENTY EIGHTY
NINETY}.unshift nil
def to_w
return @word if @word
p "making word for #{self}" if $DEBUG
digits = to_s.split('').reverse.map{|c|c.to_i}
return @word = "DECILLIONS" if digits.size > 33
phrase,group = [],0
until digits.empty?
phrase << GROUPS[group]
d = digits.slice!(0,3)
d[1]||=0
if d[1] == 1
phrase << TEENS[d[0]]
else
phrase << DIGITS[d[0]] << TENS[d[1]]
end
phrase << "HUNDRED" << DIGITS[d[2]] if (d[2] and d[2]!=0)
phrase.pop if (phrase.compact! and phrase[-1] == GROUPS[group])
group+=1
end
@word = phrase.reverse.join ' '
end
end


if __FILE__ == $0

phrase = ARGV[0]||"LOOK AND SAY"
print = ARGV[1] == 'p'
results=[];
h=Hash.new(0)
i=0
str = phrase.upcase
puts str
until (m = results.index str)
print "#{i}: ", str, "\n" if print
results<< str
str.split('').each{|c| h[c]+=1}
h.delete(' ')
str = h.to_a.sort.map{|c,n| [n.to_w,c] }.join " "
h.clear
i+=1
end
puts "\nAfter #{i} iterations, repeated pattern #{m}: "
puts str
puts "Loop length = #{i-m}"
end
 
R

Rubén Medellín

The three rules of Ruby Quiz:

Here is my solution. Pretty simple.

______________________________________

#! /usr/bin/ruby
# Quiz 138 - Ruben Medellin

# Will find cycles on a deterministic action
# (that is, applying one defined action to an object, it will always
# produce the same result)
def find_cycles(initial, action, times, output)

collector = []

collector << initial
iteration = initial

1.upto(times) do |i|
print "#{i}: " if output
iteration = action[iteration]
if collector.include? iteration
puts "Found cycle at #{x = collector.index(iteration)} -- #{i}",
iteration,
"cycle length is #{i - x}"
return
end
collector << iteration
puts iteration if output
puts if output
end
puts "No cycles found for \"#{initial}\" in #{times} iterations"
end

require 'number_names'

if __FILE__ == $0

require 'optparse'

options = {}
OptionParser.new do |opts|

opts.banner = "Usage: ruby quiz138 [WORDS]+ [options]"

opts.on("-t", "--times [INTEGER]") {|times| options[:times] =
times.to_i }
opts.on("-o", "--output") { options[:eek:utput] = true }
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end

end.parse!

text = ARGV.join(' ')
ALPHABET = [*'a'..'z']
find_cycles( text,
proc do |text|
ALPHABET.inject('') do |str, letter|
x = text.count(letter)
str + (x == 0 ? '' : "#{x.name} #{letter} ")
end.strip
end,
options[:times] || 1000, options[:eek:utput])
end

____

# I assume Integer#name method is implemented, for brevity of the post.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,264
Messages
2,571,323
Members
48,006
Latest member
MelinaLema

Latest Threads

Top