# Golfing A Weasel Program

Richard Dawkins in his book The Blind Watchmaker, describes a Weasel program. The algorithm can be described as follows:

1. Start with a random string of 28 characters. Valid characters are all upppercase letters, and space.

2. Make 100 copies of that string, with a 5% chance per character of that character being replaced with a random character.

3. Compare each new string with the target "METHINKS IT IS LIKE A WEASEL", and give each a score according to the number of letters in the string which are correct and in the correct position.

4. If any of the new strings has a perfect score (28), halt.

5. Choose the highest-scoring string from step 3. How you work out a tie is up to you, but only one string may be chosen. Take the chosen string and go to step 2.

The winner will be the shortest code snippet to get to the correct answer while printing the highest-scoring string of each generation in the following format:

If people could help by checking other peoples answers would be very helpful!

• Which characters are allowed? Unicode? Lowercase? – Oriol Jan 3 '14 at 17:42
• Ah, I love Dawkins. Beauty, and feasibility of evolution shown in a simple algorithm. – Cruncher Jan 3 '14 at 18:16
• May step 4 be better replaced with "step 1.5) If the new strings has a perfect score (28), halt" and "step 4) Take the highest scoring string, and go to step 1.5."? That is, if the initial random string is a winner, need we fan out? – Rob Starling Jan 3 '14 at 18:21
• I'm a bit confused as to the order of operations here. Is the intent that we make 100 new strings, based on the original string? Or is it 100 new strings, with the first string being based on the original, and each subsequent string based on the previous string? The algorithm description seems to imply the former, while the sample output appears to be of the latter. – Iszi Jan 6 '14 at 19:18
• The instructions are pretty clear, but what if the original string is the target? – Christian Palmstierna Jan 8 '14 at 15:41

## APL (143)

0{⍵≢T←'METHINKS IT IS LIKE A WEASEL':c∇⍨1+⍺⊣⎕←(⍕⍺),':'c'-- score:',s⊣c←⊃c/⍨G=s←⌈/G←{+/⍵=T}¨c←{⍵{⍵:⍺⋄C[?27]}¨9≠?28/20}¨100⍴⊂⍵}⊃∘(C←27↑⎕A)¨?28/27

Explanation:

• 0{...}⊃∘(C←27↑⎕A)¨?28/27: set C to the first 27 capital letters. There are only 26, so the 27th element will be a space. Select 28 random items from C. This will be the first . The first (generation) will be 0.

• ⍵≢T←'METHINKS IT IS LIKE A WEASEL: set T to the string 'METHINKS IT IS LIKE A WEASEL'. As long as is not equal to T:

• {...}¨100⍴⊂⍵: Make 100 copies of . For each of these...
• 9≠?28/20: select 28 random numbers from 1 to 20. Make a bitmask where each 1 means that the random number was not equal to 9. (This means 5% chance of a 0).
• ⍵{⍵:⍺⋄C[?27]}¨: for each letter in , if the corresponding bit was 1, keep that letter, otherwise replace it with a randomly chosen element from C.
• c←: store the 100 mutated strings in c.
• G←{+/⍵=T}¨c: for each element in c, calculate the score (amount of characters that match T) and store the scores in G.
• s←⌈/G: find the maximum score and store that in s.
• c←⊃c/⍨G=s: select the first item from c whose score is equal to s (the maximum), and store it in c again.
• ⎕←(⍕⍺),':'c'-- score:',s: print the generation in the given format ( is current generation, c is current best string, s is score)
• c∇⍨1+⍺: Increment the generation and run the mutation again using the current best string (c) as input.
• Explanation? This looks like alphabet soup! :) – ToastyMallows Jan 7 '14 at 16:46
• @ToastyMallows: added explanation – marinus Jan 7 '14 at 17:20
• Best answer so far, great to have an explaination with it. – Noelkd Jan 7 '14 at 17:22
• @marinus Are you a wizard? – ToastyMallows Jan 8 '14 at 13:52
• Bullcrap, you just opened MS Word and used WingDings font – Embattled Swag Jan 9 '14 at 22:04

# Mathematica - 238236 225

