Here we go again, it's been a few years since playing with this
stuff, but recently I found a neat programming language
called yabasic, for "yet another BASIC". I've been using it
for simple scripts but got the itch again and learned the language
better and used it to make yet another redcode evolving program...
YabEvolver. This one is similar to most of my previous evolvers -
a two dimensional soup where randomly selected warriors battle an
immediately surrounding warrior with the loser being replaced with
an evolved copy of the winner.
Here's an animated gif showing the early moments of a run...
The numbers show the number of instructions in each warrior, the
colors represent the warrior's "species" which is a random number
which is changed whenever a mutation can potentially change the
base instruction sequence. The warriors start out random,
optionally the minimum length and the initial instruction sequence
can be specified, in this run the warriors start out with random
instructions and length. Very quickly natural selection kicks in
and favors the stronger warriors which multiply and form islands
of similar warriors within the soup. Within these islands the
warriors strengthen by competing against their own kind, at the
borders between islands the warriors battle dissimilar warriors
and learn new skills. Usually one particular sequence will mostly
or completely take over but the species will keep changing as a
new random species number is selected whenever an operation occurs
that might result in a sequence change, regardless if the sequence
actually changed. Besides helping to keep the display interesting,
it highlights the warrior forms with more successful strategies as
they multiply more.
After a bit the length 5 warriors have almost completely taken
over except for a small patch of 4's...
The user interface permits cursoring around the soup then pressing L or B to list or benchmark warriors...
Pressing V selects alternate soup views that use characters to
represent warrior species and instruction sequence...
When mapping the instruction sequence to a limited set of characters collisions are inevitable so the program has two different sequence methods, the one above is mod 52 to map instruction sequences to A-Z and a-z, the next view mode is mod 94 to map the sequences to ascii 33-126. The above screenshots are using 16-color ANSI to color the species, the program also supports using 256 color ANSI and 24-bit RGB ANSI.
Pressing numpad keys 1-9 battles the warrior against a surrounding warrior in pmarsv(sdl), pressing 0 battles the warrior against a randomly selected warrior from the test set...
67_03 beat Free the Fish! This time.. the score in this case is
from 10 rounds randomly positioned.
In addition to on-demand benchmarking, the evolver periodically
benchmarks a randomly selected soup warrior and saves it to a
separate directory if it scores above a specified threshold and
within a specified percentage of the top score. Pressing O brings
up an "other" menu with options to change the benchmark set,
change parameters or load another INI file (ignores any settings
such as soup/top directories and size parameters that would
invalidate the current run), show soup instruction sequences and
population numbers, and show the sequences along with a full
benchmark of the soup...
This program is for Linux-type system, it uses sh/nix-type shell commands ("[" ls echo mkdir read chmod etc), assumes /dev/shm is a user-writable ram disk for temp files, and outputs lots of ANSI screen codes. Requires yabasic, pmars and pmarsv, links in the source code. Yabasic is in the Ubuntu repositories, here's my patched pmars092N3 source/binaries compiled for 64-bit Linux. Here's my slightly modified pmars-0.9.2-5sdlN source and 64-bit Linux binaries for the pmarsv SDL port (added a delay to slow it down), requires the SDL 1.2 libraries. For newer Ubuntu etc look for the libsdl1.2debian package. For nano warriors the old pmarsv looks about right with view options "-v 564", for my patched SDL version I use view options "-v 784".
Here's the latest YabEvolver program code...
#!/usr/bin/env yabasic REM YabEvolver - Evolves Redcode Warriors for Core War REM usage: yabevolver [inifile] REM Requires pmars/pmarsv and yabasic... REM yabasic githib: https://github.com/marcIhm/yabasic (or repository) REM Various versions of pmars/v are here: https://corewar.co.uk/pmars.htm REM Recommend version 0.9.2 or 0.9.2-5 (SDL). By convention the nongraphical REM pmars is named "pmars" and the graphical version is named "pmarsv", REM both are compiled from the same source code. The SDL version of pmarsv REM uses different view options so I name it "pmarsvsdl" to avoid conflict. REM Note - the pmars package in Ubuntu etc repositories is really pmarsv REM and won't work for evolving. REM This program uses ANSI codes and Unix/Linux-specific commands paths etc REM Assumes sh syntax for system commmand, embedded inkey.sh script uses bash REM Must run in a terminal large enough for soup display (xdim+2 by ydim+3) REM ANSI soup dump player Fast/Slow feature requires awk (scripted FP math) REM For best results tempdir$ should be on a ram disk (default /dev/shm). REM DO NOT set tempdir$ to a solid state drive! This program really messes REM with automatic file indexers (like baloo) or anything that monitors or REM intercepts disk writes. Changes/License/Disclaimer after program code. e=system("[ -t 1 ]"):if e end rem exit if not in terminal or OS not supported print "*** YabEvolver *** Version 230303-08" REM --- yabevolver ini file ------------------------------------------------ REM copy this section to a file and specify filename on command line to load header$ = ";redcode-nano" rem first line of program (start with ;) author$ = ";author yabevolver" rem author line (start with ;) comment$ = ";strategy evolved" rem comment line (start with ;) tempdir$ = "/dev/shm/yabevoltmp" rem temp directory for battling warriors soupdir$ = "soup" rem where soup warriors are stored topdir$ = "top" rem where top-scoring warriors are saved benchdir$ = "nano2301" rem benchmark dir for testing warriors REM soup/pmars specs xdim = 77 rem soup x dimension ydim = 20 rem soup y dimension xwrap = 0 rem enable wraparound in x dimension ywrap = 0 rem enable wraparound in y dimension length = 5 rem max warrior length mincrelen = 1 rem minimum warrior length at creation coresize = 80 rem core size processes = 80 rem max processes cycles = 800 rem instruction cycles per match rounds = 100 rem matches per battle REM mutation rates, 0-1 instrate = 0.015 rem chance of changing an instruction modrate = 0.02 rem chance of changing a modifier addrrate = 0.03 rem chance of changing an address mode numrate = 0.04 rem chance of changing a number reprate = 0.005 rem chance of replacing with new random line insrate = 0.005 rem chance of inserting a new line (pushing rest down) duprate = 0.005 rem chance of duplicating previous or following line swaprate = 0.005 rem chance of swapping two lines (only 1 chance per evo) delrate = 0.005 rem chance of deleting a line (pulling rest up) orgrate = 0.0 rem chance of a random ORG line (ORG starts at 0) REM mutation options mutadjust = 0 rem 0-1, reduce mutation rates by up to rate*mutadjust mutadjgen = 2000 rem by mutadjgenerations. Make either 0 to disable adjrate = 0.4 rem if number changed, chance of increment or decrement localrate = 0.5 rem if new number, chance of being within warrior org0rate = 0.5 rem if ORG changed, chance of ORG 0 crossrate = 0.02 rem crossover rate adjlocref = 1 rem if not 0 adjust local refs when inserting and deleting REM evaluate and benchmark options evopseq = 0 rem evolving pmars sequence 0=random 1=fixed 2=permutate evalmode = 3 rem 0=unguided 1=rnd bench 2=all 3=rnd 0/1 4=rnd 0/1/2 evalrate = 0.5 rem for evalmode 4 and 5, chance of using bench warriors evalgen = 200 rem apply evalmode after both reach this many generations benchfreq = 1000 rem warrior benchmark interval (0 to disable) savethr = 135 rem only save if score is >= this savepc = 2 rem save if within this percentage of top score bmrounds = 142 rem number of rounds when benchmarking benchpseq = 2 rem benchmark pmars sequence 0=random 1=fixed 2=permutate reinsfreq = 0 rem warrior reinsertion interval (0 to disable) REM instructions, modifiers and address modes... REM instruction$ length must be divisible by 4 (start with space) REM modifiers$ length must be divisible by 3 REM bias encoded using duplicates REM addr1mode$ and addr2mode$ separated as they have different mixes instructions$ = " MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV SPL SPL" instructions$ = instructions$+" SPL SPL SPL SPL DJN DJN DJN DJN DJN" instructions$ = instructions$+" ADD SUB MOD MUL DIV JMP JMZ JMN SEQ SNE" modifiers$ = ".I .I .I .I .I .I .I .I .B .B .B .B .F .F .F .X .A .AB.BA" addr1modes$ = "######$$$$$>>>><<<{{}}*@" addr2modes$ = "<<<<<<{{{{{>>>>$$$$}}}@#" initialinstr$ = " SPL MOV MOV MOV DJN" rem initial warrior instructions enablepreseed = 0 rem if not zero use initialinstr$ to pre-seed the soup REM other options ssfreq = 1000000 rem automatic soup save interval, 0 to disable superror = 1 rem if not 0 redirect pmars stderr to dev/null unibox = 1 rem enable unicode chars for box surrounding soup display viewmode = 0 rem view mode 0=length 1=species 2=sequence52 3=sequence94 viewshift = 0 rem raw display sequence hash xord by this to help avoid dups ansimode = 256 rem ANSI mode 16=16colors 256=256colors 24=RGB else no color enableC = 1 rem if not 0 allow color scheme cycling by pressing C REM binaries and CL options lister$ = "less" rem [path/]name of file lister program listeropts$ = "-~" rem lister opts for warriors.. no ~ at end listeroptsb$ = "-~ +G" rem lister opts for benchmarks.. no ~, go to eof pmars$ = "pmars" rem [path/]name of pmars binary pmarsv$ = "pmarsv" rem [path/]name of pmarsv binary pmarsvopts$ = "-v 564" rem pmarsv options (-v digits speed dispmode detail) rem pmarsv$ = "./bigpmarsv.sh" rem for my pmarsv magnifying script rem pmarsv$ = "pmarsvsdl" rem for the SDL version of pmarsv rem pmarsvopts$ = "-v 784" rem opts for my speed-patched SDL version pmarsvrounds = 10 rem rounds to run in pmarsv REM --- end yabevolver ini file -------------------------------------------- REM Warrior file format... REM REM ;redcode-nano whatever is in header$ REM ;name 1_1.red current filename REM ;author yabevolver whatever is in author$ REM ;strategy evolved whatever is in comment$ REM ;origin 1_1 this maintained throughout evolution REM ;species 12345 random string changed if inst seq changes REM ;generation 0 increments with each mutated copy REM ;created 01-26-2023 11-01-49 creation time/date REM ;assert CORESIZE==80 REM ORG 0 REM SPL.AB $ 0,< 60 must be in this format REM MOV.I # 64,{ 42 coresize<9999, 4 character numbers REM ... (evolver only uses - for small numbers) REM END REM load ini file if specified on the command line args=peek("argument") if args=1 then fname$=peek$("argument"):loadinifile(fname$) else print "Using internal defaults" endif validateparms() rem make sure parameters are valid REM dimension arrays maxbw=1000 REM maximum number of benchmark warriors dim soup$(xdim,ydim,length) REM just the warrior code, first empty is end dim origin$(xdim,ydim) REM the string after origin dim species$(xdim,ydim) REM the string after species dim tdstamp$(xdim,ydim) REM creation time/date dim wlength(xdim,ydim) REM warrior lengths dim orgnum(xdim,ydim) REM warrior ORG numbers dim gennum(xdim,ydim) REM warrior generation counts dim benchwarriors$(maxbw) REM benchmark warrior names REM used by the soup analyze functions... maxseq=2000 REM maximum number of unique sequences dim seq$(maxseq,2) REM sequence code character, instruction sequence dim seqcounts(maxseq) REM population count per sequence dim seqtops(maxseq) REM score of best scoring warrior for this sequence dim seqnames$(maxseq) REM name of best scoring warrior for this sequence dim benchscores(xdim,ydim) REM benchmark scores for each warrior maxrepsave=10 REM how many categories to save to report esc$=chr$(27)+"[" rem ANSI escape sequence stat=ydim+3 rem location of status line initdirs() rem initialize directories initbenchwarlist() rem initialize bench warrior list REM yabasic's inkey$ function requires clear screen which REM prevents casual use of ANSI codes so use a script instead... REM usage: key$=system$(tempdir$+"/inkey.sh[ -t [seconds]]") REM if -t specified returns immediately (~1ms), -t 1 for 1 second etc REM if -t specified if key detected (no timeout) but can't tell what REM key was pressed (enter space etc) then returns "[extra]" e=open(2,tempdir$+"/inkey.sh","w") if e=0 myerror("Can't write inkey script") print #2 "#!/bin/bash" print #2 "to=\"\";key=\"\";if [ \"$1\" = \"-t\" ];then" print #2 "to=\"-t .001\";if [ \"$2\" != \"\" ];then" print #2 "to=\"-t $2\";fi;fi;read $to -sn 1 key" print #2 "if [ $? = 0 -a \"$to\" != \"\" ]&&[ \"$key\" = \"\" ];then" print #2 "echo -n \"[extra]\";else echo -n \"$key\";fi" close #2 e=system("chmod +x "+tempdir$+"/inkey.sh") if e myerror("Can't set permissions on inkey script") print "(press esc within 2 seconds to pause) "; a$=system$(tempdir$+"/inkey.sh -t 2") if a$=chr$(27) then print:print esc$,"A";:cleartoend() input "(press enter to continue) " a$ endif print print "Initializing..." soupchanged=0 rem flag to prevent needless writes for y=1 to ydim for x=1 to xdim for i=1 to length:soup$(x,y,i)="":next i fname$=soupdir$+"/"+warriorname$(x,y)+".red" if (open(1,fname$,"r")) then rem file exists, read into arrays close #1 loadwarrior(fname$,x,y) else rem file doesn't exist so create it origin$(x,y)=warriorname$(x,y) species$(x,y)=str$(int(ran(100000))) wl=length-int(ran(1)*(length-mincrelen)) wlength(x,y)=wl gennum(x,y)=0 tdstamp$(x,y)=mid$(date$,3,10)+" "+left$(time$,8) for ln=1 to wl soup$(x,y,ln)=rndwline$(ln) if enablepreseed and ln<=niniti then left$(soup$(x,y,ln),3)=mid$(initialinstr$,(ln-1)*4+2,3) endif next ln soupchanged=1 rem soup changed, enable save option endif normalizenumbers(x,y) rem make sure numbers are consistent next x next y print REM init globals counters constants and stuff w2x=0 rem global vars set by picksurrounding w2y=0 sc1=0 rem global vars set by battlewarriors sc2=0 lastscore=0:lastbenchwar$="" rem for ANSI soup dump vm1chars$="~!@#$%^&*?.+';" rem warrior chars for viewmode 1 c1=1:c2=1 rem constants used for viewmode 2/3 hash (1,1 for orig) varsubcount=0 rem used to compile subs for printing variables anavalid=0 rem global set when benchmark analysis is valid benchtrigger=0:sstrigger=0:reinstrigger=0 rem init cycle counters viewshiftsave=viewshift rem save viewshift to toggle back to it cursoring=0 rem set if cursoring around showsoup() rem hides cursor cwx=1:cwy=1 rem cursor warrior x,y REM global vars for ANSI dump feature ansitrigger=0 rem cycle counter for ANSI soup dump ansifreq=0 rem ANSI dump frequency (if 0 disabled) ansidir$="ansidumps" rem directory for ANSI dumps (setup can change) ansifbase$="" rem base name for dumps (setup will change) ansifnumber=0 rem sequence number - dump0000.ans dump0001.ans etc ansifmax=9999 rem max sequence number REM main loop exitprogram=0 repeat if soupchanged anavalid=0 rem bench no longer valid hidecursor():position(stat,1):cleartoend() print " [E]Evolve [L]List [B]Bench "; if pmarsv$<>"" print "[0-9]Battle "; print "[V]View [O]Other "; if soupchanged then print "[S]SaveSoup "; elseif enableC then print "[C]Colors "; else print " "; endif if cursoring then print " ",warriorname$(cwx,cwy); else print "[X]Exit"; endif position(cwy+1,cwx+1):showcursor():cursoring=0 uikey$=system$(tempdir$+"/inkey.sh") rem wait for a keypress curscode$="" rem code after esc sequence if uikey$=chr$(27) then b$=system$(tempdir$+"/inkey.sh -t") if b$="[" curscode$=system$(tempdir$+"/inkey.sh -t"):cursoring=1 endif hidecursor() REM Shift-V - randomize seqhashxor to change chars (only viewmode 2+) REM Toggles xor mask between random number and viewshift setting if uikey$="V" and viewmode >=2 then if viewshift=viewshiftsave then viewshift=int(ran(100000)) else viewshift=viewshiftsave endif showsoup() endif REM menu for other functions if uikey$="o" THEN showcursor():otherstuff() hidecursor():showsoup() endif REM toggle view if uikey$="v" viewmode=mod(viewmode+1,4):showsoup() REM if color cycling enabled change ANSI color scheme if uikey$="c" and enableC cycleansimode() REM cursor control if curscode$="A" and cwy>1 cwy=cwy-1 rem up if curscode$="B" and cwy<ydim cwy=cwy+1 rem down if curscode$="C" and cwx<xdim cwx=cwx+1 rem right if curscode$="D" and cwx>1 cwx=cwx-1 rem left REM continue evolving if uikey$="e" then rem showsoup() position(stat,1):cleartoend() position(stat,61):print "(esc to stop)"; continue_evolving():showsoup() soupchanged=1 endif REM list a warrior if uikey$="l" then fname$=tempdir$+"/temp.red" writewarrior(fname$,cwx,cwy) clearscreen() system(lister$+" "+listeropts$+" "+fname$) if lister$="cat" input "(press enter to continue)" a$ showsoup() endif REM Benchmark a warrior if uikey$="b" and nbenchwars>0 then position(stat,1):cleartoend() print "Generating benchmark report..." fname$=tempdir$+"/temp.red" writewarrior(fname$,cwx,cwy) rem write warrior to tempdir/temp.red makebenchreport(fname$,wname$) rem write report to tempdir/results.txt clearscreen() system(lister$+" "+listeroptsb$+" "+tempdir$+"/results.txt") if lister$="cat" input "(press enter to continue)" a$ showsoup() endif REM battle warrior against surrounding warrior in pmarsv REM using numpad keys.. if 5 then run just the selected warrior REM fun bonus.. if 0 then battle against random bench warrior if pmarsv$<>"" and uikey$>="0" and uikey$<="9" then bwx=0:bwy=0 if uikey$="0" and nbenchwars bwx=-1:bwy=-1 if uikey$="1" and cwx>1 and cwy<ydim bwx=cwx-1:bwy=cwy+1 if uikey$="2" and cwy<ydim bwx=cwx :bwy=cwy+1 if uikey$="3" and cwx<xdim and cwy<ydim bwx=cwx+1:bwy=cwy+1 if uikey$="4" and cwx>1 bwx=cwx-1:bwy=cwy if uikey$="5" bwx=cwx :bwy=cwy if uikey$="6" and cwx<xdim bwx=cwx+1:bwy=cwy if uikey$="7" and cwx>1 and cwy>1 bwx=cwx-1:bwy=cwy-1 if uikey$="8" and cwy>1 bwx=cwx :bwy=cwy-1 if uikey$="9" and cwx<xdim and cwy>1 bwx=cwx-1:bwy=cwy+1 if bwx and bwy then cl$=pmarsv$+" "+pmarsvopts$+" -bk -l "+str$(length)+" -d "+str$(length) cl$=cl$+" -s "+str$(coresize)+" -p "+str$(processes)+" -c "+str$(cycles) cl$=cl$+" -r "+str$(pmarsvrounds) w1$=tempdir$+"/a.red" : w2$=tempdir$+"/b.red" writewarrior(w1$,cwx,cwy):cl$=cl$+" "+w1$ opname$="unknown warrior" if uikey$<>"5" and uikey$<>"0" then rem if battling another soup war writewarrior(w2$,bwx,bwy) rem write that one to temp too opname$=warriorname$(bwx,bwy) rem name for battle text cl$=cl$+" "+w2$ rem add filename to command line endif if uikey$="0" then rem battle against a random bench warrior w2$=benchwarriors$(int(ran(nbenchwars))+1) rem select bench warrior cl$=cl$+" "+w2$ rem add filename to command line e=open(1,w2$,"r"):if e=0 myerror("Can't open bench warrior") while not eof(1) line input #1 a$:a$=trim$(a$) if left$(a$,6)=";name " opname$=left$(trim$(mid$(a$,7)),20) wend close #1 endif position(stat,2):cleartoend() if uikey$="5" then print "Running ",warriorname$(cwx,cwy); runpmarscommandline(cl$,pmarsvrounds) else print "Battling ",warriorname$(cwx,cwy)," vs ",opname$; runpmarscommandline(cl$,pmarsvrounds) if sc1 or sc2 then print " Results: "; print left$(str$(sc1)+" ",5)," "; print left$(str$(sc2)+" ",5)," "; print "(press a key) "; a$=system$(tempdir$+"/inkey.sh") endif endif endif showsoup() endif REM save soup and/or exit if (uikey$="s" or uikey$="x") and soupchanged then position(stat,1):cleartoend():print " Saving soup..."; savesoup():soupchanged=0 endif if uikey$="x" exitprogram=1 rem make x because q quits less until exitprogram position(stat,1):showcursor():print end REM ----------------- subs ------------------ REM error handling sub.. pause before exiting sub myerror(a$) if a$<>"" print a$ input "----- press enter to exit program ----- " a$ end end sub REM write benchmark report to tempdir/results.txt REM uses file handles 1 and 2 sub makebenchreport(fname$,wname$) local e,bscore,wn,w$,bname$,a$,j e=open(2,tempdir$+"/results.txt","w") if e=0 myerror("Can't write to result file") print #2 "Battling ",wname$,".red against..." bscore=0 for wn=1 to nbenchwars rem get actual benchmark warrior name w$=benchwarriors$(wn) e=open(1,w$,"r") if e=0 myerror("Can't read bench warrior") bname$="" while not eof(1) line input #1 a$ if left$(a$,6)=";name " bname$=trim$(mid$(a$,7)) wend close #1 print #2 left$(bname$+" ",25)," "; battlewarriors(fname$,benchwarriors$(wn),bmrounds,benchpseq) rem into sc1 bscore=bscore+sc1 print #2 left$(str$(sc1)+" ",6)," "; rem make a line of * showing strength for j=1 to int(sc1*(40/300)) rem max 40 chars with perfect score print #2 "*"; next j print #2 next wn bscore=bscore/nbenchwars print #2 "Benchmark score: ",left$(str$(bscore)+" ",6) close #2 end sub REM cycle through available ANSI modes sub cycleansimode() if ansimode=0 then ansimode=16 elseif ansimode=16 then ansimode=256 elseif ansimode=256 then ansimode=24 elseif ansimode=24 then ansimode=0 endif showsoup() end sub REM load INI file sub loadinifile(fname$) local iflag,mflag,a1flag,a2flag,tflag,e,a$,z,ln,i e=open(1,fname$,"r") if e=0 myerror("Can't open ini file") rem make sure it's a valid INI file.. every line must either be rem empty, start with rem, or contain a line with "=" and no binary data rem stop loading at first error and print the line number with the error ln=0:repeat ln=ln+1:e=1 rem start out with error flag set line input #1 a$:a$=trim$(a$) rem get next line of ini file if a$="" e=0 rem empty line so ok if upper$(left$(a$,4))="REM " e=0 rem starts with REM so ok z=instr(a$,"="):if z>1 and z<len(a$) e=0 rem has = so ok for i=1 to len(a$) rem check for binary/invalid characters... if asc(mid$(a$,i,1))<32 or asc(mid$(a$,i,1))>126 e=1 rem not ok next i rem if e is still 0 then loading it probably won't bug out the program until e or eof(1) close #1 if e then rem something's wrong with the ini file print "Invalid data on line ",ln print "Not loading ini file":return endif e=open(1,fname$,"r") if e=0 myerror("Can't open ini file") rem shouldn't need this print "Loading ini file ",fname$ while not eof(1) line input #1 a$:a$=trim$(a$):parseiniline(a$) wend:close #1 end sub REM validate code entries in INI file sub validatecode(entry$,nentries,entrytype) local allowed$,fw,i,a$,z,retval retval=0:entry$=upper$(entry$) if entry$="" or nentries=0 return if entrytype=1 then fw=4 allowed$=" DAT MOV ADD SUB MUL DIV MOD JMP JMZ JMN DJN" allowed$=allowed$+" SPL SLT CMP SEQ SNE NOP LDP STP" elseif entrytype=2 then fw=3 allowed$=".A .B .AB.BA.F .X .I " elseif entrytype=3 then fw=1 allowed$="#$@<>*{}" endif for i=1 to nentries a$=mid$(entry$,(i-1)*fw+1,fw) z=instr(allowed$,a$) if z=0 then print "Invalid "; if entrytype=1 print "instruction "; if entrytype=2 print "modifier "; if entrytype=3 print "address mode "; print a$:retval=1 endif next i return retval end sub REM parse a line from ini file sub parseiniline(a$) local eqs,varname$,varnum,varstr$,q1p,q2p,v,apflag if upper$(left$(a$,4))="REM " return eqs=instr(a$,"="):if eqs<2 return varname$=trim$(left$(a$,eqs-1)) varnum=val(mid$(a$,eqs+1)) q1p=instr(a$,"\"") q2p=instr(a$,"\"",q1p+1) varstr$=mid$(a$,q1p+1,q2p-q1p-1) apflag=instr(trim$(mid$(a$,eqs+1)),varname$) rem check for append if apflag<>1 apflag=0 rem apflag set if varname is right after = v=0 rem recognized entry flag if varname$="xdim" v=1:xdim=varnum if varname$="ydim" v=1:ydim=varnum if varname$="xwrap" v=1:xwrap=varnum if varname$="ywrap" v=1:ywrap=varnum if varname$="length" v=1:length=varnum if varname$="coresize" v=1:coresize=varnum if varname$="processes" v=1:processes=varnum if varname$="cycles" v=1:cycles=varnum if varname$="rounds" v=1:rounds=varnum if varname$="mincrelen" v=1:mincrelen=varnum if varname$="instrate" v=1:instrate=varnum if varname$="modrate" v=1:modrate=varnum if varname$="addrrate" v=1:addrrate=varnum if varname$="numrate" v=1:numrate=varnum if varname$="reprate" v=1:reprate=varnum if varname$="insrate" v=1:insrate=varnum if varname$="duprate" v=1:duprate=varnum if varname$="swaprate" v=1:swaprate=varnum if varname$="delrate" v=1:delrate=varnum if varname$="mutadjust" v=1:mutadjust=varnum if varname$="mutadjgen" v=1:mutadjgen=varnum if varname$="adjrate" v=1:adjrate=varnum if varname$="localrate" v=1:localrate=varnum if varname$="orgrate" v=1:orgrate=varnum if varname$="org0rate" v=1:org0rate=varnum if varname$="crossrate" v=1:crossrate=varnum if varname$="adjlocref" v=1:adjlocref=varnum if varname$="evopseq" v=1:evopseq=varnum if varname$="evalmode" v=1:evalmode=varnum if varname$="evalrate" v=1:evalrate=varnum if varname$="evalgen" v=1:evalgen=varnum if varname$="ssfreq" v=1:ssfreq=varnum if varname$="superror" v=1:superror=varnum if varname$="benchfreq" v=1:benchfreq=varnum if varname$="savethr" v=1:savethr=varnum if varname$="savepc" v=1:savepc=varnum if varname$="bmrounds" v=1:bmrounds=varnum if varname$="benchpseq" v=1:benchpseq=varnum if varname$="reinsfreq" v=1:reinsfreq=varnum if varname$="enablepreseed" v=1:enablepreseed=varnum if varname$="unibox" v=1:unibox=varnum if varname$="viewmode" v=1:viewmode=varnum if varname$="viewshift" v=1:viewshift=varnum if varname$="ansimode" v=1:ansimode=varnum if varname$="enableC" v=1:enableC=varnum if varname$="pmarsvrounds" v=1:pmarsvrounds=varnum rem these strings have to be a single line if varname$="header$" v=1:header$=varstr$ if varname$="author$" v=1:author$=varstr$ if varname$="comment$" v=1:comment$=varstr$ if varname$="tempdir$" v=1:tempdir$=varstr$ if varname$="soupdir$" v=1:soupdir$=varstr$ if varname$="benchdir$" v=1:benchdir$=varstr$ if varname$="topdir$" v=1:topdir$=varstr$ if varname$="lister$" v=1:lister$=varstr$ if varname$="listeropts$" v=1:listeropts$=varstr$ if varname$="listeroptsb$" v=1:listeroptsb$=varstr$ if varname$="pmars$" v=1:pmars$=varstr$ if varname$="pmarsv$" v=1:pmarsv$=varstr$ if varname$="pmarsvopts$" v=1:pmarsvopts$=varstr$ if apflag then rem these strings can be appended to if varname$="instructions$" v=1:instructions$=instructions$+varstr$ if varname$="modifiers$" v=1:modifiers$=modifiers$+varstr$ if varname$="addr1modes$" v=1:addr1modes$=addr1modes$+varstr$ if varname$="addr2modes$" v=1:addr2modes$=addr2modes$+varstr$ if varname$="initialinstr$" v=1:initialinstr$=initialinstr$+varstr$ else rem overwrite if apflag not set if varname$="instructions$" v=1:instructions$=varstr$ if varname$="modifiers$" v=1:modifiers$=varstr$ if varname$="addr1modes$" v=1:addr1modes$=varstr$ if varname$="addr2modes$" v=1:addr2modes$=varstr$ if varname$="initialinstr$" v=1:initialinstr$=varstr$ endif if v then print varname$; if apflag then print " + "; else print " = "; endif if right$(varname$,1)="$" then print "\"",varstr$,"\"" else print varnum endif else print varname$," not recognized" endif end sub REM validate parms sub validateparms(noexit) rem if non-0 parm supplied don't exit just warn local e rem (defaults to error exit if called with no parms) pe=0 rem parm error flag if left$(header$,1)<>";" print "header$ must start with ;":pe=1 if left$(author$,1)<>";" print "author$ must start with ;":pe=1 if left$(comment$,1)<>";" print "comment$ must start with ;":pe=1 if tempdir$="" print "tempdir$ must be specified":pe=1 if soupdir$="" print "soupdir$ must be specified":pe=1 if xdim<2 or xdim>316 print "xdim must be >=2 and <=316":pe=1 if ydim<2 or ydim>74 print "ydim must be >=2 and <=74":pe=1 if coresize<=0 or coresize<length*3 or coresize>9999 print "bad coresize":pe=1 rem this evolver does not support huge cores, udb wasting cycles even trying if length=0 or length*3>coresize print "bad pmars length value":pe=1 if processes<=0 or processes>coresize print "bad pmars processes value":pe=1 if cycles<length or cycles<coresize print "bad pmars cycles value":pe=1 if rounds<=1 print "rounds must be >= 1":pe=1 if mincrelen<1 or mincrelen>length print "bad mincrelen":pe=1 if instrate<0 or instrate>1 print "instrate must between 0 and 1":pe=1 if modrate<0 or modrate>1 print "modrate must between 0 and 1":pe=1 if addrrate<0 or addrrate>1 print "addrrate must between 0 and 1":pe=1 if numrate<0 or numrate>1 print "numrate must between 0 and 1":pe=1 if mutadjust<0 or mutadjust>1 print "mutadjust must be between 0 and 1":pe=1 if adjrate<0 or adjrate>1 print "adjrate must between 0 and 1":pe=1 if localrate<0 or localrate>1 print "localrate must between 0 and 1":pe=1 if reprate<0 or reprate>1 print "reprate must between 0 and 1":pe=1 if insrate<0 or insrate>1 print "insrate must between 0 and 1":pe=1 if duprate<0 or duprate>1 print "duprate must between 0 and 1":pe=1 if swaprate<0 or swaprate>1 print "swaprate must between 0 and 1":pe=1 if delrate<0 or delrate>1 print "delrate must between 0 and 1":pe=1 if orgrate<0 or orgrate>1 print "orgrate must between 0 and 1":pe=1 if org0rate<0 or org0rate>1 print "org0rate must between 0 and 1":pe=1 e=evopseq:if e<0 or e>2 or e<>int(e) print "evopseq not int 0-2":pe=1 e=evalmode:if e<0 or e>4 or e<>int(e) print "evalmode not int 0-4":pe=1 if evalrate<0 or evalrate>1 print "evalrate must be between 0 and 1":pe=1 if ssfreq>0 and ssfreq<10000 print "ssfreq set too low":pe=1 if savethr<0 or savethr>300 print "savethr must be 0-300":pe=1 e=benchpseq:if e<0 or e>2 or e<>int(e) print "benchpseq not int 0-2":pe=1 ninst=len(instructions$)/4 if ninst<>int(ninst) print "instructions$ not divisible by 4":pe=1 if ninst=0 print "instructions$ empty":pe=1 nmods=len(modifiers$)/3 if nmods<>int(nmods) print "modifiers$ not divisible by 3":pe=1 if nmods=0 print "modifiers$ empty":pe=1 naddr1=len(addr1modes$):if naddr1=0 print "addr1modes$ empty":pe=1 naddr2=len(addr2modes$):if naddr2=0 print "addr2modes$ empty":pe=1 niniti=len(initialinstr$)/4 if niniti<>int(niniti) print "initialinstr$ not divisible by 4":pe=1 rem make sure instructions$ initialinstr$ modifiers$ addr1mode$ addr2modes$ rem all contain valid entries pe=pe+validatecode(instructions$,ninst,1) pe=pe+validatecode(initialinsts$,niniti,1) pe=pe+validatecode(modifiers$,nmods,2) pe=pe+validatecode(addr1modes$,naddr1,3) pe=pe+validatecode(addr2modes$,naddr2,3) rem disable out of bounds stuff if mutadjgen<2 print "MutRate adjust disabled":mutadjust=0 if viewmode<0 or viewmode>3 or int(viewmode)<>viewmode then print "bad viewmode, making 0":viewmode=0 endif if viewshift<0 or int(viewshift)<>viewshift then print "bad viewshift, making 0":viewshift=0 endif rem disable functions if empty strings if benchdir$="" print "benchdir$ empty":benchfreq=0 if topdir$="" print "topdir$ empty":benchfreq=0 if benchfreq=0 print "Benchmarking disabled":evalmode=0 if niniti=0 print "$initialinstr$ empty, preseed disabled":enablepreseed=0 rem ensure binaries are available e=system(">/dev/null which "+pmars$) if e print "pmars$ "+pmars$+" not found":pe=1 e=system(">/dev/null which "+pmarsv$) if e print "$pmarsv not found, disabled":pmarsv$="" e=system(">/dev/null which "+lister$):if e then print "$lister not found" lister$="cat" endif if lister$="cat" then print "Using cat, clearing listeropts$ listeroptsb$" listeropts$="":listeroptsb$="" endif if pe then if noexit then return pe rem return error code else myerror("") endif rem halt if parm error endif end sub REM initialize/verify directories sub initdirs() topscore=0:topwarrior$="" REM make/check directories and get top score e=system("mkdir -p "+soupdir$) if e myerror("Can't make soup directory") e=system("mkdir -p "+tempdir$) if e myerror("Can't make temp directory") if benchfreq>0 then e=system("mkdir -p "+topdir$) if e myerror("Can't make top directory") e=open(1,topdir$+"/topscore.file","r") if e=1 then input #1 topwarrior$,topscore rem space separated print "Top score = ",topscore," by ",topwarrior$ close #1 endif endif end sub REM initialize benchmark warrior list sub initbenchwarlist() nbenchwars=0 if benchfreq>0 then nbenchwars = getbenchwarriors() rem get list of benchmark warriors if nbenchwars=0 then print "No benchmark warriors, benchmarking disabled" evalmode=0:benchfreq=0 else print "Testing with ",nbenchwars," warriors from ",benchdir$ endif endif end sub sub continue_evolving() rem all vars here are global stopevolving=0 while stopevolving=0 if ansifreq>0 then rem if ANSI dumps enabled ansitrigger=ansitrigger+1 if ansitrigger>ansifreq ansitrigger=0:doanotheransidump() endif w1x=int(ran(xdim))+1 rem choose a warrior from the soup w1y=int(ran(ydim))+1 picksurrounding(w1x,w1y) rem choose opponent, into w2x and w2y position(stat,2) print warriorname$(w1x,w1y)," vs ",warriorname$(w2x,w2y)," ",chr$(8); w1name$=tempdir$+"/a.red" w2name$=tempdir$+"/b.red" battlemode = 0 if gennum(w1x,w1y)>=evalgen and gennum(w2x,w2y)>=evalgen then battlemode=evalmode if evalmode=3 if ran(1)<evalrate battlemode=1 if evalmode=4 if ran(1)<evalrate battlemode=int(ran(2))+1 endif if battlemode<>2 then rem evalmode 2 writes its own files writewarrior(w1name$,w1x,w1y) writewarrior(w2name$,w2x,w2y) endif if battlemode = 1 then rem guide with random bench warrior print "$",chr$(8); bwar$=benchwarriors$(int(ran(nbenchwars))+1) battlewarriors(w1name$,bwar$,rounds,evopseq) s1t=sc1 rem save since battlewarriors overwrites it battlewarriors(w2name$,bwar$,rounds,evopseq) rem use evolving rounds/seq sc2=sc1 : sc1=s1t rem sc1=1st warrior score sc2=2nd warrior score else if battlemode = 2 then rem guide with all bench warriors (slow!) print "#",chr$(8); s1t=benchwarrior(w1x,w1y) s2t=benchwarrior(w2x,w2y) sc1=s1t : sc2=s2t else print "-",chr$(8); battlewarriors(w1name$,w2name$,rounds,evopseq) endif endif position(stat,21) : print left$(str$(int(sc1))+" ",3); position(stat,25) : print left$(str$(int(sc2))+" ",3)," ",chr$(8); if sc1>sc2 then tx=w2x:ty=w2y rem evolve overwrites w2x w2y if crossover enabled evolve(w1x,w1y,w2x,w2y) plotwarrior(tx,ty) else evolve(w2x,w2y,w1x,w1y) plotwarrior(w1x,w1y) endif position(stat,24) if crflag then print "*"; else print " "; endif if benchfreq>0 then benchtrigger=benchtrigger+1 if benchtrigger>=benchfreq doperiodicbenchtest():benchtrigger=0 if reinsfreq>0 then reinstrigger=reinstrigger+1 if reinstrigger>reinsfreq reinsert():reinstrigger=0 endif endif if ssfreq>0 then sstrigger=sstrigger+1 if sstrigger>=ssfreq savesoup():sstrigger=0 endif a$=system$(tempdir$+"/inkey.sh -t") if a$=chr$(27) stopevolving=1 rem stop if escape pressed if a$="[extra]" showsoup() rem redisplay soup if space or enter pressed if a$="v" viewmode=mod(viewmode+1,4):showsoup() rem adjust view if v pressed if a$="c" and enableC cycleansimode() rem adjust colors if c pressed if a$="V" and viewmode >=2 then rem randomize viewshift if shift V pressed if viewshift=viewshiftsave then viewshift=int(ran(100000)) else viewshift=viewshiftsave endif showsoup() endif wend end sub REM save soup sub savesoup() local x,y,fname$ for y=1 to ydim for x=1 to xdim fname$=soupdir$+"/"+warriorname$(x,y)+".red" writewarrior(fname$,x,y) next x next y end sub REM get list of benchmark warriors into benchwarriors$ array REM return actual number of benchmark warriors in array sub getbenchwarriors() local a$,i,w,t$,c$ for i=1 to maxbw:benchwarriors$(i)="":next i a$=system$("2>/dev/null ls "+benchdir$+"/*.red") if a$="" return 0 rem no benchmark warriors found w=0:t$="" for i=1 to len(a$) c$=mid$(a$,i,1) if c$=chr$(10) then if w<maxbw w=w+1:benchwarriors$(w)=t$ t$="" else t$=t$+c$ endif next i:return w end sub REM select a warrior and benchmark it sub doperiodicbenchtest() local x,y,wscore,t,e,wn$,saveflag,h$,a$,sh$,z1,z2,sn$,ss,hasentry,rflag,ts$ if nbenchwars=0 return x=int(ran(xdim))+1 y=int(ran(ydim))+1 wscore=benchwarrior(x,y) wn$=warriorname$(x,y) lastscore=wscore:lastbenchwar$=wn$ rem save globally for ANSI dump position(stat,30):print wn$; print " scores ",left$(str$(wscore)+" ",5)," ",chr$(8); if wscore>topscore topscore=wscore:topwarrior$=wn$ print " top=",left$(str$(topscore)+" ",5)," ",chr$(8); t=topscore-(topscore*(savepc/100)) if wscore>=t and wscore>=savethr then saveflag=1:position(stat,61):cleartoend() if wscore=topscore then rem save topscore warriorname$ to topscore.file e=open(2,topdir$+"/topscore.file","w") if e=0 myerror("Can't open topscore.file for write") print #2 wn$," ",topscore close #2 else rem don't overwrite the top scoring warrior if wn$=topwarrior$ saveflag=0:print "(cancelled)"; endif if saveflag then rem need a way to keep from saving duplicates so keep a file rem containing warrior names, hashes, testset and score rem also, avoid overwriting stronger warriors.. which leads rem to another thing.. if it does overwrite a warrior then rem it needs to remove its entry from the warinfo file h$=hashwarrior$(x,y) hasentry=0 rem set if warrior is present in warinfo file rflag=0 rem reason for rejection e=open(1,topdir$+"/warinfo.file","r") if e then rem if file exists while not eof(1) line input #1 a$ z1=instr(a$," ") rem get the 1st space if z1 then rem if multiple fields sn$=left$(a$,z1-1) rem get name field if wn$=sn$ hasentry=1 rem flag to indicate name match z2=instr(a$," ",z1+1) rem get the space after that if z2 then rem if there's a field sh$=mid$(a$,z1+1,z2-z1-1) rem get hash field if h$=sh$ saveflag=0:rflag=1 rem cancel save if dup z1=instr(a$," ",z2+1) rem get space after next field if z1 then rem if fields exist ts$=mid$(a$,z2+1,z1-z2-1) rem get testset field ss=val(mid$(a$,z1+1)) rem get saved score if sn$=wn$ then rem if warrior name matches if wscore<=ss saveflag=0:rflag=2 rem cancel if weaker endif if str$(wscore)=str$(ss) then rem if score is the same as saved if ts$=benchdir$ and benchpseq>0 rem and same testset, using fixed saveflag=0:rflag=3 rem cancel presumed functional duplicate endif endif endif endif wend close #1 endif if saveflag then if hasentry then print "Replacing ",wn$; else print "Saving ",wn$; endif writewarrior(topdir$+"/"+wn$+".red",x,y) if hasentry then rem if there's already an entry e=open(1,topdir$+"/warinfo.file","r") if e=0 myerror("Has entry but can't open warinfo file") e=open(2,tempdir$+"/warfile.tmp","w") if e=0 myerror("Can't open temp war file for write") while not eof(1):line input #1 a$:print #2 a$:wend close #2:close #1 e=open(1,tempdir$+"/warfile.tmp","r") if e=0 myerror("Can't open temp war file for read") e=open(2,topdir$+"/warinfo.file","w") if e=0 myerror("Can't open warinfo file for replacing") while not eof(1) line input #1 a$ z1=instr(a$,wn$) rem check line for warrior name if z1=0 print #2 a$ rem if not write the line wend:close #1:close #2 endif rem update warinfo file e=open(2,topdir$+"/warinfo.file","a") rem append if e=0 myerror("Can't open warinfo file for append") print #2 wn$," ",h$," ",benchdir$," ",wscore close #2 else cleartoend() if rflag=1 print "(",wn$," dup)"; if rflag=2 print "(",wn$," weak)"; if rflag=3 print "(",wn$," fdup)"; endif endif endif end sub REM return hash of the warrior code REM this is not a good hash.. just has to catch dupes sub hashwarrior$(x,y) local h,i,j,a$,lc,c1,c2,c3 c1=377:c2=5911:c3=225 h=0:for i=1 to wlength(x,y) a$=upper$(soup$(x,y,i)) lc=0:for j=1 to len(a$) lc=lc+asc(mid$(a$,j,1))+j*c1 next j h=h+lc+(lc+c3)*i*c2 next i return right$("00000"+str$(mod(h,1000000)),6) end sub REM benchmark specified warrior, return score REM changes global vars sc1 sc2 sub benchwarrior(x,y) local w$,s,i if nbenchwars=0 return w$=tempdir$+"/a.red" writewarrior(w$,x,y) s=0 for i=1 to nbenchwars battlewarriors(w$,benchwarriors$(i),bmrounds,benchpseq) s=s+sc1 next i return s/nbenchwars end sub REM return fixed-length warrior name sub warriorname$(x,y) local xlen,ylen,x$,y$ xlen=len(str$(xdim)) ylen=len(str$(ydim)) x$=right$("0000"+str$(x),xlen) y$=right$("0000"+str$(y),ylen) return x$+"_"+y$ end sub REM evolve winning warrior on top of losing warrior sub evolve(x1,y1,x2,y2) local ln,wl,dp,a$,b$,n,ch,docross,iline,dline,i,an,bn rem ,rmod global rem derive mutation rate modifier rmod from gennum mutadjust and mutadjgen rem affects instrate modrate addrrate numrate reprate insrate duprate rem swaprate and orgrate by gradually reducing mutation as gen increases if mutadjgen<2 mutadjgen=1:mutadjust=0 rem disable if mutadjgen<2 rmod=1-(mutadjust*(gennum(x1,y1)/mutadjgen)) rem calculate multiplier if rmod<mutadjust rmod=mutadjust rem rmod between mutadjust and 1 origin$(x2,y2)=origin$(x1,y1) species$(x2,y2)=species$(x1,y1) orgnum(x2,y2)=orgnum(x1,y1) gennum(x2,y2)=gennum(x1,y1)+1 tdstamp$(x2,y2)=mid$(date$,3,10)+" "+left$(time$,8) dp=0 rem destination line pointer wl=wlength(x1,y1) ch=0 rem species change flag if ran(1)<swaprate*rmod and wl>1 then rem swaps lines in the parent warrior ln=int(ran(1)*(wl-1))+1 rem usually fatal but sometimes not a$=soup$(x1,y1,ln):soup$(x1,y1,ln)=soup$(x1,y1,ln+1) soup$(x1,y1,ln+1)=a$:ch=1 endif docross=0:crflag=0:dline=0:iline=0 if crossrate>0 then picksurrounding(x1,y1) rem into w2x w2y if species$(w2x,w2y)=species$(x1,y1) docross=1 rem must be same length if w2x=x2 and w2y=y2 docross=0 rem probably best to not cross with loser.. if wlength(w2x,w2y)<>wlength(x1,y1) docross=0 rem in case dup species number endif for ln=1 to wl a$=soup$(x1,y1,ln) if docross if ran(1)<crossrate crflag=1:a$=soup$(w2x,w2y,ln) rem crossover if ran(1)<duprate then if ran(1)<0.5 then if ln>1 a$=soup$(x1,y1,ln-1):ch=1 else if ln<wl a$=soup$(x1,y1,ln+1):ch=1 endif endif if ran(1)<instrate*rmod then b$=mid$(a$,1,3) mid$(a$,1,3)=rndinst$() if b$<>mid$(a$,1,3) ch=1 endif if ran(1)<modrate*rmod mid$(a$,4,3)=rndmod$() if ran(1)<addrrate*rmod mid$(a$,8,1)=rndaddr1$() if ran(1)<numrate*rmod then if ran(1)<adjrate then rem adjust number n=val(mid$(a$,9,4)) n=n+(int(ran(2))-1) mid$(a$,9,4)=right$(" "+str$(n),4) else mid$(a$,9,4)=rndnum$(ln) endif end if if ran(1)<addrrate*rmod mid$(a$,14,1)=rndaddr2$() if ran(1)<numrate*rmod then if ran(1)<adjrate then rem adjust number n=val(mid$(a$,15,4)) n=n+(int(ran(2))-1) mid$(a$,15,4)=right$(" "+str$(n),4) else mid$(a$,15,4)=rndnum$(ln) endif end if if ran(1)<reprate a$=rndwline$(ln) : ch=1 if ran(1)>delrate*rmod or wl=1 then if dp<length dp=dp+1 if ran(1)<insrate*rmod then ch=1:iline=dp soup$(x2,y2,dp)=rndwline$(dp) if dp<length dp=dp+1 endif soup$(x2,y2,dp)=a$ else ch=1:dline=dp endif next ln wlength(x2,y2)=dp if orgnum(x2,y2)>=dp orgnum(x2,y2)=dp-1 rem in case length changed n=orgnum(x2,y2) if ran(1)<orgrate*rmod then if ran(1)<org0rate then orgnum(x2,y2)=0 else orgnum(x2,y2)=int(ran(dp)) endif endif if n<>orgnum(x2,y2) ch=1 if ch species$(x2,y2)=str$(int(ran(100000))) if adjlocref and (iline or dline) then rem adjust local references for i=1 to dp rem (this probably isn't right) a$=soup$(x2,y2,i):an=val(mid$(a$,9,4)):bn=val(mid$(a$,15,4)) rem when inserting, increment local refs before the iline rem if they point to iline or after and decrement local rem refs after iline if they point to iline or before if iline then if i<iline and an+i>=iline and an+i<=dp an=an+1 if i>iline and an+i<=iline and an+i>=1 an=an-1 if i<iline and bn+i>=iline and bn+i<=dp bn=bn+1 if i>iline and bn+i<=iline and bn+i>=1 bn=bn-1 endif rem when deleting, decrement local refs before the dline rem if they point to dline or after and increment local rem refs after dline if they point to dline or before if dline then if i<dline and an+i>=dline and an+i<=dp an=an-1 if i>dline and an+i<=dline and an+i>=1 an=an+1 if i<dline and bn+i>=dline and bn+i<=dp bn=bn-1 if i>dline and bn+i<=dline and bn+i>=1 bn=bn+1 endif mid$(a$,9,4)=right$(" "+str$(an),4) mid$(a$,15,4)=right$(" "+str$(bn),4) soup$(x2,y2,i)=a$ next i endif normalizenumbers(x2,y2) end sub REM normalize numbers so they range from 0 to coresize-1 REM and only backrefs within the warrior code are negative sub normalizenumbers(x,y) local i,n1,n2,a$ for i=1 to wlength(x,y) a$=soup$(x,y,i) n1=val(mid$(a$,9,4)):n2=val(mid$(a$,15,4)) n1=mod(n1,coresize):n2=mod(n2,coresize) if n1<0 n1=n1+coresize if n2<0 n2=n2+coresize if coresize-n1<i n1=n1-coresize if coresize-n2<i n2=n2-coresize mid$(a$,9,4)=right$(" "+str$(n1),4) mid$(a$,15,4)=right$(" "+str$(n2),4) soup$(x,y,i)=a$ next i end sub REM pick surrounding warrior sub picksurrounding(x,y) label pickagain d=int(ran(8)) if d=0 w2x=x-1 : w2y=y if d=1 w2x=x-1 : w2y=y-1 if d=2 w2x=x : w2y=y-1 if d=3 w2x=x+1 : w2y=y-1 if d=4 w2x=x+1 : w2y=y if d=5 w2x=x+1 : w2y=y+1 if d=6 w2x=x : w2y=y+1 if d=7 w2x=x-1 : w2y=y+1 if xwrap then if w2x<1 w2x=w2x+xdim if w2x>xdim w2x=w2x-xdim else if w2x<1 or w2x>xdim goto pickagain endif if ywrap then if w2y<1 w2y=w2y+ydim if w2y>ydim w2y=w2y-ydim else if w2y<1 or w2y>ydim goto pickagain endif end sub REM battle warriors - file1$ file2$ rounds mode REM where mode = 0 for random, 1 for fixed, 2 for permutate REM return scores in global vars sc1 sc2 sub battlewarriors(f1$,f2$,battlerounds,mode) local cl$,t$ t$="" rem default random positioning if mode=1 t$="f" rem fixed sequence positioning if mode=2 t$="P" rem permutate every position (rounds 142 for nano) cl$="":if superror cl$="2>/dev/null " cl$=cl$+pmars$+" -"+t$+"bkl "+str$(length)+" -d "+str$(length) cl$=cl$+" -s "+str$(coresize)+" -p "+str$(processes)+" -c "+str$(cycles) if mode<>2 cl$=cl$+" -r "+str$(battlerounds) cl$=cl$+" "+f1$+" "+f2$ runpmarscommandline(cl$,battlerounds) rem leave scores in global vars sc1 sc2 if sc1=0 and sc2=0 myerror("Both scores 0, check PMARS") end sub sub runpmarscommandline(cl$,battlerounds) local s$,t$,p,a,b,c,d,i s$=system$(cl$) t$="" : p=0 : a=0 : b=0 : c=0 : d=0 for i=1 to len(s$) rem parse KOTH score c$=mid$(s$,i,1) : t$=t$+c$ if p=0 and c$=" " p=1:a=val(t$):t$="" if p=1 and c$=chr$(10) p=2:b=val(t$):t$="" if p=2 and c$=" " p=3:c=val(t$):t$="" if p=3 and c$=chr$(10) p=4:d=val(t$) next i rem return normalized scores, 0-300 sc1=(a*3+b)*(100/battlerounds) sc2=(c*3+d)*(100/battlerounds) end sub REM return a random warrior line sub rndwline$(ln) a$=rndinst$()+rndmod$()+" "+rndaddr1$()+rndnum$(ln) a$=a$+","+rndaddr2$()+rndnum$(ln) return a$ end sub REM return a random instruction sub rndinst$() local i i=int(ran(ninst))*4+2 return mid$(instructions$,i,3) end sub REM return a random modifier sub rndmod$() local i i=int(ran(nmods))*3+1 return mid$(modifiers$,i,3) end sub REM return a random addressing mode 1 sub rndaddr1$() local i i=int(ran(naddr1))+1 return mid$(addr1modes$,i,1) end sub REM return a random addressing mode 2 sub rndaddr2$() local i i=int(ran(naddr2))+1 return mid$(addr2modes$,i,1) end sub REM return a random number REM small numbers refer to location within warrior length (used or not) REM large numbers are 0 to coresize-1 sub rndnum$(ln) local i if ran(1)<localrate then i=int(ran(length))-(ln-1) else i=int(ran(coresize)) end if return right$(" "+str$(i),4) end sub REM write a warrior to disk sub writewarrior(fname$,x,y) local e,i,a$ e=open(2,fname$,"w") if e=0 print "Can't write warrior",fname$:error "hosed" print #2 header$ print #2 ";name ",warriorname$(x,y),".red" print #2 author$ print #2 comment$ print #2 ";origin ",origin$(x,y) print #2 ";species ",species$(x,y) print #2 ";generation ",gennum(x,y) print #2 ";created ",tdstamp$(x,y) print #2 ";assert CORESIZE==",str$(coresize) print #2 "ORG ",orgnum(x,y) for i=1 to wlength(x,y) a$=soup$(x,y,i) print #2 a$ next i print #2 "END" close #2 end sub REM show the soup sub showsoup() local x,y rem tl$,tr$,bl$,br$,hl$,vl$ global to reuse for ANSI dumps clearscreen():hidecursor() if unibox then tl$=chr$(226)+chr$(148)+chr$(140) tr$=chr$(226)+chr$(148)+chr$(144) bl$=chr$(226)+chr$(148)+chr$(148) br$=chr$(226)+chr$(148)+chr$(152) hl$=chr$(226)+chr$(148)+chr$(128) vl$=chr$(226)+chr$(148)+chr$(130) else tl$=".":tr$=".":bl$="`":br$="'":hl$="-":vl$="|" endif print esc$,"0m",tl$;:for x=1 to xdim:print hl$;:next x:print tr$ for y=1 to ydim print vl$; for x=1 to xdim printwarrior(x,y) rem print the warrior character next x print esc$,"0m",vl$ next y print bl$;:for x=1 to xdim:print hl$;:next x:print br$ end sub REM hide cursor sub hidecursor() print esc$,"?25l"; end sub REM show cursor sub showcursor() print esc$,"?25h"; end sub REM position cursor line,column sub position(l,c) print esc$,l,";",c,"H"; end sub REM clear to end of line sub cleartoend() print esc$,"0K"; end sub REM clear screen sub clearscreen() position(1,1) print esc$,"0m"; rem reset colors print esc$,"2J"; rem clear screen end sub REM plot warrior on screen sub plotwarrior(x,y) position(y+1,x+1) printwarrior(x,y) print esc$,"0m"; end sub REM print warrior character to screen or file sub printwarrior(x,y,fnum) rem if fnum specified write to file # local r,g,b,c,d,l,w$,a$ rem if ansimode specified color by species if ansimode=16 then rem ANSI-16 colors (14 colors 1-7,9-15) c=mod(val(species$(x,y)),14)+1:b=0:if c>7 b=1:c=c-7 a$=esc$+str$(b)+";"+str$(c+30)+"m" elseif ansimode=256 then rem ANSI-256 colors (214 colors 17-230) c=mod(val(species$(x,y)),214)+17 a$=esc$+"38;5;"+str$(c)+"m" elseif ansimode=24 then rem ANSI 24 bit RGB color c=val(species$(x,y)):r=mod(c,30)*7+40 g=mod(int(c/46),30)*7+40:b=mod(int(c/2116),30)*7+40 a$=esc$+"38;2;"+str$(r)+";"+str$(g)+";"+str$(b)+"m" else a$="" rem no color endif if viewmode=1 then rem use characters for species d=mod(val(species$(x,y)),len(vm1chars$))+1 w$=mid$(vm1chars$,d,1) elseif viewmode>=2 then rem use characters for instruction sequence w$=getwarriorbasechar$(x,y) rem reduce base instr.seq. to a character else rem use numbers and letters for length w$="*":l=wlength(x,y) if l<62 w$=chr$(l+87) if l<36 w$=chr$(l+55) if l<10 w$=str$(l) endif if fnum=0 then print a$,w$; else print #fnum a$,w$; endif end sub REM simple hash of the instruction sequence for display purposes REM messing with this again, still too many dups. Dups are unavoidable REM (the birthday paradox) but added mechanisms to adjust for a particular REM soup - added constants C1 C2 initialized at the beginning of the program REM (right now they're 1,1 for the original characters but can be changed) REM and added a viewmode setting that is xor'd against the raw hash, changing REM that shifts everything to find a combo with no dups in the dominant types sub getwarriorbasechar$(x,y) local d,i,j,m,e,a$,w$ d=0:for i=1 to wlength(x,y) rem do a simple hash on the first a$=upper$(soup$(x,y,i)) rem 3 letters of each line e=0:for j=1 to 3:e=e+asc(mid$(a$,j,1))*(1+(j-1)*c1):next j d=d+e*(1+(i-1)*c2) next i d=xor(d,viewshift) rem change all the characters if viewmode=3 then m=mod(d,94):w$=chr$(m+33) rem 94 chars ! to ~ else m=mod(d,52):w$=chr$(m+65):if m>25 w$=chr$(m+71) rem 52 chars A-Z a-z endif:return w$ end sub REM dump soup display as an ANSI file REM write as a linear file with no positioning and no background color sub dumpansifile(fname$) local e,x,y,z e=open(2,fname$,"w"):if e=0 return 1 rem if error exit sub with error rem tl$ tr$ bl$= br$= hl$ vl$ set by showsoup(), always called before this print #2 esc$,"0m",tl$;:for x=1 to xdim:print #2 hl$;:next x:print #2 tr$ for y=1 to ydim print #2 vl$; for x=1 to xdim printwarrior(x,y,2) rem write warrior char to file #2 next x print #2 esc$,"0m",vl$ next y print #2 bl$;:for x=1 to xdim:print #2 hl$;:next x:print #2 br$ if benchfreq>0 then if topwarrior$="" topwarrior$=left$("------",len(warriorname$(1,1))) if lastbenchwar$="" lastbenchwar$=topwarrior$:lastscore=topscore z=instr(fname$,"/"):print #2 " ",mid$(fname$,z+1)," "; rem base name print #2 "Top=",left$(str$(topscore)+" ",5)," by ",topwarrior$," "; print #2 "Last=",left$(str$(lastscore)+" ",5)," by ",lastbenchwar$," "; endif close #2 end sub REM do another ANSI dump REM directory in ansidir$, base filename in ansifbase$ REM last sequence number in ansifnumber, max # dumps in ansifmax sub doanotheransidump() local e,dump$,a$ e=system("mkdir -p "+ansidir$) rem setup should have already made this if e error("Can't make ANSI dump dir") rem but in case removed etc ansifnumber=ansifnumber+1 if ansifnumber>ansifmax ansifreq=0:sleep 5:return rem stop dumping dump$=ansidir$+"/"+ansifbase$+right$("000"+str$(ansifnumber),4)+".ans" e=dumpansifile(dump$) if e then rem if error occurs position(stat,1):cleartoend():print "Error dumping ANSI file ",dump$; print " (press a key)"; : system(tempdir$+"/inkey.sh") ansifreq=0:showsoup() endif end sub REM load a warrior into the soup sub loadwarrior(fname$,x,y) local ln,done e=open(1,fname$,"r") if e=0 myerror("Can't load warrior") origin$(x,y)="" species$(x,y)="" orgnum(x,y)=0 gennum(x,y)=0 ln=0 : done=0 while not eof(1) and not done line input #1 wline$ wline$=trim$(wline$) if upper$(left$(wline$,3))="END" or wline$="" then done=1 else if left$(wline$,8)=";origin " origin$(x,y)=trim$(mid$(wline$,9)) if left$(wline$,9)=";species " species$(x,y)=trim$(mid$(wline$,10)) if left$(wline$,12)=";generation " gennum(x,y)=val(mid$(wline$,13)) if left$(wline$,9)=";created " tdstamp$(x,y)=trim$(mid$(wline$,10)) if upper$(left$(wline$,4))="ORG " then orgnum(x,y)=val(trim$(mid$(wline$,5))) else if left$(wline$,1)<>";" and ln<length then ln=ln+1 soup$(x,y,ln)=wline$ endif endif endif wend close 1 wlength(x,y)=ln end sub REM Reinsert a saved warrior back into the soup sub reinsert() local x,y,i,n,p,q,w,war$,warname$,a$ if nbenchwars=0 return rem select random soup warrior to replace x=int(ran(xdim)+1) y=int(ran(ydim)+1) rem select random warrior from top a$=system$("2>/dev/null ls "+topdir$+"/*.red") if a$="" return rem no warriors in top n=0 for i=1 to len(a$) if mid$(a$,i,1)=chr$(10) n=n+1 next i w=int(ran(n)) rem find position in dir listing string p=0:for i=1 to w:p=instr(a$,chr$(10),p+1):next i q=instr(a$,chr$(10),p+1):war$=mid$(a$,p+1,q-p-1) rem get name of reinserted warrior warname$=mid$(war$,len(topdir$)+2,len(str$(xdim))+len(str$(ydim))+1) position(stat,61) print warname$,">",warriorname$(x,y); : cleartoend() loadwarrior(war$,x,y) end sub REM Other functions that won't fit on the main UI menu REM File dir/naming note - report/INI file writes from here go to the REM topdir$ and add the .txt/.ini extension (because almost always saving REM the parms for that particular run and also want to make it harder to REM accidently overwrite a file), INI file load comes from the program REM directory and does not add the extension (because most of the time REM loading a file from there and might not end with .ini) sub otherstuff() local selection,nseq,fname$,a$,b$,c$,t$,e,x,y,z,i,seqtmp$,sc$,sm,score,tflg local f$,avg,again,v1,v2,v3,v4,v5,v6,v7,s1$,s2$,s3$,s4$,subname$,code$,vss,wc local addlistings,addsoupdisplay,addfullbench,savefname$ label otherstuffmenu clearscreen() print print " Other functions..." print " 1 - Change the benchmark set" print " 2 - Load settings file (some parms ignored)" print " 3 - Show soup sequences and population numbers" print " 4 - Sequence and benchmark the entire soup" print " 5 - Change settings variable(s)" print " 6 - Display variable(s)" print " 7 - Display all settings" print " 8 - Save settings to file" if soupchanged print " 9 - Save soup (not saved yet)" print " 10 - Start/stop ANSI dumps"; if ansifreq>0 then print " (enabled, select for info)" else print endif print " 11 - Play back ANSI dumps" input " Select function or none to exit: " t$ : selection=val(t$) print if selection=9 then if soupchanged then print "Saving soup..." savesoup():soupchanged=0 sleep 1:goto otherstuffmenu endif elseif selection=10 then rem ANSI dump control if ansifreq>0 then print "ANSI dumps enabled, saving to ",ansidir$,"/",ansifbase$,"*.ans" print "Dump interval = ",ansifreq," Last sequence = ",ansifnumber; print " Max sequence = ",ansifmax input "Stop ANSI dumps? " t$:t$=left$(upper$(trim$(t$)),1) if t$="Y" ansifreq=0:print "ANSI dumps disabled" else input "Base name for ANSI dump files: " a$ ansifbase$=trim$(a$):if ansifbase$="" goto otherstuffmenu print "Directory (enter to use ",ansidir$,")"; input ": " a$:a$=trim$(a$):if a$<>"" ansidir$=a$ e=system("mkdir -p "+ansidir$) if e print "Can't make that directory":sleep 2:goto otherstuffmenu e=open(1,ansidir$+"/"+ansifbase$+"0001.ans","r") if e then close #1:print "ANSI files exist, Remove or Continue? (R/C/any)"; input ": " t$:t$=left$(upper$(trim$(t$)),1) if t$="R" then print "Removing existing ANSI files" system("rm "+ansidir$+"/"+ansifbase$+"*.ans"):ansifnumber=0 elseif t$="C" then c$="for f in "+ansidir$+"/"+ansifbase$+"*.ans;do a=\"$f\";done;echo -n $a" a$=system$(c$) rem get filename for last dump file print "Last dump = ",a$ ansifnumber=val(mid$(a$,len(a$)-7,4)) rem extract sequence # print "Starting with sequence #",ansifnumber+1 else print "(cancelled)":sleep 1:goto otherstuffmenu endif else ansifnumber=0 endif input "Cycles between ANSI dumps: " ansifreq if ansifreq<=0 ansifreq=0:print "(cancelled)":sleep 1:goto otherstuffmenu if ansifreq<1000 print "(warning excessive writes, enter -1 to cancel)" input "Max number of dumps (enter for max 9999): " ansifmax if ansifmax<0 or ansifmax>9999 then ansifreq=0:ansifmax=9999:print "(cancelled)":sleep 1:goto otherstuffmenu endif ansitrigger=ansifreq:if ansifmax=0 ansifmax=9999 print "ANSI dumps enabled" endif sleep 1:goto otherstuffmenu elseif selection=11 then rem play back ANSI dumps t$="":if ansifnumber>0 then rem if previous ANSI dumps performed print "Play back ",ansifbase$;:input "? " t$ t$=left$(upper$(trim$(t$)),1) endif if t$="Y" then a$=ansifbase$:c$=ansidir$ rem play back previous dumps else input "ANSI dump base name: " a$:a$=trim$(a$) if a$="" goto otherstuffmenu print "ANSI dump dir (enter for ",ansidir$,")";:input ": " c$ if c$="" c$=ansidir$ b$=c$+"/"+a$+"0001.ans":e=open(1,b$,"r") if e=0 print "Not found":sleep 2:goto otherstuffmenu close #1 rem ANSI files exist just don't delete sequence #1 rem if ansi2txt installed then make sure term is big enough for dump z=system("which ansi2txt>/dev/null"):if z=0 then t$=system$("cat "+b$+"|ansi2txt|wc -L"):x=val(t$)-2 t$=system$("cat "+b$+"|ansi2txt|wc -l"):y=val(t$)-2 if x>max(xdim,78) or y>max(ydim,21) then print "Too big":sleep 2:goto otherstuffmenu endif endif endif input "Seconds between frames (enter for 0.1): " z if z<0 then goto otherstuffmenu else if z=0 z=0.1 endif print print "While playing press P-pause S-slower F-faster L-loop on/off," input "any other key exits. Press enter to start playback... " a$ rem one-line sh script for playing back ANSI files... b$=str$(z):t$="clear;td="+b$+";loop=0;" t$=t$+"while [ 1 ];do for f in "+c$+"/"+a$+"*.ans;do " t$=t$+"echo -n \"\\033[H\";cat $f;echo -n \"\\033[0K\";" rem use inkey.sh for delay to allow exiting (can't read -n etc under sh) rem while playing press L-loop P-pause F-faster S-slower, any other exits t$=t$+"x=$("+tempdir$+"/inkey.sh -t $td);" t$=t$+"if [ \"$x\" = \"f\" ];then td=$(echo $td|awk " t$=t$+"'{if ($1>0.01) print $1*0.8;else print $1}');" t$=t$+"elif [ \"$x\" = \"s\" ];then td=$(echo $td|awk " t$=t$+"'{if ($1<2) print $1*1.2;else print $1}');" t$=t$+"elif [ \"$x\" = \"p\" ];then "+tempdir$+"/inkey.sh;" t$=t$+"elif [ \"$x\" = \"l\" ];then loop=$((1-loop));" t$=t$+"elif [ \"$x\" != \"\" ];then exit;fi;done;" t$=t$+"if [ $loop = 0 ];then exit;fi;done" repeat hidecursor():system(t$):showcursor() print " Play again? ";:a$=system$(tempdir$+"/inkey.sh") until a$<>"y":goto otherstuffmenu elseif selection=1 then rem change/disable bench directory label enterbenchdirname input "Enter new benchmark directory: " a$:a$=trim$(a$) if a$="" then input "Disable benchmarking? " t$ t$=left$(trim$(upper$(t$)),1) if t$="Y" benchdir$="":nbenchwars=0 return endif e=system("[ -d "+a$+" ]") if e print "That is not a directory":goto enterbenchdirname benchdir$=a$:resetbenchstuff():goto otherstuffmenu elseif selection=2 then rem load an INI file rem have to be very careful here, the new INI must be compatible rem with existing soup..same dimensions, coresize, warriorsize etc. rem do not change tempdir$ soupdir$ topdir$ apply settings to current soup e=0 label enterinifilename input "Enter settings filename to load: " a$:a$=trim$(a$) if e=0 and a$="" goto otherstuffmenu rem don't go back to menu if error if a$="" print "Must load good INI file":goto enterinifilename e=system("[ -f "+a$+" ]") if e print "That is not a file":goto enterinifilename rem save variables that should not be changed while running v1=xdim:v2=ydim:v3=length:v4=mincrelen v5=coresize:v6=processes:v7=cycles s1$=tempdir$:s2$=soupdir$:s3$=topdir$ s4$=benchdir$ rem don't restore but use to detect if bench set changed vss=viewshift rem to see if new viewshift specified loadinifile(a$) rem load the INI file (prints items) rem restore variables if xdim<>v1 print "Restoring xdim from ",xdim," to ",v1 if ydim<>v2 print "Restoring ydim from ",ydim," to ",v2 if length<>v3 print "Restoring length from ",length," to ",v3 if mincrelen<>v4 print "Restoring mincrelen from ",mincrelen," to ",v4 if coresize<>v5 print "Restoring coresize from ",coresize," to ",v5 if processes<>v6 print "Restoring processes from ",processes," to ",v6 if cycles<>v7 print "Restoring cycles from ",cycles," to ",v7 if tempdir$<>s1$ print "Restoring tempdir$ from ",tempdir$," to ",s1$ if soupdir$<>s2$ print "Restoring soupdir$ from ",soupdir$," to ",s2$ if topdir$<>s3$ print "Restoring topdir$ from ",topdir$," to ",s3$ if vss<>viewshift viewshiftsave=viewshift rem if viewshift changed save new xdim=v1:ydim=v2:length=v3:mincrelen=v4 coresize=v5:processes=v6:cycles=v7 tempdir$=s1$:soupdir$=s2$:topdir$=s3$ e=validateparms(1) rem make sure parms are valid if e print "Error - must load valid settings":goto enterinifilename input "(press enter to continue)" a$ if benchdir$<>s4$ resetbenchstuff() goto otherstuffmenu rem back to other stuff menu to inspect/change elseif selection=3 or selection=4 then rem Analyze the soup, if 4 bench too addlistings=0:addsoupdisplay=0:addfullbench=0:savefname$="" again=1 rem determine if to analyze the soup again if anavalid and selection=4 and lastselection=4 then rem if no change e=open(1,tempdir$+"/anareport.txt","r") rem check if report exists if e then close #1 rem prompt to redisplay existing input "Redisplay existing anareport.txt file? " t$ t$=left$(trim$(upper$(t$)),1) if t$="Y" again=0 endif endif if again then if selection=4 then if nbenchwars=0 print "(no benchmarking)":sleep 2:goto otherstuffmenu print "Report setup... answer C to questions to cancel" input "Include listings and benchmarks? " t$ t$=left$(trim$(upper$(t$)),1):if t$="C" goto otherstuffmenu if t$="Y" then rem soup must be saved first to include listings if soupchanged print "(save soup first)":sleep 2:goto otherstuffmenu addlistings=1 print "How many sequences to list and benchmark? "; print "(enter for ",maxrepsave,")";: input " " t$ t$=trim$(t$):if left$(upper$(t$),1)="C" goto otherstuffmenu if t$<>"" maxrepsave=val(t$) endif input "Include soup display dump? " t$ t$=left$(trim$(upper$(t$)),1):if t$="C" goto otherstuffmenu if t$="Y" addsoupdisplay=1 input "Include full benchmark listing? " t$ t$=left$(trim$(upper$(t$)),1):if t$="C" goto otherstuffmenu if t$="Y" addfullbench=1 label enterreportfname savefname$="" input "Save report to a txt file? " t$ t$=left$(trim$(upper$(t$)),1):if t$="C" goto otherstuffmenu if t$="Y" then print "Report file [path/]basename (default ",topdir$,"/report)"; input ": " t$:t$=trim$(t$):if t$="" t$="report" savefname$=t$+".txt" rem always save to txt to help avoid accidents z=instr(savefname$,"/") rem check to see if path specified if z=0 savefname$=topdir$+"/"+savefname$ rem if not default to topdir$/ e=open(1,savefname$,"r") rem check to see if it exists if e then close #1:input "File exists. Overwrite? " t$ t$=left$(trim$(upper$(t$)),1):if t$="C" goto otherstuffmenu if t$<>"Y" goto enterreportfname rem reenter filename endif print "Will save report to file ",savefname$ endif endif rem selection 4 setup options print "Analyzing... "; if selection=4 print "(this will take awhile, esc to cancel)"; print:tflg=0:nseq=0:score=0:avg=0:hidecursor() for x=1 to xdim for y=1 to ydim if selection=4 and nbenchwars>0 then rem if doing full benchmark t$=system$(tempdir$+"/inkey.sh -t"):if t$=chr$(27) goto otherstuffmenu print "Benchmarking warrior ",warriorname$(x,y) print esc$,"A"; rem move cursor up f$=tempdir$+"/temp.red" writewarrior(f$,x,y):score=0 for i=1 to nbenchwars battlewarriors(f$,benchwarriors$(i),bmrounds,benchpseq) score=score+sc1 next i score=score/nbenchwars:benchscores(x,y)=score avg=avg+score endif seqtmp$="":sc$=getwarriorbasechar$(x,y) rem get soup seq display char for i=1 to wlength(x,y) rem get the actual instruction sequence seqtmp$=seqtmp$+upper$(left$(soup$(x,y,i),3))+" " next i if nseq=0 then rem first entry nseq=1:seq$(nseq,1)=sc$:seq$(nseq,2)=seqtmp$:seqcounts(1)=1 seqtops(1)=score:seqnames$(1)=warriorname$(x,y) else rem search to see if already an entry sm=0 rem match flag for i=1 to nseq if seq$(i,2)=seqtmp$ sm=i next i if sm then rem if a match seqcounts(sm)=seqcounts(sm)+1 rem increment seq pop count if score>seqtops(sm) then rem update top score for sequence seqtops(sm)=score:seqnames$(sm)=warriorname$(x,y) endif else if nseq<maxseq then nseq=nseq+1 rem new entry seq$(nseq,1)=sc$:seq$(nseq,2)=seqtmp$:seqcounts(nseq)=1 seqtops(nseq)=score:seqnames$(nseq)=warriorname$(x,y) endif endif endif next y next x avg=avg/(xdim*ydim) rem adjust average score print:showcursor() rem output temp list rem don't use file numbers 1 or 2 e=open(12,tempdir$+"/anatmp.txt","w") if e=0 myerror("Can't open anatmp.txt file") for i=1 to nseq print #12 left$(str$(seqcounts(i))+" ",5); if selection=4 then print #12 " best ",left$(str$(seqtops(i))+" ",5)," by ",seqnames$(i); endif print #12 " \"",seq$(i,1),"\" ",left$(seq$(i,2),40); if len(seq$(i,2))>40 print #12 "..."; print #12 next i close #12 rem use system commands create sorted report... a$="Total of "+str$(xdim*ydim)+" warriors":z=viewmode:if z<2 z=2 if selection=4 a$=a$+", average score = "+left$(str$(avg)+" ",5) a$=a$+chr$(10)+"Using characters for viewmode="+str$(z) a$=a$+" with viewshift="+str$(viewshift) a$=a$+chr$(10)+"Found "+str$(nseq)+" unique instruction sequences..." e=system("echo \""+a$+"\">"+tempdir$+"/anareport.txt") if e myerror("Can't write to anareport.txt file") e=system("sort -gr "+tempdir$+"/anatmp.txt>>"+tempdir$+"/anareport.txt") if e myerror("Can't sort anareport.txt file") if selection=4 then e=open(5,tempdir$+"/anareport.txt","a") if e=0 myerror("Can't open anareport.txt for append") print #5 "" if addlistings then print #5 "------------------------------------------------------" print #5 "" print #5 "Top warriors from the top ",maxrepsave," sequences..." print #5 "" rem open beginning part of the file for read e=open(3,tempdir$+"/anareport.txt","r") if e=0 myerror("Can't reopen anareport.txt for read") line input #3 a$:line input #3 a$:line input #3 a$ for wc=1 to maxrepsave rem loop through top categories if eof(3) break rem shouldn't happen but if it does line input #3 a$:if mid$(a$,7,5)<>"best " break rem no more b$=mid$(a$,21):b$=left$(b$,instr(b$," ")-1) rem base name c$=soupdir$+"/"+b$+".red" rem soup filename print #5 "------- Pop.Cnt. ",a$ rem append the analyze line e=open(4,c$,"r"):if e=0 myerror("Can't read soup warrior") while not eof(4) rem append warrior line input #4 t$:print #5,t$ wend:close #4 print #5 "------------------------" rem append benchmark report makebenchreport(c$,b$) rem write to tempdir/results.txt e=open(4,tempdir$+"/results.txt","r") if e=0 myerror("Can't read bench report") while not eof(4) rem append benchpark report line input #4 t$:print #5,t$ wend:close #4 print #5 "" next wc:close #3 endif rem add listings if addsoupdisplay then for x=1 to xdim:print #5 "-";:next x:print #5 "" rem dump soup display, no color don't bother with border v1=viewmode:v2=ansimode rem save to restore after dump ansimode=0:if v1<2 v1=2 rem force modes for y=1 to ydim:for x=1 to xdim:printwarrior(x,y,5) next x:print #5 "":next y viewmode=v1:ansimode=v2 rem restore modes for x=1 to xdim:print #5 "-";:next x:print #5 "" endif rem add soup display if addfullbench then print #5 "" print #5 "Full benchmark report..." for x=1 to xdim for y=1 to ydim print #5 warriorname$(x,y)," "; print #5 left$(str$(benchscores(x,y))+" ",5)," "; seqtmp$="":sc$=getwarriorbasechar$(x,y) for i=1 to wlength(x,y) seqtmp$=seqtmp$+upper$(left$(soup$(x,y,i),3))+" " next i print #5 "\"",sc$,"\" ",left$(seqtmp$,40); if len(seqtmp$)>40 print #5 "..."; print #5 next y next x endif rem add full bench close #5 endif rem selection 4 endif rem again rem list the report... e=system(lister$+" "+listeropts$+" "+tempdir$+"/anareport.txt") if e print "List failed, check lister settings" if lister$="cat" input "(press return to continue) " t$ lastselection=selection rem global to persist between runs if selection=4 then rem save full report anavalid=1 rem set analysis valid flag if savefname$<>"" then print "Saving to ",savefname$ e=system("cp "+tempdir$+"/anareport.txt "+savefname$) if e print "Error saving "+savefname$+" file" sleep 2 endif endif goto otherstuffmenu elseif selection=5 then rem directly change parameters print "Enter settings as variable = value (quote strings, will echo back)" print "Soup/core/temp vars will be ignored. Enter an empty line when done." label reenterparms rem save variables that should not be changed... v1=xdim:v2=ydim:v3=length:v4=mincrelen:v5=coresize:v6=processes v7=cycles:s1$=tempdir$:s2$=soupdir$:s3$=topdir$:s4$=benchdir$ iflag=1:mflag=1:a1flag=1:a2flag=1 rem for handling vars that append repeat line input a$:a$=trim$(a$):if a$<>"" parseiniline(a$) until a$="" e=0:if xdim<>v1 or ydim<>v2 or length<>v3 e=1 if coresize<>v5 or processes<>v6 or cycles<>v7 e=1 if tempdir$<>s1$ or soupdir$<>s2$ or topdir$<>s3$ e=2 if e=1 print "(can't change soup or core parm)":sleep 2 if e=2 print "(can't change soup/top/temp dir)":sleep 2 rem restore variables xdim=v1:ydim=v2:length=v3:mincrelen=v4:coresize=v5:processes=v6 cycles=v7:tempdir$=s1$:soupdir$=s2$:topdir$=s3$ print "Checking settings...":e=validateparms(1):sleep 2 if e print "Errors detected, correct them...":goto reenterparms if benchdir$<>s4$ resetbenchstuff() goto otherstuffmenu elseif selection=6 then rem display the contents of a variable repeat line input "Enter variable name: " a$:a$=trim$(a$) if a$<> "" then rem error-chech name to avoid program error e=0:if instr(a$," ") e=1 rem can contain no spaces t$=upper$(left$(a$,1)):if t$<"A" or t$>"Z" e=1 rem must start with letter t$=upper$(right$(a$,1)) rem must end with letter number $ or _ if (t$<"A" or t$>"Z")and(t$<"0" or t$>"9")and(t$<>"$")and(t$<>"_") e=1 for i=2 to len(a$)-1 rem check all other chars t$=upper$(mid$(a$,i,1)) rem must be letter, number or _ if (t$<"A" or t$>"Z")and(t$<"0" or t$>"9")and(t$<>"_") e=1 next i if not e then varsubcount=varsubcount+1 rem increment sub count subname$="printvar"+str$(varsubcount) code$="sub "+subname$+"():print "+a$+":end sub" compile(code$):execute(subname$) rem that's just scary :-) else print "Invalid variable name" endif endif until a$="" goto otherstuffmenu elseif selection=7 or selection=8 then rem dump all parameters print "Generating parameters file..." e=open(2,tempdir$+"/parms.ini","w") if e=0 myerror("Can't open parms.ini for write") if selection=8 then print #2 "REM ----- yabevolver ini file -----" print #2 "REM created ",mid$(date$,3,10)+" "+left$(time$,8) endif print #2 "header$ = \"",header$,"\"" print #2 "author$ = \"",author$,"\"" print #2 "comment$ = \"",comment$,"\"" print #2 "tempdir$ = \"",tempdir$,"\"" print #2 "soupdir$ = \"",soupdir$,"\"" print #2 "benchdir$ = \"",benchdir$,"\"" print #2 "topdir$ = \"",topdir$,"\"" print #2 "xdim = ",xdim print #2 "ydim = ",ydim print #2 "xwrap = ",xwrap print #2 "ywrap = ",ywrap print #2 "length = ",length print #2 "coresize = ",coresize print #2 "processes = ",processes print #2 "cycles = ",cycles print #2 "rounds = ",rounds print #2 "mincrelen = ",mincrelen print #2 "instrate = ",instrate print #2 "modrate = ",modrate print #2 "addrrate = ",addrrate print #2 "numrate = ",numrate print #2 "adjrate = ",adjrate print #2 "localrate = ",localrate print #2 "reprate = ",reprate print #2 "insrate = ",insrate print #2 "duprate = ",duprate print #2 "swaprate = ",swaprate print #2 "delrate = ",delrate print #2 "mutadjust = ",mutadjust print #2 "mutadjgen = ",mutadjgen print #2 "orgrate = ",orgrate print #2 "org0rate = ",org0rate print #2 "crossrate = ",crossrate print #2 "adjlocref = ",adjlocref print #2 "evopseq = ",evopseq print #2 "evalmode = ",evalmode print #2 "evalrate = ",evalrate print #2 "evalgen = ",evalgen print #2 "ssfreq = ",ssfreq print #2 "superror = ",superror print #2 "benchfreq = ",benchfreq print #2 "savethr = ",savethr print #2 "savepc = ",savepc print #2 "bmrounds = ",bmrounds print #2 "benchpseq = ",benchpseq print #2 "reinsfreq = ",reinsfreq print #2 "unibox = ",unibox print #2 "viewmode = ",viewmode print #2 "viewshift = ",viewshift print #2 "ansimode = ",ansimode print #2 "enableC = ",enableC print #2 "lister$ = \"",lister$,"\"" print #2 "listeropts$ = \"",listeropts$,"\"" print #2 "listeroptsb$ = \"",listeroptsb$,"\"" print #2 "pmars$ = \"",pmars$,"\"" print #2 "pmarsv$ = \"",pmarsv$,"\"" print #2 "pmarsvopts$ = \"",pmarsvopts$,"\"" print #2 "pmarsvrounds = ",pmarsvrounds print #2 "instructions$ = \"",instructions$,"\"" print #2 "modifiers$ = \"",modifiers$,"\"" print #2 "addr1modes$ = \"",addr1modes$,"\"" print #2 "addr2modes$ = \"",addr2modes$,"\"" print #2 "enablepreseed = ",enablepreseed print #2 "initialinstr$ = \"",initialinstr$,"\"" close #2 if selection=7 then e=system(lister$+" "+listeropts$+" "+tempdir$+"/parms.ini") if e print "List failed, check lister settings":sleep 2 if lister$="cat" input "(press enter to continue) " a$ elseif selection=8 then print "Name for .ini file (default ",topdir$," directory)"; input ": " a$:a$=trim$(a$) if a$<>"" then a$=a$+".ini" if instr(a$,"/")=0 a$=topdir$+"/"+a$ rem if path not spec'd use topdir$/ t$="Y":e=open(1,a$,"r") if e close #1:print "File ",a$," exists. Overwrite";:input "? " t$ t$=left$(trim$(upper$(t$)),1):if t$="Y" then print "Saving to ",a$:e=system("cp "+tempdir$+"/parms.ini "+a$) if e print "Error saving "+a$+" file":sleep 1 sleep 1 endif endif endif goto otherstuffmenu endif rem any other selection returns to main menu end sub sub resetbenchstuff() local e,a$,t$ initbenchwarlist() e=open(1,topdir$+"/topscore.file","r") if e then rem topscore file exists, prompt to remove it line input #1 a$:close #1 print "Existing top score: ",a$ input "Reset the top score? " t$ t$=left$(trim$(upper$(t$)),1) if t$="Y" then print "Removing topscore file and resetting top score" system("rm "+topdir$+"/topscore.file") topscore=0:topwarrior$="" endif sleep 1 else print "No top score":sleep 1 endif end sub REM Changes... REM (230124+) initial experiments with no UI, evolved until stopped REM (230129+) added/refined UI for listing, benchmarking, battling warriors REM (230205+) added/refined "other" menu with tools settings and stuff REM 230209 first fairly stable version with UI REM 230212 fixed anareport redisplay logic, loading bad INI no longer REM exits but reprompts, added mutadjust and mutadjgen options REM 230213 added viewmode and viewshift options for tweaking display REM added shift-V to toggle viewshift between spec'd and random REM 230214 added ANSI dump and playback, on other menu REM 230217 tweaked soup display and ANSI dump code, added F S P L keys REM to ANSI playback for faster slower pause loop (requires awk) REM uses unicode soup box in ANSI dumps if unibox option set REM 230225 added normalizenumbers sub to ensure that only backrefs within REM the warrior are negative, all other numbers mod coresize REM 230303 added warrior listings, benchmarks and soup dump to other opt.4 REM soup bench report with prompts to control what's included REM added detection for identical scores to avoid functional dups REM ini/report saves now only add topdir$/ if no path/ specified REM REM License... REM YabEvolver is Copyright (c) 2023 Terry Newton (WTN) REM Do whatever you want to want to do with this code provided REM that whatever you do with this code does not prevent me or REM anyone else from doing whatever we want to do with this code. REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, REM EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF REM MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. REM IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY REM CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, REM TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE REM SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
About YaBasic
I like this language! FreeBasic is ok too but with YaBasic I can
just edit and run without a compile step, # is a comment character
so it can be treated like a scripting language, and I like being
able to just write code without having to declare variables subs
etc but it does have LOCAL for declaring local variables in subs.
No need for global etc, if not declared local it's global.
Although it claims to be an interpreter it seems to be quite fast
and does compile the code to an internal format. When a program is
run it reads it completely into memory, so unlike shell scripts
the program can be safely edited while it is running.
The syntax is a bit different - IF THEN ELSE constructs must have
the ENDIF, for simple single-line conditions THEN is omitted and
ELSE is not supported. Some functions are a bit different, it's
RAN(maxval) instead of RND(1)*maxval, UPPER$ and LOWER$ instead of
UCASE$ and LCASE$, MOD(x,y) instead of x MOD y (same with XOR and
some others) and the print and file open commands are a bit
different. Thankfully there is no ON ERROR GOTO for error handling
like the old QBasic, instead file operations return error codes
for error checking without disturbing the program flow. It still
has GOTO which comes in handy for redisplaying a menu after doing
something or if the operation is cancelled, or repeating an entry
if an error is detected. YaBasic only allows branching within the
same sub level, can't just go anywhere, but unlike some basics
branching out of a loop early is fine and a recommended usage.
This is not a bug, just a quirk with reasons - the screen handling commands require that the CLEAR SCREEN command be run first to initialize certain ncurses-related things, usually in programs like this I do my own screen handling using ANSI codes however one of the functions disabled by not using clear screen is INKEY$, kinda need that, and after using clear screen to enable keystroke input, ANSI codes no longer work and all screen handling must be done using YaBasic's commands for those purposes. Not complaining since this helps maintain compatibility between the Windows and Linux versions. I'm used to doing my own screen stuff using ANSI and some of the stuff I need to do doesn't look that easy to do with YaBasic's commands (cursor on/off, clear to end etc), so instead using a shell script solution for getting keystrokes...
#!/bin/bash to="";key="";if [ "$1" = "-t" ];then to="-t .001";if [ "$2" != "" ];then to="-t $2";fi;fi;read $to -sn 1 key if [ $? = 0 -a "$to" != "" ]&&[ "$key" = "" ];then echo -n "[extra]";else echo -n "$key";fi
When called using code like a$=system$("pathto/inkey.sh") it
waits for the user to press a key then prints it so that YaBasic
can pick it up. Keyboard echo is suppressed. When called using
code like a$=system$("pathto/inkey.sh -t") it returns immediately
(after 1 second), if no key is in the key buffer then it returns
an empty string. Add a number after the -t option to specify the
number of seconds to wait. Works like a charm except for two
things.. 1) it can wait for space to be pressed for press-any-key
situations but due to the way shell script works the script cannot
return a space character back to YaBasic, and 2) keyboard echo is
suppressed only when actually running, if a key is pressed while
yabasic is running code the terminal will echo it, possibly
disrupting the display. The only way I've found to fix that is to
do system("stty -echo") to turn off echo and system("stty echo")
to turn it back on but if doing that then best to also do on
interrupt continue to disable control-C handling or you may find
yourself at a terminal prompt that doesn't echo until blindly
entering stty echo to turn it back on. YabEvolver presently
doesn't turn off echo because any echoed keys get immediately
overwritten without much effect.. except for enter which can
disrupt the display. To fix that added code to the inkey.sh script
so that if -t is specified but it can't figure out what was
pressed (space enter tab etc) then it returns "[extra]" which
YabEvolver detects and repaints the display.
About the YabEvolver program
The evolving operations are a hodgepodge of whatever came to mind as I was writing the code, not necessarily proper or useful. All the operations have variables to disable or control how frequently the operation is performed. The swap operation is brutal - it swaps two lines in the parent warrior before evolving, usually killing the winning warrior in the process. Did it that way because it was easy (harder to swap when streaming forward), tempted to revisit that but oddball random operations like that can be part of the magic so probably should leave it be. The way it does crossover is goofy.. as it's evolving the winner to the loser position it randomly swaps the source line with a surrounding warrior of the same species if one's around. The dup line operation doesn't change the length, it just swaps the current line with a copy of the previous or following line - in my previous evolvers usually dup was part of the insert operation but in this evolver the insert operation always adds a new random line when triggered. The delete operation simply doesn't write the current source line, in effect deleting that line. When inserting or deleting lines, if the adjlocref setting is set then it attempts to adjust the number fields to preserve references and loops but the way it's implemented is probably not that useful, just something else to scramble the code.
When evolving number fields the program randomly selects between a new random number and incrementing or decrementing the existing number according to the adjrate variable. If a random number is selected it is weighted towards small +/- number according to the localrate variable. In corewar the core wraps around so in the case of nano warriors, -1 is the same as 79. The program makes some attempts to limit the magnitude of negative numbers to no more than the max warrior length. When saving top-scoring warriors the program does a simple hash to avoid saving duplicates but it presently doesn't attempt to distinguish between modulo locations so a few dupes might slip through.
There are two hashing functions in the program, a simple but fast
hash that reduces the base instruction sequence to a single
character for the soup display (collisions are inevitable), and a
more elaborate 6-digit hash for detecting duplicates. Writing
hashing code was surprisingly difficult, spent way too much time
on such a seemingly trivial thing. What I come up with is ugly,
fiddled with it until it returned mostly random numbers for
variations, but works well enough for what I need it to do.
Instructions, instruction modifiers and the A and B address modes
are weighted by including duplicate entries in the strings, a lot
easier to do it that way than to (somehow) specify individual
probabilities, and more intuitive. Weighting only determines the
probability of selecting an item, if the soup favors another kind
of code then weighting won't make as much difference.
YabEvolver's INI file format is the same as the default settings
portion of the program code.. rem for comments, lines containing
variable = value or variable$ = "value". Only instruction
specifier lines can span multiple lines using the form variable$ =
variable$ + "value", for most string settings anything between '='
and the first quote is ignored.
Originally the program had to be restarted to reload different
INI file parameters but added a feature that lets an INI be loaded
without restarting (assuming the INI is valid otherwise it exits
with an error). That was a bit tricky.. pmars and soup parms and
the directory names (other than the bench dir) cannot change or
undesirable things happen. Then I rigged it so that individual
settings can be changed on the fly (because that's handy to do)
but that part was even trickier - it reuses the INI verify code
which normally exits if there's an error but that would be
unfortunate for a simple typo, so added a "noexit" flag to the
verify sub so if an error occurs it complains then prompts to fix
the error and won't continue until it passes the parms check. Good
enough, would be too much code to try to automatically recover
from bad parms.
Running the program
To run YabEvolver you will need to have pmars and pmarsv binaries in a path directory (or bin64 directory if using my run script), and yabasic needs to be installed. YaBasic is available from the Ubuntu repository or get from the link in the program code. Just about any pmars/pmarsv binaries will work so long as the Permutate option is available, by default it uses that for benchmarks for consistent scores. The program defaults are for the old X11 pmarsv 0.9.2 version, settings for the SDL version are commented out. Binaries and source for my patched versions of pmars/pmarsv and the SDL version are linked before the program listing.
To perform benchmarking and use benchmark-guided evaluation modes
it needs a set of test warriors. As written the program looks in a
directory named "nano2301" for the nano2301 test set of 30 warriors from
the recent Koenigstuhl
recursive nano hill. Another test set I've been using is nano106 consisting
of 106 older and newer nano warriors. Settings can be changed by
editing the INI section of the program code, or copying the INI
section to an .ini file and editing that and specifying it on the
command line when running the program.
To run YabEvolver, save the program code to a file named say
"yabevolver.yab" in its own directory, copy the nano2301 directory
there (or whatever test set you are using) and at a terminal in
the program's directory enter: yabasic yabevolver.yab
Add a filename to the command to specify an INI file to use
instead of the default settings.
To make things easier I use run scripts based on the script
listed below in the helper scripts section (requires xterm and
awk), each copy is edited for a unique INI file and window title,
the script checks the INI file for xdim and ydim and automatically
sizes the xterm window to fit the soup display. Note - if running
multiple experiments at once, each INI file must specify different
directories for tempdir$ soupdir$ and topdir$ or there will be
problems.
The program creates the following directories and files when it
runs...
/dev/shm/yabevoltmp - default temp file directory, change
tempdir$ to use another directory.
The following files are created in the temp directory...
inkey.sh - a script for getting keystrokes
a.red and b.red - the two warriors doing battle, these files are
overwritten constantly
temp.red - the warrior being listed or benchmarked
results.txt - benchmark results
anareport.txt - sequence or benchmark report
anatmp.txt - unsorted sequence/benchmark report
parms.ini - used when listing all settings
warfile.tmp - used when removing lines from the top/warinfo.fil
file.
Temp files are not removed when the program exits.
soup - default soup directory, change soupdir$ to change. Soup
warriors are saved here.
top - default top-scoring warrior directory, change topdir$ to
change.
In addition to warriors it also writes the following files to the
top directory...
warinfo.fil - contains a list of warriors saved to the top
directory with their benchmark scores
topscore.fil - contains the top score and warrior
Settings .ini files and sequence/benchmark reports are saved to
the top directory by default.
The User Interface
When the program starts it reads the settings file if one specified on the command line, checks the parameters, creates/verifies directories and initializes the benchmark warrior list, if you need to read the status messages press esc right after running, otherwise it loads or creates the soup and displays the main menu (using plain ascii screendumps in this section, normally it's in color with neat unicode borders)...
.-----------------------------------------------------------------------------.
|23543222422322254532355554435522535433245343354534235533343323423242242435234|
|52423352225542325322324453245442354532234322432545232234355424525433533225325|
|25343232355343423235352345254555233354443232253252355235552442422253322434322|
|33422554224533542433223333243454325353533232433243253444524422422235355353252|
|44554323445235542244555552344343355453543444444433345553552235353535354325443|
|33522524435435453554355555553234424343452245352424524245344235543445523353555|
|35354354235333443443442242423355524553322534223553453444445543323525432353543|
|54334345453543324424433322535455554343555453522452345244354352554442332325445|
|25552543523525523353434234525232552234353535523344355244355335433534543234343|
|52225552232425243343322455242542342435523232252434244254255333332434353224433|
|52444532233344243332525345553432354423444354322344452554324452355553242433422|
|53252532422232455242522332233342222525443355244325322253554535453352542535225|
|54245334444243344523255254425333523444255343243324522545544424422235355324433|
|43432325233454532242452424532342235523454535443445522354434534452423434444534|
|24252542244243544422525535442543224424424234253442445443523522243253554433533|
|52554352442352444553423433555243333333345352432543242532524555252242554355342|
|42325252325424422543452432452354422225322453545523453225353542243235434432433|
|32433424452344254244255244455452355354452525342222222524425334345555353233435|
|44424232434222325532543534524324552522245242535255524454455324245343245432425|
|43342345435553552445422534224425225222532445554554234223245344345432523232343|
`-----------------------------------------------------------------------------'
[E]Evolve [L]List [B]Bench [0-9]Battle [V]View [O]Other [S]SaveSoup [X]Exit
Press E to start evolving. After a short time the warriors start
"clumping"...
.-----------------------------------------------------------------------------.
|34433333333333333332244444222444444443442332222555554444554444555555555555555|
|34333333333533333332222224222244444443443232222555545445555445455555555555555|
|34333333353453335333222225424444444444444432222525554445555545555554555555555|
|33333333555455353332222444444444444444243433322222544444555555555555555555555|
|33333332255553533332224244333444444444422333222222244445555555555555555555555|
|33333333455555553323225443343444344424222222222225444445555555555555555555555|
|33333335522555233232255543333453444422422222222252545455555555555445554445445|
|33333335352255523355555555334333333442222222222222555555555555555444554445555|
|33333333532555555455555555333333333442222222222552555555555555555545455445455|
|33355533333555554555555555333333334444422222255225255555555555555555555555555|
|55455353333555555455555555533333334442222252555225555555555555555555555544555|
|55545543333555555555555555333333333442252525555555555555555555555555455545455|
|55444553333345554555555555353333333432445555555555555555555555555555445554455|
|55444545333333555445555555553333333345255554555555555555555555555554545454444|
|55555553553333555555555553532333333454555555455555555555555555555545454444444|
|55545555333333355555544555532233333335555555555555555555555555555555544444443|
|55555555333333535555554545553323333335555555555555555555555555555554544444445|
|55555535535535555554445555553333333355555555555555555555555555555555555554455|
|55555555333555555544445554533353332555555544554455555555555555555555555555555|
|35555555543555555544455555553332233535555555444555555555555545535555555555555|
`-----------------------------------------------------------------------------'
28_02 vs 28_03- 134 128 12_06 scores 40.56 top=61.57 (esc to stop)
Press esc to stop evolving and return to the menu...
.-----------------------------------------------------------------------------.
|33333335554455555555555533343333343344445555544545555555444554444444444554554|
|43343353544555555545545353333333434344555555554455555553445544454444444445544|
|34443355535555555555555555333333334334355555555555555533345554544444445455555|
|45444535555555553335555555333335335333555555555555455333344454444454455555555|
|44444455555455355355555555335353533533553555544544554333444444445444444545555|
|44444345555435534455555555333353535555555454444445443333333444455544455555555|
|44444543355543434555555553555333355553443544444444553333443445555554455455555|
|44435445555554545455555555553334455553333344444455553334444444455555455555555|
|44445555455553454555555555553333355555353334445555553334444444455555555555455|
|45543455555553545555555544555554535553533544445555535344444455555555555555555|
|55544455555555555555555445455444555533355444544555555355444444445555555555555|
|55444445555454555555555455555545554533355445555555555544454444554455555555555|
|44444555555444555555555555555443555333355555555555555544554445554555555555555|
|44445555554445555555555555555554555333555555555555545554454454444455554555555|
|44445555555544555555555555555555353333555555555555555544444444444455545555555|
|44545555555555555555555555555455533355555555555555555544444444444445554555555|
|55555545555555555545555555555554555355555555554555555444444444544445555555555|
|55555555555555555455555555555555555555555555555455555555445545554445555555555|
|55555555553555545555555555555554554555555555555455555555555554455545555555455|
|55555555533355455555555555555555554455555555554555455555555554455555555555555|
`-----------------------------------------------------------------------------'
[E]Evolve [L]List [B]Bench [0-9]Battle [V]View [O]Other [S]SaveSoup [X]Exit
The default is to display warriors as numbers (or numbers and
letters) to represent the warrior's length, press the V key to
cycle the soup view mode to use symbols for species (mod 14),
letters for instruction sequence (mod 52), or letters, numbers and
symbols for instruction sequence (mod 94, fewer collisions)...
.-----------------------------------------------------------------------------.
|!!!!!!!...##$$$&&$&&&&&&!!!~#####~##~~~~~~?**^#;#;...&&&+++?+..........?$@$$;|
|!!!!!!*!.$$$$$$$&&^&&%&!&!######~#~#~~~~~~&*~;##;;..&&&@++??...?......@@@$$@@|
|!!!!!!***!$$$$$$&&&&^^&&@&########~####~~~*~~~;;;&&&&&@@@.??..?...%...^..$;..|
|!#!!!*!***$$*$$$!!!&%^&&@&###~#$##~####~~*~@?&?;;;#&&@@@?...?....*+**??##....|
|!!!!!!**+$$&$'!$$!&&&&&&&&##&#$#~##~##~~#~&@@#~;'';;'@@@........?******#?.&.~|
|!!!!!!@+++!&!?$!&&&#&&&&&&####$#~#~~!~~~~#&~~~~~~;''@@@@@@@....???***?.??..~~|
|!!!!!!@!!!!!&!&!&?&#&&&&&#$&&####~~!~#!!#&###~~~?~;;@^@@..@..!?..??**??*...~~|
|!^!!!@@!!!!*?&?&?&#?$&&&&&&$##.;;~!~~#########~~%;;;@@@.........????*???..%$.|
|^^^^!!!!.!&!.!&?&?&;@$$&&&#$#####~~~~~#$##@#.#++;;;;@@@.......*@?????&??.#!..|
|^$$^$^$!!!&??!!????@@$$$$$$$$$$#~#.~~#$##~@###+;;;;@&^......&&&???'??????....|
|!#$^^^%!!!??&?!&?????@;$$$.;$###.~.~###~~@@@*##?;;%;&^~&........????????.....|
|!!^^^^^%!!!%!;?????&?$;$;;;&;!#~~.!.###~&@@@??@@;&;;%%...$....??.&??????.&...|
|~^^^^!'!!!!;;;??&????&@&;;$;&###~..####~&??&&???;;;;;%.!$$...???;????????....|
|^^^^!!%!!!@;;&&?????$&&&;&;&&&&#~~.###~&.&??&&&?@@+*%%%..$..#!!.;.????!??....|
|^^^^!!!@!!&!;;&&??&?&&&;&@@&&&&&#~####~~&+&&&$&@@?@@%@.......!!...%~?$;;.....|
|^^!^!!!!!&!!!&@&&$&&?&&&&&&&&*&&^###&~~&&&&&&&^@@@@@@@......~.!.+~^?~.'......|
|!!!!!!@!.!!+%&@&&?~*&;&&&&&&&&&#&^&#~&&&&&&&&&#;@@@@@........!...^'?...;.....|
|!!+!!!!!!!!%+@@@&#&&;;;&&&&^&&'&;&&&;~&;&&%&#&&#+++@+%++..$$!....^^..;...+...|
|!!!!!!!!!.!%;;;!&&&;;;&.&&&&&&&!&&;&&&&*&&^&&&&;+++@++%$$$++.;;...^$..;;?.*..|
|!!!@!!!!.!!!;;;;#&&;!;;%&&&?&&~&&&;;&&&&&&&&&&#...%+++++$$+++;;.......;;.....|
`-----------------------------------------------------------------------------'
.-----------------------------------------------------------------------------.
|YYYYYYYqqqUUjijiijiiiiiiYYYyYYYYYEYYEEEEZZdjjycFcFqqqvvvEEEiyUUUUUUUUUUiUoUUw|
|gYYgYYqYqUUiijijiiaiiEiYiYYYYYYYECEYEEZZZZvjZFccFFqqvvvYEEiiUUUiUUUUUUoooUUoo|
|YgggYYqqqYiiqiijiiiiDBiiiiYYYYYYYYEYYcYZZZjZZZFFFvvvvvYYYUiiyUiUUUEUUUjUjUjjj|
|gxgggqYqqqiimijjYYYiMDiiiiYYYqYTYYZYYYkZZjZxbvJFFFcvZYYYgUUUiUUUUUTUUiiUUjjjj|
|ggggggqqxiicirYjjYiiiiiiiiYYiYiYZYYZYYZZYZjxxcyFccxxcYYYUUUUUUUUiUUUUUUUUjjjr|
|gggggYyxxxVcYrjYcciUiiiiiiYYYYiYZYZZjZZZZcjcyyyyyFccYYYYYYYUUUUiiiUUUijiijjrr|
|gggggVyYYVVVcYcYcriNiiiiiYiiiYYYYZZjZYEEYccccyyyyyFFYqYYUUYUUjiiiiiUUiiUjjjrr|
|gcgYVyyVVVVqrcrcrcNriiiiiiiiYYuIIZjZZYYYYYccccyyOFFFYYYUUUUUUUUiiiiiUiiijjrUj|
|ccccVVVVWVxVdYcrcriiUiiiiipiYYYYYZZZZZYxYYgcUcxxFFFFYYYUUUUUUUUJiiiiiiiijikjj|
|cGGcgcGrVVxrrYVsrrriiiiikkiiiiicZYTZZYxYYZecccxFFFFYOYUUUUUUTTiiiiqiiiiiijjjj|
|VxGcccrVVVrrorVUrrrrrirkkisricccTZTZYYYvZeeeCccnFFxxOYTvUUUUUUUUiiiiiiiijjjjj|
|VVcccccFVVVOVGrrrrririrkrrrirbcZZTLTYYYZveeHrnFFxOxxeeUUURUUUUiiUAiiiiiiUojjO|
|OccccVrVVVVGGGrrirrrriiirrgriccYZTTYYYYvvnnvvnnnxxxxxeUqRRUUUiiiUiiiiiiiijjjj|
|cccczVLVVViGGiirrrrrviiiririiiicZZTYYYvvpvnnvvvnwwbIeeeUURUUBEEUUUiiiiUiijjjj|
|ccccVVVhVVUVGGiirririiiricMiiiiiYZYYYYvvvqvvvAcwwvwwawUUUUUUUEEUUUjpisnnjjjjj|
|ccVcVVVVVUVVVuUuiviiriiiiiiiiEiivYYYvvvvvvvvvviwowwwwwUUUUUUqUEUGaEipjNjjjjjj|
|VVVVVVsVbVVbVpUiivEairiiiiiiiiiciviYRvvvvvvvvvkmwowwwUUUUUUUUEcUUEMijjjnjjjjj|
|VVdVVVVVVVVVbUUUiEiirrriiiiEiijitivvTRvRvvRvLvvkbbbwbSbbUURREjjjUEEjjnjjjjjjj|
|VVVVVVVVVVYVrrrsiiirrriAiiiiiiiHiiIvvvvnvvsvvvRUbbRwbbSRRRbbjUUjjjEjjjnnzjUjj|
|VVVVVVVVVYYYrrertiirprriiiiqiiiiiiIIvvvvvvvvvvkbbbGRbbbbRRxbbUUjjjjjjjnnjjjjj|
`-----------------------------------------------------------------------------'
.-----------------------------------------------------------------------------.
|7777777aaa55:/://://////777}77777E77EEEEZZ*::}gPgPaaafffEEE/55555555555/+?++q|
|k77k77a7a55//:/://[//E/7/7777777E!E7EEZZZZf:ZPggPPaafff7EE//555/555555???++??|
|7kkk77aaa7//a//:////Dl////77777777E77g7ZZZ:ZZZPPPfffff7775//i5/555E555:5:+:::|
|krkkka7aaa//3/::777/wD////777?7J77Z777[ZZ:Z|ffJPPPgfP777i555/55555455//++::::|
|kkkkkkaa|//g/l7::7////////77/7/7Z77Z77ZZ7Z:||g}Pgg||g77755555555/555555+5:::l|
|kkkkk7}|||Vg7l:7gg/K//////7777/7Z7ZZdZZZZg:g}}}}}Pgg77777775555///555/://::ll|
|kkkkkV}77VVVg7g7gl/$/////7///7777ZZdZ7EE7gggg}}}}}PP7?77557550/////55//5:::ll|
|kgk7V}}VVVValglglg$l////////77MSSZdZZ77777gggg}}%PPP77755555555/////5///::l!:|
|ggggVVVVWV|V*7glgl//K/////J/77777ZZZZZ7|77ig5g||PPPP77755555555j////////:/;::|
|gGGgigGlVV|ll7Vmlll/////;;/////gZ7JZZ7|77Z?ggg|PPPP7%755555544////a//////::::|
|V|GggglVVVllilVKlllll/l;;/ml/gggJZJZ777fZ???9gg4PP4|%74f55555555////////:::::|
|VVgggggfVVV%VQlllll/l/l;lll/lfgZZJvJ777Zf??^b4PP|%||!!555(5555//5u//////K?::%|
|%ggggVlVVVVQQQll/llll///ll-l/gg7ZJJ7777ff44ff444|||||!5K((555///5////////::::|
|gggg@VvVVV/QQ//lllllp///l/l////gZZJ777ff,f44fff4qq\S!!!55(55bEE555////5//::::|
|ggggVVVnVVKVQQ//ll/l///l/Iw/////7Z7777fffafff7}qqfqq[q5555555EE555:J/m44:::::|
|ggVgVVVVVKVVVGKe/p//l////////E//f777ffffffffff/q?qqqqq555555K5E5Q[E/J:N::::::|
|VVVVVVmVfVVfVjK//pEq/l/////////g/f/7|fffffffff;]q?qqq55555555Eg55Ew/:::4:::::|
|VV*VVVVVVVVVfKKK/E//lll////E//:/0/ff4|f|ff|flff;\\\q\)\\55((E:::5EE::4:::::::|
|VVVVVVVVVV7Vlllm///lll/7///////R//Iffff4ffcfff|+\\(q\\)(((\\:55:::E:::44@:5::|
|VVVVVVVVV777ll+lD//l6ll////a//////IIffffffffff;\\\G(\\\\((|\\55:::::::44:::::|
`-----------------------------------------------------------------------------'
[E]Evolve [L]List [B]Bench [0-9]Battle [V]View [O]Other [S]SaveSoup [X]Exit
Press the S key to save the soup without exiting. To avoid
unneeded disk writes the save option is available only if the soup
has changed since the last save, otherwise (if enableC is set) the
menu changes to...
[E]Evolve [L]List [B]Bench [0-9]Battle [V]View [O]Other [C]Colors [X]Exit
The C key is still available when SaveSoup is displayed, there
just wasn't enough room to list the option. Press C to cycle
between different color schemes - none, 16-color ANSI, 256-color
ANSI or 24-bit RGB ANSI. The default can be specified in the
program or INI file in the 'ansimode' setting.. 0 16 256 or 24.
Make the 'enableC' setting 0 to disable color cycling, not all
terminals support RGB ANSI and that might be jarring.
The V and C keys can also be pressed while evolving to change the
view and colors without going back to the menu.
Use the cursor arrow keys to move around the soup display, the
Exit menu text will be temporarily replaced with the warrior
coordinates under the cursor. Press L to list the selected
warrior...
;redcode-nano
;name 23_06.red
;author yabevolver
;strategy evolved
;origin 15_09
;species 74277
;generation 51
;created 02-09-2023 18-55-54
;assert CORESIZE==80
ORG 0
SPL.F # 1,$ 71
MOV.I # 19,> 3
MOV.I { 59,> 2
MOV.B @ 1,{ -1
DJN.I $ -3,} 1
END
/dev/shm/yabevoltmp/temp.red (END)
By default text files are listed using the 'less' utility, press
Q to exit back to the program. Edit the INI settings lister$
listeropts$ and listeroptsb$ to use another lister, or replace
lister$ with "cat" for something simple.
Press B to benchmark the selected warrior...
Crisis 59.154 *******
[RS] C-Strobia 108.45 **************
eerie glow 82.394 **********
Free the Fish! 106.33 **************
Hot Soup 46.478 ******
Just a MEVO Thing 100.70 *************
Little Bang 96.478 ************
Little Red Rat 136.62 ******************
7_3 49.295 ******
NanoCracker 44.366 *****
02_08 134.50 *****************
[RS] Nextratulated Sturvi 67.605 *********
Nonlocality 2 84.507 ***********
Nonlocality 95.070 ************
Quantum Foam 76.760 **********
Reflow Oven 52.112 ******
Sleepy Lepus 80.985 **********
Steaming Pebbles 31.690 ****
SWT2-21 90.140 ************
SWT2-28 84.507 ***********
Transfer Function 73.943 *********
Unholy Fire 102.11 *************
Benchmark score: 76.690
/dev/shm/yabevoltmp/results.txt (END)
...not very strong yet, this soup has only been running for a few
minutes. Generally to be competitive on an actual hill, a redcode
warrior needs to score 145 or more against a test set that
represents the kind of warriors on that hill.
Press a number key to run the selected warrior in pmarsv, press
1,4,7,8,9,6,3 or 2 on the number keypad to battle a surrounding
soup warrior, press 5 to run the warrior by itself, or press 0 to
battle a randomly selected benchmark warrior. The default pmarsv$
and pmarsvopts$ settings are for the old 0.9.2 version of pmarsv,
add -font fixed to pmarsvopts$ if it complains about the font (my
patched 0.9.2N3 version is patched to default to fixed). Settings
for the SDL version are in the comments, I had to slightly modify
it to slow it down, for nano warriors the stock SDL version was
way too fast. The pmarsvrounds setting (default 10) determines how
many rounds to go in the core, after battling the average scores
are printed on the status line and it waits for enter to be
pressed.
Press the O key for the "Other" menu where I add various bits I
need...
Other functions...
1 - Change the benchmark set
2 - Load settings file (some parms ignored)
3 - Show soup sequences and population numbers
4 - Sequence and benchmark the entire soup
5 - Change settings variable(s)
6 - Display variable(s)
7 - Display all settings
8 - Save settings to file
9 - Save soup (not saved yet)
10 - Start/stop ANSI dumps
11 - Play back ANSI dumps
Select function or none to exit:
(my menu style may be showing my age...)
Option 1 prompts for a new benchmark directory, if a valid
directory containing benchmark warriors is entered it reloads the
benchmark warrior names and if there's a topscore.fil file in the
top directory, offers to delete it and reset the scores. If
nothing is entered then offers to disable benchmarking (might take
that out now that settings can be changed directly).
Option 2 prompts for a settings filename, include the extension.
If the file exists and looks valid then it loads it. Settings for
xdim ydim length mincrelen coresize processes cycles tempdir$
soupdir$ and topdir$ are restored if different in the settings
file, changing those settings would require a restart. After
loading it verifies the settings, if there is an error in the
settings the program will terminate so if option 9 - Save soup is
showing use it before loading an experimental INI file.
Option 3 sifts through the soup and lists unique instruction
sequences the number of members in each sequence...
Total of 1540 warriors
Found 107 unique instruction sequences...
285 "i" SPL MOV MOV MOV DJN
169 "U" SPL MOV MOV MOV
163 "Y" SPL MOV MOV
110 "j" SPL MOV MOV MOV SPL
97 "V" SPL MOV SPL MOV SPL
84 "r" SPL SPL MOV MOV SPL
75 "c" SPL SPL MOV MOV
74 "v" SPL SPL MOV MOV SUB
62 "Z" SPL MOV MOV DJN MOV
32 "F" MOV SPL SPL MOV MOV
28 "E" SPL MOV MOV DAT
27 "g" MUL SPL MOV MOV
...snip...
Option 4 does the same thing except it performs a full benchmark
of the soup. That can take awhile, if you get impatient press esc
to cancel. When complete it produces a listing like this...
Total of 1540 warriors, average score = 82.51
Found 107 unique instruction sequences...
285 best 108.5 by 72_10 "i" SPL MOV MOV MOV DJN
169 best 109.6 by 62_19 "U" SPL MOV MOV MOV
163 best 95.19 by 55_06 "Y" SPL MOV MOV
110 best 117.6 by 71_18 "j" SPL MOV MOV MOV SPL
97 best 98.97 by 05_15 "V" SPL MOV SPL MOV SPL
84 best 110.5 by 17_10 "r" SPL SPL MOV MOV SPL
75 best 94.29 by 49_05 "c" SPL SPL MOV MOV
74 best 104.1 by 34_17 "v" SPL SPL MOV MOV SUB
62 best 87.42 by 39_04 "Z" SPL MOV MOV DJN MOV
32 best 90.11 by 49_11 "F" MOV SPL SPL MOV MOV
28 best 105.9 by 68_17 "E" SPL MOV MOV DAT
27 best 82.44 by 05_06 "g" MUL SPL MOV MOV
...snip...
...followed by the benchmark results of all soup warriors. After
displaying the report it prompts for a name to save the file to,
just press enter to not save, or enter a name without an
extension. For file safety reasons the directory is set to topdir$
and the file is saved with a .txt extension. To save to another
directory enter ../path/name instead to back out of the top
directory. If the soup has been saved and hasn't changed and the
report already exists then option 4 redisplays the existing report
instead of doing the benchmarks again.
Option 5 permits changing one or more settings without having to
load a whole INI file. The entries must follow the same INI
format, variable = number or variable$ = "string". The
instructions$ setting and other code element strings can span
multiple lines by entering instructions$ = instructions$ + " ADD
SUB" etc. Press just enter to exit the entry loop and check the
settings, if there are any errors it prompts again to fix the
errors. It won't exit the entry loop until it passes the checks.
Option 6 displays the contents of a variable. Not only settings
but any program variable. Doing that was a bit tricky, generally a
BASIC program can't be made to dump its own variables unless
specifically coded, but YaBasic has compile and execute, so it
actually adds a sub to itself that prints the requested variable.
To avoid calamity the entered variable name cannot contain spaces,
must start with a letter, and after the first letter only letters,
numbers and "_" is allowed besides the "$" at the end to indicate
a string.
Option 7 lists all settings variables.
Option 8 runs the same code as option 7 except instead of listing
it prompts for an .ini name to save to. Don't add the extension,
for file safety the file is saved to the topdir$ directory and it
adds .ini to the filename. To save to the program directory
instead add ../ in front of the name. As with saving the sequence
report this is to help avoid accidently overwriting something
important and almost always when saving parms or the report it's
specific to a particular run.
Option 9 shows only if the soup has changed since the last save
as a reminder, once the soup is saved option 9 goes away.
Option 10 and 11 permit making and playing back ANSI "movies" of
the soup progress, handy for overnight runs to see what happened
and eye candy in general. When ANSI dumps are enabled, while
evolving it will periodically save a snapshot of the soup to a
numbered file, up to a hard-coded maximum of 9999 files (4 digit
sequence number) to keep things relatively sane. Each snapshot
consists of the colorized soup display using the current view mode
and colors in a text-mode box (to avoid unicode
incompatibilities), followed by the filename, top score and last
benchmark result. Separate files are used so the sequence can be
played back with a controlled frame delay.
If ANSI dumps is currently enabled, option 10 will show the current dump parameters and prompt to disable, otherwise it prompts for a base name for the dump files and the directory to put them in (default ansidumps), if ANSI files with the same base name exist (checks for basename0001.ans) then it prompts to Remove or Continue - enter R to remove existing files and start with sequence 0001, enter C to continue dumping at the next consecutive file, or anything else to return to the menu. Next it prompts for how many cycles between dumps, typically a few thousand (if under 1000 it warns about excessive writes), then prompts for the maximum number of dumps, just enter for the max of 9999, -1 to go back to the menu without enabling, or enter the number of dumps to perform before automatically disabling. Once enabled exit the other menu, make sure the view mode and colors are as desired, and start evolving to record - the first frame will be the current soup. You can stop evolving, check the soup etc without disturbing the dumps or interval but if the program is exited then to continue dumping you'll have to set it up again using the continue option, which will probably result in a score or soup glitch in the playback.
Option 11 plays back an existing ANSI dump sequence. If the
sequence number is non-zero it assumes a dump has been performed
and offers to play back from the existing basename and directory,
otherwise or if declined it prompts for the basename and directory
to play back - if installed it uses the ansi2txt utility to make
sure the current display can handle the dump, if not prints an
error and goes back to the menu. Finally it prompts for the delay
between frames (default 0.1 seconds) then plays the sequence.
While playing press F to go faster, S to go slower, P to pause, L
to enable/disable looping, H to redisplay the key choices, or any
other key to stop. After stopping or after the last frame if
looping is disabled (default) it prompts to play again - press Y
to play from the beginning or any other key to exit back to the
menu.
Some early results
This is from evolving a 138x37 soup for a couple days...
The larger soup size has helped to maintain more diversity, even
after thousands of generations there are still several unique
sequences with sizable populations...
Total of 4366 warriors, average score = 127.3
Found 85 unique instruction sequences...
1826 best 142.0 by 008_32 "i" SPL MOV MOV MOV DJN
1660 best 147.2 by 057_36 "q" SPL SPL MOV MOV DJN
894 best 155.3 by 022_19 "x" SPL SPL MOV MOV MOV
467 best 139.2 by 086_35 "U" SPL MOV MOV MOV JMP
203 best 144.9 by 067_14 "r" SPL SPL MOV MOV SPL
33 best 133.9 by 027_08 "c" SPL SPL MOV MOV
15 best 136.9 by 004_19 "Z" SPL SPL MOV MOV ADD
13 best 104.7 by 055_17 "N" SPL SPL MOV SPL MOV
12 best 115.9 by 023_07 "O" DJN SPL SPL MOV MOV
9 best 135.4 by 002_02 "W" SPL SPL MOV MOV JMZ
7 best 106.6 by 055_11 "M" MOV SPL MOV MOV DJN
6 best 138.1 by 021_08 "v" SPL SPL MOV MOV SUB
6 best 127.2 by 004_18 "W" SPL SPL MOV MOV SNE
5 best 136.2 by 090_06 "c" SPL SPL MOV MOV JMP
5 best 125.2 by 002_31 "p" SPL MOV MOV MOV MOV
5 best 124.3 by 003_30 "U" SPL MOV MOV MOV
.....
A look at a few of these and how they perform against current
nano hill warriors and the old nanoBM04 test set...
;redcode-nano
;name 008_32.red
;author yabevolver
;strategy evolved
;origin 012_23
;species 74794
;generation 4077
;created 02-05-2023 13-20-02
;assert CORESIZE==80
ORG 0
SPL.BA # 41,< 63
MOV.I } 75,{ 0
MOV.I > 8,{ -2
MOV.I { -3,< 60
DJN.B $ -2,} 14
END
Testing 008_32.red...
Anefam Vesyes 152.11 70 6 ***************
Another MEVO Thing 164.08 77 2 ****************
b69e6908-a5be0bba-ab4445 133.09 60 9 *************
Clone 148.59 68 7 **************
Cold Plasma 140.84 64 8 **************
Combat Arithmetic 136.61 61 11 *************
Creamed Corn 135.91 61 10 *************
Crimson Climber 126.05 57 8 ************
Crisis 150.70 70 4 ***************
[RS] C-Strobia 146.47 66 10 **************
eerie glow 129.57 54 22 ************
Free the Fish! 130.98 58 12 *************
Hot Soup 139.43 63 9 *************
Just a MEVO Thing 171.12 79 6 *****************
Little Bang 154.22 71 6 ***************
Little Red Rat 161.26 76 1 ****************
7_3 139.43 65 3 *************
NanoCracker 121.12 55 7 ************
02_08 147.18 64 17 **************
[RS] Nextratulated Sturv 139.43 65 3 *************
Nonlocality 2 133.09 57 18 *************
Nonlocality 128.16 55 17 ************
Quantum Foam 157.74 73 5 ***************
Reflow Oven 140.14 65 4 **************
Sleepy Lepus 116.90 47 25 ***********
Steaming Pebbles 139.43 63 9 *************
SWT2-21 146.47 65 13 **************
SWT2-28 155.63 69 14 ***************
Transfer Function 152.81 69 10 ***************
Unholy Fire 121.83 51 20 ************
Score = 142.01
Testing 008_32.red...
8c09fc1a-4799259f-174724 164.78 78 0 ****************
rdrc: Alcoholism Malt 138.73 64 5 *************
b1f3ad11-a6073e-f711ff69 155.63 72 5 ***************
Bacillus anthracis 142.95 65 8 **************
Black Sun III 154.22 69 12 ***************
rdrc: Breakaway Carte 132.39 49 41 *************
c82f15b5-85011fd8-5a969d 142.95 65 8 **************
Clear-2 167.60 78 4 ****************
Cosmic Horror 129.57 52 28 ************
Different Day 147.18 68 5 **************
written in a dream 119.01 49 22 ***********
early morning view 105.63 50 0 **********
Escherichia coli 146.47 69 1 **************
e6843-5724-xt430-4-nano- 132.39 57 17 *************
Foggy Maus (beta) 135.21 62 6 *************
girl from the underworld 138.02 62 10 *************
human resistance 147.88 66 12 **************
the kraken awakes 138.73 51 44 *************
Leishmania deanei 145.77 66 9 **************
looking glass 155.63 73 2 ***************
lord of the digital swam 119.01 49 22 ***********
Man&Machine 162.67 74 9 ****************
Military Grade Nano 168.30 76 11 ****************
New Vera City 134.50 62 5 *************
Obsidian peasoup 145.77 68 3 **************
Plasmodium vivax 159.15 73 7 ***************
qEvo[[3]] 173.23 77 15 *****************
realm of the fire flower 106.33 43 22 **********
Red Moon 154.92 72 4 ***************
rdrc: Repent Linemen 160.56 76 0 ****************
Rocket propelled monkey 155.63 70 11 ***************
rumpelstiltskin 104.22 40 28 **********
Salmonella enterica 150 70 3 **************
Science Abuse 178.16 82 7 *****************
scythe 102.81 37 35 **********
rdrc: Snapback Sprite 168.30 78 5 ****************
spawn of the dark core 166.19 68 32 ****************
Staphylococcus aureus 173.23 76 18 *****************
Stegodon Aurorae 183.80 83 12 ******************
rdrc: Strychnine Banshee 169.01 79 3 ****************
Subterranean Homesick Al 130.98 48 42 *************
tinderbox 111.26 43 29 ***********
toy soldier 173.23 79 9 *****************
Trypanosoma brucei 147.18 56 41 **************
victim of the night 155.63 70 11 ***************
war of the snowflakes 92.253 34 29 *********
wisdom of the grasshoppe 178.87 79 17 *****************
wreath of thistles 126.76 60 0 ************
written in the dust 183.80 85 6 ******************
Xinyl 110.56 46 19 ***********
Score = 145.74
--------------------------------------------------
;redcode-nano
;name 057_36.red
;author yabevolver
;strategy evolved
;origin 114_15
;species 87799
;generation 2018
;created 02-05-2023 13-21-58
;assert CORESIZE==80
ORG 0
SPL.I # 19,> 56
SPL.BA # 17,} 0
MOV.I } 13,} -1
MOV.I # 37,} -1
DJN.X { 14,< 63
END
Testing 057_36.red...
Anefam Vesyes 123.94 54 14 ************
Another MEVO Thing 136.61 62 8 *************
b69e6908-a5be0bba-ab4445 132.39 54 26 *************
Clone 147.88 63 21 **************
Cold Plasma 128.16 39 65 ************
Combat Arithmetic 157.04 71 10 ***************
Creamed Corn 163.38 73 13 ****************
Crimson Climber 135.21 56 24 *************
Crisis 156.33 63 33 ***************
[RS] C-Strobia 165.49 72 19 ****************
eerie glow 123.23 33 76 ************
Free the Fish! 133.09 39 72 *************
Hot Soup 146.47 62 22 **************
Just a MEVO Thing 161.26 72 13 ****************
Little Bang 141.54 61 18 **************
Little Red Rat 150.70 66 16 ***************
7_3 180.28 83 7 ******************
NanoCracker 156.33 69 15 ***************
02_08 189.43 84 17 ******************
[RS] Nextratulated Sturv 125.35 51 25 ************
Nonlocality 2 116.90 32 70 ***********
Nonlocality 118.30 36 60 ***********
Quantum Foam 166.19 75 11 ****************
Reflow Oven 162.67 74 9 ****************
Sleepy Lepus 145.77 47 66 **************
Steaming Pebbles 172.53 73 26 *****************
SWT2-21 171.12 69 36 *****************
SWT2-28 130.98 53 27 *************
Transfer Function 141.54 56 33 **************
Unholy Fire 138.02 45 61 *************
Score = 147.27
Testing 057_36.red...
8c09fc1a-4799259f-174724 129.57 57 13 ************
rdrc: Alcoholism Malt 138.73 61 14 *************
b1f3ad11-a6073e-f711ff69 154.22 66 21 ***************
Bacillus anthracis 180.28 79 19 ******************
Black Sun III 145.77 59 30 **************
rdrc: Breakaway Carte 142.25 49 55 **************
c82f15b5-85011fd8-5a969d 196.47 85 24 *******************
Clear-2 185.91 81 21 ******************
Cosmic Horror 151.40 51 62 ***************
Different Day 219.01 99 14 *********************
written in a dream 125.35 31 85 ************
early morning view 224.64 106 1 **********************
Escherichia coli 178.87 82 8 *****************
e6843-5724-xt430-4-nano- 108.45 17 103 **********
Foggy Maus (beta) 166.90 74 15 ****************
girl from the underworld 88.732 39 9 ********
human resistance 167.60 67 37 ****************
the kraken awakes 114.78 35 58 ***********
Leishmania deanei 195.07 85 22 *******************
looking glass 154.92 71 7 ***************
lord of the digital swam 83.098 16 70 ********
Man&Machine 123.23 48 31 ************
Military Grade Nano 141.54 62 15 **************
New Vera City 149.29 56 44 **************
Obsidian peasoup 207.04 95 9 ********************
Plasmodium vivax 170.42 75 17 *****************
qEvo[[3]] 150 57 42 **************
realm of the fire flower 106.33 13 112 **********
Red Moon 171.83 71 31 *****************
rdrc: Repent Linemen 131.69 57 16 *************
Rocket propelled monkey 121.12 56 4 ************
rumpelstiltskin 109.85 12 120 **********
Salmonella enterica 176.76 82 5 *****************
Science Abuse 124.64 47 36 ************
scythe 121.83 27 92 ************
rdrc: Snapback Sprite 166.19 76 8 ****************
spawn of the dark core 154.92 48 76 ***************
Staphylococcus aureus 165.49 66 37 ****************
Stegodon Aurorae 142.95 56 35 **************
rdrc: Strychnine Banshee 130.98 47 45 *************
Subterranean Homesick Al 129.57 38 70 ************
tinderbox 121.12 27 91 ************
toy soldier 133.09 53 30 *************
Trypanosoma brucei 137.32 38 81 *************
victim of the night 89.436 35 22 ********
war of the snowflakes 121.83 28 89 ************
wisdom of the grasshoppe 139.43 60 18 *************
wreath of thistles 169.01 80 0 ****************
written in the dust 75.352 32 11 *******
Xinyl 72.535 16 55 *******
Score = 144.14
--------------------------------------------------
;redcode-nano
;name 022_19.red
;author yabevolver
;strategy evolved
;origin 114_15
;species 28964
;generation 1913
;created 02-05-2023 13-21-47
;assert CORESIZE==80
ORG 0
SPL.I # 22,> 13
SPL.I # 48,} 0
MOV.I } 3,} -1
MOV.I # 32,} -1
MOV.I } 39,} -4
END
Testing 022_19.red...
Anefam Vesyes 171.83 78 10 *****************
Another MEVO Thing 171.12 78 9 *****************
b69e6908-a5be0bba-ab4445 164.78 69 27 ****************
Clone 167.60 71 25 ****************
Cold Plasma 107.04 28 68 **********
Combat Arithmetic 210.56 93 20 *********************
Creamed Corn 180.28 81 13 ******************
Crimson Climber 147.88 66 12 **************
Crisis 136.61 63 5 *************
[RS] C-Strobia 159.15 68 22 ***************
eerie glow 117.60 37 56 ***********
Free the Fish! 145.77 49 60 **************
Hot Soup 146.47 61 25 **************
Just a MEVO Thing 157.74 73 5 ***************
Little Bang 165.49 76 7 ****************
Little Red Rat 158.45 72 9 ***************
7_3 173.94 78 13 *****************
NanoCracker 133.09 60 9 *************
02_08 198.59 88 18 *******************
[RS] Nextratulated Sturv 128.87 57 12 ************
Nonlocality 2 122.53 40 54 ************
Nonlocality 106.33 34 49 **********
Quantum Foam 135.21 60 12 *************
Reflow Oven 165.49 72 19 ****************
Sleepy Lepus 148.59 48 67 **************
Steaming Pebbles 178.87 81 11 *****************
SWT2-21 207.04 94 12 ********************
SWT2-28 177.46 81 9 *****************
Transfer Function 171.12 74 21 *****************
Unholy Fire 103.52 37 36 **********
Score = 155.30
Testing 022_19.red...
8c09fc1a-4799259f-174724 134.50 62 5 *************
rdrc: Alcoholism Malt 164.78 77 3 ****************
b1f3ad11-a6073e-f711ff69 140.84 62 14 **************
Bacillus anthracis 137.32 62 9 *************
Black Sun III 164.78 71 21 ****************
rdrc: Breakaway Carte 72.535 14 61 *******
c82f15b5-85011fd8-5a969d 161.26 72 13 ****************
Clear-2 185.91 85 9 ******************
Cosmic Horror 116.90 35 61 ***********
Different Day 155.63 71 8 ***************
written in a dream 114.78 30 73 ***********
early morning view 114.08 54 0 ***********
Escherichia coli 132.39 58 14 *************
e6843-5724-xt430-4-nano- 114.78 24 91 ***********
Foggy Maus (beta) 173.94 79 10 *****************
girl from the underworld 113.38 50 11 ***********
human resistance 147.18 63 20 **************
the kraken awakes 94.366 24 62 *********
Leishmania deanei 180.28 77 25 ******************
looking glass 130.28 57 14 *************
lord of the digital swam 98.591 29 53 *********
Man&Machine 123.94 52 20 ************
Military Grade Nano 154.22 70 9 ***************
New Vera City 161.26 68 25 ****************
Obsidian peasoup 204.22 95 5 ********************
Plasmodium vivax 160.56 73 9 ****************
qEvo[[3]] 170.42 68 38 *****************
realm of the fire flower 116.19 21 102 ***********
Red Moon 160.56 72 12 ****************
rdrc: Repent Linemen 118.30 52 12 ***********
Rocket propelled monkey 127.46 58 7 ************
rumpelstiltskin 100.70 13 104 **********
Salmonella enterica 126.05 56 11 ************
Science Abuse 121.12 50 22 ************
scythe 116.19 24 93 ***********
rdrc: Snapback Sprite 178.16 83 4 *****************
spawn of the dark core 100.70 29 56 **********
Staphylococcus aureus 164.08 67 32 ****************
Stegodon Aurorae 174.64 75 23 *****************
rdrc: Strychnine Banshee 104.22 32 52 **********
Subterranean Homesick Al 108.45 27 73 **********
tinderbox 129.57 34 82 ************
toy soldier 141.54 64 9 **************
Trypanosoma brucei 106.33 21 88 **********
victim of the night 128.87 60 3 ************
war of the snowflakes 107.04 17 101 **********
wisdom of the grasshoppe 119.71 52 14 ***********
wreath of thistles 118.30 56 0 ***********
written in the dust 156.33 72 6 ***************
Xinyl 97.183 31 45 *********
Score = 134.90
--------------------------------------------------
;redcode-nano
;name 086_35.red
;author yabevolver
;strategy evolved
;origin 012_23
;species 7434
;generation 4101
;created 02-05-2023 13-22-06
;assert CORESIZE==80
ORG 0
SPL.A # 41,< 63
MOV.I } 75,{ 0
MOV.I > 48,{ -2
MOV.I { -3,< 60
JMP.I $ -2,} 22
END
Testing 086_35.red...
Anefam Vesyes 140.84 65 5 **************
Another MEVO Thing 136.61 64 2 *************
b69e6908-a5be0bba-ab4445 141.54 65 6 **************
Clone 157.04 72 7 ***************
Cold Plasma 144.36 65 10 **************
Combat Arithmetic 145.77 66 9 **************
Creamed Corn 157.74 72 8 ***************
Crimson Climber 133.80 62 4 *************
Crisis 156.33 73 3 ***************
[RS] C-Strobia 152.81 69 10 ***************
eerie glow 91.549 40 10 *********
Free the Fish! 126.76 53 21 ************
Hot Soup 142.95 65 8 **************
Just a MEVO Thing 155.63 72 5 ***************
Little Bang 134.50 63 2 *************
Little Red Rat 147.88 70 0 **************
7_3 149.29 69 5 **************
NanoCracker 131.69 60 7 *************
02_08 130.98 58 12 *************
[RS] Nextratulated Sturv 135.21 62 6 *************
Nonlocality 2 135.21 58 18 *************
Nonlocality 114.78 45 28 ***********
Quantum Foam 152.81 71 4 ***************
Reflow Oven 147.18 69 2 **************
Sleepy Lepus 120.42 52 15 ************
Steaming Pebbles 149.29 68 8 **************
SWT2-21 154.22 69 12 ***************
SWT2-28 145.07 65 11 **************
Transfer Function 128.87 58 9 ************
Unholy Fire 115.49 50 14 ***********
Score = 139.22
Testing 086_35.red...
8c09fc1a-4799259f-174724 167.60 79 1 ****************
rdrc: Alcoholism Malt 137.32 63 6 *************
b1f3ad11-a6073e-f711ff69 186.61 87 4 ******************
Bacillus anthracis 157.04 71 10 ***************
Black Sun III 157.74 71 11 ***************
rdrc: Breakaway Carte 127.46 47 40 ************
c82f15b5-85011fd8-5a969d 158.45 73 6 ***************
Clear-2 144.36 66 7 **************
Cosmic Horror 123.94 51 23 ************
Different Day 146.47 69 1 **************
written in a dream 145.77 61 24 **************
early morning view 105.63 50 0 **********
Escherichia coli 147.18 69 2 **************
e6843-5724-xt430-4-nano- 163.38 74 10 ****************
Foggy Maus (beta) 140.84 66 2 **************
girl from the underworld 140.84 63 11 **************
human resistance 171.83 76 16 *****************
the kraken awakes 163.38 61 49 ****************
Leishmania deanei 152.81 69 10 ***************
looking glass 167.60 78 4 ****************
lord of the digital swam 115.49 47 23 ***********
Man&Machine 139.43 64 6 *************
Military Grade Nano 163.38 75 7 ****************
New Vera City 121.83 55 8 ************
Obsidian peasoup 143.66 63 15 **************
Plasmodium vivax 184.50 86 4 ******************
qEvo[[3]] 166.90 75 12 ****************
realm of the fire flower 102.81 37 35 **********
Red Moon 152.11 72 0 ***************
rdrc: Repent Linemen 149.29 70 2 **************
Rocket propelled monkey 139.43 63 9 *************
rumpelstiltskin 104.22 40 28 **********
Salmonella enterica 155.63 72 5 ***************
Science Abuse 166.19 77 5 ****************
scythe 117.60 47 26 ***********
rdrc: Snapback Sprite 158.45 74 3 ***************
spawn of the dark core 155.63 63 32 ***************
Staphylococcus aureus 154.92 69 13 ***************
Stegodon Aurorae 181.69 80 18 ******************
rdrc: Strychnine Banshee 168.30 76 11 ****************
Subterranean Homesick Al 130.98 49 39 *************
tinderbox 150 59 36 **************
toy soldier 164.78 74 12 ****************
Trypanosoma brucei 137.32 48 51 *************
victim of the night 164.78 76 6 ****************
war of the snowflakes 117.60 43 38 ***********
wisdom of the grasshoppe 192.95 88 10 *******************
wreath of thistles 148.59 70 1 **************
written in the dust 194.36 89 9 *******************
Xinyl 111.97 47 18 ***********
Score = 149.22
--------------------------------------------------
;redcode-nano
;name 067_14.red
;author yabevolver
;strategy evolved
;origin 114_15
;species 782
;generation 1969
;created 02-05-2023 13-21-45
;assert CORESIZE==80
ORG 0
SPL.BA # 34,} 36
SPL.F # 24,} 0
MOV.I } 13,} -1
MOV.I # 54,} 79
SPL.I { 14,> 61
END
Testing 067_14.red...
Anefam Vesyes 183.09 83 11 ******************
Another MEVO Thing 165.49 76 7 ****************
b69e6908-a5be0bba-ab4445 96.478 38 23 *********
Clone 108.45 44 22 **********
Cold Plasma 111.97 25 84 ***********
Combat Arithmetic 172.53 81 2 *****************
Creamed Corn 180.28 82 10 ******************
Crimson Climber 108.45 45 19 **********
Crisis 155.63 71 8 ***************
[RS] C-Strobia 124.64 54 15 ************
eerie glow 120.42 40 51 ************
Free the Fish! 129.57 43 55 ************
Hot Soup 147.88 61 27 **************
Just a MEVO Thing 154.22 72 3 ***************
Little Bang 149.29 68 8 **************
Little Red Rat 150.70 66 16 ***************
7_3 141.54 65 6 **************
NanoCracker 132.39 57 17 *************
02_08 183.09 83 11 ******************
[RS] Nextratulated Sturv 138.73 57 26 *************
Nonlocality 2 128.16 43 53 ************
Nonlocality 144.36 54 43 **************
Quantum Foam 166.19 73 17 ****************
Reflow Oven 128.87 57 12 ************
Sleepy Lepus 135.91 41 70 *************
Steaming Pebbles 169.01 77 9 ****************
SWT2-21 159.85 72 11 ***************
SWT2-28 169.01 75 15 ****************
Transfer Function 149.29 59 35 **************
Unholy Fire 142.95 53 44 **************
Score = 144.95
Testing 067_14.red...
8c09fc1a-4799259f-174724 119.71 53 11 ***********
rdrc: Alcoholism Malt 126.05 55 14 ************
b1f3ad11-a6073e-f711ff69 119.71 51 17 ***********
Bacillus anthracis 152.11 67 15 ***************
Black Sun III 160.56 71 15 ****************
rdrc: Breakaway Carte 123.94 33 77 ************
c82f15b5-85011fd8-5a969d 158.45 72 9 ***************
Clear-2 171.12 75 18 *****************
Cosmic Horror 129.57 44 52 ************
Different Day 186.61 82 19 ******************
written in a dream 127.46 27 100 ************
early morning view 216.90 101 5 *********************
Escherichia coli 157.04 71 10 ***************
e6843-5724-xt430-4-nano- 125.35 30 88 ************
Foggy Maus (beta) 152.11 68 12 ***************
girl from the underworld 76.056 30 18 *******
human resistance 135.91 56 25 *************
the kraken awakes 88.732 20 66 ********
Leishmania deanei 161.97 72 14 ****************
looking glass 115.49 52 8 ***********
lord of the digital swam 90.140 17 77 *********
Man&Machine 185.91 81 21 ******************
Military Grade Nano 121.83 50 23 ************
New Vera City 145.07 52 50 **************
Obsidian peasoup 190.84 88 7 *******************
Plasmodium vivax 157.04 71 10 ***************
qEvo[[3]] 142.95 57 32 **************
realm of the fire flower 113.38 17 110 ***********
Red Moon 163.38 72 16 ****************
rdrc: Repent Linemen 145.07 64 14 **************
Rocket propelled monkey 126.76 59 3 ************
rumpelstiltskin 119.01 22 103 ***********
Salmonella enterica 175.35 78 15 *****************
Science Abuse 187.32 82 20 ******************
scythe 114.78 22 97 ***********
rdrc: Snapback Sprite 199.29 91 10 *******************
spawn of the dark core 145.07 42 80 **************
Staphylococcus aureus 148.59 61 28 **************
Stegodon Aurorae 148.59 61 28 **************
rdrc: Strychnine Banshee 133.80 48 46 *************
Subterranean Homesick Al 109.15 22 89 **********
tinderbox 108.45 20 94 **********
toy soldier 155.63 69 14 ***************
Trypanosoma brucei 109.15 23 86 **********
victim of the night 119.71 53 11 ***********
war of the snowflakes 111.26 19 101 ***********
wisdom of the grasshoppe 112.67 46 22 ***********
wreath of thistles 185.91 88 0 ******************
written in the dust 129.57 57 13 ************
Xinyl 75.352 14 65 *******
Score = 139.52
I didn't save the exact settings at the moment I fished these
warriors out of the soup but did save it later in the run, it
should be pretty close to this...
REM --- yabevolver ini file ------------------------------------------------
REM copy this section to a file and specify filename on command line to load
header$ = ";redcode-nano" rem first line of program (start with ;)
author$ = ";author yabevolver" rem author line (start with ;)
comment$ = ";strategy evolved" rem comment line (start with ;)
tempdir$ = "/dev/shm/yabevolbig" rem temp directory for battling warriors
soupdir$ = "bigsoup" rem where soup warriors are stored
benchdir$ = "nano2301" rem benchmark dir for testing warriors
topdir$ = "bigtop" rem where top-scoring warriors are saved
xdim = 118 rem soup x dimension
ydim = 37 rem soup y dimension
xwrap = 0 rem enable wraparound in x dimension
ywrap = 0 rem enable wraparound in y dimension
length = 5 rem max warrior length
mincrelen = 5 rem minimum warrior length at creation
coresize = 80 rem core size
processes = 80 rem max processes
cycles = 800 rem instruction cycles per match
rounds = 100 rem matches per battle
instrate = 0.007 rem chance of changing an instruction
modrate = 0.015 rem chance of changing a modifier
addrrate = 0.015 rem chance of changing an address mode
numrate = 0.03 rem chance of changing a number
adjrate = 0.4 rem if number changed, chance of increment or decrement
localrate = 0.5 rem if new number, chance of being within warrior
reprate = 0.002 rem chance of replacing with new random line
insrate = 0.002 rem chance of inserting a new line (pushing rest down)
duprate = 0.002 rem chance of duplicating previous or following line
swaprate = 0.002 rem chance of swapping two lines (only 1 chance per evo)
delrate = 0.002 rem chance of deleting a line (pulling rest up)
orgrate = 0.0 rem chance of a random ORG line (ORG starts at 0)
org0rate = 0.5 rem if ORG changed, chance of ORG 0
crossrate = 0.05 rem crossover rate
evopseq = 0 rem evolving pmars sequence 0=random 1=fixed 2=permutate
evalmode = 3 rem 0=unguided 1=rnd bench 2=all 3=rnd 0/1 4=rnd 0/1/2
evalrate = 0.3 rem for evalmode 4 and 5, chance of using bench warriors
evalgen = 50 rem apply evalmode after both reach this many generations
ssfreq = 1000000 rem automatic soup save interval, 0 to disable
superror = 1 rem if not 0 redirect pmars stderr to dev/null
benchfreq = 1000 rem warrior benchmark interval (0 to disable)
savethr = 140 rem only save if score is >= this
savepc = 4 rem save if within this percentage of top score
bmrounds = 142 rem number of rounds when benchmarking
benchpseq = 2 rem benchmark pmars sequence 0=random 1=fixed 2=permutate
reinsfreq = 25100 rem warrior reinsertion interval (0 to disable)
REM instructions, modifiers and address modes...
REM instruction$ length must be divisible by 4 (start with space)
REM modifiers$ length must be divisible by 3
REM bias encoded using duplicates
REM addr1mode$ and addr2mode$ separated as they have different mixes
instructions$ = " MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV SPL SPL"
instructions$ = instructions$+" SPL SPL SPL SPL DJN DJN DJN DJN DJN"
instructions$ = instructions$+" ADD SUB MOD MUL DIV JMP JMZ JMN SEQ SNE"
modifiers$ = ".I .I .I .I .I .I .I .I .B .B .B .B .F .F .F .X .A .AB.BA"
addr1modes$ = "######$$$$$>>>><<<{{}}*@"
addr2modes$ = "<<<<<<{{{{{>>>>$$$$}}}@#"
initialinstr$ = " SPL MOV MOV MOV DJN" rem initial warrior instructions
enablepreseed = 0 rem if not zero use initialinstr$ to pre-seed the soup
REM binaries and options
unibox = 1 rem enable unicode chars for box surrounding soup display
lister$ = "less" rem [path/]name of file lister program
listeropts$ = "-~" rem lister opts for warriors.. no ~ at end
listeroptsb$ = "-~ +G" rem lister opts for benchmarks.. no ~, go to eof
pmars$ = "pmars" rem [path/]name of pmars binary
pmarsv$ = "pmarsv" rem [path/]name of pmarsv binary
pmarsvopts$ = "-v 564" rem pmarsv options (-v digits speed dispmode detail)
rem pmarsv$ = "./bigpmarsv.sh" rem for my pmarsv magnifying script
pmarsv$ = "pmarsvsdl" rem for the SDL version of pmarsv
pmarsvopts$ = "-v 784" rem opts for my speed-patched SDL version
pmarsvrounds = 10 rem rounds to run in pmarsv
REM --- end yabevolver ini file --------------------------------------------
The program can be run directly, but usually I use copies of this
script that launches the program in a xterm window sized large
enough to accommodate the soup display to minimize fiddling with
xterm parameters...
#!/bin/bash PATH=bin64:$PATH # add bin64 dir to PATH inifile="bigsoup.ini" # name of ini file (no spaces) xtopts="-bg black -fg green" # xterm options title="YabEvolver (bigsoup)" # xterm window title if [ -f "$inifile" ];then # if ini file exists... # use awk to get xdim ydim from ini file.. long live awk! xdim=$(grep "^xdim " "$inifile"|awk '{print $3}') ydim=$(grep "^ydim " "$inifile"|awk '{print $3}') gx=$(($xdim+2));gy=$(($ydim+3)) # terminal must be at least xdim+2 by ydim+3 if [ "$gx" -lt 80 ];then gx=80;fi # minimum 80 chars wide if [ "$gy" -lt 24 ];then gy=24;fi # minimum 24 rows else gx=80;gy=24 # default terminal size fi if [ -t 1 -a "$gx$gy" = "8024" ];then # if can run in existing terminal yabasic yabevolver.yab $inifile # just run the evolver else # otherwise launch the evolver in xterm sized appropriately xterm -geometry $gx"x"$gy $xtopts -title "$title" \ -e yabasic yabevolver.yab $inifile & sleep 1 # this is needed if "run in terminal" selected fi |
The bin64 directory it adds to the path is where
I put my pmars/pmarsv/pmarsvsdl binaries. The script uses grep
and awk to read the xdim and ydim settings from the INI file, if
not present assumes an 80x24 terminal. Because it uses
awk's field print, the "=" must be surrounded by spaces.
Here's the "bigpmarsv.sh" script I made to
magnify the original pmarsv window so I could see what was going
on...
#!/bin/bash # magnify the pmarsv window - too tiny! # requires xzoom and xdotool # call this script instead of pmarsv, chains to # pmarsv with parms after launching xzoom if [ "$1" = "bk" ];then xzoomx=800 # move xzoom window here xzoomy=600 # after launching sleep 0.2 # enough time to launch pmarsv pmvw=$(xdotool search --name "pMARS 9") # get pmarsv window id if [ "$pmvw" = "" ];then exit;fi # not found, exit # get info about the pmarsv window windata=$(xdotool getwindowgeometry --shell "$pmvw") if [ ! $? -eq 0 ];then exit;fi # exit if error for d in $windata;do eval $d;done # "run" $windata to set vars X1=$(($X-10));Y1=$(($Y-46)) # this might be system dependent # launch the xzoom tool telling it where to grab from xzoom -source "$WIDTH"x"$HEIGHT"+"$X1"+"$Y1" & sleep 0.2 # wait for it to open xzw=$(xdotool search --name "xzoom") # get xzoom window id xdotool windowmove "$xzw" $xzoomx $xzoomy # tell it where to go xdotool windowfocus "$xzw" # focus it (probably already) xdotool key --delay 30 d d d # send it d keys to decrease delay xdotool windowfocus "$pmvw" # refocus pmarsv window # wait for pmarsv window to close while [ 1 = 1 ];do sleep 0.2 pmvw=$(xdotool search --name "pMARS 9") # get pmarsv window id if [ "$pmvw" = "" ];then # window closed killall "xzoom" # kill the xzoom process exit fi done else "$0" "bk" 2>/dev/null & # run self in background (suppress errors) pmarsv "$@" # run the pmars command line in forground fi |
I don't use the magnifying script that much now that I figured
out how to slow down the SDL version of pmarsv - computers are
very different now than they were when pmars/pmarsv was written,
back then 800x600 monitors were common and processors were usually
a few hundred (or dozen) MHz. But the old code still compiles.
They're trying to depreciate SDL 1.2, at first I thought it was
removed and replaced with a compat thing that didn't work but then
I found the libsdl1.2debian package which works fine on Ubuntu
22.04 in a VM, my main system is Ubuntu 20.04 with a GUI hacked
from bits of Gnome and MATE.
Dev Notes
2/11/23 - It's been about a day and a half since I had to make
any changes the program code, so yay.. but noticed a gruesome bug
in this page - had the wrong INI posted for the big soup.. oops.
When I started this program I was really just testing out YaBasic
to see what I could make it do, but then got the evolving bug
again and ended up adding way more things to it than I had planned
- originally the program had no user interface at all, it just
evolved until stopped, now it includes most of the stuff I do when
evolving warriors. If some things seem like they were bolted on
it's because they were.. and most of the code updates involved the
various interface things and not the actual evolving code.
Now that the interface is doing approximately what I want I can
focus more on the actual evolving code. I'm not particularly happy
with how I implemented line swap - it swaps lines in the parent
warrior before evolving. Probably should fix that so that it only
swaps lines in the offspring. Also I don't think the adjust local
references option is working correctly. Funny thing about corewar
evolvers is fixing these things would likely make little to no
difference or might even make it worse - the defective swap could
be viewed as a culling operation that might help to increase
diversity - winning is not always winning - and incorrect or not I
haven't noticed much difference whether references are adjusted or
not, at least with nano warriors, as inserts and deletes tend to
kill mature warriors anyway. Inserts and deletes are mainly only
useful at the start of evolution while the warriors are weak, but
occasionally it might get lucky and result in a viable warrior.
Usually one warrior form will completely take over the soup but I
have noticed with this evolver it tends to take longer for that to
happen and sometimes multiple forms can coexist for quite a while.
This "huge" soup of 8000 warriors has been evolving for over 24
hours and around 1500 generations but there are still several
forms present...
Total of 8000 warriors, average score = 120.0
Found 123 unique instruction sequences...
5804 best 148.1 by 032_42 "M" MOV SPL MOV MOV DJN
1203 best 127.3 by 093_28 "F" SPL MOV MOV SPL MOV
451 best 133.4 by 073_45 "p" SPL MOV MOV MOV MOV
31 best 109.5 by 131_20 "Z" SPL MOV MOV DJN MOV
31 best 106.9 by 120_24 "G" SPL MOV SPL MOV
26 best 93.75 by 030_48 "i" MOV SPL MOV DJN
26 best 129.8 by 002_25 "q" SPL SPL MOV MOV DJN
26 best 122.9 by 102_47 "b" SPL MOV SPL MOV MOV
22 best 124.9 by 159_43 "N" MOV SPL MOV MOV SPL
18 best 126.8 by 016_47 "T" MOV SPL MOV MOV MOV
18 best 102.1 by 057_32 "d" SPL MOV MOV SEQ MOV
17 best 139.5 by 043_38 "u" MUL SPL MOV MOV DJN
16 best 132.7 by 076_02 "c" ADD SPL MOV MOV DJN
...snip...
;redcode-nano
;name 032_42.red
;author yabevolver
;strategy evolved
;origin 027_14
;species 20045
;generation 1597
;created 02-11-2023 13-05-51
;assert CORESIZE==80
ORG 0
MOV.I > 50,$ 15
SPL.AB # 73,> 20
MOV.I { -2,{ -1
MOV.I { -2,{ -3
DJN.F $ 78,{ -4
END
It's not particularly strong on benchmarks but scores over 142 on
all my test sets, sometimes when evolving against a particular
test set the warriors will learn how to beat those warriors but
perform poorly against warriors it has not encountered. I ran this
soup for a few hundred more generations, it maintained diversity
but didn't get any stronger.
Here's the INI file I used for this soup...
REM --- yabevolver ini file ------------------------------------------------
REM copy this section to a file and specify filename on command line to load
header$ = ";redcode-nano" rem first line of program (start with ;)
author$ = ";author yabevolver" rem author line (start with ;)
comment$ = ";strategy evolved" rem comment line (start with ;)
tempdir$ = "/dev/shm/yabevolhuge" rem temp directory for battling warriors
soupdir$ = "hugesoup" rem where soup warriors are stored
benchdir$ = "nano2301" rem benchmark dir for testing warriors
topdir$ = "hugetop" rem where top-scoring warriors are saved
xdim = 160 rem soup x dimension
ydim = 50 rem soup y dimension
xwrap = 0 rem enable wraparound in x dimension
ywrap = 0 rem enable wraparound in y dimension
length = 5 rem max warrior length
mincrelen = 1 rem minimum warrior length at creation
coresize = 80 rem core size
processes = 80 rem max processes
cycles = 800 rem instruction cycles per match
rounds = 100 rem matches per battle
instrate = 0.01 rem chance of changing an instruction
modrate = 0.02 rem chance of changing a modifier
addrrate = 0.03 rem chance of changing an address mode
numrate = 0.04 rem chance of changing a number
adjrate = 0.5 rem if number changed, chance of increment or decrement
localrate = 0.5 rem if new number, chance of being within warrior
reprate = 0.002 rem chance of replacing with new random line
insrate = 0.002 rem chance of inserting a new line (pushing rest down)
duprate = 0.002 rem chance of duplicating previous or following line
swaprate = 0.002 rem chance of swapping two lines (only 1 chance per evo)
delrate = 0.002 rem chance of deleting a line (pulling rest up)
orgrate = 0 rem chance of a random ORG line (ORG starts at 0)
org0rate = 0.5 rem if ORG changed, chance of ORG 0
crossrate = 0.01 rem crossover rate
adjlocref = 0 rem if not 0 adjust local refs when inserting and deleting
evopseq = 0 rem evolving pmars sequence 0=random 1=fixed 2=permutate
evalmode = 3 rem 0=unguided 1=rnd bench 2=all 3=rnd 0/1 4=rnd 0/1/2
evalrate = 0.2 rem for evalmode 4 and 5, chance of using bench warriors
evalgen = 100 rem apply evalmode after both reach this many generations
ssfreq = 1000000 rem automatic soup save interval, 0 to disable
superror = 0 rem if not 0 redirect pmars stderr to dev/null
benchfreq = 1000 rem warrior benchmark interval (0 to disable)
savethr = 140 rem only save if score is >= this
savepc = 3 rem save if within this percentage of top score
bmrounds = 142 rem number of rounds when benchmarking
benchpseq = 2 rem benchmark pmars sequence 0=random 1=fixed 2=permutate
reinsfreq = 0 rem warrior reinsertion interval (0 to disable)
REM instructions, modifiers and address modes...
REM instruction$ length must be divisible by 4 (start with space)
REM modifiers$ length must be divisible by 3
REM bias encoded using duplicates
REM addr1mode$ and addr2mode$ separated as they have different mixes
instructions$ = " MOV MOV MOV MOV MOV MOV MOV MOV SPL SPL"
instructions$ = instructions$+" SPL SPL SPL SPL DJN DJN DJN DJN DJN"
instructions$ = instructions$+" ADD SUB MOD MUL DIV JMP JMZ JMN SEQ SNE"
modifiers$ = ".I .I .I .I .I .I .I .I .B .B .B .B .F .F .F .X .A .AB.BA"
addr1modes$ = "######$$$$$>>>><<<{{}}*@"
addr2modes$ = "<<<<<<{{{{{>>>>$$$$}}}@#"
initialinstr$ = " SPL MOV MOV MOV DJN" rem initial warrior instructions
enablepreseed = 0 rem if not zero use initialinstr$ to pre-seed the soup
REM binaries and options
unibox = 1 rem enable unicode chars for box surrounding soup display
lister$ = "less" rem [path/]name of file lister program
listeropts$ = "-~" rem lister opts for warriors.. no ~ at end
listeroptsb$ = "-~ +G" rem lister opts for benchmarks.. no ~, go to eof
pmars$ = "pmars" rem [path/]name of pmars binary
pmarsv$ = "pmarsv" rem [path/]name of pmarsv binary
pmarsvopts$ = "-v 564" rem pmarsv options (-v digits speed dispmode detail)
rem pmarsv$ = "./bigpmarsv.sh" rem for my pmarsv magnifying script
pmarsv$ = "pmarsvsdl" rem for the SDL version of pmarsv
pmarsvopts$ = "-v 784" rem opts for my speed-patched SDL version
pmarsvrounds = 10 rem rounds to run in pmarsv
REM --- end yabevolver ini file --------------------------------------------
2/12/23 - fixed a bug in the part that redisplays the existing
benchmark report if it's still valid, while at it fixed the load
settings file option so that it doesn't terminate the program if a
bad INI file is loaded (it won't exit the filename prompt until a
valid settings file is loaded but that's better than crashing),
and trying something new - gradually reducing the mutation rates
as warriors mature. Been occasionally doing that manually but
added two settings, mutadjust and mutadjgen, to automate the
process. The mutadjust setting ranges from 0 to 1 and sets the
maximum amount to reduce the mutation rates, for example if
mutadjust is 0.5 then if instrate is 0.02 then the instruction
mutation rate will eventually be reduced to 0.01 but no lower. The
mutadjgen setting sets the warrior generation where full mutation
reduction takes place, after which there is no further reduction.
The code bit that perform the adjustment is...
rem derive mutation rate modifier rmod from gennum mutadjust and mutadjgen rem affects instrate modrate addrrate numrate reprate insrate duprate rem swaprate and orgrate by gradually reducing mutation as gen increases if mutadjgen<2 mutadjgen=1:mutadjust=0 rem disable if mutadjgen<2 rmod=1-(mutadjust*(gennum(x1,y1)/mutadjgen)) rem calculate multiplier if rmod<mutadjust rmod=mutadjust rem rmod between mutadjust and 1
...then the individual mutation rates are multiplied by rmul.
Fairly simple mod that shouldn't change anything else. Whether it
helps or not ???. By default mutadjust is set to 0 to disable for
compatibility with previous INI files. Tempted as it is, broken or
not, trying to leave the core evolving operations alone - changing
it would likely change the entire character of the evolver and I
like what it's doing, particularly maintaining diversity for much
longer than previous experiments. The warrior code it's producing
so far hasn't been super-strong against current hill nanos (does
better on older benchmarks) but it's more interesting.. doesn't
always end up only boring SPL MOV MOV MOV DJN warriors, other
forms have a chance and in larger soups can coexist with each
other for long durations.
I have ideas but when it comes down to it I don't have that much
of a clue what operations really make a difference in the output,
that's why I like playing this stuff and trying to figure it out -
I throw stuff at my wall and see what sticks. Fundamentally
though, mix together the combination of a system with a random
starting population, mutation, and a scoring function then
something is going to happen. I remember years ago there was some
fuss about Artificial
(simulated) Life, programs like Tierra
etc but two-dimensional redcode evolvers seem to meet at least
some of the definitions of AL - "executable DNA" (love that term),
a world in which creatures evolve, simple open-ended evaluation
(warriors either survive or they don't), and nearest-neighbor
interactions that mimick how real creatures interact (or at least
how they used to, transportation changed all that - sure enough if
I simulate that via reinsertion then almost inevitably one form
will dominate). One difference is the creatures it produces have
silly but actual real-world applications - they can compete on
hills with other warriors and take on a life of their own. Well
sort of...
2/13/23 - Ok just a bit more monkeying... one of the things that
bugged me a bit was often different instruction sequences would be
assigned duplicate characters when in viewmode 2 or 3. Partially
because my hashing formula isn't exactly great but mainly because
of the
birthday problem (aka birthday paradox) - when there are a
given number of choices it takes suprisingly few members with the
same choice. To fix added viewshift (and the existing viewmode) to
the settings (XOR's the instruction sequence hash with viewshift
before picking a soup view character), and added (hidden) shift-V
keystrokes to toggle between the viewshift from the settings and a
random integer. Saving a settings file will save the new viewshift
value. The viewmode/viewshift settings are also displayed in the
sequence report.
2/14/23 - Wow... this is cool, ANSI soup evolution "movies"!
Totally worth the 11K or so it added to the program size.
Described in the user interface docs section. Here's a script I
use to play back the ANSI files outside of the evolver program,
put this in the ANSI dump directory (requires xterm zenity and
ansi2txt from colorized-logs)...
#!/bin/bash # "play" ANSI dump files # requires ansi2txt and zenity if [ "$1" = "doit" ];then while [ 1 ];do # loop until ctrl-C or window closed clear;for f in $2*.ans;do echo -ne "\033[H";cat "$f";sleep 0.2 done done else bn=$(zenity --title "Play ANSI" --entry --text "Enter base name") if [ $? != 0 ];then exit;fi # exit if cancel clicked for f in $bn*.ans;do fn="$f";done;fi # get last fn if [ -f "$fn" ];then # if ANSI files exist columns=$(cat "$fn"|ansi2txt|wc -L) # get width lines=$(cat "$fn"|ansi2txt|wc -l) # get # lines lines=$((lines+1)) # bump lines, last line has no lf xterm -geometry $columns"x"$lines -e $0 doit "$bn" # play in xterm fi fi
...hmm, VIM convert messed up the color on the last fi, not a bug
for today. But a bug I might have to watch out for is the
difference between sh's echo and bash's echo - in the sh shell
'echo -ne' isn't recognized but it prints ANSI codes just fine
with just 'echo -n'. In bash you need 'echo -ne' to print ANSI
sequences. YaBasic uses sh so in YabEvolver used the 'echo -n'
version to print the home in between frames.
2/17/23 - The ANSI thing is addictive.. when sped up it really
looks like a colony of living organisms - various warrior forms
compete for territory and numbers then another form arises and
puts stress on the dominant form which either adapt or be
consumed. Despite being an extremely limited simulation of...
something. Core war is a convenient "critter" base because
(besides being old and cool) the language basically has no invalid
combinations, just various degrees of it does something and a
clear-cut evaluation scheme - fight two warriors in a simulated
core with 3 points per win and 1 point per tie. Pretty much the
same behavior can result when using any non-brittle creature
format with a simple way to evaluate fitness, and if done on a
grid similar to YabEvolver and other grid-based nearest-neighbor
evolvers with similar color/character schemes it would probably
look about the same when played back at high speed.
Here's the enhanced ANSI dump player bash script... (will update
as needed)
#!/bin/bash # 0_playansi.sh 230221 # play YabEvolver ANSI dump files # requires xterm ansi2txt zenity awk xtermopts="-bg black -fg green" function processkeys { [ "$key" = "q" ] && exit if [ "$key" = "f" ];then fd=$(echo $fd|awk '{if ($1>0.01) print $1*0.8;else print $1}') echo -ne "\033[0K (fd=$fd)" elif [ "$key" = "s" ];then fd=$(echo $fd|awk '{if ($1<2) print $1*1.2;else print $1}') echo -ne "\033[0K (fd=$fd)" elif [ "$key" = "n" ];then fd="0.2";echo -ne "\033[0K (fd=$fd)" elif [ "$key" = "l" ];then loop=$((1-loop));echo -ne "\033[0K" if [ $loop = 1 ];then echo -n " (loop on)";else echo -n " (loop off)";fi fi } helptxt=" Q-quit P-pause F-faster S-slower N-normal B-begining L-loop on/off " if [ "$1" = "doit" ];then echo;echo "$helptxt H-Show again ";read -sn 1 -t 2 fd=0.2;loop=1;clear echo -ne "\033[?25l" # hide cursor while [ 1 ];do # loop until stopped for f in $2*.ans;do echo -ne "\033[H";cat "$f" read -sn 1 -t $fd key if [ "$key" = "p" ];then echo -ne "\033[0K (press a key)" read -sn 1 key;echo -ne "\033[14D\033[0K" fi if [ "$key" = "h" ];then echo -ne "\033[1;4H$helptxt" read -sn 1 key fi processkeys [ "$key" = "b" ] && break done if [ $loop = 0 -a "$key" != "b" ];then echo -ne "\033[0K (press a key)" read -sn 1 key;echo -ne "\033[14D\033[0K" processkeys fi done else bn=$(zenity --title "Play ANSI" --entry \ --text "Enter base name (default all)")||exit for f in $bn*.ans;do fn="$f";done # get last fn if [ -f "$fn" ];then # if ANSI files exist columns=$(cat "$fn"|ansi2txt|wc -L) # get width lines=$(cat "$fn"|ansi2txt|wc -l) # get # lines lines=$((lines+1)) # bump lines, last line has no lf [ $columns -lt 79 ] && columns=79 # minimum 79 columns xterm $xtermopts -geometry $columns"x"$lines -e $0 doit "$bn" #play in xterm fi fi
This version uses keys to Pause Faster Slower Normal and Loop
on/off - default is loop on, press L to toggle to pause after the
last frame. Uses awk for faster/slower to do floating point math -
each press of F multiplies the frame delay by 0.8 (min 0.1) and
each press of F multiplies the delay by 1.2 (max 2). N resets the
delay to the default, edit fd=0.2 for the default speed.
Similar techniques have been added to YabEvolver's ANSI play
system command, also requiring awk (on my system awk points to
gawk but there are other versions that should work the same). The
ANSI player is implemented using sh and cat because that's faster
and easier than trying to write the same thing in basic.. hard to
beat cat for display speed. The ANSI soup dumps now use unicode
box characters if the unibox setting is enabled, was using only
ascii chars for compatibility but the crude box bugged me and if I
need ascii-only I can just useuni=0. The soup display code has
been restructured to make showsoup() faster when exiting listers,
the other menu etc.. was pretty fast but was calling unnecessary
positioning code, separated the actual warrior print from
plotwarrior to just print without positioning first. Less code,
noticibly faster with large soup displays (been evolving 160x50
"huge" soups), and now rather than duplicating the display code,
the ANSI dump code can just call the position-free warrior print
with a parm to tell it to write to a file instead of the screen.
Much better.
2/20/23 - Playing back ANSI snapshots is neat, but making self
contained animated GIFs and MP4s is a bit more convenient than a
bash script and hundreds of ANSI files. Before adding ANSI dumps
to make an animated GIF I used a crude script that periodically
ran the xwd utility to make a bunch of screen snapshots then used
convert to turn them into an animated GIF. This process rendered
the computer unusable for the duration of the run as covering up
the window would spoil the snapshots. ANSI dumps make the process
a lot more usable, the script can just play back the ANSI frames
to make each GIF, still have to avoid covering the window but it
only ties up the computer for a couple minutes. Making GIFs longer
than a few hundred frames failed with out of memory warnings, had
to edit a file in /etc to fix that, see the comments. Once the
animated gif was made, turning it into a MP4 video was fairly easy
with ffmpeg (at least after a bit of googling).
Here's the script... (will update as needed)
#!/bin/bash # mkansigif.sh 230220 # This script makes an animated GIF from a set of YabEvolver ANSI dumps # Requires xterm zenity ansi2txt (from colorized-logs) awk xdotool convert # (from imagemagick). Optionally uses ffmpeg to convert the GIF to a mp4 video # Note - on my Ubuntu 20.04 system convert would fail after a few hundred # frames, to fix I had to edit /etc/ImageMagick-6/policy.xml and change # <policy domain="resource" name="memory" value="256MiB"/> value to "8GiB" xtermopts="-bg black -fg green" # xterm options tempdirprefix="/dev/shm" # path to put tempdir in, "." to put under current if [ "$1" = "doit" ];then shift;bname=$1;oname=$2;tempdir=$3;title=$4; fdelay=$5;fskip=$6;makemp4=$7;quality=$8;scale=$9 wid=$(xdotool search "$title") # get window ID (getactive window fails) mkdir -p $tempdir # make temp dir >/dev/null 2>&1 rm $tempdir/*.gif # make sure there are no GIFs in tempdir [ "$wid" = "" -o "$wid" = "0" ] && exit # bail if ID command failed fcnt=$fskip # frame counter for frame skip (output 1st frame then skip) clear;echo -ne "\033[?25l" # hide cursor for f in $bname*.ans;do echo -ne "\033[H";cat $f # show frame if [ $fcnt -ge $fskip ];then # time to dump xwd -id $wid -out "$tempdir/$(basename $f).xwd" # dump frame to xwd file convert $tempdir/$(basename $f).xwd $tempdir/$(basename $f).gif rm $tempdir/$(basename $f).xwd # convert/remove each to minimize disk/ram fcnt=0 # reset frame counter else fcnt=$((fcnt+1)) # not time yet, increment frame counter fi done echo -ne "\033[?25h\033[79D\033[0K Converting... " #show cursor, clear line convert -delay $fdelay -loop 0 $tempdir/*.gif $oname rm $tempdir/*.gif rm -d $tempdir if [ "$makemp4" = "1" ];then framerate=$(echo $fdelay|awk '{print 100/$1}') # calculate framerate mp4name="${oname%.*}.mp4" # replace .gif extension with .mp4 echo;echo Running: ffmpeg -r $framerate -f gif -i $oname -f mp4 \ -crf $quality -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" "$mp4name" ffmpeg -r $framerate -f gif -i $oname -f mp4 -pix_fmt yuv420p \ -crf $quality -vf "scale=trunc(iw/2)*$scale:trunc(ih/2)*$scale" \ "$mp4name" || read -n 1 fi else timestr=$(date +%H%M%S) # get 6-digit string with current time tempdir="$tempdirprefix/mkansitmp$timestr" # temp directory - no spaces title="MkANSIgif $timestr" # for identifying window to dump, must be unique bname=$(zenity --width 300 --title "Make ANSI GIF" --entry \ --text "ANSI path/basename (default all)")||exit echo "$bname"|grep " " && exit # no spaces allowed >/dev/null 2>&1 ls $bname*.ans || exit # exit if .ans files not found oname=$(zenity --width 300 --title "Make ANSI GIF" --entry \ --text "Output GIF path/name")||exit echo "$oname"|grep " " && exit echo "$oname"|grep ".gif$" || oname="$oname.gif" # add .gif if not present fdelay=$(zenity --width 300 --title "Make ANSI GIF" --entry \ --text "Frame delay (x10ms, def 10)")||exit [ "$fdelay" = "" ] && fdelay=10 fdelay=$((fdelay+0)) fskip=$(zenity --width 300 --title "Make ANSI GIF" --entry \ --text "Frame skip (def 0)")||exit [ "$fskip" = "" ] && fskip=0 fskip=$((fskip+0)) makemp4=0;zenity --width 200 --title "Make ANSI GIF" --question \ --text "Make MP4 video too?" && makemp4=1 quality="";scale=2 if [ $makemp4 = 1 ];then quality=$(zenity --width 350 --title "Make ANSI GIF" --entry \ --text "Video quality 0-63 (0=best, none for 25)") || exit sel=$(zenity --width 250 --height 250 --title "Make ANSI GIF" \ --column "" --hide-header --text "Select video scaling..." \ --list "Actual size" "Upscale 1.5X" "Upscale 2.0X" "Upscale 3.0X") || exit [ "$sel" = "Upscale 1.5X" ] && scale=3 [ "$sel" = "Upscale 2.0X" ] && scale=4 [ "$sel" = "Upscale 3.0X" ] && scale=6 fi [ "$quality" = "" ] && quality=25 quality=$((quality+0)) [ $quality -lt 0 -o $quality -gt 63 ] && exit for f in $bname*.ans;do fn="$f";done # get last fn columns=$(cat "$fn"|ansi2txt|wc -L) # get width lines=$(cat "$fn"|ansi2txt|wc -l) # get # lines lines=$((lines+1)) # bump lines, last line has no lf xterm $xtermopts -title "$title" -geometry $columns"x"$lines -e $0 doit \ "$bname" "$oname" $tempdir "$title" $fdelay $fskip $makemp4 $quality $scale fi
It's a little crazy but seems to be working fairly well now. The
upscale option is useful for magifying smaller soups but added
mainly because anything less than 480p tends to look fuzzy on
YouTube no matter how high quality the source.
Here's a few YT soup movies I made...
Run5a -
stock parms, 77x20 grid, 1600 frames, about 800 generations
Run5b -
later in the same run, 1055 frames, 1000 battles per frame, about
500 generations
Hugerun5
- 160x50 grid, 559 frames, 10000 battles per frame, about 600
generations
Hugerun6
- 160x50 grid, 1365 frames, 10000 battles per frame, about 1500
generations
At the end of Run5 a strong type "M" suddenly evolved and wiped
out everything else, top warrior...
;redcode-nano
;name 14_12.red
;author yabevolver
;strategy evolved
;origin 38_11
;species 96444
;generation 1318
;created 02-18-2023 00-44-12
;assert CORESIZE==80
ORG 0
MOV.I > 36,$ 51
SPL.I # 73,> 47
MOV.I > 26,{ -1
MOV.I { -1,< -2
DJN.I $ -2,@ -2
END
...scores 152.25 against the nano2301 test set, 152.09 against
the nano106 test set, and 154.39 against the old nanoBM07 test
set. Not bad. Other high-scoring warriors from that run...
;redcode-nano
;name 59_13.red
;author yabevolver
;strategy evolved
;origin 38_11
;species 60045
;generation 1342
;created 02-18-2023 00-43-48
;assert CORESIZE==80
ORG 0
MOV.I > 31,$ 51
SPL.I # 73,> 47
MOV.I > 26,{ -1
MOV.I { -1,< -2
DJN.F $ -2,@ -2
END
...scores 152.08 against nano2301, 152.23 against nano106 and
154.11 against nanoBM07
;redcode-nano
;name 01_19.red
;author yabevolver
;strategy evolved
;origin 38_11
;species 60045
;generation 1262
;created 02-18-2023 00-33-36
;assert CORESIZE==80
ORG 0
MOV.I > 41,$ 52
SPL.B # 73,} 47
MOV.I > 26,{ -1
MOV.I { -1,< -2
DJN.F $ -2,@ -2
END
...scores 148.12 against nano2301, 151.48 against nano106 and
155.15 against nanoBM07.
Hugerun5 didn't produce anything particularly strong, at the end
of the run this was the top warrior with a score of about 140-143
points...
;redcode-nano
;name 116_10.red
;author yabevolver
;strategy evolved
;origin 121_10
;species 26534
;generation 325
;created 02-18-2023 09-26-28
;assert CORESIZE==80
ORG 0
SPL.BA # 3,< 64
SPL.I # 32,< 0
MOV.I $ 76,< -2
MOV.I # 6,} 1
DJN.I < 15,{ -6
END
At the end of Hugerun6 this was the top warrior...
;redcode-nano
;name 135_11.red
;author yabevolver
;strategy evolved
;origin 041_18
;species 3435
;generation 1280
;created 02-19-2023 08-59-58
;assert CORESIZE==80
ORG 0
SPL.BA # 42,> 48
MOV.I # 9,} 1
SPL.A { 12,{ 73
MOV.I @ 0,{ 72
DJN.X $ -1,{ 54
END
...scores ~148 against nano2301, ~142 against nano106 and ~138
against nanoBM07, not so great. The large soups are visually
interesting but don't necessarily produce stronger code and take
longer to run for a given number of generations.
2/21/23 - Sometimes big soups produce something strong. Still
using the same "hugesoup.ini" settings as the previous runs that
didn't amount to much...
REM --- yabevolver ini file ------------------------------------------------
REM copy this section to a file and specify filename on command line to load
header$ = ";redcode-nano" rem first line of program (start with ;)
author$ = ";author yabevolver" rem author line (start with ;)
comment$ = ";strategy evolved" rem comment line (start with ;)
tempdir$ = "/dev/shm/yabevolhuge" rem temp directory for battling warriors
soupdir$ = "hugesoup" rem where soup warriors are stored
benchdir$ = "nano2301" rem benchmark dir for testing warriors
topdir$ = "hugetop" rem where top-scoring warriors are saved
xdim = 160 rem soup x dimension
ydim = 50 rem soup y dimension
xwrap = 0 rem enable wraparound in x dimension
ywrap = 0 rem enable wraparound in y dimension
length = 5 rem max warrior length
mincrelen = 5 rem minimum warrior length at creation
coresize = 80 rem core size
processes = 80 rem max processes
cycles = 800 rem instruction cycles per match
rounds = 100 rem matches per battle
mutadjust = 0.5 rem gradually reduce mutation rates by up to rate*mutadjust
mutadjgen = 1000 rem by this warrior generation then stop changing rates
instrate = 0.015 rem chance of changing an instruction
modrate = 0.03 rem chance of changing a modifier
addrrate = 0.04 rem chance of changing an address mode
numrate = 0.05 rem chance of changing a number
reprate = 0.003 rem chance of replacing with new random line
insrate = 0.003 rem chance of inserting a new line (pushing rest down)
duprate = 0.003 rem chance of duplicating previous or following line
swaprate = 0.003 rem chance of swapping two lines (only 1 chance per evo)
delrate = 0.003 rem chance of deleting a line (pulling rest up)
orgrate = 0 rem chance of a random ORG line (ORG starts at 0)
org0rate = 0.5 rem if ORG changed, chance of ORG 0
adjrate = 0.5 rem if number changed, chance of increment or decrement
localrate = 0.5 rem if new number, chance of being within warrior
crossrate = 0.01 rem crossover rate
adjlocref = 0 rem if not 0 adjust local refs when inserting and deleting
evopseq = 0 rem evolving pmars sequence 0=random 1=fixed 2=permutate
evalmode = 3 rem 0=unguided 1=rnd bench 2=all 3=rnd 0/1 4=rnd 0/1/2
evalrate = 0.15 rem for evalmode 4 and 5, chance of using bench warriors
evalgen = 100 rem apply evalmode after both reach this many generations
ssfreq = 1000000 rem automatic soup save interval, 0 to disable
superror = 0 rem if not 0 redirect pmars stderr to dev/null
benchfreq = 1000 rem warrior benchmark interval (0 to disable)
savethr = 135 rem only save if score is >= this
savepc = 4 rem save if within this percentage of top score
bmrounds = 142 rem number of rounds when benchmarking
benchpseq = 2 rem benchmark pmars sequence 0=random 1=fixed 2=permutate
reinsfreq = 0 rem warrior reinsertion interval (0 to disable)
REM instructions, modifiers and address modes...
REM instruction$ length must be divisible by 4 (start with space)
REM modifiers$ length must be divisible by 3
REM bias encoded using duplicates
REM addr1mode$ and addr2mode$ separated as they have different mixes
instructions$ = " MOV MOV MOV MOV MOV MOV MOV MOV SPL SPL"
instructions$ = instructions$+" SPL SPL SPL SPL DJN DJN DJN DJN DJN"
instructions$ = instructions$+" ADD SUB MOD MUL DIV JMP JMZ JMN SEQ SNE"
modifiers$ = ".I .I .I .I .I .I .I .I .B .B .B .B .F .F .F .X .A .AB.BA"
addr1modes$ = "######$$$$$>>>><<<{{}}*@"
addr2modes$ = "<<<<<<{{{{{>>>>$$$$}}}@#"
initialinstr$ = " SPL MOV MOV MOV DJN" rem initial warrior instructions
enablepreseed = 0 rem if not zero use initialinstr$ to pre-seed the soup
REM binaries and options
unibox = 1 rem enable unicode chars for box surrounding soup display
viewmode = 2 rem view mode 0=length 1=species 2=sequence52 3=sequence94
viewshift = 0 rem raw display sequence hash xord by this to help avoid dups
ansimode = 256 rem ANSI mode 16=16colors 256=256colors 24=RGB else no color
enableC = 1 rem if not 0 allow color scheme cycling by pressing C
lister$ = "less" rem [path/]name of file lister program
listeropts$ = "-~" rem lister opts for warriors.. no ~ at end
listeroptsb$ = "-~ +G" rem lister opts for benchmarks.. no ~, go to eof
pmars$ = "pmars" rem [path/]name of pmars binary
pmarsv$ = "pmarsv" rem [path/]name of pmarsv binary
pmarsvopts$ = "-v 564" rem pmarsv options (-v digits speed dispmode detail)
rem pmarsv$ = "./bigpmarsv.sh" rem for my pmarsv magnifying script
pmarsv$ = "pmarsvsdl" rem for the SDL version of pmarsv
pmarsvopts$ = "-v 784" rem opts for my speed-patched SDL version
pmarsvrounds = 10 rem rounds to run in pmarsv
REM --- end yabevolver ini file --------------------------------------------
...but this time after this...
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│iiiSiSSScSSSfSiiiiiiiPiSSSSSiiSSiiiiiiiiiiiiiiiiiiiiiiiiiiiiTiiiiiiTTSSSSSSSSSSSSSiiiiiiiiiSSSSSiSSLiiiiiiiiiiiiiiiiiiiiTTTTTSSSiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii│
│SSSiiSiSSSSSiiiiiiiiiiPSiSSSSSSSiiiiiiiiiiiiiiiiiiiiiiiiiiiiiTiiiiiiTTSvSiSSSSSSSSiSiiiiiiSSSSSSSSiiiiiiiiiiiiEiiiiiiiiiTTTTTSSiiiiiiiiiiiiioyiiiiCiiiiiiiOiiiii│
│iSSSSSSSSoSSSiiiiiiiiPiPSiEiiSSSSiiiiiiiiiiiiiiiiiiiiiiiiiiiiTiiiiiTTiiSSSiiSiSSSiSSiiiiSiiSTTiSSiiiiiiiiiiiiEiiiiiiiiijiTZTSSiiYiiiiiiiiEiiiiiiiiiiiiiiiiiiiiii│
│iiSSSiiSSSSSiiiiiiiiiiUPPEEiiSSiSiiSiiiiiiEiiiiiiiiEiiiiiiiiiiiiiiiiiiiSSSiSiSSSiSSiiiiSSSTBSTTSSiSSiaiiriiiiiiiiiiiZiiiiiTZSiYYYYiiiiiiiiiiiqiiiiiiiiiiiiiiiiii│
│iSSSSSSSSEiiYiiiiiiiiiiUPPPSiSSSSWiSiiiiiiiiiiiiiiiiiiiEiiiEiiiiiiiiiSSSSiijSiSSYiiiiiiiiTTTTTTTSSSiiiiiiiiiiiiiiiiiiiiiiiTTTYYYYYYiiiiJciiiiiiiiiiiiiiiiiiSiiii│
│iSSSSSSSSSSiiiiiiiiiiiiiiiSSSSSSSiSLiiiiiiiimmiiiiiiiiiiiiiiiiiiiiiiiiSSSSjiSSiiYiiiiiiiiTTTTTTTSSiiiiiiiiiiiiiiiiiiiiiiiTiTTTYYYYnYiNiiiiiiiiiiiiiiiiiiiiiiiiii│
│SSSSSSSSSSSiSiiiiiiiiiiiiiSSSSSSSUiiiiiiiiiimmiiSiSiiiiiiisiiiiiiiiiiStSnnSSEYyiiSiiiiiiiTTTTTTTTSiiiiiiiiiiiiiiiiiiiiiiiiiTTZSSYYriYYiiiiiiiiiiiiiiiiiiiiiiiiii│
│SSiSStSSSiiiSiiSiiiiiiiiAiiSSiSSSSiiiiiiiqiimmiiiiiiiiiiiiiiiiiiDiiiSSttSnSiSiiiiiiiiiiiiTTTTTSSSSSiiiiiiiiiiiJiiiiiiiiZZZiZTYZSirYYYYiiiiiiSiiiiiiiiiJiiiiiiiii│
│SiiSSSSSiSitiiiiiiziiiiiiiSSiSiSiSikiiSSimmmmtmiiiiAiiiiiiiiiiiiiiiiiitHHSHSiiiSSiiiiiiSSSTTTSSSSSSiiiiiiiiiiiiiiiiiiiiZZSSSYYSZrrYYSYiiiiiSiiiiiiiiiiiiMiiiiiNi│
│iSiSSSSSSSStSSiiSiiiiiiiSiSSSiiiShiiiiSSnnmmmmtyiiiiiqiiiiiiiiiiiiiiSSSSSHSwSiiSiSiiiiiSSSTTSSSiSiiiiiiiiiiiiiiiiiMZiZZZZSSSSYiiSYYSiiiiiiiiiiiiiiiiiiiMiiSiiiii│
│iittiSttSSttSSiiiiiiiiiSSSSSiiiiiSSsiimmmmmmmmiiiiiiiiiiiiiiiiiiiiiSSSSSSSHHHiiSSSiiSiTjSSTSSSiiiiiiiiiippiiiiiiTiZiZZZZGhSSSSSSSYYSiiiiiSiiqiiiiiiiiiiiiiiiiiii│
│tttttttSttStSiSiiiiiiiiiSSSySUiiSSiSSiimmmmimiiiiiiiiiiifiiiiiiiiiiiiSSiSSSHHttiSiSiiSSSFSTiSiiiiiiiiiiiipiiiiZiZTiTTZZZihSSSoSSSSYYiiiiiiiiiiiiiOfiiiiiiiiioiii│
│ttttttttmtttpSiiiiiiiiiSSSSSSSSiiiSiSSiiimmiiiiiiiiiiiiiiiiiiiiiiiiiiiSiSiSSSHtiitSiiiSSSSSSiiiiiiiiiiiiiiiiiqiiTZTTTiZZiZSSSSSSSSSSiiiiiiiiiiiiiiEiJiiiiiiiiiii│
│tttttTttttSStSSSiiiiiiSSSSSSSSSiiiiSiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiSSSSittFFFdSSSvSiiiiiiiiiiiiiiiiiiJiTTTTZTiZSSSSSSSSSSSSSiiiiiiiiiiiiuiiiiiiiiiiiiiii│
│tttttStttStSSSSkSiiSiiiSSSSSSSiiiiAiiiiiiiiiiiiiiiiiiiNiiiiiiiiiiiiiiiiiUSiSStSSHtFFtFSSSSSSiEiiiiiiiiiiiiiiiiTTTTZTTZSZSSSiSSSSSSSSSSSiiiiiUiiiiiiiiiiqiiiiiiii│
│ttttttStttSSSSSSSiSSiiiiSSSSSSiiiiiiiiaiiiiiiiiipOiiiiiiiiiiiiiiiiiiiiiiiiSStSSSttFFiSSiSSSiiiiiiiiiiiiiiiiiiiiTTiTZiTiSSiiiiiiSSXXSSXiiiiiiiiiiiiiiiiiiiiiiiiii│
│ttttttSStSSSSSSiSiSVqiiSSEiSiiiiiiiiiiiiiiiiiiiiiiiiiiqiiiiiiiiiiiniiiiiiiiSttSHittiFiiiSZiiiiiiiiqiiiiiiiiiiiiTTTiiTiSiiiiiiiiSSXXXXXXiyiiiiiiiiiiiiiiiiiiiiiii│
│ttStttSttSSSSSiSiiiiiiiiiwiiiiEiqiiiiiiiiiiiiiiiiiiipiiiiiiiiiiiiiiViSiiiiqSttSiitiiiicyiiiiiiiiiiiqiiiiiiiiiijTTTiiiiiiiiiiiiiiiiiXXXXiiiiiiiZiZZiiZiAiiijiiiii│
│tSttttttttSSiiiiiiSiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiitDiitiiiiiiViiiiiiittttiiiitTiiiiiiiiiiiiiiiiiiiiiiiiiiiTTiTTiTiiiiiiiiiiiiiiXiiiiiiiiZZZZZZZZAiiiiiiiiii│
│SSttttttSSSSiiiiSiSSSSSiiiiiiiJiEiiiiiiiiiiiiiiiiiJiiitittiitiiiiVnViiiiitttittiiiTiTiiiiiiiiiiiiiiiiiiiiiTiiiTTiTiiiiiiiiiiiiiiiiiiiiiiiiiiiZpxZZZZZiiiiiiiiiii│
│SSStttttiSiiSiiiiSSSSSSiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiitttttiiiiinZiiiiiittittttiiCiiiiifiiiiiiiiTiiiiiiiiiiiTTTTTiiiiiiiiiiiiiiiiiiiiiiiZiZZZpZZZiiiOiJiiiiiiii│
│SStStStiiiSyyiiSSSSSSSSSiiiiiiiiiiiiiiiiiiiiiiiiSiiiiiiittttBininniiiiitittiiiiiiiiiTTiiiTiiiiiiiiiiiiTiiiiiiiiTiTTiiiiiiiiiiiiiiiiiiniiiZZZZZZZZiZiiiiipiiiiEii│
│SSiiSYSiiiiSSSSSSSiSiiSSiiiiiiiiiiiiiEiiSiiiiiiiiiiiiiiitttttiininniiiiiitttitiiiiipiTiiiTiiiiiiiiiiTTiiiEiiiiiTiTiiiiTiiiiiiiiiiinnniiiZZZZZZZZZiiiiiiiiiiiiiii│
│SSSSiSYiiiiiSSSSSiSSiiiiiiUUUiiiiiiiiSiSiiiiiiiiiiiiiiiitittiiijinniiiiitiiitiiiiipiiiiTTiiiTiiiiiiiTTiiiiiiiiTTiiiTifiTiiiiiiiiinnnTiiZivZZZZZZZqiiiiiiiiiiiiii│
│SSSSiiSSiPPPPSSPPiiSiiiUyiiUiiiiiiiiSiSiiiiiiiiiiiiYtttiiitiiiiaiiiUiiimmiiiiiiiiiiiiiiiiTiiiTUiTiTiTiiiiiiiiiiiiifffiiiiEUiiiiiiininZiiiiZAZZZZZiiiiiiiiiJiiiii│
│SSSSSSiSPPiPPSMPPiiSiiiiUUiiiiiiiiiiSSSSiiAiiiiiiiYtttiiiittiiiiiiiiqiiimmiiiitiiiiiiiiiiiiiTTiTiZTTiiiiiTTiRiiiiiiiiiiiiiiiiiiiiinzZiiZZZhZZZZZiiiiiiitiiEiiiii│
│SSSSSiiiPPPPiPPPPiiiYYiUUiiiiiiiiiSYiSSiiiiiiiiiiYittttiiintiiiiiiiiiiiiSSiiEiiiiiiiiiiiSiiTpTTTTTTiiiiiiiiTiiiiiiTiiiiiiiiiiiiiiiiniiZZZZZZZZiiiiiiiiiiiiiiiiii│
│SSSSSiiiiPPPPPZPPSiiiYYUmymmmJiiSSSSoSiiSiiiiiiiYYYttttittttiiiiiiiiiiiiSSijiSyiipNiiSSSSSTTTTiTTlTTTiiiiiTTiiiiiiiTTTiiiiiiiEiiiiiniiiiiZZaZZiiiiiiiiNiiiiiiiii│
│SSSSxiiiiPPiiiiSPiPSSSYYmmmmJmmSiSSSSSiSSiiiiiiiiYttiYYiiiniiiiiiiiiiiiiiSiiSSSiiiiiiSSiSisSTTiiTTTTTiiiiiiTiiiiiiiiTkiiiiiiiiiiiinniiiiZZrZiiiiiMiiiiiiZiiiiiii│
│ESSSPiPiimiiiiSiSPPSSSSmPmmmmmiiSSSSSSSiSiiiiiiiiittiYiiiniiiiisiiiiiiiiiSSSSSSiSiiiiSSiTTSiSSiiiTiTTiiiiiiiTMiiiiiTjTiiiiiqiiiiiiiiiiiiZZZZZiiiMiiiiiMZiiiiiiii│
│SESSPjiimmiiiiSyPPXXSSSmmmYmmimSiSSSSSiSwSUiiUiiiiiiiiiiiiMiiisiiiiiiiiiiiSSiiiiiiiiiSiTiTTiSSiiiiTiiTTiiiiiiiiiiSiVTVTViiiiiiiiiiiiiiiviZiZZZiiMiiiiiiZiiiiiiii│
│EiSESPPimiiiiiPPPPXPPSSmmammmmmSiiSSSSSSSiSSiiiiUiiiYYEiipiMiiiititiiiiiiiisiiiiiiiiiSiiiiiZTZZgiiiiiiiiiiiNiiSiiSSTViViiiiiiiiiiiiiiiiiZiZZZJZZZiiiiZZZZZiiiiii│
│PPiPSSPPmmmiiiPPPXPPSSSmmmmmmmiiiiiSSSSSiiSiiiiiiiOiYYntiiijiiiiittiiiiiiiiiiiiiiiiiiipiiiiZZZZiiiiiiiiiiiiiiSSSSSVVViiZiViiiiiciiiiiiiiiiinZZZiZZZZOZZZZiiiiiii│
│PPiiSPPPPmmmiPPPPSPPPPmPmmmmmiiiiiiiSSSSiUiiiiiiiiiiYYtttiiitiitttiiiiiiiiiiiiiRiiiiiiiiiZiZZZnmiiiiiiiiiiiiiSSVSSSVEZZEEiiiiiiiiiiiiiiiiinniZiiqZZZZZZZZiiiiiif│
│sPsimSPPPPmmmmPmSPSSPPPPPmmmSiiiiiiSASSiiiiSiiiiiiiYiYtttpiiiiiiLtiiiiiiiiiiiiiiiiiiiiiAZZVZZZnmJiiiiiiiiiiiSiSVVSVVVZEEEiiiiiiiiipiiiiiMnniiimqZZZiZZZZJiiiiiii│
│PsPmmmmPPmmmEmmmZmSPSSPPmmnmmSSaSiSSSSSiiiiiSiiiiiiiiYYtttitiiiaYiiiiiiiiiiiSiiiiiiiiiiiZZZZiZmniiiiiiiiiiiSiiSVESSVZZSSEipikiSiiiiniiiiiiiiiiiiZZZZinZniiiqiiii│
│PPmmmPmxPmrSSmmZZZBSSSSSSnSmmSSSSSSSSSSiiiiiiiiiiiiiYYttPitiiiiiiYYiiiiqiiiSiiiSiiiiiiiiZZZZZmmrVViiiiiiiiiSiiiSSSVSZTSSESiiiiiiSnXiiyiiiniiiiZZZZiZniiiiiPUiiii│
│mSmmmmSSmSSSmmmZZBPSSSSSSSmSiSSSSSiSiSSSiiiiiiiiiiiiitSYPiYYiYYYYYYiiiiiiiiSSSSSSiiiiicTZZZZZZTViViiiiiiiiiiiiiSSVVVSSSSSiiiiiiiiiipiisnsnsiiZZnZinnZninnYUYUUii│
│mmmmmSmmiSSSSiSBBPPiiUYYSSttSSSSSSiiSSSSiiiiiiiiiiiiiiiSYiYYYYYYiiiiiiiiiiiiiSSSiSiiiiiTTTTZVTNiViiiEiiiiiiiiiEiSSYSSSSSSSiiiiiiiiniiissniiiiZiiiiiiininnUYUUyUi│
│gmmmmSmiSSSSSiiBBBSiSiYYVVStSSSiSiiSSSSiiiiiiiiiiiiiiYiSYYYYYYYiiiiiiiiiiiiiiiSSiiiiiiiTTTTjTVVTViViiiiiiiiiiiiiXSSSSSSSSSiiiiiiiiiiiiisssiiiiiiiniiiinnUnEUUUii│
│mmmmmmSmiPiiiiiiBiiiiiEYYYSSSSSSiiiiiSiiSiiiiiiiiiiiiYStrrYYYYiiiiiiiiiiiiiiiiiiijiiiiiiTTTjTTTVVViViiiiZiiiXiiXiSSSSSSSSiiiiiiiiniiiiiiiiiiiiiinniinnnnUEEnUiUU│
│mmmmmmmiiiiiiiiiiPPiiiiYYYYYYYYYiiiiiiSiiiiiiiiiiiiiiiYrirSYYYYYiiiiiiiiiitiiipiiiiiiiiiinTTTVVTViSiiiiiZZSiiXmXXXSSSSSSSiiiiiiiiiiiiiiiiiiiiiiiiinnnnnEEEUWiiii│
│mmmmmmisiiJiEiiiPriiiiiYmmYYYYYYiiSSSiiiiiiiiiiiiiisiioiirSYYYiiiiiiiiiiiiitiiiiiiUiinSiiiiiVVVVTSiiiijSXZSSXXXXYSSSSSSSSiiiiiiiiiiiiiiiiiiiiiiiiiiinnnnnEiiiiiN│
│SSmmmiiiiiiiiiiiiirimiimmYIYYYYiYSSSiiiiiiiiiiiiiSiiiiiiSSSSYYiiiiiiOiiiiiitiaiiiiiiinnniiVVdVVTVViiitSSXXSSXXSXXXXSSSSSSiiiiiiiXiiiiiiiiiiiiiiiiUiinnnnEEiniiii│
│SmmmimmiijjiiiigiirrmiimmummYSkSSSSiiiiiiiiiiiiiiiiiiiiiaSSSSSiiiiiiiiiiiiqiiiiipinniiEnniiiVVVTTVTiitSSkpXXiYXXttSSSSSSiiiiiiXXXiijjOiiiiUiiiiiiiinnnYEEinniiii│
│SimiimiiiUiiiiiiririiiiimuumzYYSSSSiiiiiiiiiiiiiiiiiiiiJiSSvSiSiiiiiiiiiiiiiitiinnniiiiiniiVVVtVTiiiiSSSXSXXSXXXXtSSmStiiiiiiiiXiiiiiiiiiiiiiyiEiiiinninnnniiiii│
│SmiiiiiiiiSiiiiirrUfmmiiEuumYEEESiiiiiiiiiiiiiiiiiiiiSiSSStSiiJiiiqiiiiiiiiiitiiiniiiiiiiiVVVtVtTTiitTSSSSSYYSXXXXtttmtttiiiiiiXiiiiiiiiiiiiiiiiiiininnUnnnnniii│
│SSiiiiiSSiiUiiiirrEErEEEmEEYYEEiSiiiiiiiiiiiiiiiiiiiSSStSSSSSiiSiiiiiiiiiiiiiiOiiiiiiiiiiiiitVzMVVTiiiTSSSSSSSSXXXnptttttxiiiiiiiiiiiiiiiiiiiiiiipiitZUUnniiiiii│
│SSiiiiiSiSSiiiiirrrEEEEEEmEmEEESiiiiiiiiiiiiiiiiiiSSiiStSSSSSSiiiiiiiiiiiiiiiiOiiiiiiiiiiiiiVtttnnniiTSSSSSSSSSSSSSttttttiiiiiiiiiiiiiiiiiiiiiiiiiiinnZinniiiiEi│
│iSiiSiiSiSEiiiiiirrrEMEEEEmEEEEiiiiiiiiiiiiiiiiiqSiiEttPSSSSSSiiiiiiiOiiiiiiiiiiiiiiiiiiiiiAittntnnniiiiSSnSSSSSSSSStttEtiiiqiiiiiiiiiiiiiiiiUiiiiiinZiiiiiiiiUi│
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Total of 8000 warriors, average score = 126.6
Using characters for viewmode=2 with viewshift=0
Found 140 unique instruction sequences...
4934 best 151.3 by 063_43 "i" SPL MOV MOV MOV DJN
583 best 139.6 by 007_03 "S" SPL MOV MOV DJN DJN
522 best 139.0 by 077_16 "S" SPL MOV MOV JMP SNE
278 best 138.8 by 071_09 "t" SPL MOV MOV JMP MOV
234 best 133.0 by 003_27 "Z" SPL MOV MOV DJN MOV
234 best 127.3 by 092_08 "T" SPL MOV MOV DJN SPL
223 best 137.1 by 117_46 "m" SPL MOV MOV JMP DJN
146 best 138.1 by 040_09 "n" SPL MOV MOV JMP SPL
111 best 139.3 by 020_36 "P" SPL MOV MOV DJN MOD
.....
There was this in the top dir...
;redcode-nano
;name 097_12.red
;author yabevolver
;strategy evolved
;origin 045_26
;species 1216
;generation 907
;created 02-20-2023 11-02-58
;assert CORESIZE==80
ORG 0
SPL.I # 39,< 55
MOV.I * 71,{ 0
MOV.I > 55,{ -2
MOV.I { -3,< 52
DJN.I $ -2,{ -4
END
Back to the boring SPL MOV MOV MOV DJN form but it scores 151.90
against the nano2301 test set, 151.24 against nano106, and 150.04
against nanoBM07. Scores 150-156 against all of my test sets,
consistent.
Here's another strong one...
;redcode-nano
;name 085_31.red
;author yabevolver
;strategy evolved
;origin 045_26
;species 7916
;generation 869
;created 02-20-2023 10-20-57
;assert CORESIZE==80
ORG 0
SPL.I # 39,< 55
MOV.I * 70,{ 0
MOV.I > 57,{ -2
MOV.I { -3,< 52
DJN.I $ -2,{ -4
END
...very similar. Scores 151.43 against nano2301, 152.04 against
nano106 and 151.78 against nanoBM07.
High score against just one test set doesn't always translate,
this warrior gets 156.64 against nanoBM07...
;redcode-nano
;name 145_13.red
;author yabevolver
;strategy evolved
;origin 045_26
;species 58402
;generation 758
;created 02-20-2023 08-13-36
;assert CORESIZE==80
ORG 0
SPL.B # 34,< 56
MOV.I } 75,{ 0
MOV.I > 61,{ -2
MOV.I { -3,< 53
DJN.I $ -3,< 37
END
...but only 144.03 against nano2301 and 150.12 against nano106.
This is why the evolver saves warriors within a certain percentage
of the top score as the top-scoring warrior itself is often
over-specialized and adapted to the current test set.
The next run also produced fairly strong but more specialized
warriors...
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│MExxxxxxxxxlxxxxxxxxxxMMMMMMMMMMxMxMxMMMMMMMMMMMMMMxMMMMxxxRxxxxMMMMMMSMxxxxxxxxqMMMMMMMMMMMMMMEMMMMMMMKMMMMMMMMMMMMMMMxxxxxxxxMiMMMMMMMMMMMMMMEEEEEEEMMMMMMMMMM│
│MEEMxxxjxxxxxxLxxxxxxqMMMMMMMMMMMMMMxMMMMMMMMMMMMMMMMMMMxxxxxxxxxxMMMMMxMxxxxxxxMMMMMMMMMMOMMMMMMMMMMMMMMMMMMMMMMMMMMMxxxxxxxxxMMMMMMMMMMMMMMMMMMEEEMEEMMMMMMMMM│
│MMMxxxxxxxxxqxxxxxxxxxMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMxxxxxxxxxxMMMxMMMxxxxxxxMqMMMMMMMMMMMMMMMMMMMMMMMMnMMMMMMMMMMMMMxxxxxMxxxMMMMMMMMMMMMMMMEEEEEMEuMMMMMMMM│
│MMxxxxxxxxxxxxxxxxxxxxMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMcxxxxxxqxxxMxMxMxMxxxxMMMMMMMMMMMMiMMMMMMMMMMMMMMMMMMMMMMMgMMMMMxxxxxxMxxxMMMMMMMMMMMMMMEEEEEMMMMMMMMMMM│
│MMxxMxMMxxxxxxMMMxxxxxMxEEMMMxMMMMMMxMMMMMRMMMMMMwMMxMMcxxxxxxxxxxxxxxMxxMMxxxxMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMzMMMMMMMxxxxxMMxxxxMxMMMMMMMxMMMEEEEEEMMyMMMMMMN│
│MMMxxMMxxxxxxhMMxxxxxxxxxMMwwMxxMMMMMMMMMMMMMMMMMMMxxMxxxxxxMxxxxxxxTMxxxxxxxxxMMMMxMMMMMwMMMMMMMMMMMMMyMMMMMMMMMMMMMMMMMRxxxxxxxxxMMMMMMMxxxxMEEEExEEEMyyMMMMNN│
│xxxhMxxMxxxxxMMxxMxxxxxxxMMMMMMMMxxMMMMxxMMMMMMMMMMMxxxxxxxMxMxxxxxxxxMxxxxxxMMMMMxWxxMMMMMMxMMMMMMMMMMMMMMMMMMMMMMMMMMMxMMMMxxxxxxxxMxMMMxxxxxMEExExxMMxMMMMNNN│
│MxMMxxMMxxxxxMMxDMxxxxxxxMxMMxxMxxxMMxiMMMMMMMMMMMMMMMxxxxMMMMxwxxxxxxxxxxxxMMMMMxxxxMMMcMMxMMMMMMMMMMMzMMMMMMMMMEMMMMMMxMxMxMxxMxxMMxMMMxMxxxMzxxExxxxMxxMMNxxM│
│BxxUxxxMxxMMMMxxMMMxxxxMxMMxxxxxxxxxxMMMMMMMMMMMMMMMMxxxMxxMMMMxxxMxxxxxxhxxxMMMMxxxMMMMMxMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMxxxxMNxxMMMMMMMqxMzxqqxxxxxxxMxxxxMx│
│xxxxjxMxMMxxMxxxxxMxxxMxMMMMxxxxxxxxMMMMMMMMMMMMMMMMMxxMMjxxxxMMMxxxxxxxxxxxxMMMxcccMMxMxMxMMMMMMMMMMMMMMGMMqMMMMMMMMyyUMMMMMxxxMMqMMMMMMMMqxqqqqqExxxxxxxxxxxMM│
│xxxxxMxxxxxxxxxxxMxMxxMMMMxxxxxxxxMxxMMMMMMMMMMMMMMMMMMxMMMpxxMMMMxxxxxxxxxMxMMMMMxxMYMxxxMxxMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMxMMMMMMMMMMMMMMxqqqqqqxxxxxxxxxxMMMM│
│xxxxxxxxxxxxxxxxxxxMMMMxMxxxxxxxxxxxMMMMMMxMMMMMMMMMMMMMMMMxxxMMMxxxxxxxxxxMxMMMMMxwNNMMxxxpxMMMMMMMMMMMMMMMMMMMMMMMMRMMMMMMxMMMMMMMMMMMMxxqqqiqqqxxxxxxxxxxMMMM│
│xYxxxxNxxxxxxxxxxxxxMMMxMxxxxxxUMUMxMMMMMxMxMMMxxxxMMMMMMMMMMMMMqMxxxxxxxMxxMxMMMMyMNMMxxMMxxxxMMMMaaMxMMMMMMMMMMMMMMMMMMMMMMMxMMMbMMTMMMMxqqqqiqqqqqxxxEExMMMME│
│xxxxxxxxxxxxxxxxxxxMxxxxMxxxxxxMxMxMMMMMMMMMMMMxjxMMMMMMMMMMMMMMMMxxxxxxxxxMMMMMMMMMMMMMMxMxxxxMMMMMMxxxxMMMMxMMMMMMMMMMMxxMMxxxMMMMMMMMMMqMqqqiMqqqMxxxiEMMEEEE│
│xxxxxxxxxxxxxxxxxxxxxxMMMxxxxxxMMMMMMMMxMMMMEMMxxMMMMMMMMMMMMMMxMMxxxxxxxxxxMMMMMMMMMMMMMMxxxxxMMMMMMxxxxxxxxMMMMMMMMMMMxMMMMMMMMMMMMMMMxxxMMqMMMqqqMMxxEEMMEEEE│
│MxRJxxxxxxxxxxxxxxxxxMMMMMMxxxxxxMMMxMMxMMMBMMMMMxMMMMMMMMMMMMMMxMxxxMMTxxxxMxxMxMMMMMMxxMxxxxxMMMMxxxxxxxxxxqMMMMMMMMMMMMMaMMMMMMMMMMMMMcxcxMcMMMxxMMMMxMEMEEEE│
│xxJxxxxxxxxxxxxMxxxxdxMMMxMxxxxxxxMMxMxxxMcMMMMMExMMMMMMMMuMMMMxxMxxxxMMuuxxxxxMMMMMMMMMMMxxxxxMMqxMxxxxMMuMMMMMMMMMMMMMMMxxMMMMMMMMMyMcMccxccxMMqyyMMMMMMEEEEEE│
│xxxxxxxxxxxxxxMMMxxxxxxxxxxxxxxxxxMMMMMxMMMMMMMMxxMMMMMMMMMMMMMxxxxxxMxMuxxxxxMxMMqqMMMMMMMxxxxMMMMxMxxMMMMMMMMMMEMMMMMMMMMMbMMMMMMMMMMcMccxxcxxMqMMMMMMMMEMMMEx│
│xxxxxxxxxxxxxxMMMEMxxMxxxxxMxxxxxxMxxMMMMMMxMMMMMxMhMwMMMMMMMMMMxxxxMxxxMxxxxxRxxxxqMMMMMMWMMMMMMMMxxcMMiMMMMMMMMMMMMMMMMMMMxMMMMyqMMMMMMcccxxxxMxxxMMMMMxxxxMxx│
│xxxxUxxxxxxxxxMMMxxxxxxxxxMxxxxxxxMMxMMMxMMMcAMcMMMMMMMMVMMMMMMMxxxNNxxxxxxxxxxxxxMMxxxMxMMMiMMMMMxxxxxMMMMMMMMMMMMMMMMxMMMMMMMMMMMMMMRMMcMxxxxxMMMxMxxMMxxxxMxx│
│xxxxxxxxxpxxxxMMMxxxxxxxxxMxxxxxxxxxxxMxxxxMxcxxMMMMMMMMMNMMMMMMMMMxMxxBxxxxxxxxxxMxxxxxxxMMMMMMMMMxxxMMMMMMMMMxMMMMMMxMxMxMMMMMMMMMMMMMMxxMMxxxMMxMMMxMMMxQMxxx│
│MMMmxxxxxxxxxxxMMxxxxxxxxxxxxxxxxxxxxxjxxxMxxMxxpMMMOMMTMMxxMMMMMMMhxMMxxxxxxxxxxxxxxxWxxxMMMMxxxxMxxMMMMMMxYMxxMxxMMMMMMxxMMMMMMMMMMMMMMMMMxxMMMxxMMMMMMxxxxMMx│
│MMMxxxxxxxxxxxxxxxxMxxxxxxxUxxxxxxxxxxxxxxxxxxxxxMxxMMMyMMMMMMxMGxxMMxxxxxxxxxxxxxxxxxxxxxxxMMxxxxxxMMMVMxxxxxxxxxxMxxxxMMxMMMMMMMMMMMMMMMMMxxMMxMMMMMMMMxxxxxxx│
│MMMxxxTxxxxxxxxMxxxMxxxxxxxxxxxxxxxxxxxxxxRxxxxxxxxxMMxMMMMMMxxMMMxMWMxtxxxxxxxxxxxxxxbxxxMxMqMxMxxxMMMMMxMxMxxMRxxxxxMMMMMxMMMMMMMMMMMMMMMMMMMxMqMMMMxxMxxxxxxx│
│MMxxxxMxxxxMMxxxMMMxxxxxxUxxxxxxxxxxxxxxxxxxxxxxxxxMMMMMMMMMxMMMMxxxMMMxxxxxxxxxxxxxxxxMMMMMOOMxxxMxxwMMMxMMxxxMMxxMxUMMMMnMMMMMMMMMMTMMMMMMxxyxxMMxMMMxxxxxxxxx│
│MxxMMMMNxMMxxMMMMMMMRxxxxxxxxxxxxxxxxxxxxxxxxxxxxMxMxMMMMMMMxxxxMMMxMMxxxxxxxxxxMxMxxMMMMMMMxOxxMMxxxMxMMMMMxxxxxxxMxMDMMMMMMMMMMuMMMMEMMMMMxxMMMqxMxMMMMxxxxxxx│
│xMMMMxMxxxrxxxMMxMMMMMxxMIxxxxxxxxxHxxxxxxxxBbxxxxhxMxxMxMMMMxxxxxMMMxxxxxxxxxxxxMMsxiMMMMMMMxxxxMxxxxxxMMMMMMxMxxpMMMDMMMMMMMMMMMMMMMMMMMMxMMMMMMxxMxMMxxxxxxxx│
│MMMMMMxxxxMMMMMMxMMMMMMxMMxxxxxxxxxxqxxxxxxMxxxxxxxMxxxMMMMxxMMMxxMMxxxxxxxxxxxxxxMMMxMMMMMMMxxMMxxxxxxxMMMxMMMMMMMMMMMMMMMMMMMMMEMMMMMMMyMMxxMMxxxMxxxxxxxxxxxx│
│MMMMMxMxxMEiMMMxMxMMMMMMMxxxxxxxxxDxxxxxxMxxxxxxxxxxxxxxxxxxxxMMMMMxxMMMxxxxxxxxxxMMxwMMMMMMMMMMMxxxxxxxxMMMMxMxMMiwMMMMxxMMMMMMMMMMMMMMMMMxxxxxxxxxxxMMxxxxxxxx│
│MMMMMMxxMMMMMMMMMxMMMMxxxEExxTxxxxxxxxxxxxxxxxxxxxxxxUxxxxxxxxxMMMuMMMMMxMxMMxxxxxxMMMMMMMMMMxxMxxxxxxxxxxMMMMMMMxMMMMMxxxMMMMMEMMMMxxxxMMMxxxMxxxxxxxMxxlxxxxxx│
│MMMxMMMxxMMMMMMMMMMMMEMWxMMxMxxxxVxxxxxxxxxxxxxxxxxxxxxxxxxxxxHMxMxMMMMMMxxMMxxxxxMMMMMMMMMxxxxxxxxxxxxxxMMMMMMMMMMMxxMxxMMMMMMMMMMMMMxxxxxMxxMMxxxaMxxpxxxxxxxx│
│MMxMMyMMMMMMMMMEMMMMMMMxMMMMxxxxxxxxxxxxpxxxxxMxxcxxxxMxMxxxxxxxxxxxMMMMMxMMxxxMMxxMMMMMMMMMMxxxxxxxxxxxxMMMMxxMxxxxxxxxTMMMMMMMMMMMMyMMxxMxxxxxMMMMMMMxxxxxxxxx│
│MxxxMMMMxxxxMMEMMMMMMMMMxxxMMxxxxxxxxxxxxYxxxxxxxxxxxxMxMxxxxxxxxxxxMxMxxMMMxxrMMxxMxMMMMMMMMxxxxxxxxxxxxMMxxxxxxxxxxMxxMMMMMMMMVMxMMMMMMMMxxxxMxMMMMMMxxxMxjxxx│
│xxxxMRBxxxxxxMMMMMMMMpMMMxMxxxxxxbxxxxxxxxxxxxxxxxxxxxxxMMxxxxxxxxxMxxxxxxxMMxMMwxMMMxMMMMMMMxxxxxxxxxxxxxxxxMxxMxxxxMMxMMMMMWMxMMuMMMMMMMxMMxxxxMMMMMMxxxMMxxxx│
│MMxxxxRxxMxxxxMMMMMMMMxMxMMxxxxxxxxxxxxxxxxxxxxxxxxxBIxxxxYxjxxxxxxxxxxxxxxMMMMMxxxMMMMMMMMMMMxxxxxxxxxxxxMxxxxMMMxMEMMxMMMMMxMxxMuuMMMxMMMMMxxxxMMMMMMxMxMMMxMM│
│MMxxxxxxxMxxxMqMMMMMxxMxMMMxMMMMxxxMMxMMxxxxxxxxxxxxxxxxxxxExxxxxxxxxxxxxxxMMMMMMMMMMMMMMMMxxcxxxxxxxxxxxxxxMxMMMMMxxxMxxxxMxxxxxxxMMxMMxMMMMMxxEMMMMMMgMxxxMMMM│
│MMMxxxxxMMxxMMMMMxMxxxxxxMMxxMMMMEMMMxMMMxxxxxxxxxxxxxxxxxExxxxxxxxxxxxxxxxxMMMMMMMMMMMMMMMMxxxMMxxxxxxxxxxxMMMMMMMMMMxxMxxxxxxxxMMMxxpxMxxxMxxMUfEMNMMMxxxMMMMM│
│MMMvMxxxMxMMMMrMxxMMMxMxxxxMxMMMMMMxxMMMMMxxxxxxxxxxxxMMMMMxxxxxxxxxxxxxxxxMMMMMMEccMMMMMMMMMixMMxxxxxxxxMMMMMMMEMMxMMMxxxxxxxxxxxxxcxxxxqqMMxxxMxEEMEMMxxxMMxMx│
│MMMxxxxqMMMMMMrxxxxMMsMxxxxMMMMMMMMMEMMMMMxxxxxxxxxxxxxMNxxxxcxxxxRxxxxxYxxMMxMMxMcwccMMMxxMMxxMMxxxxbxxxOMyMWMMMMMMMMMxhWxxxxxxxxxxxxxxxNMMMMMMMMNEMMMMxxMxxxxx│
│MMMxMMMMMMMxMxxxxxxxMMMxxMMxxxMMMMMMMMnMMMMxMxxcxxxxxxxUMMMMMxxxxxxxxxxxxxxxxxxxxxcccciMMxxxxMMMMMxxxxxxxMMMMMMMMMMMMMMMxxxxxxMxxxxxxxxxxxxMMMMMMMMMMMMMMMMxxxxx│
│MMMMMMMMxMMMxxxxxxxxxMxxxxxxxxxMMMMMMMMMRMMMMxxxxxxxxxxMUMMMMMMxxxxxxxxxxxxxxxxxxxccccMEMxxcxxxMMxxxMMxxxxMMMMMMMMMMMMMMMxxxxxMMrMMMMxxxxxMMMMMMMMMMMxxMMxxMxxxx│
│MMMMMxMMMxxxxpxxxxxfxxxxxxMvxxMMMMMxxMUMMMsxxxxxxxxxxxxMMMMxsxMMxxxxxxxxxxxxxxxxxczUxccExMxxxxxxxwxxMMMUxMMMMMMMMMVMMMMMxxxxxxxMMMMMxxxxxxxMMMxMMMMMMxxMMMxxxxxx│
│MMiMxxMMMMMxMxxxxxxxfbxxxxvxMxxMMMMMxxxxxMMxxxxxxxxxxxxMMMMMMxxxxxxxxxxxxxxxxxxxFxxxxcEcxxxxxxxxxxxxxxcxMqMMMMMMMMMMMcMxxxxxMxMMMMMMxxxxxxMxMxMMMMMMMMxMMMMxxxxx│
│MMxxxxMMMMwMMMxxxxxxxxxxxxxxxMxMMMMMnxMxxMxxxxxxxxxxxxxqMMMMMxxxxxxxxxxxxxxxjxxxxxxxcExxxMxxMMMxxxxxxcMMMMMMMMMMMMMMMxMMMxxMMxxMMMMMxMxxxxxxxMMMMMxMMxxxMMMxxxxr│
│MMxxxMxMXxxMMxxMxxxxxxxxxxxxxMMMMMMMxMxxMxcxxxxxrxxcxxxqMMMMMxxxxxxxxMMMxxxxxxxxxxxxxxxxMxxMKMMMxxxxXQMMMMMMMiMMMMMMxxxMxxMMMMxMMMMMMMMMMxxxxMMMxxxxxMMxxMMxxxrx│
│MxxxxMxMxxxMxxxMMMxxMMxxxxxxMMMMwMMMxxxxxxxxxxxxxxxxxxxxxMMxMMMxxxMMMMMMMxxxxxxxxxxxxxxxxxxxMMKxxxxMMMMMMMMMMMMMMMMRMRRMMxbMxMMMMMMMMMMMMxxxxoMWxxhxxxxxxxxxxxxx│
│MMMMMUMMMxxMxxxMMxxxxMMxxxMMMMMMMMMMMMxxxxxxxxxxxxMMMxxxxMxxMMxxxMwMMMMMxxxxxxxxxxxxxrxxxxxxMMMxpxxMMMMMMMMMMMMMRMMMRRRxMMxxxMMMMMMMMMMMxxxxxxxxxxxxxxxxxxxxxxxx│
│MMMMMMMKMxxxxxxMxMxxMMxMxMxMMMMMMMxxxxxxxxxxxxxxxxMxMMxxxxxMMxMMMMMMMMMxxxxxxxxxxxxxHxxMxxxxMMMMrxxxMMMxNMMMMMMMMMRRRRxxxxxxxxMxxMMMMMMMxxxMxxxxxxxxxxxxxxxxxxxx│
│MMMMMMMMMxxMxxxxxxxxMMxxxxxMMMMMMMMxxxxxxxxxxxxxxxxxhxxxxxxxMMxMMMxMMMxxxxxxxxxxxxxxxxxxxxRxExMxMxxxxMMMxxMMMMMMyMRRRRRMxxxxxxxxMMMMMMMMxqxxMxxxxxxxxxxxxxxxxxxx│
│MMMMMMMMMxxMxxxxxxxxxMMMxxMMMMMMMMNMRxxxxxxxxxxxxxxxxxxxxxMMMMxxxMxxMxxMMxxxxxxxxxxcxxxxxxxxxxxxMMxxxMxxxMxMMMMMMMRWRRMRMxxxxWMMMMMMMMMMxMMMMxxxxxxxxxxxxxxxxxxx│
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Total of 8000 warriors, average score = 121.7
Using characters for viewmode=2 with viewshift=0
Found 104 unique instruction sequences...
3729 best 148.9 by 077_09 "M" MOV SPL MOV MOV DJN
3716 best 146.6 by 078_06 "x" SPL SPL MOV MOV MOV
99 best 134.6 by 144_01 "E" SPL MOV MOV DJN
78 best 125.2 by 061_17 "q" SPL SPL MOV MOV DJN
47 best 129.5 by 083_42 "c" ADD SPL MOV MOV DJN
.....
Top scoring warrior against nano2301...
;redcode-nano
;name 006_12.red
;author yabevolver
;strategy evolved
;origin 083_42
;species 72236
;generation 701
;created 02-21-2023 05-55-31
;assert CORESIZE==80
ORG 0
SPL.I # 4,> 75
SPL.I # 18,} 0
MOV.I } 48,} -1
MOV.I { 2,} -1
MOV.I # 12,} -1
END
...153.59 against nano2301 but only 141.12 against nano106 and
134.73 against nanoBM07 - very specialized.
Top scoring warrior against nano106 and nanoBM07...
;redcode-nano
;name 119_34.red
;author yabevolver
;strategy evolved
;origin 061_10
;species 68564
;generation 611
;created 02-21-2023 04-32-57
;assert CORESIZE==80
ORG 0
MOV.I > 39,$ 61
SPL.I # 54,< 75
MOV.I < 26,{ 79
MOV.I { -1,< -2
DJN.I $ 78,$ -3
END
...152.82 against nano106 and 158.97 against nanoBM07 but only
143.19 against nano2301.
This one is more balanced...
;redcode-nano
;name 079_07.red
;author yabevolver
;strategy evolved
;origin 061_10
;species 40400
;generation 832
;created 02-21-2023 08-01-23
;assert CORESIZE==80
ORG 0
MOV.I > 40,$ 60
SPL.B # 50,{ 75
MOV.I > 24,{ 79
MOV.I { -1,< -2
DJN.I $ -2,$ -3
END
...148.99 against nano2301, 150.19 against nano106 and 151.43
against nanoBM07. Note that the last lines of the two preceding
warriors are the same - "78" and "-2" refer to the same location,
it's all mod 80, sometimes dupes slip through because of this.
Probably should fix the warrior write code so that any back
reference to within the warrior code is negative, otherwise
positive so the identical code will always be written the same
way.
To find the strongest overall warrior I made a script that cycles
through the warriors and grabs and accumulates the scores from my
various benchmarks to produce a cross-referenced report...
Cross-referenced benchmarks...
Acc.Score Warrior nano106 nano2301 nanob2 nanobm15 nanoBM07 nanoht1 nanoht2 nanoht3
1222.53 138_16.red 152.58 143.96 153.30 152.69 158.54 155.07 153.89 152.50
1217.37 119_34.red 152.82 143.19 153.41 151.70 158.97 153.16 151.66 152.46
1216.29 089_38.red 151.90 143.35 152.46 152.21 156.97 154.17 152.81 152.42
1213.8 028_40.red 151.49 143.09 152.25 152.34 156.33 153.45 152.66 152.19
1210.32 092_15.red 150.95 143.12 153.38 151.28 155.80 152.93 151.85 151.01
1210.32 039_50.red 150.95 143.12 153.38 151.28 155.80 152.93 151.85 151.01
1207.77 082_30.red 150.65 142.72 151.47 151.47 155.49 152.32 152.18 151.47
1207.57 074_19.red 150.74 143.84 151.97 151.17 155.05 152.27 151.44 151.09
1206.68 153_39.red 151.58 143.00 152.60 149.68 157.85 151.43 150.09 150.45
1206.68 127_19.red 151.58 143.00 152.60 149.68 157.85 151.43 150.09 150.45
1195.07 082_02.red 150.19 148.99 154.43 145.59 151.43 148.73 148.79 146.92
1195.07 079_07.red 150.19 148.99 154.43 145.59 151.43 148.73 148.79 146.92
....
(LOL) and the winner is...
;redcode-nano
;name 138_16.red
;author yabevolver
;strategy evolved
;origin 061_10
;species 31211
;generation 671
;created 02-21-2023 05-26-26
;assert CORESIZE==80
ORG 0
MOV.I > 39,$ 58
SPL.F # 54,< 74
MOV.I < 26,{ 79
MOV.I { -1,< -2
DJN.I $ 78,$ -3
END
2/25/23 - Modified YabEvolver so that only back-references within
the warrior code are negative, all other numbers are mod coresize.
To implement this added a normalizenumbers(x,y) sub that is called
when warriors are created or mutated, hopefully this doesn't slow
it down too much but tired of seeing "78" when it should be "-2".
This also prevents saving equivalent dups.
Here's a strong nano warrior from a huge run...
;redcode-nano
;name 128_48.red
;author yabevolver
;strategy evolved
;origin 030_43
;species 81224
;generation 820
;created 02-24-2023 01-56-15
;assert CORESIZE==80
ORG 0
SPL.I # 76,> 67
MOV.I { 0,> 23
MOV.I > 30,{ -2
MOV.I { -1,{ 39
DJN.I $ -2,{ 53
END
...scores over 152 against all my test sets...
Acc.Score Warrior nano106 nano2301 nanob2 nanobm15 nanoBM07 nanoht1 nanoht2 nanoht3
1241.66 HR10c_128_48.red 156.21 155.91 156.51 153.96 155.59 153.94 156.67 152.87
It's yet another sort of boring SPL MOV MOV MOV DJN but it puts
up a pretty good fight...
Testing HR10c_128_48.red...
Anefam Vesyes 142.25 66 4 **************
Another MEVO Thing 168.30 76 11 ****************
b69e6908-a5be0bba-ab4445 178.16 82 7 *****************
Clone 166.19 77 5 ****************
Cold Plasma 97.887 40 19 *********
Combat Arithmetic 111.26 49 11 ***********
Creamed Corn 163.38 76 4 ****************
Crimson Climber 142.95 66 5 **************
Crisis 133.80 61 7 *************
[RS] C-Strobia 156.33 73 3 ***************
eerie glow 166.90 75 12 ****************
Free the Fish! 165.49 72 19 ****************
Hot Soup 142.25 65 7 **************
Just a MEVO Thing 159.85 75 2 ***************
Little Bang 154.22 71 6 ***************
Little Red Rat 180.98 85 2 ******************
7_3 135.21 63 3 *************
NanoCracker 147.88 66 12 **************
02_08 133.09 61 6 *************
[RS] Nextratulated Sturv 147.18 68 5 **************
Nonlocality 2 161.97 72 14 ****************
Nonlocality 178.16 80 13 *****************
Quantum Foam 180.98 83 8 ******************
Reflow Oven 147.18 67 8 **************
Sleepy Lepus 176.05 80 10 *****************
Steaming Pebbles 156.33 71 9 ***************
SWT2-21 172.53 81 2 *****************
SWT2-28 156.33 73 3 ***************
Transfer Function 140.14 64 7 **************
Unholy Fire 214.08 99 7 *********************
Score = 155.91
In the performance chart the numbers after the score represent
wins and ties, the opponent wins aren't noted but can be inferred
by subracting the numbers from 142, the number of rounds in a -P
nano match.
Here are the scripts
and test sets I'm currently using for testing warriors, at
least for now. The scripts require Blassic which is
still available but is no longer maintained as far as I can tell,
need to rewrite them to use something else.. one day maybe.
3/3/23 - The option 4 analysis/benchmark report now can include
listings of the top-scoring warriors from the top sequences and
how they perform against the test warriors (same format as soup
display benchmark option), a snapshot of the soup display, the
full benchmark list is now optional, and prompts for all the
options up front. It now works like this...
Other functions...
1 - Change the benchmark set
2 - Load settings file (some parms ignored)
3 - Show soup sequences and population numbers
4 - Sequence and benchmark the entire soup
5 - Change settings variable(s)
6 - Display variable(s)
7 - Display all settings
8 - Save settings to file
10 - Start/stop ANSI dumps (enabled, select for info)
11 - Play back ANSI dumps
Select function or none to exit: 4
Report setup... answer C to questions to cancel
Include listings and benchmarks? y
How many sequences to list and benchmark? (enter for 10) 5
Include soup display dump? y
Include full benchmark listing? n
Save report to a txt file? y
Report file [path/]basename (default top/report): report1
Will save report to file top/report1.txt
Analyzing... (this will take awhile, esc to cancel)
Benchmarking warrior 03_15 [etc till done]
Total of 1540 warriors, average score = 102.0
Using characters for viewmode=2 with viewshift=0
Found 86 unique instruction sequences...
633 best 121.2 by 72_18 "E" SPL MOV MOV DJN
270 best 127.3 by 07_10 "M" MOV SPL MOV MOV DJN
249 best 114.2 by 64_09 "U" SPL MOV MOV MOV
87 best 127.6 by 24_06 "u" MUL SPL MOV MOV DJN
76 best 115.9 by 14_11 "q" SPL SPL MOV MOV DJN
...etc...
------------------------------------------------------
Top warriors from the top 5 sequences...
------- Pop.Cnt. 633 best 121.2 by 72_18 "E" SPL MOV MOV DJN
;redcode-nano
;name 72_18.red
;author yabevolver
;strategy evolved
;origin 60_18
;species 16479
;generation 191
;created 03-03-2023 06-58-24
;assert CORESIZE==80
ORG 0
SPL.B # 49,< 60
MOV.I } 0,{ 78
MOV.I > 21,{ -2
DJN.I $ -2,$ -3
END
------------------------
Battling 72_18.red against...
Anefam Vesyes 132.39 *****************
Another MEVO Thing 123.94 ****************
b69e6908-a5be0bba-ab4445f 126.76 ****************
Clone 139.43 ******************
Cold Plasma 94.366 ************
Combat Arithmetic 164.78 *********************
Creamed Corn 138.73 ******************
Crimson Climber 119.01 ***************
Crisis 134.50 *****************
[RS] C-Strobia 128.16 *****************
eerie glow 94.366 ************
Free the Fish! 100 *************
Hot Soup 99.295 *************
Just a MEVO Thing 128.87 *****************
Little Bang 136.62 ******************
Little Red Rat 111.97 **************
7_3 135.21 ******************
NanoCracker 140.14 ******************
02_08 110.56 **************
[RS] Nextratulated Sturvi 119.71 ***************
Nonlocality 2 112.67 ***************
Nonlocality 92.957 ************
Quantum Foam 150.70 ********************
Reflow Oven 129.57 *****************
Sleepy Lepus 106.33 **************
Steaming Pebbles 131.69 *****************
SWT2-21 132.39 *****************
SWT2-28 113.38 ***************
Transfer Function 95.070 ************
Unholy Fire 94.366 ************
Benchmark score: 121.26
...etc listings/benchmarks for specified # sequences
-----------------------------------------------------------------------------
MhhuuuuuuqqZuhhMMCMvMMUUUUUWgUUUUEEEEEYUUUEEUUUUUUEEEEEEEEEEEEEEEUUUUEEEEEEEE
MuhhuuuuhhhhhMMMNMvyubMUUUWWuuUUUUEEEUUUUUUeUUUUUUEEEEEEEEEEEIEEEUUUEEOYWWEEE
hhuhuuuuuhBhhhhMMMdvuUUUUuWWWcEYUEEEEUUuUlUUUUUUUEEEEEEEMEEEEEEEEUUEEEWWWWWEE
ouhuVuuuuuuuMOMMUCCCUuUUuueWEWUUMEEEEUUUUUUUnUUUUYEEUEEEEEMEUEUEEUEEEUEWEWEEE
hMhRuuuuhMuuqMUUUCCKCUUUUcucEWMMEEEEEEUUUUUUUUUUEEUUEvMMUMMUMMMMEUEUEEESEEWEE
hMMuuhhuMMMuMMMMMUUuCuuuJuccEUUEqEEUEEEEUxUUUUEUEEUUUUMUUMyUMMMMUEUUEEEWEWEaE
MMMyMMhhMBMMMMMMMqkEuuuKuqEcUEEMEEEUEEEEUUUUUUUEEUEUUUUUUUUMMUMMMUEEEEEzEWEWW
jMMMhMhThMMMMMMMqqqqueuuuEVEUEEiEEEEEUEEUUUUUUUEEEUUENUUUUMUUUUMUUEEEEEWEEEEE
MjMMqhhMMMMMyMqqqqqqRUuJuuEEEEEEEEUUUUUEUUUUUUUUEEEUEUUUAUjUUUUUUUUEEEEWEEEEU
MMMMhMMMMMMMMMMqqqqcUUEuuyEEEEEEEEAUUoEUUUUUUUUUUEEEEUUUUEBBBMMUUuUEUEAEEEEWE
MMEMMMMMMMMqIqMMqqMqqquuEEEEEEEEEEEMUEoUUUUUUUUYEEMEMEEUEEEEMMEEuuuUEEEEEEEEk
MgMMMWMMMMMMMiMMcMWiqqEEEEEEEEEEGEUEEEEoUEEEEUUEEEEMEEEEEEfEMEMEuEuUUuEEEEWEE
MMMMMMMMMMMMMMMMMqqqqqqMMMEEEEEEEEEiEEEEEUUVUUUUUEEEEEkEEppEEMMMuuuiupMMEEEEE
hMhhMMMMMMMqMMMMqcqUVqEEIEEEEEEEEEEEEEEEEaMEEqUEEEEEEEEaEEEEEMMqEEEuMMMEEEEEE
hhhhMMMMMMMSMaMMqqUqEEEEEEEEEEqEEEEEEYEEEEUUEAEEEEEEEEEEEEEEEMMuMMMKuEEEEEEEE
hhhMMMwwMMyWWqqMMqqGqEEEEEEEEEEwEEEEEEEEEUEEEEEEEEEEqEEEEEEEEEIEEMMMuEEEEEEEE
VhhMMMMMMMMMMWqMMqqEEEEEEEEEEEEEwEoEEEEEEEEEEEEEIUUEEEEEEqEEEEEEMMriREEEEEzEE
MhXlMMMMMMMMMqqqqrrqEEqqqEEEEEEwEoEEEVEEEEEEEEEEEiUEEEEEEEEMEMEMMMMMEEEEEEEEE
hMXMMMaMMMMMMqqqqqqEEqEEqEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEiEEEMMEMMMuMMEEEEEEEEE
MMMMMMMMMMMMMMqqqqxiqqqqqEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEaEaMMMMMuuuuuuEEEEEEE
-----------------------------------------------------------------------------
Basically it's now doing something that's similar to what I was
doing manually, and saving a minimal snapshot of the soup state to
avoid missing something without having to save everything every
time. The current version lists the top sequences by population
count, that was fairly easy as the report file was (at that point)
already sorted that way but still involved a bit of trickery - it
reopens the same file it's writing to in read mode to grab the
initial entries, was kind of surprised that it let me do that but
so long as the beginning part of the file is no longer changing
there's no inconsistency. It's temping to code it so that it lists
the top sequences by top score rather than population count but
that would involve a lot more trickery (sorting on another field)
for not much gain since the top scoring warriors are almost always
found in the most populous sequences.
Things that save files - presently the analysis/benchmark report
and the settings file - always add the extension (.txt or .ini)
and default to the specified top directory for file safety
reasons. Modified the code so that it only adds the "top/" part if
no path is specified, previous code added it all the time and
required contortions like "../soup/name" to back out of top to
save to soup dir, now can just say "soup/name" for soup dir or
"./name" for current dir.
One thing that was bugging me was it saved functional duplicates
- warriors with slightly different code (usually a different
instruction modifier) that did exactly the same thing. When
fixed-sequence or permutate benchmarking is used (benchpseq 1 or
2), these can be detected when two warriors get exactly the same
benchmark score against a given test set. This was a bit tricky to
implement since YaBasic's floating point representation is not
necessarily the same as what comes back after printing it to a
file then reading it back, as it is with just about every
programming language that uses binary FP - one of the first
lessons of programming is don't directly compare FP numbers for
equality if they've passed through any process or computation. A=2
... IF A=2 THEN ... is safe but pretty much anything else has a
chance of failing an equality test even when the numbers look
exactly the same. As far as I can tell YaBasic has only one number
type - float - which is fine by me (in other languages I waste a
lot of time with number types), so long as you treat it like
integers with up to 9 digits it acts like integers but once you
get into 10 digit integers or any kind of floating point
representation never assume equality. In this case, 'if wscore=ss'
(wscore is the warrior score, ss is the saved score extracted from
the warinfo file) failed to detect duplicate scores but 'if
str$(wscore)=str$(ss)' worked as str$ (I'm assuming) replicates
what gets printed. In this case anyway, for anything critical the
code should specify an "equality range" - instead of 'if a=b' use
something like 'if abs(a-b)<0.00001'.
Terry Newton (wtn90125@yahoo.com)