From: Eugene Kalenkovich Date: 2007-09-10T03:15:09+09:00 Subject: Re: [QUIZ] Count and Say (#138) > by Martin DeMello I decided not to miss all the fun, and implemented my own spelling not lookong in prior quuiz solutions. BTW, the full-fledged spelling is not necessary, as the biggest number to spell for this quiz I found was 37 (bigger input texts will require more), but - fun is fun. Interesting facts (hope I did not make any typos, they would screw up all statistics): Worst (or one of) word in unix dictionary is 'SYMPATHIZED' - 303 hops before entering loop of 885 iterations; Best - surprise! - 'ERROR' - only 7+5 ################## spelling part ########################## TOTEENS=[nil, 'one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen'.split].flatten TENS=[nil, nil, 'twenty thirty forty fifty sixty seventy eighty ninety'.split].flatten EXPS_US=[nil,'thousand million billion trillion quadrillion quintillion sextillion septillion octillion nonillion decillion undecillion duodecillion tredecillion quattuordecillion quindecillion sexdecillion septendecillion octodecillion novemdecillion vigintillion'.split].flatten EXPS_NON_US=[nil,'million billion trillion quadrillion quintillion sextillion septillion octillion nonillion decillion'.split].flatten class Integer def spell(us=true) return 'zero' if self==0 self<0 ? 'minus '+(-self).spell_unsign(us) : self.spell_unsign(us) end def spell_unsign(us=true) size=us ? 3 : 6 res=[] self.to_s.reverse.scan(%r"\d{1,#{size}}").each_with_index {|s, i| n=s.reverse.to_i if n>0 sp=us ? n.spell_small : n.spell(true) sp.gsub!('thousand','milliard') if i==1 && !us sc=us ? EXPS_US[i] : EXPS_NON_US[i] res << sc if sc res << sp end } res.compact.reverse.join(' ') end def spell_small res=[] hundred=TOTEENS[self/100] res << hundred << 'hundred' if hundred res << TENS[self%100/10] << (self<20 ? TOTEENS[self%100] : TOTEENS[self%10]) res.compact.join(' ') end end ################## actial quiz part ########################## def count_and_say str h=str.split(//).inject(Hash.new(0)){|h,c|h[c]+=1; h} h.delete(' ') res='' h.keys.sort.each {|k| res << ' ' unless res.empty? res << h[k].spell << ' ' << k } res end it=start=0 hres={(orig=last=ARGV[0].downcase.delete("^a-z"))=>it} while true puts now=count_and_say(last) it+=1 key=now.delete(' ') # slight optimization, gives ~10% on 'sympathized' break if start=hres[key] hres[key],last=it,key end puts "#{start} + #{it-start}"