c:="@"~CharacterRange~"Z"~RandomChoice~28/."@"->" "
For[s=""<>c;i=0,{d,s}=Sort[{#~HammingDistance~"METHINKS IT IS LIKE A WEASEL",#}&@
StringReplace[s,_/;20Random[]<1:>c〚1〛]&~Array~100]〚1〛;
d>0Print[i++,":"s," -- score: ",28-d],]

Example output

2:  CYPMEIHA IRXVTFBIRYOZNRVFCSQ  -- score: 3
...
50:  METHINKS IT IS LIKE A WEASEL  -- score: 28

# Python (273)

from random import choice as c
n=range
a=map(chr,n(65,91)+[32])
s=map(c,[a]*28)
p=x=0
while p<28:
p,s=max((sum(g==r for g,r in zip(y,'METHINKS IT IS LIKE A WEASEL')),y)for y in ([c(a+[x]*513)for x in s]for _ in n(100)));print '%d: %s -- score: %d' % (x,''.join(s),p);x+=1

# K, 173 167

o:"METHINKS IT IS LIKE A WEASEL"
i:0;{~x~o}{-1($i),": ",(r:a@*&b=c)," -- score: ",$c:max@b:+/'o=/:a:{x{if[0~*1?20;x[y]:*1?s];x}/!#x}'100#,x;i+:1;r}/28?s:"c"$32,65+!26; / 0: FQRZPHACDIBHZOUUCYKKFBJWVNVI -- score: 1 1: FQRZP ACDITHCOUUCYKKFBJWVNVI -- score: 2 2: FQRZP AFDIT COUUCYKKFBJWVNVI -- score: 3 ... 51: METHINKS IT IS LIKECA WEASEL -- score: 27 52: METHINKS IT IS LIKECA WEASEL -- score: 27 53: METHINKS IT IS LIKE A WEASEL -- score: 28 # Python: 282 characters no semi colons from random import* g,r,l,c=0,0,"ABCDEFGHIJKLMNOPQRSTUVWXYZ ",choice k=map(c,[l]*28) while(r!=28): r,k=max((sum(i==j for i,j in zip(t,"METHINKS IT IS LIKE A WEASEL")),t)for t in[[c(l)if random()<.05 else i for i in k]for i in[1]*100]) printg+":","".join(k),"-- score:",r g+=1 # 278 with: from random import*;g,r,l,c=0,0,"ABCDEFGHIJKLMNOPQRSTUVWXYZ ",choice;k=map(c,[l]*28) while(r!=28):r,k=max((sum(i==j for i,j in zip(t,"METHINKS IT IS LIKE A WEASEL")),t)for t in[[c(l)if random()<.05 else i for i in k]for i in[1]*100]);printg+":","".join(k),"-- score:",r;g+=1 • You should explicitly state the language and since the question is tagged code-golf, you should provide a character count. – Tim Seguine Jan 3 '14 at 12:27 • Will do, thanks for the tips tim. – Noelkd Jan 3 '14 at 12:47 • Also, you should use all one letter variable names to decrease the character count further. – Doorknob Jan 3 '14 at 14:40 • Waiting till later to golf it down some more, still got some easy wins. Thanks. – Noelkd Jan 3 '14 at 14:45 • Is it really supposed to start with all same letters? :) – Joachim Isaksson Jan 7 '14 at 18:51 # JavaScript, 277 246 c=m=>" ABCDEFGHIJKLMNOPQRSTUVWXYZ"[0|Math.random()*m];for(s=[k=28];e=k;s[--k]=c(27));for(;alert(k+++": "+s.join("")+" -- score: "+e),e<28;s=t)for(z=100;f=0,z--;f>e&&(t=n,e=f))n=s.map((h,p)=>(h=c(540)||h,f+=h=="METHINKS IT IS LIKE A WEASEL"[p],h)) (requires arrow function support; indentation added only for readability) // c() returns a random char using m as an index max c=m=>" ABCDEFGHIJKLMNOPQRSTUVWXYZ"[0|Math.random()*m]; // generate base string s for(s=[k=28];e=k;s[--k]=c(27)); // while score e is < 28 for(;alert(k+++": "+s.join("")+" -- score: "+e),e<28;s=t) for(z=100;f=0,z--;f>e&&(t=n,e=f)) // do 100 mutations; keep best score n=s.map((h,p)=>( // map s to n with 5% mutation h=c(540)||h, // change the char in 5% of cases f+=h=="METHINKS IT IS LIKE A WEASEL"[p], // score++ if char matches h // arrow function return character )) Feel free to change alert to console.log if you want a more pleasant execution experience. There are some nifty golfy bits in here: • The function c returns a random character from the alphabet string " ABC...". The function takes an argument to use as an upper bound for the random index selection. When generating the base string, we use 27, so the function behaves normally. However, we abuse this behavior by asking for a random upper bound of 540 in h = c(540) || h. Only 5% of the time will c actually return a string (because 540 * .05 = 27); the other 95% of the time, the randomly-chosen index falls beyond the length of the string, so the function returns undefined. This falsey value causes a logical-OR cascade in c(540) || h, so the original map value h is used (i.e., no replacement occurs). • The score-summing operation does f+=h=="METHINKS IT IS LIKE A WEASEL"[p], which says "add true to f if the current map character h matches the pth character of the WEASEL string". The number-plus-boolean addition coerces the boolean result to either 0 or 1, which means that f is incremented only when there is a match against the target WEASEL string. • Why have you got v stated in the code? It's not mentioned anywhere else in there. You can save yourself 2 chars.? – WallyWest Jan 7 '14 at 1:24 • @Eliseod'Annunzio v is an argument to the arrow function stored in c: c = (v => ...). If you want to define an arrow function without arguments, it costs two characters, ()=>... , instead of one, v=>..., so it's better to simply have an unused argument. – apsillers Jan 7 '14 at 1:26 • Clever use of code! – WallyWest Jan 7 '14 at 1:29 • Nice trick with k=s=[28] and ++, I had no idea! – Dom Hastings Jan 7 '14 at 6:16 ## R (245239 238 characters) t=strsplit("METHINKS IT IS LIKE A WEASEL","")[[1]] h=sample s=h(f<-c(LETTERS," "),28,T) c=0 while(!all(s==t)){for(i in 1:100){z=ifelse(runif(28)<.05,h(f,1),s) y=sum(s==t) if(sum(z==t)>y)s=z} cat(c<-c+1,": ",s," -- score: ",y,"\n",sep="")} Gives: 1: HSSSIMJM ETJISGBSCIELUYPLSED -- score: 7 2: HSSSIMJM ETJISGBSKIELUYPLSED -- score: 8 3: EETLITLM ETJISTBSKIELUYLLSEL -- score: 11 ... 78: METHINKS IT IS LIKEEA WEASEL -- score: 27 79: METHINKS IT IS LIKEEA WEASEL -- score: 27 80: METHINKS IT IS LIKEEA WEASEL -- score: 27 81: METHINKS IT IS LIKE A WEASEL -- score: 28 • how to you get your first line 0: ... if the first time you invoke cat you increment c to 1? (+1 nonetheless as i m trying since an hour to do something shorter and i still can't :) ) – plannapus Jan 8 '14 at 14:20 • @plannapus That is true, was from an old version (which was somewhat longer). Either I change it to -1 in the beginning, or use 1 in the first line... – Henrik Jan 8 '14 at 22:34 • I see two problems with your code. First, this ifelse(…,h(f,1),…) replaces all selected positions with the same random char. You can interpret the rules in this direction, but it feels like bending them so I'd at least mention it. Second, you replace s=z within the 1:100 loop, so you are not making 100 copies of the same string, but sometimes copies of a copy. This seems like breaking a rule to mee, not merely bending it. – MvG Jan 9 '14 at 22:43 # C 256 char c[101][29],s,n,z,b,j,i,w;g;main(){for(;w<28;printf("%d: %s -- score: %d\n",g++,c[b=n],w))for(i=w=0;i<101;i++)for(s=j=0;j<28&&!(i==b&&g);j++)(s+=(c[i][j]=g&&rand()%20?c[b][j]:(z=rand()%27)?'A'+z-1:' ')=="METHINKS IT IS LIKE A WEASEL"[j])>w?n=i,w=s:0;} Simple three loops, initialization, generation of new strings from parent and score calculated by the same statement. It's not very readable even with indentation. # C 252 i,g,n,b,o,s,w,z;char c[2929];main(){for(;(o=i%29)|i|w<28;(i=(i+1)%2929)||printf("%d: %s -- score: %d\n",g++,&c[b=n],w))(s+=o>27?-s:((i-o!=b||!g)&&(c[i]=g&&rand()%20?c[b+o]:(z=rand()%27)?'A'+z-1:' ')=="METHINKS IT IS LIKE A WEASEL"[o]))>w?n=i-o,w=s:0;} One loop, with one array holding all 101 strings. This second version breaks the rules because it prints the string from (the equivalent of) step 1, but it was either that or not print the last string. I'm stumped how to fix it without exploding in size. I'm posting it anyway for inspiration. # C 256 struct{char d[29];}p,t,n;i,j=-1,z,s,w,g;main(){for(;w<28;j>1&&printf("%d: %s -- score: %d\n",g++,(p=n).d,w))for(;j++%100;p=j?p:t)for(s=0,i=28;i--;)(s+=(t.d[i]=j&&rand()%20?p.d[i]:(z=rand()%27)?'A'+z-1:' ')=="METHINKS IT IS LIKE A WEASEL"[i])>w?n=t,w=s:0;} Different approach, instead of making an array to hold 101 strings just regenerate the string 100 times and use struct assignment for easy copying. Initialization is done by starting the "repeat 100 times" counter at -1 and handling it carefully by strategically chosen post-increment. Despite a very different approach it ends up exactly the same as the first attempt - 256 characters. ## C# - 436 namespace System.Linq{class W{static void Main(){var r=new Random(); Func<char>c=()=>(char)(r.Next(33,60)%59+32);var s=""; while(s.Length<28)s+=c();var a="METHINKS IT IS LIKE A WEASEL";int b=0; while (s!=a){int m=-1;var f=s;for(int i=0;i<100;i++){ var l=string.Join("",s.Select(j=>(r.Next(20)!=0?j:c()).ToString())); int o=Enumerable.Range(0,28).Sum(j=>l[j]==a[j]?1:0);if(o>m){f=l;m=o;}} Console.WriteLine(b+++": "+(s=f)+" -- score: "+m);}}}} • This is broken. You need using System; or manually qualifying System. – It'sNotALie. Jan 9 '14 at 16:34 • No, you don't. ideone.com/4alNSi. – tia Jan 9 '14 at 17:23 • Ah nice. Looked at the NS declaration as a using sorry. – It'sNotALie. Jan 11 '14 at 23:21 Lua 5.1 (502) The minimised version: s,t,b,c,i,q,a,d,f="ABCDFGHJYUEGKSHNCOLPQIEJUSNC","METHINKS IT IS LIKE A WEASEL",1,math.random,table.insert,1,string.sub,100,28 while q~=f do r,p={},{} for x=1,d do i(r,s) i(p,0) e="" for o=1,f do if c(1,20)==1 then if c(1,27)==1 then e=e.." " else e=e..string.char(c(65,90)) end else e=e..a(r[x],o,o) end end r[x]=e for y=1,f do if a(r[x],y,y)==a(t,y,y) then p[x]=p[x]+1 end end if p[x]==f then s=r[x] end end for x=1,d do if p[x]>=q then s,q=r[x],p[x] end end print(b..":",s,"-- score: "..q) b=b+1 end and the easier to read version (with comments!): s,t,b,c,i,q,a,d,f="ABCDFGHJYUEGKSHNCOLPQIEJUSNC","METHINKS IT IS LIKE A WEASEL",1,math.random,table.insert,1,string.sub,100,28 --s=random string, t=target, b=counter, c=reference to math.random, i=reference to table.insert, q=top score,a=reference to string.sub, d=constant (100), f=constant (28) while q~=f do r,p={},{} for x=1,d do --add 100 copies to the table of strings i(r,s) i(p,0) e="" for o=1,f do --for each character in string if c(1,20)==1 then -- 5% chance if c(1,27)==1 then e=e.." " else e=e..string.char(c(65,90)) end --set it to an ASCII char between 65 and 90 (A-Z) or a space character else e=e..a(r[x],o,o) end end r[x]=e --current string = mutations for y=1,f do if a(r[x],y,y)==a(t,y,y) then p[x]=p[x]+1 end end --for each char increment score if it is correct if p[x]==f then s=r[x] end --if 28 then final string is this! end for x=1,d do if p[x]>=q then s,q=r[x],p[x] end --if this is the highest score so far, then make the string equal to this end print(b..":",s,"-- score: "..q) --print it! b=b+1 --add one to the counter! end To be honest even though this definitely won't win, I was just glad to find and minimise a reasonably short solution for this problem! (emphasis on reasonably) :p ## SAS - 374 %macro r;ranuni(7)%mend;%macro s;r=int(%r*27);substr(x,t,1)=byte(ifn(r,64+r,32));%mend;%macro y;char(y,t)=char(x,t)%mend;options nonotes nosource;data x;length x$28;do t=1to 28;%s;end;y="METHINKS IT IS LIKE A WEASEL";do z=1by 1;o=x;do i=1to 100;c=0;x=o;do t=1to 28;if %r<=.05then do;%s;end;c+%y;end;if c>m then do;m=c;v=x;end;end;x=v;put z":" x"-- score:" m;if m<28;end;run;

->

1 :GUUVLNUSILSRZLRBXVVCWXX HXKC -- score:2
2 :MUUVLNUSILSRZLRBXVMCWXX HXKC -- score:3
3 :MUUVLNESILSRILRBXVMCWXX HXKC -- score:4
4 :MEUVLNESILSRIRRBXVMCWXX HXKC -- score:5
....
95 :METHINKS IT IS LIKE A XEASEL -- score:27
96 :METHINKS IT IS LIKE A XEASEL -- score:27
97 :METHINKS IT IS LIKE A XEASEL -- score:27
98 :METHINKS IT IS LIKE A WEASEL -- score:28

%macro r;
ranuni(7)   /* seed 0 will make new each time (seed=clock), otherwise fixed results */
%mend;
%macro s;  /* does the rand char, used both to initialize and replace; */
r=int(%r*27);
substr(x,t,1)=byte(ifn(r,64+r,32)); *r=0 becomes space otherwise upper char;
%mend;
%macro y;  /*compares using new to 9.2 CHAR function which is equivalent to substr(str,start,1) */
char(y,t)=char(x,t)
%mend;
options nonotes nosource; /*cheapest way to get clean log */
data x;
length x$28; /*annoyingly necessary*/ do t=1to 28;%s;end; /*initialize string*/ y="METHINKS IT IS LIKE A WEASEL"; /*compare string */ do z=1by 1; /*start iterating */ o=x; /*save this iteration's string */ do i=1to 100; c=0; /*score for this iteration*/ x=o; /*string to fudge about start out clean, reusing x so no params to macro*/ do t=1to 28; if %r<=.05then do;%s;end; /*if 5% then change the char out */ c+%y; /*score that character*/ end; if c>m then do; /*if on better scoring line, save it */ m=c; v=x; end; end; x=v; *for next iter - this is cheaper than other options involving o=v due to first iter; put z":" x"-- score:" m; if m<28; *quit at 28; end; run; ## C 361 331 Not as good as Art's solution, but here's my (newbie) attempt at a C solution. 361 characters if you remove newlines and tabs. char*w="METHINKS IT IS LIKE A WEASEL";char b[101][29];t,s,n,i,j,x,a;main(){for(;i<28;i++)b[0][i]=w[rand()%28];while(s<28){for(j=1;j<101;j++){x=0;for(i=0;i<28;i++){if(!(rand()%20))b[j][i]=w[rand()%28];else b[j][i]=b[0][i];if(b[j][i]==w[i])x++;}if(x>s){s=x;t=j;}}printf("%d: %s -- score %d\n",n++,b[t],s);for(;i>=0;--i){a=b[0][i];b[0][i]=b[t][i];b[t][i]=a;}t=0;}} Edit: Got rid of the nested loop and used a 1D array. Was hoping it would make a bigger difference, but it only saved me 30 characters. Here's the code: char*w="METHINKS IT IS LIKE A WEASEL";char b[2929];t,s,n,i,x;main(){for(;i<28;i++)b[i]=w[rand()%28];while(s<28){for(;i<2929;i++){if((i+1)%29){if(!(i%29))x=0;b[i]=rand()%20?b[i%29]:w[rand()%28]; x+=b[i]==w[i%29];if(x>s){s=x;t=i/29;}}}for(i=0;i<29;i++){x=b[i+t*29];b[i+t*29]=b[i];b[i]=x;}printf("%d: %s -- score %d\n",n++,b,s);t=0;}} Edit: This is the original, ungolfed code, for those who are interested in knowing how the "golfing" was done. The code produces no warnings when compiled with GCC with -Wall and C99 enabled. Maybe you're a golfing newbie like me, or a C newbie like me, or maybe you're just curious. :) https://gist.github.com/cpx/97edbce4db3cb30c306a ## Scala, 347341 337 chars: import util.Random.{nextInt=>r} val t="METHINKS IT IS LIKE A WEASEL" def c="ABCDEFGHIJKLMNOPQRSTUVWXYZ "(r(27)) def s(a:String)=t.zip(a).map{x=>if(x._1==x._2) 1 else 0}.sum def w(a:String,i:Int=0){println(f"$i%2d: $a -- score:${s(a)}")
if(s(a)!=28){w((0 to 99).map{_=>a.map(o=>if(r(20)<1) c else o)}.sortBy(s).last,i+1)}}
w(t.map(_=>c))

=>

0: PGSHWAEPALQFTCORUKANPNUTRVXH -- score: 2
1: PGSHWAEPALQ TCOQUKANPNUTRVXH -- score: 3
...
47: METHINKS WT IS LIKE A WEASEL -- score: 27
48: METHINKS IT IS LIKE A WEASEL -- score: 28
• oops. i misread the algorithm and instead of "a 5% chance per character of that character being replaced with a random character", i had permuted a single random character. will fix. – Rob Starling Jan 6 '14 at 4:39
• fixed and trimmed a little! – Rob Starling Jan 6 '14 at 5:36
• in scala 2.10, println("%2d: %s -- score: %d".format(i,a,s(a)) can change to println(f"$i%2d:$a%s -- score: ${s(a)}%d"), saving 4 chars! – Rob Starling Jan 8 '14 at 9:47 • ((('A'to'Z')toSeq):+' ') == "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", and the 2 %s are not necessary for printing string, saving 9 chars – Chris Jan 10 '14 at 11:24 • @Chris what version of scala did you run that under? def c=(' '+:('A'to'Z'))(r(27)) gives me error: type mismatch; found : Int required: scala.collection.generic.CanBuildFrom[scala.collection.immutable.IndexedSeq[Char],Char,?] – Rob Starling Jan 10 '14 at 17:30 ## PHP 442 <? function r(){$n=rand(65,91);if($n==91) return ' ';else return chr($n);}function s($s){$c=0;$t='METHINKS IT IS LIKE A WEASEL';for($i=0;$i<28;$i++) if($s[$i]==$t[$i]) $c++;return$c;}function m($s){for($i=0;$i<28;$i++) if(rand(0,99)<5) $s[$i]=r();return $s;}$s='';for($i=0;$i<28;$i++)$s.=r();for($i=0;;$i++){$l=s($s);printf("%2d: %s -- score: %d\n",$i,$s,$l);if($l==28) break;$x=$s;for($j=0;$j<100;$j++){$t=m($s);if(s($t)>$l)$x=$t;}$s=$x;} Readbly: <? //random char function r(){$n=rand(65,91);
if($n==91) return ' '; else return chr($n);
}
//score
function s($s){$c=0;
$t='METHINKS IT IS LIKE A WEASEL'; for($i=0;$i<28;$i++)
if($s[$i]==$t[$i]) $c++; return$c;
}
//mutate
function m($s){ for($i=0;$i<28;$i++)
if(rand(0,99)<5) $s[$i]=r();
return $s; }$s='';
for($i=0;$i<28;$i++)$s.=r();
for($i=0;;$i++){
$l=s($s);
printf("%2d: %s -- score: %d\n",$i,$s,$l); if($l==28) break;
$x=$s;
for($j=0;$j<100;$j++){$t=m($s); if(s($t)>$l)$x=$t; }$s=$x; } • removing extra whitespace after if\for, it is at 436. you could also check$n>90 for another char – Einacio Jan 7 '14 at 18:41
• I like this, it's actually readable. I've found a few possible improvements to your r() and s() functions. Here's the changes with comments: ideone.com/4ecZQc – Mr. Llama Jan 9 '14 at 23:12
• Oh, and your printf statement can be shortened. The %s is always the same length and the %d is left justified, so you can use the following instead: printf("%2d: $s -- score:$l\n",$i); – Mr. Llama Jan 9 '14 at 23:14 # Java (632) class C {public static void main(String[] a){String b="AAAAAAAAAAAAAAAAAAAAAAAAAAAA";for(int i=1;;i++){String c=w(b);int s=s(c);if(s==28)break;if(s(b)<s){b=c;System.out.println(i+": "+c+" -- score: "+s);}}}public static String w(String b) {StringBuffer c = new StringBuffer(b);int max = 0;for (int i=0;i<100;i++){for(int j=0;j<28;j++)if(Math.random()<.06){double d=Math.random();c.setCharAt(j,(char)(d==1?32:d*26+65));}String d=c.toString();int s=s(d);if(s>max){max=s;b=d;}}return b;}public static int s(String s){String b="METHINKS IT IS LIKE A WEASEL";int sum=0;for(int j=0;j<28;j++)sum+=s.charAt(j)==b.charAt(j)?1:0;return sum;}} Java is such a verbose language.. :( # Python (330 321) def b(i,s):print i,':',''.join(s),'-- score:',p(s) from random import*;a=" ABCDEFGHIJKLMNOPQRSTUVWXYZ";i,s,t=0,choice(a)*28,"METHINKS IT IS LIKE A WEASEL";p=lambda n:sum(n[c]==t[c]for c in range(28)) while p(s)<28:b(i,s);s=sorted([[(c,choice(a))[random()<.05]for c in s]for k in[1]*100],key=lambda n:p(n))[-1];i+=1 b(i,s) Readable version: def b(i,s): print i,':',''.join(s),'-- score:',p(s) import random as r a=" ABCDEFGHIJKLMNOPQRSTUVWXYZ" i,s,t=0,r.choice(a)*28,"METHINKS IT IS LIKE A WEASEL" p=lambda n:sum(1for c in range(28)if n[c]==t[c]) while p(s)<28: b(i,s) s=sorted([[(c,r.choice(a))[r.random()<.05]for c in s]for k in[1]*100],key=lambda n:p(n))[-1];i+=1 b(i,s) Example output: 0 : SSSSSSSSSSSSSSSSSSSSSSSSSSSS -- score: 3 1 : SSSQSSSSSSSSSSSSISSSSSSSSSSS -- score: 4 2 : SSSQISSSSSSSSSSSISSSSSSSSSSS -- score: 5 3 : SSSQISSSSSSSSSSSIKSSSSSSSSSS -- score: 6 4 : SMSQISSSSSSSISSSIKSSSSGSSSSS -- score: 7 ... 53 : METHINKS IT IS UIKE A WEASEL -- score: 27 54 : METHINKS IT IS UIKE A WEASEL -- score: 27 55 : METHINKS IT IS LIKE A WEASEL -- score: 28 edit: removed a few characters based on AMKs and Timtechs answer • sum(1for c in range(28)if n[c]==t[c]) may be shortened to sum(n[c]==t[c] for c in range(28)) (-3 chars) – AMK Jan 6 '14 at 22:21 • Save 5 chars, change import random as r to from random import* and then remove the three instances of r. – Timtech Jan 7 '14 at 15:24 • Sorry, I don't speak Python. Is line zero in your sample output just a freak coincidence or does your script always start with all S's? The challenge requires starting with a string of random characters. – Iszi Jan 7 '14 at 20:21 • It starts with 28 random character, but they are always the same. – PsHegger Jan 7 '14 at 22:24 • @Iszi Lol, it never said that each individual character had to be random! PsHegger: lol starting with all S's is fitting for the name of your language ;) – Doorknob Jan 9 '14 at 0:47 PHP (381 397 323 319 312): <? function s(&$s,&$i=0){$t='METHINKS IT IS LIKE A WEASEL';$i=0;$c=$s;$f=28;while($f--){$n=rand(0,26);$i+=($s[$f]=($c=='_'||!rand(0,19)?chr($n?$n+64:32):$s[$f]))==$t[$f];}}$s='_';s($s);$x=$y=0;do{$f=100;while($f--){$m=$s;s($m,$i);if($i>$y){$y=$i;$l=$m;}}printf("%2d: %s -- score: $y\n",$x++,$s=$l);}while($y<28); Readable version: <? function s(&$s, &$i = 0) {$t = 'METHINKS IT IS LIKE A WEASEL';
$i = 0;$c = $s;$f = 28; while ($f--) {$n = rand(0, 26);
$i += ($s[$f] = ($c == '_' || !rand(0, 19) ? chr($n ?$n + 64 : 32) : $s[$f])) == $t[$f];
}
}

