# \[QUIZ\] Pangrams (#86)

**URL:** <https://www.ruby-forum.com/t/quiz-pangrams-86/98141>\
**Category:** Ruby\
**Created:** [July 12, 2006, 6:53pm UTC](https://www.ruby-forum.com/t/quiz-pangrams-86/98141 "2006-07-12T18:53:00Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![johnnybutler7](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johnnybutler7](https://www.ruby-forum.com/u/johnnybutler7)\
**Post date:** [July 12, 2006, 6:53pm UTC](https://www.ruby-forum.com/t/quiz-pangrams-86/98141/1 "2006-07-12T18:53:00Z")

</div>

I let it run overnight in two irb sessions (with two different starter  
sentences) and they both finally converged - but I don’t know how long  
it  
took.  
Looking at the other solutions, I think I have plenty to learn about  
Ruby -  
especially when to modify an existing class, such as Integer or FixNum,  
and  
when to just do it in the domain-specific class. Everything here is in  
the  
domain-specific class but could be simpler in others.

iteration 2860162:  
My sentence contains three 'a’s, one ‘b’, three 'c’s, two 'd’s, thirty  
'e’s,  
five 'f’s, four 'g’s, eight 'h’s, nine 'i’s, one ‘j’, one ‘k’,  
one ‘l’, two 'm’s, twenty-one 'n’s, seventeen 'o’s, one ‘p’, one ‘q’,  
eight  
'r’s, twenty-four 's’s, twenty-two 't’s, four 'u’s, three 'v’s,  
eight 'w’s, two 'x’s, six 'y’s and one ‘z’.

iteration 3224814:  
John’s cool pangram program created this sentence which contains  
exactly  
eight 'a’s, one ‘b’, seven 'c’s, three 'd’s, forty-one 'e’s, eight  
'f’s, five 'g’s, thirteen 'h’s, twelve 'i’s, two 'j’s, one ‘k’, four  
'l’s,  
three 'm’s, twenty-two 'n’s, seventeen 'o’s, three 'p’s, one ‘q’  
, fifteen 'r’s, thirty-three 's’s, twenty-six 't’s, four 'u’s, seven  
'v’s,  
seven 'w’s, four 'x’s, six 'y’s and one ‘z’.

I haven’t tried a French version yet but it would likely work…

#===============================================================  
require ‘Win32API’ # for checking the keyboard to stop and show the  
progress

EXAMPLE\_SENTENCE = “Darren’s ruby panagram program found this sentence  
which  
contains exactly  
nine 'a’s, two 'b’s, five 'c’s, four 'd’s, thirty-five 'e’s, nine  
'f’s,  
three 'g’s, nine 'h’s, sixteen 'i’s, one ‘j’, one ‘k’, two 'l’s,  
three 'm’s,  
twenty-seven 'n’s, fourteen 'o’s, three 'p’s, one ‘q’, fifteen  
'r’s,  
thirty-four 's’s, twenty-two 't’s, six 'u’s, six 'v’s, seven  
'w’s,  
six 'x’s,  
seven 'y’s, and one ‘z’.”

class Pangram  
DEFAULT\_SENTENCE = “John’s cool pangram program created this sentence  
which contains exactly”  
ENGLISH\_NUMBERS = %w[? one two three four five six seven eight nine  
ten  
eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen  
nineteen  
twenty]  
ENGLISH\_THIRTY\_PLUS = %w[thirty forty fifty sixty seventy eighty  
ninety]  
#this isn’t quite right for french: 21 and 31 and 41 are “thirty and  
one”…  
FRENCH\_NUMBERS = %w[? un deux trois quatre cinq six sept huit neuf dix  
onze douze treize quatorze quinze seize dix-sept dix-huit dix-neuf  
vingt]  
FRENCH\_THIRTY\_PLUS = %w[trente quarante cinquante soixante  
soixante-dix  
quatre-vingt quatre-vingt-dix]  
MAX\_COUNT = 50

attr\_accessor :sentence

# expect args to be [sentence,number\_words,thirty\_plus]

def initialize \*args  
@attempts = Hash.new(nil)  
@sentence = args[0] || DEFAULT\_SENTENCE  
@words = args[1] || ENGLISH\_NUMBERS  
@words = @words.dup  
@thirty\_plus = args[1] || ENGLISH\_THIRTY\_PLUS  
count = 30  
@thirty\_plus.each do |word|  
@words[count] = word  
count += 10  
end

```
extend_wordlist MAX_COUNT
#puts "@sentence=#{@sentence}"
# only add one the first time, all the others already have the extra 

```

one

```
@result = letter_frequency @sentence
@result.each { |k,v| @result[k] += 1 }
#puts full_sentence( @result )
self

```

end

def distance hash1, hash2  
dist = 0  
hash1.each { |k,v| dist += (v - hash2[k]).abs }  
return dist  
end

def approximate current, start  
# apply each letter-word to an empty list  
approximation = {}  
“a”.upto(“z”) { |c| approximation[c] = start }  
current.each do |k,v|  
@words[current[k]].split(’’).each do |c|  
approximation[c] += 1 if approximation[c] and approximation[c]

> = 0  
> end  
> end  
> return approximation  
> end

def unique\_solution sentence,count  
#puts “#{count}: crypt=#{crypt} for #{sentence}”  
if @attempts[sentence] != nil  
puts “Oops, we’ve already tried this solution! (#{count} ==\>  
#{@attempts[sentence]})”  
return nil  
else  
@attempts[sentence] = count  
return 1  
end  
end

def make\_randomly\_similar! dest, src  
diffs = “”  
dest.each { |k,v| diffs += k if v != src[k] }  
c = diffs[(rand \* diffs.length).to\_i].chr  
dest[c] = src[c]  
end

def solve  
iteration = 0  
hash = {}  
s = full\_sentence( @result )  
hash = letter\_frequency( s )  
w = Win32API.new( “MSVCRT”, “\_kbhit”, [], ‘i’)  
io = IO.new(0)  
while hash != @result ## and unique\_solution(s,iteration) != nil  
iteration += 1  
dist = distance( hash, @result )  
puts “#{iteration}: #{dist}”  
c = make\_randomly\_similar! @result, hash  
#puts “iteration #{iteration}: #{dist},#{c} ==\>  
#{hash.sort.collect{|i| i[1] }.join(’,’) }”  
s = full\_sentence( @result )  
hash = letter\_frequency( s )  
if w.Call() \> 0  
io.getc  
puts “iteration #{iteration}: #{dist} ==\> #{hash.sort.collect  
{|i|  
“#{i[0]}\>#{i[1]}” }.join(’,’) }”  
puts s  
end  
end  
puts “\nSOLVED!\n #{s}”  
puts “iteration #{iteration}: #{dist} ==\> #{hash.sort.collect {|i|  
i[1]  
}.join(’,’) }”  
show\_freq letter\_frequency(s)  
end

def full\_sentence hash  
s = @sentence.rstrip + " "  
“a”.upto(“x”) do |letter|  
s += to\_letter\_count( letter, hash[letter] ) + ", "  
end  
s += to\_letter\_count( “y”, hash[“y”] ) + " and "  
s += to\_letter\_count( “z”, hash[“z”] ) + “.”  
return s  
end

def to\_letter\_count letter, count  
ret = “#{@words[count]} ‘#{letter}’”  
ret += “s” if count \> 1  
return ret  
end

def extend\_wordlist count  
0.upto(count) do |n|  
@words[n] = @words[10\*(n/10).floor] + ‘-’ + @words[n % 10] unless  
@words[n]  
#puts “#{n}: #{@words[n]}”  
end  
end

def show\_freq hash  
hash.sort.each { |k, v| puts “#{k}: #{v}” }  
end

def letter\_frequency \*sentence  
s = sentence[0] || @sentence  
s = s.downcase.gsub(/^a-z/,’’)  
s.gsub!(/ |,|’|-|./,’’)  
freq = Hash.new(0)  
“a”.upto(“z”) { |c| freq[c] = 0 }  
s.split(’’).each { |c| freq[c] += 1 }  
freq  
end  
end
