# 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? Commented Jan 3, 2014 at 17:42
• Ah, I love Dawkins. Beauty, and feasibility of evolution shown in a simple algorithm. Commented Jan 3, 2014 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? Commented Jan 3, 2014 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
Commented Jan 6, 2014 at 19:18
• The instructions are pretty clear, but what if the original string is the target? Commented Jan 8, 2014 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! :) Commented Jan 7, 2014 at 16:46
• @ToastyMallows: added explanation Commented Jan 7, 2014 at 17:20
• Best answer so far, great to have an explaination with it. Commented Jan 7, 2014 at 17:22
• @marinus Are you a wizard? Commented Jan 8, 2014 at 13:52
• Bullcrap, you just opened MS Word and used WingDings font Commented Jan 9, 2014 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

0:  CYPMEIHADXRXVTFHERYOZNRVFCSQ  -- score: 0
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  ## 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 :) ) Commented Jan 8, 2014 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... Commented Jan 8, 2014 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 Commented Jan 9, 2014 at 22:43 # 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. Commented Jan 3, 2014 at 12:27 • Will do, thanks for the tips tim. Commented Jan 3, 2014 at 12:47 • Also, you should use all one letter variable names to decrease the character count further. Commented Jan 3, 2014 at 14:40 • Waiting till later to golf it down some more, still got some easy wins. Thanks. Commented Jan 3, 2014 at 14:45 • Is it really supposed to start with all same letters? :) Commented Jan 7, 2014 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.? Commented Jan 7, 2014 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. Commented Jan 7, 2014 at 1:26 • Clever use of code! Commented Jan 7, 2014 at 1:29 • Nice trick with k=s=[28] and ++, I had no idea! Commented Jan 7, 2014 at 6:16 # 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. Commented Jan 9, 2014 at 16:34 • No, you don't. ideone.com/4alNSi. – tia Commented Jan 9, 2014 at 17:23 • Ah nice. Looked at the NS declaration as a using sorry. Commented Jan 11, 2014 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. Commented Jan 6, 2014 at 4:39
• fixed and trimmed a little! Commented Jan 6, 2014 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! Commented Jan 8, 2014 at 9:47 • ((('A'to'Z')toSeq):+' ') == "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", and the 2 %s are not necessary for printing string, saving 9 chars Commented Jan 10, 2014 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,?] Commented Jan 10, 2014 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 Commented Jan 7, 2014 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 Commented Jan 9, 2014 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); Commented Jan 9, 2014 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 Commented Jan 6, 2014 at 22:21 • Save 5 chars, change import random as r to from random import* and then remove the three instances of r. Commented Jan 7, 2014 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 Commented Jan 7, 2014 at 20:21 • It starts with 28 random character, but they are always the same. Commented Jan 7, 2014 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 ;) Commented Jan 9, 2014 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 Commented Jan 10, 2014 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) Commented Jan 10, 2014 at 15:27
• Generator + randomizer + score computation. :) Thanks, I applied your optimizations. Commented Jan 10, 2014 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. Commented Jan 12, 2014 at 1:48 • @DarrenStone Good call, thanks! Costs a character but I couldn't think of a better way. Commented Jan 12, 2014 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 Commented Aug 24, 2015 at 17:14
• Good call! I'll edit it in. Commented Aug 24, 2015 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 Commented Sep 20, 2015 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. Commented May 31, 2018 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! Commented Jan 7, 2014 at 18:50
• could be better, but i shoud work Commented Jan 7, 2014 at 19:00
• you can always come back and update your answer Commented Jan 7, 2014 at 19:03

Golfscript (168 167)

:x;0['METHINKS IT IS LIKE A WEASEL'{}/]:o{;{27rand.!96*+64^}:r~}%{o=!}{100,{;.{20rand{}{;r}if}%}%{{[o\]zip{~=},,}:s~}$)@;\;x 2$+': '+1$+' -- score: '+1$s+n+:x;\)\}/;;x


Sadly, I can't seem to compress it quite to APL's level, but it's afaict currently a shared second place.

This is what it does;

# Grab the empty parameter string as initially empty output string.
:x;
# Start count at row #0
0
# Store the target string as an array in 'o'
['METHINKS IT IS LIKE A WEASEL'{}/]:o
# Create a random starting string, and define 'r' as a function generating a random char.
{;{27rand.!96*+64^}:r~}%
# Unfold as long as the latest string is different from the target string.
{o=!}
{
// Generate 100 strings, sort by score and keep the highest.
100,{;.{20rand{}{;r}if}%}%{{[o\]zip{~=},,}:s~}$)@;\; // Append the row to the output string, and increase the row number x 2$+': '+1$+' -- score: '+1$s+n+:x;\)\
}/
// Clean some junk on the stack
;;
// Output string
x