$s = '_'; s($s);
$x =$y = 0;

do {
$f = 100; while ($f--) {
$m =$s;
s($m,$i);

if ($i >$y) {
$y =$i;
$l =$m;
}
}

printf("%2d: %s -- score: $y\n",$x++, $s =$l);
} while ($y < 28); Optimization credits (319): Optimization credits (312): • @Einacio's comments • i like the joint generator + randomizer – Einacio Jan 10 '14 at 15:07 • you could change both for for$f=N;while($f--){ for 3 char each. and for another char:$n=rand(0,26);[...]chr($n?$n+64:32) – Einacio Jan 10 '14 at 15:27
• Generator + randomizer + score computation. :) Thanks, I applied your optimizations. – brother Filip Jan 10 '14 at 16:40

## Ruby, 218

g,s,p,t=-1,'',1;while t!=28;t,b=-1;100.times{|i|m,n='',0
28.times{|j|n+=1if(m[j]=(rand<p ?[*?A..?Z,' '].sample: s[j]))=="METHINKS IT IS LIKE A WEASEL"[j]}
b,t=m,n if n>t};puts"#{g+=1}: #{s=b} -- score: #{t}";p=0.05;end

example run

0: LRAZZMKL IKUOGEHLKPWEVNEAZWX -- score: 6
1: LRAZZMKL IKUIGEALKMWEVNEAZWX -- score: 7
2: HRAGZMKL IKUIGEALKMWEVNEAZWX -- score: 7
3: HVAGZMKL IKUISAALKYWEVNEAZWX -- score: 8
...
48: METHIUKS IT IS LIKEIA WEASEL -- score: 26
49: METHINKS IT IS LIKEIA WEASEL -- score: 27
50: METHINKS IT IS LIKEIA WEASEL -- score: 27
51: METHINKS IT IS LIKE A WEASEL -- score: 28

