Code
--Acid Tweaker v2.5
--Acid Tweaker v1.78 by Steven Pletsch
--modded by rav3n_pl;]
-- modded by BitSpawn, March 2012
-- v2.00: LUAV2, thanks Timo
-- modded by B.Kestemont, March 2013
-- v2.1: bug fixed on rotamers, set default as in v1.78
-- v2.2 Bug fixed on structure.WiggleAll (replaced by structure.WiggleSelected)
-- management of slow filters and cleaned BK 8/4/2013
--adding starting score in the log BK 20 Sept 2013
--v2.2.1 adding range of seg in user inputs BK 20 Sept 2013
--v2.3.0 adding sphere_worst and automatic improvement on further loops in order to get the
--full power of original Acid Tweaker v1.78 by Steven Pletsch for long run. BK 8 Oct 2013
--adding report with zone of substantial gains.
--reducing info in log to only gaining segments
--adding successive loops management with more and more desperate options
--adapted for exploration puzzle scores 18/10/2013
--added puzzleprop for later & draft adapted for centroid 25/10/2013
--8/4/2013 loops of 2 wiggles in place of 1 end each loop (susume says to wiggle by 2, I obey)
--v2.4.0 public
--v2.4.5 debugged line 73
--v2.5 filters and some small changes for optimisation
--v2.5.1 GENERICFILTER only after dialog (test), FILTERMANAGEMENT in dialog
--v2.5.2 debugged in detectligand (secCnt2 problem)
g_segments = structure.GetCount() -- total number of segments in puzzle
g_total_score = 0 -- recent best to compare to and see if score was improved
g_score = {} -- array of segment scores for comparisons (total for segment)
normal= (current.GetExplorationMultiplier() == 0)
startRecTime=os.clock () -- New BK 23/10/13
p=print --a short
segCount=structure.GetCount()
segStart=1
segEnd=segCount -- will try to tweek ligands also (to verify)
segCnt2=segCount -- later for ligands
OriginalFilterSetting = behavior.GetSlowFiltersDisabled() -- new BK 8/4/2013
FILTERMANAGEMENT=false
CENTROID=false -- new BK 20/10/2013
badpuzzle={'999'} -- list of not implemented puzzles - to be edited on each bug with puzzle nb
--START Generic Filter Management by BitSpawn 21/12/2014
--Source: http://fold.it/portal/node/1998917
PROBABLEFILTER=false
GENERICFILTER=false
--identifying filtered puzzles
function detectfilter()
local descrTxt=puzzle.GetDescription()
if #descrTxt>0 and (descrTxt:find("filter") or descrTxt:find("filters")) then
PROBABLEFILTER=true
GENERICFILTER=true
FILTERMANAGEMENT=false
end
return
end
detectfilter()
-- 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.GetSlowFiltersDisabled() then
behavior.SetSlowFiltersDisabled(false)
end
end
function FiltersOff()
if behavior.GetSlowFiltersDisabled()==false then
behavior.SetSlowFiltersDisabled(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)
--[[ it does not work good here, testing it in dialog
if GENERICFILTER then
MutClass(structure, false)
MutClass(band, false)
MutClass(current, true)
MutClass(recentbest, true)
MutClass(save, true)
print("Disabling filters always but for scoring")
end
]]--
--STOP Generic Filter Management
indexligand={} -- not used here yet
--Detect ligands (from Jean-Bob)
function DetectLigand()
local lastSeg1=structure.GetCount()
local lastSeg2=lastSeg1
while structure.GetSecondaryStructure(lastSeg1)=="M" do
flagligand=true
lastSeg1=lastSeg1-1
end
if lastSeg1+1==lastSeg2 then indexligand={lastSeg2}
else indexligand={lastSeg1, lastSeg2} end
segCnt2=lastSeg1
end
DetectLigand()
function puzzleprop() -- by Bruno Kestemont 20/10/2013, Simplified for AT
local descrTxt=puzzle.GetDescription()
--p(true,descrTxt)
local puzzletitle=puzzle.GetName()
--p(true,puzzletitle)
if #puzzletitle>0 then
for i=1,#badpuzzle do
if puzzletitle:find(i) then -- check if not bizarre puzzle
NOTIMPLEMENTED=true
end
end
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("Tetramer") then sym=3
elseif puzzletitle:find("Dimer of Dimers") or puzzletitle:find("Tetramer") then sym=4
elseif puzzletitle:find("Pentamer") then sym=5
else --SymetryFinder() debugged 03/06/2014
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
if #descrTxt>0 and (descrTxt:find("filter") or descrTxt:find("filters")) then
PROBABLEFILTER=true
end
if #puzzletitle>0 and puzzletitle:find("Sepsis") then -- new BK 17/6/2013
SEPSIS=true
end
if #puzzletitle>0 and puzzletitle:find("Electron Density") then -- for Electron Density
ELECTRON=true
end
if #puzzletitle>0 and puzzletitle:find("Centroid") then -- New BK 20/10/2013
--p(true,"-Centroid")
CENTROID=true
end
return
end
-- Score functions -- NEW from tvd for exploration puzzles
function Score(pose)
if pose==nil then pose=current end
local total= pose.GetEnergyScore()
-- FIX for big negatives
if total < -999999 and total > -1000001 then total=SegScore(pose) end
if normal then
return total
else
return total*pose.GetExplorationMultiplier()
end
end
function SegScore(pose)
if pose==nil then pose=current end
local total=8000
for i=segStart, segCnt2 do
total=total+pose.GetSegmentEnergyScore(i)
end
return total
end
function RBScore() -- not used yet
return Score(recentbest)
end
--[[function Score()
return current.GetEnergyScore()
end]]--
-- END score functions
function ds(val)
if mutate==true then
if FILTERMANAGEMENT then behavior.SetSlowFiltersDisabled(OriginalFilterSetting) end -- new BK 8/4/2013, always back to user settings
structure.MutateSidechainsSelected(val+1)
else
structure.ShakeSidechainsSelected(val)
end
end
global_ci=1
function CI(val)
global_ci=val
behavior.SetClashImportance(global_ci)
end
function WiggleSimple(val,how)
if FILTERMANAGEMENT then behavior.SetSlowFiltersDisabled(true) end-- new BK 8/4/2013, always disable filter here
if CENTROID then -- new BK 20/10/2013
if how=="s" or how=="ws" then
how="wa"
end
end
if how == "s" then ds(1)
elseif how == "wb" then structure.WiggleSelected(val, true, false) -- backbones
elseif how == "ws" then structure.WiggleSelected(val, false, true) -- sidechains
elseif how == "wa" then structure.WiggleSelected(val, true, true) -- all
elseif how== "lw" then structure.LocalWiggleSelected(val) -- new
elseif how=="rb" then structure.RebuildSelected(1) -- don't use, it's chaotic
end
if FILTERMANAGEMENT then behavior.SetSlowFiltersDisabled(OriginalFilterSetting) end -- new BK 10/10/2013, always back to user settings
end
function WiggleAT(ss, how, iters, minppi)
local valiter=2
local val=1
if fast==true then valiter=1 end
if how==nil then how="wa" end
if CENTROID then -- new BK 20/10/2013
if how=="s" or how=="ws" then
how="wa"
end
end
if iters==nil then iters=6 end
minppi=(g_total_score-Score())/100
if ((minppi==nil) or (minppi<0.001)) then
minppi=0.001
end
if global_ci==1.00 then val=valiter end
if iters>0 then
iters=iters-1
local sp=Score()
WiggleSimple(val,how)-- new function BK 8/4/2013
local ep = Score()
local ig=ep-sp
if how~="s" then
if ig > minppi then WiggleAT(ss, how, iters, minppi) end
end
end
end
function SelectSphere(sg,radius,nodeselect)
if nodeselect~=true then selection.DeselectAll() end
for i=1, segCount do
if structure.GetDistance(sg,i)<radius then selection.Select(i) end
if sphere_worst==true then
if current.GetSegmentEnergyScore(i)<sphere_worst_value then selection.Select(i) end
end
end
end
function Fix(sg)
if fix_band==false then
return
end
-- selection.DeselectAll()
local nb=1
for i=1, segCount do
dist=structure.GetDistance(sg,i)
if (dist<12 and dist>6) then
local cband=band.GetCount()
band.AddBetweenSegments(sg, i)
if cband<band.GetCount() then
band.SetGoalLength(nb,dist)
nb=nb+1
end
-- else if dist>12 then
-- selection.Select(i)
-- end
end
end
-- freeze.FreezeSelected(true,true)
-- selection.DeselectAll()
-- SelectSphere(sg,esfera)
--structure.WiggleSelected(1,true,true)
WiggleSimple(1,"wa") -- new function BK 8/4/2013
band.DeleteAll()
-- freeze.UnfreezeAll()
end
function round(x)--cut all afer 3-rd place
return x-x%0.001
end
--Start score management and report
--better to enable filter during setup => these scores will be reset after dialog
bestScore=Score() -- for savebest, I'll reset it after knowing the parameters
startenergypersegment=(SegScore()-8000)/segCnt2-- NEW BK 18/10/2013 for maximo settings
winnerseg=2 -- arbitrary
function SaveBest(seg)
local s=Score()
local g=s-bestScore
local WaitingTime=os.clock ()-StartChrono
if g>0 then
--local sscore=current.GetSegmentEnergyScore(seg) -- NEW BK 9/10/2013
if g>=0.001 then
p("Gained another ",round(g)," pts on seg ",seg, " scoring: ", round(sscore), ". Total score:",s)
elseif WaitingTime > 300 then-- in sec, every 5 minutes, show something to make patience
StartChrono=os.clock ()
p("No gain up to seg",seg,"/",segCnt2,". Score:", s)
end
bestScore=s
save.Quicksave(3)
if g>bestg then -- NEW BK 9/10/2013
bestg=g
winnerseg=seg
end
end
end
--End score management and report
function usableAA(sn)
local usable=false -- a priori, aucun segment n'est utilisable sauf s'il rpond une des conditions ci-dessous
sscore=current.GetSegmentEnergyScore(sn)-- NEW BK 9/10/2013 global to print in savebest
---------------------------------------------
if sscore>minimo then
return usable -- donc false ici (true si score > minimo = 600)
end
if sscore<maximo then -- NEW BK 8/10/2013
return usable -- donc false ici (true si score < maximo)
end
if rebuild==true then -- tous ceux qui restent si rebuild
selection.DeselectAll()
selection.Select(sn)
structure.RebuildSelected(2)
usable=true
return usable
end
--if one of the above condition is met, we verify not further
---------------------------------------------
if #useThat>0 then
for i=1,#useThat do
if sn==useThat[i] then
usable=true
break
end
end
else
if #useOnly > 0 then
for i=1,#useOnly do
local ss=useOnly[i][1]
local se=useOnly[i][2]
for s=ss,se do
if s==sn then
usable=true
break
end
end
end
else
usable=true -- each segment usable by default
if #doNotUse>0 then
for i=1,#doNotUse do
local ss=doNotUse[i][1]
local se=doNotUse[i][2]
for s=ss,se do
if s==sn then
usable=false
break
end
end
if usable==false then break end
end
end
if #skipAA>0 then
local aa=structure.GetAminoAcid(sn)
for i=1,#skipAA do
if aa==skipAA[i] then
usable=false
break
end
end
end
end
end
local se=segCount
if ATend~=nil then se=ATend end
if sn<ATstart or sn>se then usable=false end
return usable
end
function wiggle_out(seg)
CI(.6)
--structure.WiggleSelected(1,true,true)
WiggleSimple(2,"wa") -- new function BK 8/4/2013
CI(1.)
WiggleAT(seg)
WiggleAT(seg,"s",1)
--selection.SelectAll()
CI(.6)
WiggleAT(seg)
CI(1.)
WiggleAT(seg)
recentbest.Restore()
SaveBest(seg)
end
function getNear(seg)
if(Score() < g_total_score-1000) then
selection.Deselect(seg)
CI(.75)
--ds(1)
WiggleSimple(1,"s") -- new function BK 8/4/2013
--structure.WiggleSelected(1,false,true)
WiggleSimple(1,"ws") -- new function BK 8/4/2013
selection.Select(seg)
CI(1)
end
if(Score() < g_total_score-1000) then
if fix_band==true then
Fix(seg)
else
recentbest.Restore()
SaveBest(seg)
return false
end
end
return true
end
function sidechain_tweak()
p("Pass 1 of 3: Sidechain tweak")
for i=segStart, segEnd do
if usableAA(i) then
selection.DeselectAll()
selection.Select(i)
local ss=Score()
g_total_score = Score()
CI(0)
--ds(2)
WiggleSimple(1,"s") -- new function BK 8/4/2013
CI(1.)
--p("Try sgmnt ", i)
SelectSphere(i, esfera)
if (getNear(i)==true) then
wiggle_out(i)
end
end
end
end
function sidechain_tweak_around()
p("Pass 2 of 3: Sidechain tweak around")
for i=segStart, segEnd do
if usableAA(i) then
selection.DeselectAll()
for n=1, g_segments do
g_score[n] = current.GetSegmentEnergyScore(n)
end
selection.Select(i)
local ss=Score()
g_total_score = Score()
CI(0)
--ds(2)
WiggleSimple(1,"s") -- new function BK 8/4/2013
CI(1. )
--p("Try sgmnt ", i)
SelectSphere(i,esfera)
if(Score() > g_total_score - 30) then
wiggle_out(i)
else
selection.DeselectAll()
for n=1, g_segments do
if(current.GetSegmentEnergyScore(n) < g_score[n] - 1) then
selection.Select(n)
end
end
selection.Deselect(i)
CI(0.1)
--ds(1)
WiggleSimple(1,"s") -- new function BK 8/4/2013
SelectSphere(i,esfera,true)
CI(1.0)
if (getNear(i)==true) then
wiggle_out(i)
end
end
end
end
end
-- debugged:
function sidechain_manipulate() -- negative scores avoided
--p("Dernire chance: manipulateur brutal des chaines latrales")
p("Last chance: bruteforce sidechain manipulate on best segments")
maximo=maximo+10 -- new BK 14/12/13 because rotamers need best segments
for i=segStart, segEnd do
if usableAA(i) then
selection.DeselectAll()
rotamers = rotamer.GetCount(i)
save.Quicksave(4)
if(rotamers > 1) then
local ss=Score()
--p("Sgmnt: ", i," rotamers: ",rotamers, " Score= ", ss)
for r=1, rotamers do
--p("Sgmnt: ", i," position: ",r, " Score= ", ss)
save.Quickload(4)
g_total_score = Score()
rotamer.SetRotamer(i,r)
CI(1.)
if(Score() > g_total_score - 30) then
SelectSphere(i,esfera)
wiggle_out(i) -- this can change the number of rotamers
end
if rotamers > rotamer.GetCount(i) then break end --if nb of rotamers changed
end
end
end
recentbest.Restore()-- because rotamers can puzzle everything
end
maximo=maximo-10 -- new BK 14/12/13 einitiaization of current maximo
end
-- end debugged
--To BE IMPLEMENTED VIA DIALOG BOX
useThat={ --only segments what have to be used OVERRIDES all below
--18,150,151,205,320,322,359,361,425,432,433 --382
}
useOnly={ --ranges what have to be used OVERRIDES BOTH LOWER OPTIONS
--{12,24},
--{66,66},
}
doNotUse={ --ranges that should be skipped
--{55,58},
--{12,33},
}
skipAA={ --aa codes to skip
'a',
'g',
} -- default skiping these 2 AAs that have no rotamer
--option to easy set start and end of AT work to-- to be implemented in dialog
ATstart=1 --1st segment
ATend=nil --end of protein if nil
--END TO BE IMPLEMENTED VIA DIALOG BOX
sphere_worst=false -- include worst segments in sphere
sphere_worst_value=0
function Run()
puzzleprop()-- new BK 21/10/2013
CI(1.00)
recentbest.Restore()
save.Quicksave(3)--in save 3 always best solution. Load in case of crash.
s1=Score()
StartChrono=os.clock ()
sidechain_tweak()
s2=Score()
p("Tweak gain: ",round(s2-s1))
StartChrono=os.clock ()
sidechain_tweak_around()
s3=Score()
p("Around gain: ",round(s3-s2))
if manipulate==true then
StartChrono=os.clock ()
sidechain_manipulate()
s4=Score()
if s4-s3 <0 then recentbest.Restore() end --against the bug !!!
p("Manipulate gain: ",round(s4-s3))
end
selection.SelectAll() -- or 2 lines in one structure.WiggleAll(4,true,true)
WiggleSimple(2,"wa") -- new function BK 8/4/2013 BK 15/01/2013 changed 1 to 2
WiggleSimple(2,"ws") -- new function BK 8/4/2013 BK 15/01/2013 changed 1 to 2
selection.SelectAll()
WiggleSimple(2,"wa") -- new function BK 8/4/2013 BK 15/01/2013 changed 1 to 2
recentbest.Restore()
s5=Score()
--p("Start score Loop ",loop,": ",round(s1))
--p("Tweak gain: ",round(s2-s1))
--p("Around gain: ",round(s3-s2))
--p("Manipulate gain: ",round(s4-s3))
p("Total Acid gain Loop ",loop,": ",round(s5-s1))
--p("End score: ",round(s5))
end
esfera=8
minimo=600 -- score for working with worst segments. Don't use, usually worst segs have no rotts
if startenergypersegment<-100 then maximo=-100 -- NEW BK 8/10/2013 (filters not considered here before dialog)
elseif startenergypersegment<-5 then maximo=-50
elseif startenergypersegment<10 then maximo=-10
else maximo=10
end
mutate=false -- Don't use, very bad results yet (TODO)
rebuild=true -- for very end in a puzzle, rebuild segment before tweak
fix_band=false -- if you want to try with the worst segments
fast=false
manipulate=true -- test rottamers
function GetParam()
local dlg = dialog.CreateDialog("Acid Tweeker 2.2")
dlg.fast = dialog.AddCheckbox("Fast mode (gain 25% less)", false)
dlg.fix_band = dialog.AddCheckbox("Fix geometry with bands when score breaks down", false)
dlg.manipulate = dialog.AddCheckbox("Brute force in phase 3", true)
dlg.sphere_worst = dialog.AddCheckbox("Include worst segments in sphere", false)
dlg.rebuild = dialog.AddCheckbox("Rebuild before search rotts, for very end only", true)
dlg.segStart=dialog.AddTextbox("From seg ", segStart)
dlg.segEnd=dialog.AddTextbox("To seg ", segEnd)
dlg.label1=dialog.AddLabel("Skip segments scoring less than: ")
dlg.maximo = dialog.AddSlider("min pts/seg: ",maximo,-100,30,0)
--dlg.minimo = dialog.AddSlider("more than",minimo,30,600,0)
if PROBABLEFILTER then
dlg.FILTERMANAGEMENT=dialog.AddCheckbox("Disable filter during wiggle", FILTERMANAGEMENT)
dlg.GENERICFILTER=dialog.AddCheckbox("Always disable filter, unless for scoring", GENERICFILTER)
end
dlg.ok = dialog.AddButton("OK", 1)
dlg.cancel = dialog.AddButton("Cancel", 0)
if dialog.Show(dlg) > 0 then
fast = dlg.fast.value
fix_band = dlg.fix_band.value
manipulate = dlg.manipulate.value
sphere_worst=dlg.sphere_worst.value
rebuild = dlg.rebuild.value
segStart= dlg.segStart.value
segEnd= dlg.segEnd.value
--minimo=dlg.minimo.value
maximo=dlg.maximo.value
if PROBABLEFILTER then
GENERICFILTER=dlg.GENERICFILTER.value
FILTERMANAGEMENT=dlg.FILTERMANAGEMENT.value
end
if GENERICFILTER then
FILTERMANAGEMENT=false --(because reduntant and to avoid enabling filters after wiggles)
MutClass(structure, false)
MutClass(band, false)
MutClass(current, true)
MutClass(recentbest, true)
MutClass(save, true)
print("Always disable filter, unless for scoring")
end
if FILTERMANAGEMENT then
print("Disable filter during wiggle")
end
return true
end
return false
end
if GetParam()==false then
return
end
recentbest.Save()
ini_score=Score()
print("Acid Tweeker starting at score: "..ini_score)
if behavior.GetSlowFiltersDisabled() then print("... without the filters !") end
bestScore=Score() -- for savebest, reset with default filter parameters (filter enabled or not)
loop=0
hop=0
function MAINAT()
while(true) do
print("################################")
local startlooptime=os.clock ()
local startloopscore=Score()
loop=loop+1
if hop ==1 then if not manipulate then manipulate = true print("Upgrading options: Adding manipulate-----") else hop=hop+1 end end
if hop ==2 then if not fix_band then fix_band = true print("Upgrading options: Adding Fixing bands----------") else hop=hop+1 end end
if hop ==3 then if fast then fast = false print("Upgrading options: Disabling fast----------") else hop=hop+1 end end
if hop ==4 then if not rebuild then rebuild = true print("Upgrading options: Adding Rebuild before manipulate---------") else hop=hop+1 end end
if hop ==5 then if not sphere_worst then sphere_worst=true print("Upgrading options: Adding sphere-----------") else hop=hop+1 end end
if hop ==6 then if fix_band then fix_band = false print("Upgrading options: No Fixing bands----------") else hop=hop+1 end end
hop=hop+1
print("Loop ",loop, "Options:")
print("fast=",fast,", fix_band=",fix_band,", manipulate=",manipulate)
print(", rebuild=",rebuild, ", sphere=", sphere_worst, ", segs =",segStart,"-",segEnd)
print("Use only segments scoring at least",maximo,"pts")
print("-------------------------------")
bestg=0
Run()
print("Best gain this loop: ",bestg," pts on seg ",winnerseg)
local stoplooptime=os.clock ()
local stoploopscore=Score()
print("This loop gained",round(stoploopscore-startloopscore),"in",round(stoplooptime-startlooptime)/60,"minutes")
--if minimo<600 then minimo=minimo+10 end -- good scoring segs will gain much with at
maximo=maximo-10 -- worst scoring segs will not gain with at, but if you've so much time, ok we try
print(">>>Total Gain: ", round(Score()-ini_score), "Score:", round(Score()),"Start score: ", round(ini_score))
print("CPU time =",round((stoplooptime-startRecTime)/60),"minutes")
end
end
function DumpErr(err)
start,stop,line,msg=err:find(":(%d+):%s()")
err=err:sub(msg,#err)
p('---')
if err:find('Cancelled')~=nil then
p("User stop.")
else
p("unexpected error detected.")
p("Error line:", line)
p("Error:", err)
end
LastWish()
end
function LastWish()
recentbest.Restore()
CI(1)
behavior.SetSlowFiltersDisabled(OriginalFilterSetting)
end
--MAINAT()
xpcall(MAINAT, DumpErr)
--end