Code
--[[
Bands! Bands in space!
GAB - Genetic Algorythm on Bands
by Rav3n_pl
based on CartoonVillan and Crashguard303 scripts
Lua V2
Definitions:
band: random band to space from random segment
critter: set of bands
herd: set of critters
1.
- randomize needed bands
- randomly assigning them to criters
2.
- score each critter
3.
- keep critters scoring above score
- breed best critters
- breed bastards (best one + random one)
- forget about rest of critter
- randomize new critters to fill herd
porky added the filter management
BK added more filters on recentbest and save
ver 2.02 Filter
--debugged line 239
ver 2.03
--debugged filter
ver 2.04
--debuggeg monomer
ver 2.05
-- just update the commands Get/SetFiltersDisabled
ver 2.06
-- debugged generic filter & second dialog
ver 2.1
-- second dialog with sliders (no text box). This reduces the range available
but it's also more convenient and it avoids user errors
ver 2.1.1 Generic filter only after dialog to save time at start
ver 2.1.2 Check conditions option on exploration puzzles
ver 2.1.3 debugged conditions
ver 2.2.0 added Jeff101's display on each loop, and archive in note by pauldunn
keep user bands
FILTERMANAGE activated (disable filter during wiggle)
ver 2.2.1 bug fixed in loop_count
ver 2.2.2 added quickshake
ver 2.2.3 undo.SetUndo
ver 2.2.4 fixed possible unideal loop bug
]]--
recipename= "Rav3n_pl GAB BIS Filter 2.2.4"
p=print
userbands=band.GetCount()
p("Starting "..recipename.. " on\n puzzle "..(puzzle.GetName()))
p(' with puzzle ID '..(puzzle.GetPuzzleID())..' and '..userbands..' user-supplied bands.\n ')
ssstr="" -- jeff101
gen=0
--SLOTS:
--[[
3 is best
4 used in recipe
5 used in recipe
50-100 used to record each big steps for movie at the end
]]--
SlotStepStart=50 -- New for SaveBigSteps()
SlotStep=SlotStepStart
--START Generic Filter Management by BitSpawn 21/12/2014
--Source: http://fold.it/portal/node/1998917
--identifying filtered puzzles and all properties by Bruno Kestemont 15/2/2015
undo.SetUndo(false)
OriginalFilterSetting = behavior.GetFiltersDisabled()
PROBABLEFILTER= false
GENERICFILTER=false
FILTERMANAGE= false
HASMUTABLE= false
IDEALCHECK= false
PROBABLESYM= false
SEPSIS= false
ELECTRON= false
CENTROID= false
HOTSPOT= false
EXPLORATION= false
conditions=false
sym=1
-- Handy shorts module
segCnt=structure.GetCount()
segCnt2=segCnt
while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2=segCnt2-1 end -- not used yet (ligand)
function detectfilterandmut() -- new BK 10/10/2013; 13/2/2015 from old Puzzleprop
local descrTxt=puzzle.GetDescription()
local puzzletitle=puzzle.GetName()
if #descrTxt>0 and (descrTxt:find("filter") or descrTxt:find("filters")) then
PROBABLEFILTER=true
FILTERMANAGE=true -- Default yes during wiggle (will always be activate when scoring)
GENERICFILTER=false
end
if #descrTxt>0 and (descrTxt:find("design") or descrTxt:find("designs")) then
HASMUTABLE=true
IDEALCHECK=true
end
if #descrTxt>0 and (descrTxt:find("De-novo") or descrTxt:find("de-novo") or descrTxt:find("freestyle")
or descrTxt:find("prediction") or descrTxt:find("predictions")) then
IDEALCHECK=true
end
if #descrTxt>0 and (descrTxt:find("Exploration") or descrTxt:find("exploration")
or descrTxt:find("far from the starting conformation"))
or not current.GetExplorationMultiplier() == 0
then
EXPLORATION=true
print("Exploration puzzle. Using energy score")
energy=true
end
if #puzzletitle>0 then
if (puzzletitle:find("Sym") or puzzletitle:find("Symmetry") or puzzletitle:find("Symmetric")
or puzzletitle:find("Dimer") or puzzletitle:find("Trimer") or puzzletitle:find("Tetramer")
or puzzletitle:find("Pentamer")) then
PROBABLESYM=true
if puzzletitle:find("Dimer") and not puzzletitle:find("Dimer of Dimers") then sym=2
elseif puzzletitle:find("Trimer") or puzzletitle:find("trimer") then sym=3
elseif puzzletitle:find("Dimer of Dimers") or puzzletitle:find("Tetramer") then sym=4
elseif puzzletitle:find("Pentamer") then sym=5
else sym=6
end
end
end
if #descrTxt>0 and (descrTxt:find("Sym") or descrTxt:find("Symmetry") or descrTxt:find("Symmetric")
or descrTxt:find("sym") or descrTxt:find("symmetry") or descrTxt:find("symmetric")) then
PROBABLESYM=true
if (descrTxt:find("Dimer") or descrTxt:find("dimer"))
and not (descrTxt:find("Dimer of Dimers") or descrTxt:find("dimer of dimers")) then sym=2
elseif descrTxt:find("Trimer") or descrTxt:find("trimer") then sym=3
elseif (descrTxt:find("Dimer of Dimers") or descrTxt:find("Tetramer"))
and not (descrTxt:find("dimer of dimers") or descrTxt:find("tetramer"))then sym=4
elseif descrTxt:find("Pentamer") or descrTxt:find("pentamer") then sym=5
end
end
--print resulting sym info
if PROBABLESYM then
print("Symmetric")
if sym==2 then
print("Dimer")
elseif sym==3 then
print("Trimer")
elseif sym==4 then
print("Tetramer")
elseif sym==5 then
print("Pentamer")
elseif sym>5 then
print("Terrible polymer")
end
else print("Monomer")
end
if #puzzletitle>0 and puzzletitle:find("Sepsis") then -- new BK 17/6/2013
SEPSIS=true
--p(true,"-Sepsis")
print("Sepsis")
end
if #puzzletitle>0 and puzzletitle:find("Electron Density") then -- for Electron Density
--p(true,"-Electron Density")
ELECTRON=true
print("Electron density")
end
if #puzzletitle>0 and puzzletitle:find("Centroid") then -- New BK 20/10/2013
--p(true,"-Centroid")
CENTROID=true
print("Centroid")
end
if #puzzletitle>0 and puzzletitle:find("Hotspot") then -- New BK 21/01/2014
HOTSPOT=true
print("Hotspot")
end
return
end
detectfilterandmut()
-- function to copy class/table
function CopyTable(orig)
local copy = {}
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
return copy
end
-- functions for filters
function FiltersOn()
if behavior.GetFiltersDisabled() then
behavior.SetFiltersDisabled(false)
end
end
function FiltersOff()
if behavior.GetFiltersDisabled()==false then
behavior.SetFiltersDisabled(true)
end
end
-- function to overload a funtion
function mutFunction(func)
local currentfunc = func
local function mutate(func, newfunc)
local lastfunc = currentfunc
currentfunc = function(...) return newfunc(lastfunc, ...) end
end
local wrapper = function(...) return currentfunc(...) end
return wrapper, mutate
end
-- function to overload a class
-- to do: set the name of function
classes_copied = 0
myclcp = {}
function MutClass(cl, filters)
classes_copied = classes_copied+1
myclcp[classes_copied] = CopyTable(cl)
local mycl =myclcp[classes_copied]
for orig_key, orig_value in pairs(cl) do
myfunc, mutate = mutFunction(mycl[orig_key])
if filters==true then
mutate(myfunc, function(...)
FiltersOn()
if table.getn(arg)>1 then
-- first arg is self (function pointer), we pack from second argument
local arguments = {}
for i=2,table.getn(arg) do
arguments[i-1]=arg[i]
end
return mycl[orig_key](unpack(arguments))
else
--print("No arguments")
return mycl[orig_key]()
end
end)
cl[orig_key] = myfunc
else
mutate(myfunc, function(...)
FiltersOff()
if table.getn(arg)>1 then
local arguments = {}
for i=2, table.getn(arg) do
arguments[i-1]=arg[i]
end
return mycl[orig_key](unpack(arguments))
else
return mycl[orig_key]()
end
end)
cl[orig_key] = myfunc
end
end
end
-- how to use:
--setting default options if filters BK 4/2/2015
--MutClass(structure, false)
--MutClass(band, false)
--MutClass(current, true)
function GenericFilterMngt()
if GENERICFILTER then -- WARNING: TO VERIFY !! (may be it's irreversible for several funtions bellow)
MutClass(structure, false)
MutClass(band, true) -- must be true to avoid unideal loop bug
MutClass(current, true)
MutClass(recentbest, true) -- otherwise, it remembers cut solutions
MutClass(save, true) -- better to save with full score
end
end
--STOP Generic Filter Management
--START SET NOTES BY PD
--[[ Set note with author, recipe and big steps -- By Pauldunn
This subroutine is used in much group recipe versions in various groups
originally in Go Science
It traces the various recipes and players that improved the current solution
Module to quick copy-paste it in existing recipes, by Bruno Kestemont
]]--
--HOW TO include in a recipe?
--1a) COPY from here ================
function InitNotes(recipename)
local recipename=recipename or ""
note_number=structure.GetCount()
for seg=structure.GetCount(),1,-1 do
if structure.GetNote(seg)~="" then break end
note_number=seg
end
print(string.format("Recording "..recipename.." results in Note for segment %i",note_number))
starting_score=current.GetScore()
--structure.SetNote(note_number,string.format("(%s) %.3f + %s(%i) %.3f",user.GetPlayerName(),starting_score,recipename,loop_count,current.GetScore()))
end
function SetNote(note_number, starting_score, recipename, loop_count)
local recipename=recipename or ""
local starting_score=starting_score or 0
local loop_count=loop_count or 1
--print(string.format("Recording "..recipename.." results in Note for segment %i",note_number))
structure.SetNote(note_number,string.format("(%s) %.3f + %s(%i) %.3f",user.GetPlayerName(),starting_score,recipename,loop_count,current.GetScore()))
end
InitNotes(recipename) -- WARNING: and match "recipename" with the recipename of the recipe
--1b) COPY to here. ================
-- options:
energy=false --set true to seek energy in exploration puzzles; false works on all puzzles
pullCI=0.9 --Clash Impotrance during pull
shakeCI=0.21 --CI when shake on qstab or mutate once
maxCI=1 --maximum CI used by script
fastQstab=true -- only 1s1w after pull if true
fuzeThresh = 1 -- run fuze if we are close to best score (negative=new best score)
qstabThresh=1 -- run qstab if score drops more than... wiggle only in other case
onlyMutable=true --if true use ONLY all mutable aas, no matter of always use
mutateOnce=true --if true use mutate(1) instead of shake in qstab
mutateAlwas=false --if true use muatate(1) instead of all shakes
herd= --herd options
{
breedBest = 5, --breed best 4 critters - all combinations => 6 kids form 4 critters, 3 form 3, 1 form 2, 9 form 5 ;]
keepBest = 3, --save up to 3 best scoring critters, rest are forgotten
breedBastards = 8, --number of best will have one random bastard
newRandom = 10, --adding new random ones each generation
maxGen= 1000, --maximum generations
shuffle = true, --set true to run critters in random order
renew=4, --create totally fresh herd after that many gens w/o improvement
}
critter= --critter options
{
minBands=3, --minimum bands
maxBands=7, --maximum bands
keepScore = 0 , --survive to next gen only if score higher than
breedScore=-20, --will breed kids only if score higher. Basttards always breed
maxLoss=30, --maximum loss by critter. set 0 to disable
}
bands= --bands options
{
minStr=0.3, --minimum band str
maxStr=1.1, --maximum band str
maxUp = 12.1, -- maximum band lenght
minUp = 0.1 -- debugging case=0
}
DoNotUse={--just comment lines below or add more areas to avoid
--{segCnt,segCnt}, --ligand cant be used
--{120,134},
--{1,10},
}
AlwaysUse={ --areas should be always used
--{238,238}--ligand need to be at one end
--{308,311}, --loopy
--{272,319}, --loopy
}
UseSegments= --use ONLY this segments
{
--2,3,4,5
}
-- bands by secondary structure
use=
{
Sheet=true, --set false to not band sheets
Helix=true, --set false to not band helices
Loop=true, --set false to not band loops
}
--end of options
--START quick save algorithm
function QuickShake()
--[[------------------------------------------------------------------------------------------------
-- Algorithm for faster shake
REFERENCES
1. N/A
Copyright (C) 2014 Seagat2011 <http://fold.it/port/user/1992490>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
$Id$
------------------------------------------------------------------------------------------------]]--
--[[
v1
- Inception
1.2
- Loops until nogain
]]--
local idx = 1
local idx2 = structure.GetCount ()
local hash = {}
local cs = current.GetScore ()
--print ( 'Quick Shake Algorithm v1.2 SG2011 - Current Score: '..cs )
local function New ( obj )
return obj -- pass-new-obj-by-value
end
local _gses = New ( current.GetSegmentEnergySubscore )
local function SmartShake ( iters )
local gain = true
while (gain) do
gain = false
for i=idx,idx2 do
local ci = _gses ( i,'clashing' )
if ci < _gses ( i,'hiding' ) and
ci < _gses ( i,'packing' ) and
ci < _gses ( i,'ideality' ) and
ci < _gses ( i,'sidechain') and
ci < _gses ( i,'bonding' ) and
ci < _gses ( i,'other' ) and
ci < _gses ( i,'reference') then
selection.Select ( i )
end -- test ci --
end -- loop --
if selection.GetCount () then
local css = current.GetScore ()
structure.ShakeSidechainsSelected ( iters )
selection.DeselectAll ()
if current.GetScore () > css then
gain = true
end -- test --
end -- test --
end -- loopf --
end
structure.SmartShake = SmartShake
structure.SmartShake ( 1 )
--print ( 'Done.' )
end
--END quick save algorithm
function CI(c)
if c>maxCI then c=maxCI end
behavior.SetClashImportance(c)
end
function round(x)--cut all afer 3-rd place
return x-x%0.001
end
function down(x)
return x-x%1
end
function Score()--return score, exploration too
if energy==true then
return current.GetEnergyScore()
else
return current.GetScore()
end
end
--local seed=recipe.GetRandomSeed() --NOT WORKING!!!
--calculate REALLY good seed
seed=os.time()/math.abs(Score())
seed=seed%0.001
seed=1/seed
while seed<10000000 do seed=seed*1000 end
seed=seed-seed%1
p("Seed is: "..seed)
math.randomseed(seed)
--REALLY good seed made by rav3n_pl :P
--[[ original Wiggle
function Wiggle(how, iters, minppi)
if how==nil then how="wa" end
if iters==nil then iters=3 end
if minppi==nil then minppi=0.3 end
if iters>0 then
iters=iters-1
sp=Score()
if how == "s" then
if mutateAlwas==true then structure.MutateSidechainsSelected(1)
else structure.ShakeSidechainsSelected(1) end
elseif how == "wb" then structure.WiggleAll(25, true,false)
elseif how == "ws" then structure.WiggleAll(25, false,true)
elseif how == "wa" then structure.WiggleAll(25, true,true)
end
ep = Score()
ig=ep-sp
if how~="s" then
if ig > minppi then return Wiggle(how, iters, minppi) end --tail call
end
end
end
]]--
function Wiggle(how, iters, minppi) -- NEW one, with filter management, 17/4/2016
if FILTERMANAGE then behavior.SetSlowFiltersDisabled(true) end-- new BK 8/4/2013, always disable filter here
if how==nil then how="wa" end
if iters==nil then iters=6 end
if minppi==nil then minppi=0.1 end
if iters>0 then
iters=iters-1
sp=Score()
if how == "s" then
if FILTERMANAGE then behavior.SetSlowFiltersDisabled(OriginalFilterSetting) end -- new BK 8/4/2013, always back to user settings
if mutateAlwas==true then structure.MutateSidechainsSelected(1)
--else structure.ShakeSidechainsSelected(1) end
else QuickShake() end
elseif how == "wb" then structure.WiggleAll(2, true,false)
elseif how == "ws" then structure.WiggleAll(2, false,true)
elseif how == "wa" then structure.WiggleAll(2)
end
ep = Score()
ig=ep-sp
if how~="s" then
if ig > minppi then return Wiggle(how, iters, minppi) end --tail call
end
end
if FILTERMANAGE then behavior.SetSlowFiltersDisabled(OriginalFilterSetting) end -- new BK 10/10/2013, always back to user settings
end
function SaveBest()
local g=Score()-bestScore
if not (conditions and not current.AreConditionsMet) then
if g>0 then
if g>0.01 then p("Gained another "..round(g).." pts.") end
bestScore=Score()
save.Quicksave(3)
end
else
print("Conditions not met. Returning to former solution") -- for DEBUG
end
end
function SaveRB()
if recentbest.GetScore()>bestScore or (recentbest.GetEnergyScore()>bestScore and energy==true)then
if not (conditions and not current.AreConditionsMet) then
save.Quicksave(4)
recentbest.Restore()
SaveBest()
save.Quickload(4)
end
end
end
function Qstab()
selection.SelectAll()
CI(shakeCI)
if mutateOnce==true then
structure.MutateSidechainsSelected(1)
else
Wiggle("s",1)
end
if fastQstab==false then
CI(0.4)
Wiggle("wa",1)
CI(1)
Wiggle("s",1)
end
CI(1)
Wiggle()
end
function FuzeEnd()
CI(1)
Wiggle("wa",1)
Wiggle("s",1)
Wiggle()
srb()
end
function Fuze1(ci1,ci2)
CI(ci1)
Wiggle("s",1)
CI(ci2)
Wiggle("wa",1)
end
function Fuze2(ci1,ci2)
CI(ci1)
Wiggle("wa",1)
CI(1)
Wiggle("wa",1)
CI(ci2)
Wiggle("wa",1)
end
function srb()
recentbest.Restore()
SaveBest()
end
function Fuze()
p("Fuzing...")
local scr=Score()
selection.SelectAll()
recentbest.Save()
Fuze1(0.3,0.6) FuzeEnd()
Fuze2(0.3,1) srb()
Fuze1(0.05,1) srb()
Fuze2(0.7,0.5) FuzeEnd()
Fuze1(0.07,1)
srb()
end
function random(n1,n2) --random function returns int or float depends on input vars
if n1==nil then return math.random()
else
if n2==nil then
if n1%1==0 then
return math.random(n1) --integer
else
return math.random()*n1 --float
end
else
if n1%1==0 and n2%1==0 then
return math.random(n1,n2) --integer between
else
return math.random()*(n2-n1)+n1 --float between
end
end
end
end
function FillHerd() --fill up herd
local n=#critters
if n>0 then --fill up
n=herd.newRandom
else --fresh herd
n=herd.breedBest + herd.keepBest + herd.breedBastards
end
p("Randomizing "..n.." new critters...")
for i=1,n do
AddCritter()
end
end
function AddCritter() --vreate new random critter
local c={}
critterID=critterID+1
c.no=critterID
c.name=c.no..'-rnd'
c.bands={}
local r=random(critter.minBands, critter.maxBands)
for i=1,r do
c.bands[#c.bands+1]=AddBand()
end
critters[#critters+1]=c
p(c.name.." bands: "..#c.bands)
end
function AddBand() --create one random band
local cnt=0
local b={}
while true do --try till die
cnt=cnt+1
local s1=random(segCnt)
if onlyMutable==true or #UseSegments>0 then
s1=UseSegments[random(#UseSegments)]
end
if #UseSegments>0 or CanBeUsed(s1) then
local str=random(bands.minStr,bands.maxStr)
local length=random(bands.minUp,bands.maxUp) --debugged BK 15/2/2015, length cannot be 0
local theta = math.acos(math.random())
local phi = 2 * math.pi * math.random()
local segmentXAxis=0
local segmentYAxis=0
while true do --all 3 must be different
segmentXAxis = random(segCnt)
segmentYAxis = random(segCnt)
if segmentXAxis~=s1 and segmentYAxis~=s1 and segmentXAxis~=segmentYAxis then break end
end
--{segmentOrigin, segmentXAxis, segmentYAxis, rho, theta, phi}
b={s1, segmentXAxis, segmentYAxis, length, theta, phi, str}
break
end
if cnt>100 then
p("Sorry! Cant create band! Breaking script!")
BreakScript() --there is no such function, so it crashes script
end
end
return b
end
function deletebands() --leave user bands intact
nbands=band.GetCount()
if nbands>userbands then
for i=nbands,userbands+1,-1 do -- count down from nbands to userbands+1
band.Delete(i)
end -- for i
end -- if nbands
end -- function
function CanBeUsed(sg1) --checking end of bands
function ssCheck(ss)
local good=false
if use.Sheet and ss=="E" then good=true end
if use.Helix and ss=="H" then good=true end
if use.Loop and ss=="L" then good=true end
return good
end
local ok=true
if #DoNotUse>0 then --none of 2 can be in that area
for i=1, #DoNotUse do
local r=DoNotUse[i] -- r={from,to}
for x=r[1],r[2] do
if x==sg1 then
ok=false
break
end
end
if ok==false then break end
end
end
if ok==false then
return false --if false can`t be used
else
ok=false
if #AlwaysUse>0 then --at least one have to be there
for i=1, #AlwaysUse do
local r=AlwaysUse[i]
for x=r[1],r[2] do
if x==sg1 then
ok=true
break
end
end
if ok==true then break end
end
else
ok=true
end
end
if ok==true then --check structure
ok=false
if ssCheck(structure.GetSecondaryStructure(sg1)) then ok=true end
end
return ok
end
function ScoreHerd() --score all critters from herd
save.Quickload(3)
p("Scoring "..#critters.." critters...")
save.Quicksave(5)
local herdScore=Score()
for i=1,#critters do
--band.DeleteAll()
deletebands()
local crt=critters[i] --critter
local s=Score() --start score
local bnds=crt.bands
for b=1,#bnds do
local bnd=bnds[b]
local atom=5
local sn=bnd[1]
if sn==segCnt then atom=6 end --bug in last segment
if structure.GetAminoAcid(sn)=='g' then atom=0 end --glycyne
band.Add(sn,bnd[2],bnd[3],bnd[4],bnd[5],bnd[6],atom)
local bc=band.GetCount()
band.SetStrength(bc,bnd[7])
end
selection.SelectAll()
CI(pullCI)
recentbest.Save()
Wiggle("wb",1)
--band.DeleteAll()
deletebands()
CI(1)
if s-Score() > qstabThresh then
Qstab()
else
Wiggle()
end
if Score()-bestScore>fuzeThresh then
SaveRB()
Fuze()
else
SaveRB()
end
crt.score=Score()-s
p("Critter "..crt.name.." : "..round(crt.score))
if critter.maxLoss>0 then
if Score()>herdScore-critter.maxLoss then
save.Quicksave(5)
herdScore=Score()
else
save.Quickload(5)
end
else
save.Quickload(3)
end
end
save.Quickload(3)
if band.GetCount()>0 then --clean bands from best solution (if any)
--band.DeleteAll()
deletebands()
save.Quicksave(3)
end
end
function BreedCritters(mom,dad,t) --breed 2 critters. bands are taken randomly
local kid={}
critterID=critterID+1
kid.no=critterID
kid.name=kid.no.."-"..t..mom.no..'/'..dad.no
kid.bands={}
local mb=#mom.bands
local db=#dad.bands
if mb>db then mb,db=db,mb end --kid have bands count between mom and dad bands
local bn=random(mb,db)
for i=1,bn,2 do
kid.bands[#kid.bands+1]=mom.bands[random(#mom.bands)]
kid.bands[#kid.bands+1]=dad.bands[random(#dad.bands)]
end
p(kid.name.." bands: "..#kid.bands)
return kid
end
function KeepGood() --copy best scoring critters form last gen if score above
local newHerd={}
for i=1,herd.keepBest do
if critters[i].score>critter.keepScore then
newHerd[#newHerd+1]=critters[i]
end
end
return newHerd
end
function SortCritters() --bubble sort
for i=1,#critters do
for j=i+1,#critters do
if critters[i].score<critters[j].score then
critters[i],critters[j]=critters[j],critters[i] --love lua :)
end
end
end
end
function BreedHerd()
p("Breeding...")
SortCritters()
newHerd=KeepGood()
for i=1, herd.breedBest do
local mom=critters[i]
if mom.score>critter.breedScore or i<2 then --breed only good ones, 1st is always breed anyway
for j=i+1, herd.breedBest do
local dad=critters[j]
newHerd[#newHerd+1]=BreedCritters(mom,dad,"kid-")
newHerd[#newHerd+1]=BreedCritters(dad,mom,"kid-")
end
end
end
for i=1, herd.breedBastards do --they will always appear ;]
local mom=critters[i]
local j=random(herd.breedBastards+1,#critters)
local dad=critters[j]
newHerd[#newHerd+1]=BreedCritters(mom,dad,"bas-")
newHerd[#newHerd+1]=BreedCritters(dad,mom,"bas-")
end
critters=newHerd
FillHerd()
end
function ShuffleHerd()
if herd.shuffle==true then
for i=1,#critters do
local r=random(#critters)
if r~=i then
critters[i],critters[r]=critters[r],critters[i]
end
end
end
end
function GAB()
if onlyMutable==true then
for i=1,segCnt do
if structure.IsMutable(i) then
UseSegments[#UseSegments+1]=i
end
end
end
critterID=0
gen=0
ss=Score()
bestScore=ss
save.Quicksave(3)
recentbest.Save()
p("Rav3n_pl Bands! Bands in space! GAB BiS")
p("Start score: "..round(ss))
if energy then
energy=false
ssNormal=Score()
p("Normal score: "..round(ssNormal).. " Conditions= "..ss-ssNormal)
energy=true
end
critters={}
FillHerd()
badGen=0
ssstr=(ssstr..round(ss)) -- jeff101
while true do --this is (almost) endless script ;]
undo.SetUndo(false) -- reset each loop if gain will give a long list of interesting undos
genScore=Score()
gen=gen+1
p()
p("Generation: "..gen..", score: "..round(Score())..", gain: "..round(Score()-ss))
ShuffleHerd()
ScoreHerd()
save.Quickload(3)
if gen==herd.maxGen then break end --end of script
if genScore<=Score() then badGen=badGen+1 else badGen=0 end
if badGen>=herd.renew then
p("Creating fresh random herd...")
critters={}
FillHerd()
badGen=0
else
BreedHerd()
end
-- START jeff101's display
genEndScore=Score()
genGain=genEndScore-genScore
if gen>1 and (gen-1)==5*down((gen-1)/5) then -- New 18/1/2016 jeff101 log display
ssstr=(ssstr..'\n ') -- start new line every 5 generations
end
if genGain>=0 then
ssstr=(ssstr..' + '..round(genGain))
undo.SetUndo(true)
else
ssstr=(ssstr..' - '..(-round(genGain)))
end
p(ssstr..' = '..round(genEndScore))
--END jeff101's display
--3a) COPY from here ---------------
loop_count=gen
SetNote(note_number, starting_score, recipename, loop_count) -- WARNING: and mach "recipename" and "loop_count" with the names of the recipe
--3b) COPY to here --------------
SaveBigSteps() -- for movie at the end
end
p("Final score: "..round(Score()).." Total gain: "..round(Score()-ss))
end
--START Movie store big steps
StepScore= Score() -- New 4/11/2014
function StoreBigStep()
StepScore= Score()
save.Quicksave(SlotStep)
SlotStep=SlotStep+1
end
function SaveBigSteps() -- in order to be able to display big steps afterwards in undos
local g=Score()-StepScore
local s= Score()
if s >0 and ( (s <7000 and g>500) or (s <9000 and g>200) or (s <10000 and g>100) or (s >10000 and g>50)) then
StoreBigStep()
end
end
function MovieSteps()
undo.SetUndo(true)
for i= SlotStepStart, SlotStep do
save.Quickload(SlotStep)
end
--save.Quickload(3)
print("See remembering of big steps in undos")
end
--END Movie store big steps
function Cleanup(err) -- NEW BK 10/10/2013
start,stop,line,msg=err:find(":(%d+):%s()")
err=err:sub(msg,#err)
print('---')
if err:find('Cancelled')~=nil then
print("User stop.")
else
print("unexpected error detected.")
--p("Error line: %i.")
--p("Error : %s.")
p("Error line: ", line)
p("Error: ", err)
end
print("Restoring CI, best result, filter and structures")
CI(1)
undo.SetUndo(true)
if FILTERMANAGE then behavior.SetSlowFiltersDisabled(OriginalFilterSetting) end -- always back to user settings
StoreBigStep()
MovieSteps()
save.Quickload(3)
--3a) COPY from here ---------------
loop_count=gen
SetNote(note_number, starting_score, recipename, loop_count) -- WARNING: and mach "recipename" and "loop_count" with the names of the recipe
--3b) COPY to here --------------
deletebands() -- WARNING must be defined anywhere !!
print(err)
end
function dialogOptions()
local mut=false
for i=1,segCnt do
if structure.IsMutable(i) then mut=true break end
end
if not mut then
onlyMutable=false
mutateOnce=false
end
opt = dialog.CreateDialog("Main Options")
opt.lbl1 = dialog.AddLabel("GAB BiS main options:")
opt.gen = dialog.AddTextbox("Generations:", herd.maxGen)
opt.pull= dialog.AddSlider("Pulling CI", pullCI, 0.05, 1, 2)--desctip, default, min, max, precision
opt.shak= dialog.AddSlider("Shake CI", shakeCI, 0.01, 1, 2)
opt.maxci= dialog.AddSlider("Maximum CI", maxCI, 0.05, 1, 2)
opt.qstab=dialog.AddCheckbox("FastQstab", fastQstab)
opt.energy=dialog.AddCheckbox("Seek energy", energy) -- will be better on on exploration puzzles
opt.mutonly=dialog.AddCheckbox("Only mutable", onlyMutable)
opt.mutonce=dialog.AddCheckbox("Mutate once", mutateOnce)
opt.mutalways=dialog.AddCheckbox("Mutate always", mutateAlwas)
opt.fuzeth=dialog.AddTextbox("Fuze threshold: ",fuzeThresh)
opt.qsth=dialog.AddTextbox("Qstab threshold: ",qstabThresh)
if EXPLORATION then
opt.conditions=dialog.AddCheckbox("Check conditions", conditions)
end
if PROBABLEFILTER then
opt.FILTERMANAGE=dialog.AddCheckbox("Fast filter during wiggle only: ",FILTERMANAGE)
opt.GENERICFILTER=dialog.AddCheckbox("Fast filter unless for score: ",GENERICFILTER)
end
opt.run = dialog.AddButton("Start", 1)
opt.more = dialog.AddButton("More", 2)
opt.cancel = dialog.AddButton("Cancel (???)", 0)
res=dialog.Show(opt)
if res>0 then
energy=opt.energy.value
pullCI=opt.pull.value
shakeCI=opt.shak.value
maxCI=opt.maxci.value
fastQstab=opt.qstab.value
fuzeThresh = tonumber(opt.fuzeth.value)
qstabThresh= tonumber(opt.qsth.value)
onlyMutable=opt.mutonly.value
mutateOnce=opt.mutonce.value
mutateAlwas=opt.mutalways.value
herd.maxgen=tonumber(opt.gen.value)
if PROBABLEFILTER then
FILTERMANAGE=opt.FILTERMANAGE.value
GENERICFILTER=opt.GENERICFILTER.value
end
if EXPLORATION then
conditions=opt.conditions.value
end
if res==2 then
opt = dialog.CreateDialog("More Options")
opt.lbl1 = dialog.AddLabel("Herd:")
opt.brbest=dialog.AddSlider("Breed best", herd.breedBest, 1, 20, 0)
opt.kbest=dialog.AddSlider("Keep best", herd.keepBest, 1, 20, 0)
opt.bas=dialog.AddSlider("Breed bastards", herd.breedBastards, 1, 20, 0)
opt.rnd=dialog.AddSlider("New random", herd.newRandom, 1, 30, 0)
opt.renew=dialog.AddSlider("Renew hers", herd.renew, 1, 10, 0)
opt.shuff=dialog.AddCheckbox("Shuffle critters", herd.shuffle)
opt.lbl2 = dialog.AddLabel("Critter:")
opt.minb=dialog.AddSlider("Minimum bands:", critter.minBands, 1,4,0)
opt.maxb=dialog.AddSlider("Maximum bands:", critter.maxBands,4,50,0)
opt.keeps=dialog.AddSlider("Keep score:", critter.keepScore, -10, 10, 0)
opt.breeds=dialog.AddSlider("Breed score:", critter.breedScore, -40, 10,0)
opt.maxloss=dialog.AddSlider("Max loss:", critter.maxLoss, 0,50,0)
opt.lbl4 = dialog.AddLabel("(0 to disable max loss)")
opt.lbl3 = dialog.AddLabel("Bands:")
opt.minst=dialog.AddSlider("Min str", bands.minStr, 0.1, 2, 1)
opt.maxst=dialog.AddSlider("Max str", bands.maxStr, 0.2, 2, 1)
opt.maxup=dialog.AddSlider("Max lenght", bands.maxUp, 1, 20, 0)
opt.run = dialog.AddButton("Start", 1)
dialog.Show(opt)
herd.breedBest = opt.brbest.value
herd.keepBest = opt.kbest.value
herd.breedBastards = opt.bas.value
herd.newRandom = opt.rnd.value
herd.shuffle = opt.shuff.value
herd.renew=opt.renew.value
critter.minBands=tonumber(opt.minb.value)
critter.maxBands=tonumber(opt.maxb.value)
critter.keepScore = tonumber(opt.keeps.value)
critter.breedScore=tonumber(opt.breeds.value)
critter.maxLoss=tonumber(opt.maxloss.value)
bands.minStr=opt.minst.value
bands.maxStr=opt.maxst.value
bands.maxUp = opt.maxup.value
end
else
p("Exiting...")
BreakScript()
end
end
-- main call
function MAIN()
dialogOptions()
GenericFilterMngt()
GAB()
end
xpcall(MAIN,Cleanup)
--end of script