## Ruby - 225202203 198 chars

Ruby seems under-represented in this challenge so far so I thought I would give it a try! Improvements welcome.

g=-1
s=[]
puts"#{g+=1}: #{$.,s=(0..99).map{n=(r=0..27).map{|i|x=[' ',*?A..?Z].sample;rand<0.05?x:s[i]||=x};[r.count{|i|n[i]=='METHINKS IT IS LIKE A WEASEL'[i]},n*'']}.max;s} -- score: #$."until$.>27 • In your output, "generation #" begins at 1 but the question specifies 0. If you init with g=-1 then it's fine. There may be a smarter way but I did it that way. Cheers, fellow RubyGolfer. – Darren Stone Jan 12 '14 at 1:48 • @DarrenStone Good call, thanks! Costs a character but I couldn't think of a better way. – Paul Prestidge Jan 12 '14 at 7:10 • By moving the code into the string, you can get to 198 chars: (same first two lines, then this for the rest) puts"#{g+=1}: #{$.,s=(0..99).map{n=(r=0..27).map{|i|x=[' ',*?A..?Z].sample;rand<0.05?x:s[i]||=x};[r.count{|i|n[i]=='METHINKS IT IS LIKE A WEASEL'[i]},n*'']}.max;s} -- score: #$."until$.>27 – Justin Aug 24 '15 at 17:14
• Good call! I'll edit it in. – Paul Prestidge Aug 24 '15 at 22:08

