```This isn't much to look at, but it appears to be > 48 hours since the
posting.  So I thought I'd post it anyway.  I still can't generate
the example pangrams given at http://www.cs.indiana.edu/~tanaka/GEB/
pangram.txt but it does generate this pangram in 1-5 minutes:

This terribly inefficient pangram contains five a's, two b's, three
c's, two d's, thirty-one e's, six f's, four g's, ten h's, sixteen
i's, one j, one k, three l's, two m's, twenty n's, thirteen o's, two
p's, one q, twelve r's, twenty-eight s's, twenty-eight t's, three
u's, three v's, nine w's, four x's, six y's and one z.

It's a basic randomized robinsoniziz..ing.  With a rather absurd
amount of test code.
-Mat

-- pangram.rb
#!/usr/bin/ruby

# Ruby Quiz 86, Pangrams: Solution by Mat Schaffer <schapht / gmail.com>
# uses numeric_spell library available from http://tanjero.com/svn/
plugins/numeric_spell/

require 'numeric_spell'

class SelfDocumentingPangram
LETTERS = (?a..?z).to_a

def initialize(starter_string = "This test starter contains ")
@start = starter_string
end

def to_s
current = count(@start)
while current != actual
LETTERS.each do |letter|
current[letter] = rand_between(current[letter], actual[letter])
end
end
end

def rand_between a,b
range = (a - b).abs + 1
rand(range) + [a,b].min
end

@start + counts_to_s(counts)
end

def count_to_s(char, count)
if count != 1
count.spell + " " + char.chr + "'s"
else
count.spell + " " + char.chr
end
end

def counts_to_s(count)
string_counts = []
LETTERS.each do |letter|
string_counts << count_to_s(letter, count[letter])
end
last = string_counts.pop
string_counts.join(", ") + " and " + last + "."
end

def count(string)
count = Hash.new(0)
string.downcase.each_byte do |letter|
if LETTERS.include? letter
count[letter] += 1
end
end
count
end
end

if ARGV[0] =~ /test/i
require 'test/unit'

class TestSelfDocumentingPangram < Test::Unit::TestCase
# checks that count will yield accurate counts for only letters,
ignoring case
def test_count
# check basic case containing only a..z
string = ('a'..'z').to_a.to_s
count = SelfDocumentingPangram.new.count(string)
assert_equal(26, count.length)
count.each do |key, value|
assert_equal(1, value)
end

# check case for a..z, A..Z, and some punctiation that we're
likely to use
string = (('a'..'z').to_a + ('A'..'Z').to_a + ['\'', ',', '.',
'-']).to_s
count = SelfDocumentingPangram.new.count(string)
assert_equal(26, count.length)
count.each do |key, value|
assert_equal(2, value)
end
end

def test_count_to_s
assert_equal("one a", SelfDocumentingPangram.new.count_to_s(?
a, 1))
assert_equal("fifteen z's",
SelfDocumentingPangram.new.count_to_s(?z, 15))
assert_equal("forty-two d's",
SelfDocumentingPangram.new.count_to_s(?d, 42))
end

def test_counts_to_s
start = "The last of these contained "
expected = "two a's, zero b's, one c, one d, four e's, one f,
zero g's, two h's, one i, zero j's, zero k's, one l, zero m's, two
n's, two o's, zero p's, zero q's, zero r's, two s's, four t's, zero
u's, zero v's, zero w's, zero x's, zero y's and zero z's."
pangram = SelfDocumentingPangram.new
result = pangram.counts_to_s(pangram.count(start))
assert_equal(expected, result)
end

def test_rand_between
100.times do
a = rand(100)
b = [a, rand(100)].max
c = SelfDocumentingPangram.new.rand_between(a,b)
assert (a..b) === c, "#{c} is not between #{a} and #{b}"
end
end

pangram = SelfDocumentingPangram.new("hi ")
count = Hash.new(0)
expected = "hi " + pangram.counts_to_s(Hash.new(0))
end

# runs the SelfDocumentingPangram class to verify that it can
produce the pangrams found at
# http://www.cs.indiana.edu/~tanaka/GEB/pangram.txt
def test_to_s
pangram1 = "This pangram tallies five a's, one b, one c, two
d's, twenty-eight e's, eight f's, six g's, eight h's, thirteen i's,
one j, one k, three l's, two m's, eighteen n's, fifteen o's, two p's,
one q, seven r's, twenty-five s's, twenty-two t's, four u's, four
v's, nine w's, two x's, four y's and one z."
assert_equal(pangram1, SelfDocumentingPangram.new("This
pangram tallies ").to_s)

#pangram2 = "This computer-generated pangram contains six a's,
one b, three c's, three d's, thirty-seven e's, six f's, three g's,
nine h's, twelve i's, one j, one k, two l's, three m's, twenty-two
n's, thirteen o's, three p's, one q, fourteen r's, twenty-nine s's,
twenty-four t's, five u's, six v's, seven w's, four x's, five y's and
one z."
#assert_equal(pantram2, SelfDocumentingPangram.new("This
computer-generated pangram contains ").to_s)
end

# This is mainly a sanity check to see that a pangram will
evaluate to itself when counted and regenerated
def test_approach
prefix = "This pangram tallies "
solution = "This pangram tallies five a's, one b, one c, two
d's, twenty-eight e's, eight f's, six g's, eight h's, thirteen i's,
one j, one k, three l's, two m's, eighteen n's, fifteen o's, two p's,
one q, seven r's, twenty-five s's, twenty-two t's, four u's, four
v's, nine w's, two x's, four y's and one z."
pangram = SelfDocumentingPangram.new(prefix)
(solution)))

prefix = "This terribly inefficient pangram contains "
solution = "This terribly inefficient pangram contains five
a's, two b's, three c's, two d's, thirty-one e's, six f's, four g's,
ten h's, sixteen i's, one j, one k, three l's, two m's, twenty n's,
thirteen o's, two p's, one q, twelve r's, twenty-eight s's, twenty-
eight t's, three u's, three v's, nine w's, four x's, six y's and one z."
pangram = SelfDocumentingPangram.new(prefix)
(solution)))
end
end
else
puts SelfDocumentingPangram.new("This terribly inefficient pangram
contains ").to_s
end

On Jul 7, 2006, at 11:01 AM, Ruby Quiz wrote:

> The three rules of Ruby Quiz:
>
> 1.  Please do not post any solutions or spoiler discussion for this
> quiz until
> 48 hours have passed from the time on this message.
>
> 2.  Support Ruby Quiz by submitting ideas as often as you can:
>
> http://www.rubyquiz.com/
>
> 3.  Enjoy!
>
> Suggestion:  A [QUIZ] in the subject of emails about the problem
> helps everyone
> quiz message,
> if you can.
>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
> =-=-=-=-=-=-=
>
> by Darren Kirby
>
> One thing that interests me are word puzzles and language oddities.
> One such
> example is the self-documenting panagram. If a panagram is a
> sentence that uses
> every letter in the alphabet, then a self-documenting panagram is a
> sentence
> that enumerates its own letter count. Simple enough, but what if we
> state that
> the letter count must be spelled ie: 'twenty-seven' instead of
> '27'.  Now we
> have a challenge.
>
> A while back I wrote a script in Python that finds these sentences.
> Today I
> rewrote it in Ruby and it found me this 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'.
>
> My script does have its problems, and I would love to see what kind
> of code the
> Ruby experts could come up with to find self-documenting panagrams.
>
> There is a lot more info on self-documenting panagrams at this