######!/bin/bash # Redcode evolver bash script # Requires pmars (compiled with no display) # Docs follow the script code version="1.4a0-nano" # new variables... sleeptime=.03 # sleep time in seconds per iteration minstartsize=1 # minimum number of starting instructions # pmars configuration.... rounds=100 # rounds per battle size=80 # size of CORE processes=80 # max processes cycles=800 # cycles before tie maxsize=5 # max size of warriors pmars="pmars" parms="-b -s $size -p $processes -c $cycles -r $rounds -d $maxsize -l $maxsize" enablefixed=0 # 0=random 1=double fixed fixedoption="-f" deleteiferror=1 # if zero halts, otherwise removes offending code # display/files setup... # For standard display xsize=77, ylines=21, statline=24, warriors=1617. # For 22-line display make ylines=19, statline=22, warriors=1463. wardir="soup80" # directory to put warriors killfile="DeleteMe" # name of stop file tempfile="evolver.tmp" # file to put output of pmars warriors=1617 # max number of warriors fndigits=4 # number of digits in base filename topology=2 # 0=random 1=ring 2=grid xsize=77 # for grid, number of warriors per line (also for display) enableplot=1 # 0=status display 1=ansi-colored soup display ylines=21 # how many warrior lines to display statline=24 # line to show status line on xhome=2 # column to start in from 1 yhome=2 # line to start in from 1 drawframe=1 # 0=no border 1=draw frame around soup display showprevsoup=1 # 0=just start 1=show previous soup first numcolors=15 # number of colors, max 15 startcolor=31 # ANSI color to start with (normally 31) colormethod=2 # 0=color by origin 1=color by size 2=color by species coloroffset=0 # make >0 to shift color assignment # evolver configuration... redcodeline=";redcode" authorline=";author rebs$version" assertline=";assert 1" ninstructions=41 # number of instructions - 4 char fields instructions="spl spl spl spl spl spl spl spl spl spl spl spl" instructions="$instructions mov mov mov mov mov mov mov mov mov mov mov mov" instructions="$instructions djn djn djn djn djn djn dat dat jmz jmz" instructions="$instructions div add mod jmp seq sne mul " nmodifiers=9 # number of modifiers - 3 char fields modifiers="i i i f x a b ab ba " nadrmodes=8 # number of address modes - 2 char fields adrmodes="# @ < > { } $ * " # chances are in proportion to 0-32767 sizechangechance=100 # chance of insertion or deletion duplinechance=1000 # if insertion, chance of duplicate evolved line instchance=100 # chance of instruction change modchance=100 # chance of modifier change mode1chance=150 # chance of adrmode1 change data1chance=200 # chance of data1 change mode2chance=150 # chance of adrmode2 change data2chance=200 # chance of data2 change datatweekchance=15000 # for data, chance of inc/dec rather than random localchance=15000 # for data random, chance of local-sized [-]number endchance=300 # chance of end number change endtweekchance=15000 # chance of end inc/dec rather than random end0chance=15000 # if random end pick chance of end 0 # more display variables... dispchars="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" # chars for warrior display topleftcorner="." # chars for frame toprightcorner="." bottomleftcorner="\`" bottomrightcorner="'" horizontalchar="-" verticalchar="|" # --- end normal setup variables ----------------------------------------- # this determines the format of the code... ilen=3 # length of instruction mlen=2 # length of modifier amlen=1 # length of address mode dlen=4 # length of data ipos=0 # position of instruction mpos=4 # position of modifier # (other pos vars replaced by per-word read) # derive other variables... instdiv=$[32768/$ninstructions+1] moddiv=$[32768/$nmodifiers+1] modediv=$[32768/$nadrmodes+1] filediv=$[32768000/$warriors+1] # scaling by 1000 to improve accuracy datadiv=$[32768000/$size+1] # of file and data selection localdiv=$[32768/$maxsize+1] startsizevariance=$[$maxsize-$minstartsize+1] sizediv=$[32768/$startsizevariance+1] maxwarnum=$[32768000/$filediv] maxdatanumber=$[$size-1] maxnegdata=$[0-$maxsize+1] ndispchars=${#dispchars} # flow continues after functions function getinstruction { # input: $instdiv $instructions # output: random $instruction strpos=$[$RANDOM / $instdiv * 4] instruction="${instructions:$strpos:$ilen}" } function getmodifier { # input: $moddiv $modifiers # output: random $modifier strpos=$[$RANDOM / $moddiv * 3] modifier="${modifiers:$strpos:$mlen}" } function getadrmode { # input: $modediv $adrmodes # output: random $adrmode strpos=$[$RANDOM / $modediv * 2] adrmode="${adrmodes:$strpos:$amlen}" } function getdata { # input: $localchance $maxsize $localdiv $datadiv # output: random $data if [ $RANDOM -lt $localchance ]; then n_tmp=$[$maxsize / 2] s_tmp="$[$RANDOM/$localdiv - $n_tmp] " else s_tmp="$[($RANDOM * 1000)/$datadiv] " fi data="${s_tmp:0:4}" } function fixdata { # input: $data possibly corrupted or nonexistent # output: numeric $data, possibly defaulting to 0 data=${data// /} # remove spaces and data=${data///} # cause syntax error data=$[$data] # force numeric } function modifydata { # input: $data $datatweekchance $size $maxnegdata plus getdata's reqs # output: modified $data if [ $RANDOM -lt $datatweekchance ]; then fixdata # avoid errors from corrupted code if [ $RANDOM -lt 16384 ]; then data=$[$data - 1] else data=$[$data + 1] fi if [ $data -lt $maxnegdata ]; then data=$[$data + $size] fi if [ $data -ge $size ]; then data=$[$data - $size] fi data="$data " data="${data:0:4}" else getdata fi } function makerandomline { # input: # output: $line containing random redcode getinstruction getmodifier getadrmode && adrmode1="$adrmode" getdata && data1="$data" getadrmode && adrmode2="$adrmode" getdata && data2="$data" line="$instruction.$modifier $adrmode1 $data1 , $adrmode2 $data2" } function getendnumber { # input: $end0chance $linecount # output: $endadr from 0 to $linecount-1 if [ $RANDOM -lt $end0chance ]; then endadr=0 else # generate rnd between 1 and $linecount-1 temp1=$[$linecount - 1] if [ $temp1 -le 0 ]; then endadr=0 # length 1 warrior always has end 0 else temp1=$[32768/$temp1 + 1] endadr=$[$RANDOM/$temp1 + 1] fi fi } function printevolvedend { # input: $line containing end line, $endchance $end0chance # $endtweekchance $linecount # output: prints evolved end line to stdout line="$line " data=${line:4:3} # grab end number fixdata # avoid error if end line never read endadr=$data if [ $RANDOM -lt $endchance ]; then if [ $RANDOM -lt $endtweekchance ]; then if [ $RANDOM -lt 16384 ]; then if [ $endadr -gt 0 ]; then endadr=$[$endadr - 1] species=$destname fi else endadr=$[$endadr + 1] # final check catches overflow species=$destname fi else getendnumber fi fi if [ $endadr -ge $linecount ]; then getendnumber species=$destname fi echo "end $endadr" } function printheader { # input: name and parent as parms, $redcodeline $authorline # $assertline $generation $origin # output: prints header to stdout echo "$redcodeline" echo ";name $1" echo "$authorline" echo ";parent $2" echo ";origin $origin" echo ";generation $generation" echo "$assertline" } function readinputline { # work around bash memory leak (with newer versions at least) read -r word1 word2 word3 word4 word5 word6 w7 w8 w9 w10 w11 w12 line="$word1 $word2 $word3 $word4 $word5 $word6 $w7 $w8 $w9 $w10 $w11 $w12" } function readheader { # input: stdin # output: $generation $origin $warriorname # a bit more complex than needed to allow evolving 1.0 warriors # generation defaults to zero # origin defaults to name readinputline readinputline warriorname=$word2 generation=0 origin=$warriorname readinputline readinputline if [ "${line:2:6}" == "arent " ]; then readinputline origin=$word2 readinputline generation=$word2 if [ "$generation" == "" ]; then generation=0 fi readinputline fi } function printrandomwarrior { # input: name as parm, $localdiv $author # output: prints random warrior to stdout generation=0 origin=$1 species=$1 printheader $1 "random" warsize=0 warsize=$[$RANDOM/$sizediv + $minstartsize] linecount=0 while (($linecount < $warsize)); do makerandomline echo "$line" linecount=$[$linecount+1] done getendnumber echo "end $endadr" echo ";species $species" } function evolveline { # input: $word1 to $word6 containing one line of redcode # layout vars - ipos ilen mpos mlen dlen # chance vars for inst mod mode1 data1 mode2 data2 # output: possibly modified $line word1="$word1 " word3="$word3 " word6="$word6 " instruction="${word1:$ipos:$ilen}" modifier="${word1:$mpos:$mlen}" adrmode1="$word2" data1="${word3:0:$dlen}" adrmode2="$word5" data2="${word6:0:$dlen}" if [ $RANDOM -lt $instchance ]; then getinstruction species=$destname fi if [ $RANDOM -lt $modchance ]; then getmodifier fi if [ $RANDOM -lt $mode1chance ]; then getadrmode && adrmode1="$adrmode" fi if [ $RANDOM -lt $data1chance ]; then data="$data1" && modifydata && data1="$data" fi if [ $RANDOM -lt $mode2chance ]; then getadrmode && adrmode2="$adrmode" fi if [ $RANDOM -lt $data2chance ]; then data="$data2" && modifydata && data2="$data" fi line="$instruction.$modifier $adrmode1 $data1 , $adrmode2 $data2" } function evolvewarrior { # input: stdin, name and parent as parm, $maxsize $sizechangechance # output: warrior printed to stdout endofwarrior=0 linecount=0 destname=$1 # in case species changes species="" # default to no species change readheader generation=$[$generation + 1] printheader $1 $2 # replace with new comments while [ $endofwarrior = 0 ]; do readinputline if [ "$word6" == "" ]; then endofwarrior=1 else evolveline if [ $RANDOM -lt $sizechangechance ]; then if [ $RANDOM -lt 16384 ]; then # delete line if [ $linecount -eq 0 ]; then echo "$line" # don't delete 1st to avoid empty linecount=$[$linecount + 1] else species=$destname # new species fi else # add line if [ $linecount -lt $maxsize ]; then echo "$line" # write previous evolved line linecount=$[$linecount + 1] if [ $linecount -lt $maxsize ]; then if [ $RANDOM -lt $duplinechance ]; then evolveline # duplicate evolved line else makerandomline # random line fi echo "$line" linecount=$[$linecount + 1] species=$destname # new species fi fi fi else # no size change, write evolved line if [ $linecount -lt $maxsize ]; then echo "$line" linecount=$[$linecount + 1] fi fi fi done printevolvedend readinputline if [ "$word2" == "" ]; then word2=$origin # default to origin if no species line fi if [ "$species" == "" ]; then species=$word2 fi echo ";species $species" } function grabscores { # input: stdin # output: $score1 $score2 readinputline score1=`echo $line` score1="${score1/scores / }" scorepos=$[${#score1}-5] score1=${score1:$scorepos} readinputline score2=`echo $line` score2="${score2/scores / }" scorepos=$[${#score2}-5] score2=${score2:$scorepos} } function battlewarriors { # input: warrior1 warrior2 as parms, $file1 $file2 $pmars etc # output: $score1 $score2, $pmerror set to 1 if error, 0 if ok # creates random warrior(s) if file(s) don't exist if [ ! -e "$file1" ]; then if [ $enableplot -eq 0 ]; then echo "Creating warrior $1";fi printrandomwarrior $1 > "$file1" fi if [ ! -e "$file2" ]; then if [ $enableplot -eq 0 ]; then echo "Creating warrior $2";fi printrandomwarrior $2 > "$file2" fi # battle the warriors... echo -n "$warnum1 vs $warnum2 " pmerror=0 if [ $enablefixed -eq 0 ]; then # normal random battle, max rounds=3333 $pmars $parms $file1 $file2 1> $tempfile if [ ! $? -eq 0 ]; then pmerror=1 fi grabscores < $tempfile else # double fixed battles, max rounds=1666 $pmars $fixedoption $parms $file1 $file2 1> $tempfile if [ ! $? -eq 0 ]; then pmerror=1 else grabscores < $tempfile total1=$score1 total2=$score2 $pmars $fixedoption $parms $file2 $file1 1> $tempfile grabscores < $tempfile total1=$[$total1+$score2] total2=$[$total2+$score1] score1=" $total1" score2=" $total2" scorepos=$[${#score1}-5] score1=${score1:$scorepos} scorepos=$[${#score2}-5] score2=${score2:$scorepos} fi fi } function getwarriorname { # input: $warnum # output: $warriorname warriorname="000000$warnum" strpos=$[${#warriorname}-$fndigits] warriorname="${warriorname:$strpos}.red" } function picktwofiles { # input: $wardir $filediv $topology $maxwarnum # output: $war1 $war2 $file1 $file2 $warnum1 $warnum2 # war1/2 return filename only, file1/2 return full path # warnum1/2 return filenumber only in string form (0123 etc) warnum=$[($RANDOM * 1000)/$filediv] getwarriorname war1=$warriorname warnum1=${war1:0:$fndigits} if [ $topology -eq 1 ]; then # circular topology if [ $RANDOM -lt 16384 ]; then warnum=$[$warnum-1] if [ $warnum -lt 0 ]; then warnum=$maxwarnum fi else warnum=$[$warnum+1] if [ $warnum -gt $maxwarnum ]; then warnum=0 fi fi getwarriorname war2=$warriorname warnum2=${war2:0:$fndigits} else if [ $topology -eq 2 ]; then # grid-like topology # wrap on sides, no wrap on top/bottom gotit=0 while [ $gotit = 0 ]; do n=$[$RANDOM / 4096] # 0-7 opponent=$[$warnum - 1] if [ $n -eq 1 ]; then opponent=$[$warnum - $xsize - 1] fi if [ $n -eq 2 ]; then opponent=$[$warnum - $xsize] fi if [ $n -eq 3 ]; then opponent=$[$warnum - $xsize + 1] fi if [ $n -eq 4 ]; then opponent=$[$warnum + 1] fi if [ $n -eq 5 ]; then opponent=$[$warnum + $xsize + 1] fi if [ $n -eq 6 ]; then opponent=$[$warnum + $xsize] fi if [ $n -eq 7 ]; then opponent=$[$warnum + $xsize - 1] fi if [ $opponent -ge 0 ]; then if [ $opponent -le $maxwarnum ]; then warnum=$opponent getwarriorname war2=$warriorname warnum2=${war2:0:$fndigits} gotit=1 fi fi done else # random topology war2=$war1 while [ $war1 == $war2 ]; do warnum=$[($RANDOM * 1000)/$filediv] getwarriorname war2=$warriorname warnum2=$warnum done fi fi file1="$wardir/$war1" file2="$wardir/$war2" } function drawframe { # input: $maxwarnum and display variables # output: draws frame xoffset=$[($maxwarnum/($ylines*$xsize) )*($xsize+1)] nframechars=$[$xoffset + $xsize] fxhome=$[$xhome-1] ; fyhome=$[$yhome-1] fxend=$[$xhome+$nframechars] ; fyend=$[$yhome+$ylines] echo -ne "\033[$fyhome;$fxhome""H$topleftcorner" echo -ne "\033[$fyend;$fxhome""H$bottomleftcorner" x=$xhome while (( $x < $fxend )); do echo -ne "\033[$fyhome;$x""H$horizontalchar" echo -ne "\033[$fyend;$x""H$horizontalchar" x=$[$x + 1] done y=$yhome while (( $y < $fyend )); do echo -ne "\033[$y;$fxhome""H$verticalchar" echo -ne "\033[$y;$fxend""H$verticalchar" y=$[$y + 1] done echo -ne "\033[$fyhome;$fxend""H$toprightcorner" echo -ne "\033[$fyend;$fxend""H$bottomrightcorner" } function plotwarrior { # input: $warnum $linecount $origin $species and display vars # output: plots warrior xoffset=$[($warnum/($ylines*$xsize) )*($xsize+1)] xpos=$[($xoffset + $warnum - ( ($warnum/$xsize)*$xsize) ) + $xhome] ypos=$[$warnum/$xsize] ypos=$[($ypos-( ($ypos/$ylines)*$ylines) ) + $yhome] echo -en "\033[$ypos;$xpos""H" # set char position if [ $linecount -ge $ndispchars ]; then char="*" else char="${dispchars:$linecount:1}"; fi if [ $colormethod -eq 1 ]; then color=$linecount # color by length else if [ $colormethod -eq 0 ]; then color="10#${origin:0:$fndigits}" # color by origin else color="10#${species:0:$fndigits}" # color by species fi fi color=$[$color+$coloroffset] color=$[$startcolor+$color-($color/$numcolors)*$numcolors] if [ $color -gt 37 ]; then color=$[$color - 8] color="\033[1;$color""m" else color="\033[0;$color""m" fi echo -en "$color"$char } function getwarfilestats { # input: stdin # output: $origin $linecount $generation readheader linecount=0 endofwarrior=0 while [ $endofwarrior = 0 ]; do readinputline if [ "$word6" == "" ]; then endofwarrior=1 else linecount=$[$linecount + 1] fi done readinputline if [ "$word2" == "" ]; then species=$origin # default to origin if no species line else species=$word2 fi } function plotsoup { # input: $maxwarnum $wardir and display variables # output: draws soup from existing files for ((warnum=0;$warnum<=$maxwarnum;warnum++)); do getwarriorname warfile="$wardir/$warriorname" if [ -e "$warfile" ]; then getwarfilestats < "$warfile" # grab length origin and species if enabled plotwarrior fi done } # end of functions, flow continues... # # -------- initialize -------- # if [ -e $killfile ]; then echo "$killfile exists, remove before running." exit 1 fi mkdir "$wardir" &> /dev/null # make sure soup directory exists echo "Delete this file to stop evolution script" > $killfile nobegin=0;redir=0 if [ "$1" == "-redir" ]; then # rebs -redir > file to record "ansi movie" deleteiferror=0 # always exit if pmars error redir=1 # suppresses printing of extra text fi if [ "$1" == "-append" ]; then # rebs -append >> file to continue recording deleteiferror=0 # always exit if pmars error nobegin=1 # suppresses initial frame/soup display redir=1 # suppresses printing of extra text fi if [ $redir -eq 0 ]; then echo "Redcode Evolver Bash Script version $version" echo "Delete the $killfile file to stop evolution" echo "First two random numbers: $RANDOM $RANDOM" sleep 2 fi if [ $nobegin -eq 0 ]; then if [ $enableplot -ne 0 ]; then echo -ne "\033[0m" ; clear if [ $drawframe -ne 0 ]; then drawframe ; fi if [ $showprevsoup -ne 0 ]; then plotsoup ; fi fi fi # # -------- main loop -------- # stopevolving=0 while [ $stopevolving = 0 ]; do if [ ! -e $killfile ]; then if [ $enableplot -ne 0 ]; then echo -e "\033[$statline;1H\033[0m" fi stopevolving=1 else if [ $enableplot -ne 0 ]; then echo -en "\033[$statline;1H\033[0m" # position stat line, no color fi picktwofiles battlewarriors $war1 $war2 if [ $pmerror -eq 0 ]; then echo -n "$score1$score2 " if [ $score1 -lt $score2 ]; then echo -n "$warnum2->$warnum1" evolvewarrior $war1 $war2 < "$file2" > "$file1" warnum=10#${war1:0:$fndigits} else echo -n "$warnum1->$warnum2" evolvewarrior $war2 $war1 < "$file1" > "$file2" warnum=10#${war2:0:$fndigits} fi linecount="$linecount " echo -n " O:${origin:0:$fndigits} S:${species:0:$fndigits}" echo -n " L:${linecount:0:3} G:$generation " if [ ! "$sleeptime" == "" ]; then # only sleep if sleeptime defined sleep $sleeptime # otherwise run flat-out 100% CPU fi if [ $enableplot -ne 0 ]; then plotwarrior else echo fi else echo "**********************" echo "** Error in redcode **" echo "**********************" if [ ! $deleteiferror -eq 0 ]; then echo "Deleting $war1 and $war2" rm "$file1" rm "$file2" sleep 2 if [ $enableplot -ne 0 ]; then echo -ne "\033[0m" ; clear if [ $drawframe -ne 0 ]; then drawframe ; fi if [ $showprevsoup -ne 0 ]; then plotsoup ; fi fi else stopevolving=1 fi fi fi done if [ -e $tempfile ]; then rm $tempfile ; fi exit 0 # # This is the "nano" version of REBS, set to generate warriors for coresize # 80 with a maximum warrior size of 5. Default soup directory is "soup80". # # Usage notes... # # This script evolves redcode warriors for the game of Corewar. The interface # is simple: delete the DeleteMe file in the current directory to make it stop. # Don't stop by any other means or corrupted redcode may be left in the soup. # Edit the script to change filenames, number of files and other variables. # # When run it creates a directory for the warriors then runs # the following steps until terminated: # # pick two files # if either file doesn't exist, create random warrior(s) # battle the two warriors using pmars # copy the winner over the loser while making random changes # # It's a little more complicated than that but that's the general idea. # How the files are picked determines topology, topology=0 for random # pick, topology=1 to increment/decrement the warrior number (50/50 chance) # with wraparound to form a circle of warriors, topology=2 for a grid # of warriors with wraparound on the sides, no wrap from top/bottom. # In the event of a tie battle, the first selected warrior wins. # Instruction, modifier and address mode weighting is done using # duplicate entries in the array strings, numbers are either large # positive numbers or if $RANDOM is less than localchance, then a small # offset usually within the range of the warrior code. The end line # has either a number from 1 to warrior size (at time of creation), # or if $RANDOM is less than end0chance, end 0 to start the warrior # from the beginning. The end number is evolved according to endchance, # endtweekchance determines the likelyhood of an inc/dec rather than rnd. # During the copy process code lines are changed according to chance vars, # instchance controls how often the instruction changes (for each line), # modchance controls how often the modifier changes, etc. For data fields, # datatweekchance controls how often the change is inc/dec rather than rnd. # The sizechangechance var controls frequency of insertion or deletion # (50/50 odds to avoid size bias), if inserting then duplinechance determines # the likelyhood of an evolved duplicate line rather than an all-random line. # All chance variables are relative to 32767 max, the change is triggered # when $RANDOM is less than the number. n>32767 always triggers, n<1 disables. # For ex. if endchance=328 changes the end number changes roughly 1 out of 10 # evolves, if sizechangechance=328 then *each line* has a 1 in 10 chance of # being deleted or a new line being inserted. The odds are applied to every # occurence of the object, if data1chance=328 for 1 in 10 odds per object, # a 10-line warrior will have a 50/50 chance of at least one data1 change. # # The standard pmars program, compiled without graphics, is used to evaluate # the warriors to determine which warrior to evolve. I'm using version 0.8.6. # If pmars isn't in a path directory, specify full name in pmars var at the # beginning of the script. Make sure wardir and killfile don't conflict with # existing files/directories. Adjust rounds and number of warriors as needed. # If enablefixed=0 max rounds is 3333, with enablefixed=1 max rounds is 1666. # # REBS has an ANSI soup display enabled by default, make enableplot=0 to # disable. When continuing a run it scans and plots the existing soup unless # disabled by making showprevsoup=0. Width is automatic, derived from xsize # and how many warriors are specified. Normally for grids, set ylines to # warriors divided by xsize (or make warriors xsize times ylines), if ylines # isn't big enough to contain all the lines then columns are displayed. # Make statline equal to ylines plus 3 to place underneath the soup. # For standard display xsize=77, ylines=21, statline=24, warriors=1617. # For 22-line display make ylines=19, statline=22, warriors=1463. # # Command line redirection options... # -redir as 1st parm to suppress printing of extra text, for use when # redirecting the screen output to record an ANSI "movie" file. # Usage: rebs -redir > file & # -append as the 1st parm to additionally suppress the clearscreen and # initial frame/soup display, for use when continuing an ANSI recording. # Usage: rebs -append >> file & # rm -f DeleteMe to stop rebs, cat file to play back the ANSI file. # Caution: redirecting makes huge files, get right before attempting. # # REBS processor usage is fairly high by default, increase the sleeptime # variable at the beginning of the script to use less CPU time. If your # sleep command only supports integer seconds change to 0 or 1 etc. # For flat out speed comment the sleeptime variable (or set to ""). # # Don't run REBS on a solid-state (flash) disk! Set up a ramdisk and run it # from there. If OS writes last access info it also will write for every read, # putting options,noatime in fstab can fix that. Monitor disk writes to make # sure writes don't occur, perhaps using iostat from the sysstat package. # # Bugs/features that I know about... # # Every run is different and results are generally not repeatable, don't # judge the worthiness of parameters based on only a few runs. If nothing # interesting is happening after a few hundred generations, start a new run. # I usually do a few runs and take the best from each run and put in an empty # soup to evolve further, take the best from that to add to my selects, # repeat until I can't get the scores any higher then contemplate what I # need to do to the parameters (or REBS) to try to generate stronger code. # # There is no error-checking of the parameter variables, if not correct and # consistent REBS will hang, generate error messages or bad code or otherwise # won't work. For example warriors must equal xsize * ylines, minstartsize # must be less than or equal maxsize, ninstructions, nmodifiers, nadrmodes # must be equal to (or less than) the number of fields in the corresponding # strings, when modifying the strings make sure the formatting is preserved. # Always run REBS in its own directory and never run it as root. # # New random warriors are not displayed, only the evolved winner is plotted. # Many because doing a plot at that point would disrupt the status display. # # REBS might trigger a memory leak when running in older versions of bash, # especially noticeable when evolving nano-size warriors due to the high rate # of evolution. Monitor memory usage, if leaking periodically stop and restart # to reclaim memory. Need to stop after a few hundred generations anyway to # check the soup warriors, if run for too long warriors tend to get weaker. # # Don't run multiple instances of REBS, even if the DeleteMe and tempfile # names are changed for some reason multiple instances of pmars get confused # and (apparently) cause it to occasionally not output a score. # # If copying this script from a web display to run under Linux make sure # it's converted to "unix" format (dos2unix, flip, etc) and has executable # permissions. To run under Windows use Cygwin (http://www.cygwin.com/) # with a Windows-compatible pmars in a path directory. Recommend associating # *.red to edit for viewing/editing, notepad doesn't like unix-format files # (there may be Cygwin settings to make it generate dos-format warriors). # # Changes... # 2/6/09 1.4a0-xxxx (xxxx=nano, tiny or standard) # The "0" in the version is to indicate parameter changes. # Added minstartsize variable, fixed data format when changing data, # changed grabscores code and added more word vars to readinputline in # case it's later used to test warriors against an external test set, # changed big number scaling to * 1000 for better accuracy, # other minor fixes and edits. # 1/21/09 1.4exp3-nano added condition so sleeptime can be commented # modified readheader to better adapt to new readinputline function # added species tracking and comment, any change to base instruction, # length or end line changes species (defaults to origin if not present) # added new plot option to color by species, indicating major mutations # shortened status display line, added species indicator # replaced things like ${var1:var2:var3} with ${var1:$var2:$var3} # (no reason other than consistency and so gedit will colorize correctly) # messed with fixdata, still ugly but more resistant to invalid numbers # if pmars error occurs redraws soup if plot enabled # 1/19/09 1.4exp1-nano added sleeptime setting, workaround for memory leak # Bash read command does not release memory when reading redirected files. # Partially fixed in newer bash version (3.2.39 here) but still leaks if # line contains spaces. To work around reads into multiple words instead... # added readinputline function that reads word1-word9, combines for line # (line var now has extra spaces if less than 9 words, multiple spaces lost) # replaced all read -r line with call to readinputline # modified evolveline to parse from word1-word6 rather than from line # modified evolvewarrior and getwarstats to check for empty word 6 to # detect end of redcode rather than line length not equal constant # rewrote grabscores to use readinputline/word5 (name must be one word) # modified main loop display to compensate for altered score format # warrior format is slightly different - data is now left-justified # A side-effect of the mod is it isn't quite as sensitive now to redcode # formatting but warriors must begin with 7 comments and have an end line. # 4/9/05 1.3f added -redir and -append command line options # 4/9/05 1.3e added coloroffset variable, different parms # 4/7/05 1.3d scaled $RANDOM to cover entire file/data range, parms # 4/7/05 1.3c fixed display bugs, different parms, rearranged code/vars # 4/3/05 1.3b color by origin or length # 4/2/05 1.3a added/rearranged code to display existing soup at startup # added color variables to colorize soup in different ways # 3/28/05 1.3 removed seed stuff, read -t fails on Cygwin 1.1/bash 2.04 # New experimental soup display - shows length and colors by species, for # small xsize displays soup as multiple columns, ylines determines number # of screen lines, width determined by number of files in soup. Status # line shows current battle on the left of cursor blob, results of the # *last* battle shown after [first] cursor. # 3/26/05 1.2b altered RNG seed method, different parms # 3/24/05 1.2a fixed size bug again, randomizes end if out of range # 3/23/05 1.2 double fixed battles, grid topology, data/end tweeks # 3/19/05 1.1 added line topology and generation/parent/origin comments # 3/12/05 1.0f ok let's try that again (still has size bugs though) # 3/12/05 1.0e added check to prevent warrior from growing too big # 3/11/05 1.0d eliminated grep usage, simplified end number processing # 3/11/05 1.0c fixed picktwofiles, eliminated head/tail string processing # 3/10/05 1.0b more instructions, neater status display, code tweeks # 3/9/05 1.0a changed pmars redirect to 1> for Cygwin compatibility # 3/7/05 1.0 initial version # # Copyright Terry Newton under the terms of the GNU Public License (GPL) # Send comments, bugs reports or questions to wtn90125 at yahoo.com. # Evolution page: http://www.infionline.net/~wtnewton/corewar/evol/ # Other stuff at: http://newton.freehostia.com/cw/ #