# Ruby, 206200 199

q,i,*R=*-2..27
puts"#{i+=1}: #{$.,s=(-2..q).map{x=R.map{|j|!s||rand<0.05?[*?A..?Z,' '].sample: s[j]};[R.count{|i|x[i]=='METHINKS IT IS LIKE A WEASEL'[i]},x]}.max;q=97;s.join} -- score: #$."until$.>27 The first line is simply a fancy way to define q=-2, i=-1, and R=(0..27).to_a. All the work is done in the 2nd line: puts"..."until$.>27 # Prints the string in quotes until we reach the desired score
^
|
+---+
|
"#{i+=1}: #{...} -- score: #$." ^ ^ ^ +--------|---------------|-- Generation counter +----------+---------------|-- Current string | +-- Score of current string (interpolates the $. variable)
|
#{$.,s=(-2..q).map{...}.max;q=97;s.join} # Generate the score & string ^ ^ ^ ^ ^ ^ ^ +---------|--|---|----|---|----|------ Store the score; this variable makes | | | | | | string interpolation shorter. +--|---|----|---+----|------ q automatically takes care of generating | | | | the string vs randomizing the string. +---|----|--------|------ Make 100 (or 1 the first time) strings, | | | and compute their score. | +--------|------- Take the string with the max score. +------------------+ +------- s is stored as an array | x=R.map{...};[R.count{...},x] # Compute string and its score, store in array ^ ^ ^^ ^ +-----|----|+-------|------ R is 0..27, we use the constant to save chars. | +--------|------ max orders by first element, then second. We clearly want | | the highest score, so make the score first. +-------+-------------|------ Generate the string, store in x. | +------ Count the number of chars that overlap with 'METHINKS...' | | | {|i|x[i]=='METHINKS IT IS LIKE A WEASEL'[i]} {|j|!s||rand<0.05?[*?A..?Z,' '].sample: s[j]} ^ ^ ^ ^ ^ +---+---------|-------------|-------|---- 5% chance of randomizing, or 100% for | | | first string. +-------------+-------|---- Sample from alphabet + ' '. +---- Don't alter the string 95% of the time • @ZachGates Glad you like the commenting style – Justin Sep 20 '15 at 7:14 # Japt v2.0a0, 112 108 bytes ª(T=Si26õdI q¹ö28 _¬í¥Ú0ˆks Š ‰ ¦ke a Øâelu q)x (OpW+: {U} -- sÖ: +(K=[U]xV¹WÄ K<28©ßLÆ®p513 iT ö}ÃñV o Try it online! -4 bytes thanks to @ETHproductions. ### Unpacked & How it works U||(T=Si26õdI q) ö28 Initialize primary input U|| If U is not initialized... 26õdI Generate uppercase alphabets q Convert to string Si Add space (T= ) Assign to variable T ö28 Sample 28 random chars from T and form a string Implicitly assign to U _q í==Ú0ˆks Š ‰ ¦ke a Øâelu q)x Match counting function _ Declare a function... q í== ) Convert to array of chars and pair with the next, and map with equality... Ú0ˆks Š ‰ ¦ke a Øâelu q "methinks it is like a weasel" to uppercase split into chars x Sum (true == 1, false == 0) Implicitly assign to V (OpW+: {U} -- sÖ: +(K=[U]xV) W+1 Output and increment counter (Op ) Output with newline... W+: {U} -- sÖ: + {W}: {U} -- score:  [U]xV Call V on [U] and force cast to number (K= ) Assign to K W+1 Add 1 to W and implicitly assign to W K<28&&ßLo@Um_p513 iT ö}} ñV o Termination check and recursion K<28&& If the match count is less than 28... ß Recurse the program with... Um_ Map over chars of U... p513 iT The char repeated 513 times plus T ö} Sample a char from it Lo@ } Generate array of 100 of the above ñV o Sort by V, pop the largest, pass it as U • 106 bytes, with a switch to v1.4.5. – Shaggy May 31 '18 at 16:53 # Japt-R, 94 bytes A different approach to but with a little inspiration from Bubbler's solution. ;C±S ö28 È¶Ú0ks ¦ke a ØâelgY @=#dÆ£20ö ?X:CöÃÃñ_¬xVÃo)Ê¶G}a@Np[X+':Uu '-²sÖ:G=U¬xV]¸ ## Explanation ### Line 1 Result gets assigned to variable U. ;C±S ö28 ;C :The lower case alphabet ±S :Append a space and reassign result to C ö28 :Generate a string of 28 random characters ### Line 2 Result gets assigned to variable V. È¶Ú...lgY È :A function that takes 2 arguments; a string (X) and an integer (Y) Ú...l : The compressed string "methinks it is like a weasel" gY : Get the character at index Y ¶ : Test for equality with X ### Line 3 The result of this line is implicitly joined with newlines and output. @=#dÆ£20ö ?X:CöÃÃñ_¬xVÃo)Ê¥G}a@Np[X+':Uu '-²sÖ:G=U¬xV]¸ @ }a@ :Repeat until true [ ] :Build an array containing ... X+': : A colon appended to the number of the current iteration Uu : The current value of U uppercased '-² : A hyphen repeated twice sÖ: : The compressed string "score: " U¬ : Split U to an array of characters V : Pass each character X at index Y through function V x : Reduce by addition G= : Assign the result to variable G ¸ :Join with spaces Np :Push to N (initially an empty array) #d :100 Æ :Generate the range [0,100) and pass each through a function £ : Map over each character X in U 20ö : Generate a random number in the range [0,20), which has a 5% chance of being 0 (falsey) ?X : If thruthy, return X :Cö : Else return a random character from C Ã : End mapping Ã :End function ñ_ :Sort by passing each through a function ¬ : Split to an array of characters V : Pass each character X at index Y through function V x : Reduce by addition Ã :End sorting o :Pop the last element = ) :Reassign to U Ê :Length ¶G :Equal to G ## Perl 5, 219 bytes$_="METHINKS IT IS LIKE A WEASEL";sub r{(A..Z,$")[rand 27]};sub t{~~grep/$t[$-++%28]/,pop=~/./g}$}.=r for@t=/./g;printf"%3d: %s -- score: %d
",$i++,(($})=sort{t($b)<=>t$a}map s/./rand>.05?$&:r/ger,($})x100),t$}until/$}/

