#!/usr/bin/perl use strict; my $GERM = "Any Perlmonk could write a sentence using\n"; my $RESET = 4096; my $PROB = .5; my $words = makewords(); my $letts = makeletters(); my ($sent, $iter, $best); while (1) { $sent = makesentence($GERM, $words, $letts); updatecounts($letts, $sent); my ($broke, $score) = scoreclaim($letts); if ($iter++ % $RESET == 0) { $best = $score; print "\n"; } if ($score == 0) { last; } elsif ($score < $best) { $best = join('', @{$broke}); $best = "$score-$best"; print "$iter $best\n"; $best = $score; } for my $letter (@{$broke}) { if (rand() < $PROB) { my $amount = int(rand(abs($letts->{$letter}{score}+1)))+1; if ($letts->{$letter}{score} > 0) { $amount *= -1; } $letts->{$letter}{claim} += $amount; } } } print "\n$sent\n"; #----------------------------------------------------------- sub scoreclaim { my ($letts) = @_; my ($total, @broke); for my $ch ('a'..'z') { my $score = $letts->{$ch}{claim} - $letts->{$ch}{count}; $letts->{$ch}{score} = $score; $total += abs($score); if (abs($letts->{$ch}{score}) > 0) { push(@broke, $ch); } } return (\@broke, $total); } #----------------------------------------------------------- sub updatecounts { my ($letts, $sent) = @_; for my $ch ('a'..'z') { $letts->{$ch}{count} = (() = $sent =~ m{$ch}ig); } } #----------------------------------------------------------- sub makesentence { my ($sent, $words, $letts) = @_; my ($num); for my $ch ('a'..'y') { $num = $letts->{$ch}{claim}; if ($num != 1) { $sent .= " $words->{$num} ${ch}'s,\n"; } else { $sent .= " $words->{$num} $ch,\n"; } } $num = $letts->{z}{claim}; $sent .= " and $words->{$num} z"; if ($num != 1) { $sent .= "'s"; } $sent .= '.'; return $sent; } #----------------------------------------------------------- sub makeletters { my $letters = {}; for my $ch ('a'..'z') { $letters->{$ch} = {}; $letters->{$ch}{claim} = 1; $letters->{$ch}{count} = 0; $letters->{$ch}{score} = 0; } return $letters; } #----------------------------------------------------------- sub makewords { my (%words, $line); while (chomp ($line = )) { my ($key, $val) = split(' ', $line); $words{$key} = $val; } for ($line = 0; $line < 100; $line++) { if (!defined($words{$line})) { my $tens = int($line / 10); my $ones = $line - ($tens * 10); $tens .= '0'; $words{$line} = "$words{$tens}-$words{$ones}"; } } return \%words; } __DATA__ 0 no 1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 eight 9 nine 10 ten 11 eleven 12 twelve 13 thirteen 14 fourteen 15 fifteen 16 sixteen 17 seventeen 18 eighteen 19 nineteen 20 twenty 30 thirty 40 forty 50 fifty 60 sixty 70 seventy 80 eighty 90 ninety