Try it online!

# Ruby - 410

#!/usr/bin/env ruby
C,RC=[32]+(65..90).to_a,->{C[rand(27)].chr}
T,CO,CH,OU,s,sc,a,aa,z,TR="METHINKS IT IS LIKE A WEASEL",->x{a=0;(0...28).each{|z|a+=1 if x[z]==T[z]};a},->{a[aa.rindex(sc)]},->x,y{print x;print " Score: ";puts y},(0...28).map{RC[]}.join,0,[0],[0],0,->{rand(20)==0}
until sc==28
a=[s]*100;aa=[0]*100;(0...100).each{|x|(0...28).each{|y|a[x][y]=RC[] if TR[]};z=CO[a[x]];aa[x]=CO[a[x]];OU[a[x],z]};sc=aa.max;s=CH[] end

Edit* It's currently failing (for some reason a[any] is being set to 0 (type=>fixnum)). However, the actual design is right, I just need to find the bug causing this to happen (it's very mysterious)

## Python 284

from random import*
C=choice
A=map(chr,range(65,91)+[32])
s=[C(A)for i in[0]*28]
N=x=0
while N!=28:N,s=max((len([i for i,j in zip(X,"METHINKS IT IS LIKE A WEASEL")if i==j]),X)for X in[[c if random()<.95 else C(A)for c in s]for i in[0]*100]);printx+":",''.join(s),"-- score:",N;x+=1

## GolfScript 207

{91,{64>},32+''+27rand=}:g;'METHINKS IT IS LIKE A WEASEL':s;{{\.@\=s@==}+s,,\%{+}*}:c;0:k;{k):k\.': '@@c' -- score: '\++++n+}:f;[{g}]28*{~}%{s=!}{{100,\{\;{100rand 5>{ }{;g}if}%''+}+}~%{c}$)\;{ }%}/{f}/s f Below is a slightly unpacked version of the above GolfScript with explanation. Since I don't think it could beat the APL or some other answers, I didn't bother to truly minify it. I think that with inlining variable declarations, eliminating unnecessary variables, and other such tricks, this code could achieve approximately 190 characters without really changing the algorithm. I think about about 10-15 characters could be removed if I better sorted out the conversion between arrays of ASCII values and strings. #g is a function that returns the ASCII value of a random character or space. #The ASCII values for capital letters are 65-90, and 32 is space. {91,{64>},32+''+27rand=}:g; #s is the string of interest. 'METHINKS IT IS LIKE A WEASEL':s; #c is a function that returns the 'score' of a given string #(the number of correct characters in the correct place). {{\.@\=s@==}+s,,\%{+}*}:c; #t is a function that transforms a given string according to #the specification (by replacing characters with a random character 5% of the times). {{100rand 5>{ }{;g}if}%''+}:t; #i is the initial random string. [{g}]28*{~}%:i; #Use '/' to unfold the initial value until the string is equal to the string of interest. #Every loop, do the transformation 100 times, then sort by score c, and then take the top scoring string. #Aggregate the results into an array a. i{s=!}{{100,\{\;t}+}~%{c}$)\;{ }%}/:a;

#Instantiate a counter variable k
0:k;

#f is the formatting function, that takes a string and formats it according to the spec.
{k):k\.': '@@c' -- score: '\++++n+}:f;

#Format every string in the array, and then format the string of interest
a{f}/
s f

# JavaScript - 312

There is already a shorter JS solution above but it is using experimental pointer functions, so I thought I'd throw in another solution that is running in any JS environment:

for(r=Math.random,R=function(){return'METHINKS CODZAWFLBUGYQRXVJP'[~~(r()*27)]},_=[],_.$=n=0,D=function(s){for(c=[],c.$=i=0;i<28;){c[i]=s&&r()<.95?s[i]:R();_=(c.$+=c[i]=='METHINKS IT IS LIKE A WEASEL'[i++])>_.$?c:_};return c},D();_.$<28;){for(j=0;j++<1e2;)D(_);console.log(n+++': '+_.join('')+' -- score: '+_.$)}

## Java: 557 534

enum W{W;public static void main(String[]a){char[]c=new char[28],h,d[];int i,k,e,s=W.s(c);for(i=0;i<28;i++)c[i]=W.r();for(i=0;;){W.p(i++,h=c,s);if(s>27)break;d=new char[100][28];for(char[]b:d){for(k=0;k<28;k++)b[k]=Math.random()<.05?W.r():h[k];if((e=W.s(b))>s){s=e;c=b;}}}}int s(char[]c){int s=0,k;for(k=0;k<28;k++)if(c[k]=="METHINKS IT IS LIKE A WEASEL".charAt(k))s++;return s;}void p(int i,char[]c,int s){System.out.println(i+": "+new String(c)+" -- score: "+s);}char r(){int i=(int)(Math.random()*27);return(char)(i==26?32:i+65);}}

Unwrapped:

enum W {
W;

public static void main(String[] a) {
char[] c = new char[28], h, d[];

int i, k, e, s = W.s(c);

for(i = 0; i < 28; i++)
c[i] = W.r();

for(i = 0;;) {
W.p(i++, h = c, s);

if(s > 27)
break;

d = new char[100][28];

for(char[] b : d) {
for(k = 0; k < 28; k++)
b[k] = Math.random() < .05 ? W.r() : h[k];

if((e = W.s(b)) > s) {
s = e;
c = b;
}
}
}
}

int s(char[] c) {
int s = 0, k;
for(k = 0; k < 28; k++)
if(c[k] == "METHINKS IT IS LIKE A WEASEL".charAt(k))
s++;

return s;
}

void p(int i, char[] c, int s) {
System.out.println(i + ": " + new String(c) + " -- score: " + s);
}

char r() {
int i = (int)(Math.random() * 27);
return (char)(i == 26 ? 32 : i + 65);
}
}

PHP 429 426 421 415

<? function t(){$a="ABCDEFGHIJKLMNOPQRSTUVWXYZ ";return$a{rand(0,26)};}$c='';$j=$g=0;$i=28;while($i--)$c.=t();function r($s){$i=28;while($i--)!rand(0,19)&&$s{$i}=t();return$s;}function s($s,&$r){$c="METHINKS IT IS LIKE A WEASEL";$i=28;$r=0;while($i--)$r+=$s{$i}==$c{$i};}while($g<28){$n='';$v=0;$i=100;while($i--){s($t=r($c),$a);($a>$v)&&($v=$a)&($n=$t);}($v>$g)&&($g=$v)&($c=$n);echo$j++.": $c -- score:$g\n";}

pretty print

<?php
function t(){
$a="ABCDEFGHIJKLMNOPQRSTUVWXYZ "; return$a{rand(0,26)};
}
$c='';$j=$g=0;$i=28;
while($i--)$c.=t();
function r($s){$i=28;
while($i--) !rand(0,19)&&$s{$i}=t(); return$s;
}
function s($s,&$r){
$c="METHINKS IT IS LIKE A WEASEL";$i=28;
$r=0; while($i--)
$r+=+($s{$i}==$c{$i}); } while($g<28){
$n='';$v=0;
$i=100; while($i--){
s($t=r($c),$a); ($a>$v)&&($v=$a)&($n=$t); } ($v>$g)&&($g=$v)&($c=$n); echo$j++.": $c -- score:$g\n";
}

I'll need a less verbose language next time

• shortest php answer so far well done! – Noelkd Jan 7 '14 at 18:50
• could be better, but i shoud work – Einacio Jan 7 '14 at 19:00
• you can always come back and update your answer – Noelkd Jan 7 '14 at 19:03

# Python 2.7 - 319 bytes

Sure it's not the smallest, but it was fun to program.

from random import*
a=map(chr,range(65,91))+[' ']
c,i,y=choice,0,{}
s=[c(a)for i in[0]*28]
while 1:
for j in[0]*100:v=[c(a)if .05>random()else x for x in s];y[sum(1if'METHINKS IT IS LIKE A WEASEL'[k]==v[k]else 0for k in range(28))]=v
v=max(y.keys());s=y[v];print"%d: %s -- score: %d"%(i,''.join(y[v]),v);i+=1
if v==28:break

Uses a recursing function, so it may reach the maximum recursion depth if there is some kind of weird devolution with the string.

ubuntu@ubuntu-OptiPlex-980:~\$ python weasel.py
0: VPBHBSPWFTOG HAXSESCDNFPKWYE -- score: 1
1: VABHBSPWFTOG HAXSESCDNWPKWYE -- score: 2
2: VAWHBSPWFTOGIHAXSESSDNWPKWYE -- score: 3
3: VAWHBSPWFTOGIHAXSEFSGNWPKWYL -- score: 4
4: XAWHBSPYFTOGIHAXSEFSGNWPKWYL -- score: 4
5: XAWHBSKYFTOGIHAXSEFSGNWPKWYL -- score: 5
6: XAWHBSKYFTOGIHAXSEF GNWPKWYL -- score: 6
7: XAWHBSKYFTOGIHALSEF ANWPKWYL -- score: 8
8: XAKHBSKYFTTGIHALSEY ANWPKWYL -- score: 9
9: XAKHISKYFTTGIHALSEE ANWPKWYL -- score: 11
10: XAKHISKSFTTGIHALSEE ANWPKWYL -- score: 12
11: XAKHISKSFTTGIHALSBE ANWPKWKL -- score: 12
12: XAQHISKSFRT IHALSBE ANWPKWKL -- score: 13
13: XAQHISKSFIT IHALSBE ANWPKWKL -- score: 14
14: XAQHISKSFIT IHALSBE ANWPKWKL -- score: 14
15: XAQHISKSFIT IHALSBE ANWPKWKL -- score: 14
16: XALHISKSFIT ISALSBE ANWPKWKL -- score: 15
17: JALHISKSFIT ISALSBE ANWPAWKL -- score: 16
18: JALHISKSFIT ISALIBE ANWPAWKL -- score: 17
19: JALHISKSFIT ISALIBE ANWPAWKL -- score: 17
20: JALHISKSFIT ISALIBE ANWPAWKL -- score: 17
21: JALHISKSFIT ISALIKE ANWPAWYL -- score: 18
22: JALHISKSFIT IS LIKE ANWPAWYL -- score: 19
23: JALHISKSFIT IS LIKE ANWEAWYL -- score: 20
24: JALHISKSFIT IS LIKE ANWEAWYL -- score: 20
25: JALHISKSFIT IS LIKE ANWEAWZL -- score: 20
26: JALHISKS IT IS LIKE ANWEAAZL -- score: 21
27: JACHISKS IT IS LIKE ANWEASZL -- score: 22
28: JACHISKS IT IS LIKE ANWEASZL -- score: 22
29: MACHISKS IT IS LIKE ANWEASZL -- score: 23
30: MACHISKS IT IS LIKE ANWEASZL -- score: 23
31: MACHISKS IT IS LIKE AUWEASZL -- score: 23
32: MACHISKS IT IS LIKE AUWEASZL -- score: 23
33: MACHISKS IT IS LIKE AJWEASZL -- score: 23
34: MACHISKS IT IS LIKE A WEASZL -- score: 24
35: MACHISKS IT IS LIKE A WEASZL -- score: 24
36: MACHINKS IT IS LIKE A WEASZL -- score: 25
37: MACHINKS IT IS LIKE A WEASZL -- score: 25
38: MACHINKS IT IS LIKE A WEASZL -- score: 25
39: MBCHINKS IT IS LIKE A WEASZL -- score: 25
40: MBCHINKS IT IS LIKE A WEASZL -- score: 25
41: MBCHINKS IT IS LIKE A WEASZL -- score: 25
42: MBCHINKS IT IS LIKE A WEASZL -- score: 25
43: MBCHINKS IT IS LIKE A WEASZL -- score: 25
44: MBCHINKS IT IS LIKE A WEASZL -- score: 25
45: MECHINKS IT IS LIKE A WEASCL -- score: 26
46: MECHINKS IT IS LIKE A WEASCL -- score: 26
47: MECHINKS IT IS LIKE A WEASCL -- score: 26
48: MECHINKS IT IS LIKE A WEASCL -- score: 26
49: MECHINKS IT IS LIKE A WEASCL -- score: 26
50: MECHINKS IT IS LIKE A WEASCL -- score: 26
51: MEQHINKS IT IS LIKE A WEASCL -- score: 26
52: MEQHINKS IT IS LIKE A WEASCL -- score: 26
53: MEQHINKS IT IS LIKE A WEASCL -- score: 26
54: MEQHINKS IT IS LIKE A WEASCL -- score: 26
55: MEQHINKS IT IS LIKE A WEASCL -- score: 26
56: MEQHINKS IT IS LIKE A WEASCL -- score: 26
57: METHINKS IT IS LIKE A WEASCL -- score: 27
58: METHINKS IT IS LIKE A WEASCL -- score: 27
59: METHINKS IT IS LIKE A WEASCL -- score: 27
60: METHINKS IT IS LIKE A WEASCL -- score: 27
61: METHINKS IT IS LIKE A WEASCL -- score: 27
62: METHINKS IT IS LIKE A WEASCL -- score: 27
63: METHINKS IT IS LIKE A WEASCL -- score: 27
64: METHINKS IT IS LIKE A WEASCL -- score: 27
65: METHINKS IT IS LIKE A WEASEL -- score: 28

Massive thanks to Sp3000 for golfing help.