Icon representing a recipe

Recipe: clash1 AFK3.1.1 & Banded Worm Pairs Inf Filt 1.4.5

created by zo3xiaJonWeinberg

Profile


Name
clash1 AFK3.1.1 & Banded Worm Pairs Inf Filt 1.4.5
ID
104060
Shared with
Public
Parent
Banded Worm Pairs Inf Filt 1.4.7
Children
Created on
October 19, 2020 at 09:49 AM UTC
Updated on
October 19, 2020 at 09:49 AM UTC
Description

You must login to both the game AND the fold.it website to add to cookbook.

You can share this recipe.
This combines the 2 best recipes.

Away From Keyboard until 5 dog-days (consecutive failed iters) for fast fuseki.
Endgame:
Banded worm, with pairs of bands and more random action, including user bands - Filter optimization and infinite run.
Not totally AFK in Design puzzles as it spawns another dialog box.

Best for


Code


behavior.SetClashImportance(1) --jon for BWP --------------- -- Variables -- --------------- AFK = {} AFK.SaveSlot = 98 AFK.StartScore = current.GetEnergyScore() AFK.StartCI = behavior.GetClashImportance() AFK.IsMutable = false AFK.BounceWiggle = {} AFK.Init = {} AFK.Helper = {} AFK.BounceWiggle.DoShake = false AFK.BounceWiggle.DoMutate = false AFK.BounceWiggle.Iterations = 5 --jon testing AFK.BounceWiggle.IterationCount = 0 --jon AFK.BounceWiggle.DogDays = 0 --jon AFK.BounceWiggle.MinGain = 0.1 AFK.BounceWiggle.SkipCIMaximization = true AFK.BounceWiggle.PrintFailures = true ---------------------- -- Helper Functions -- ---------------------- AFK.Helper.IsMutable = function() for n=1, structure.GetCount() do if (structure.IsMutable(n)) then AFK.IsMutable = true end end end AFK.Helper.PrintStart = function(choice) if (choice > 2) then mode = "Mutate" AFK.BounceWiggle.DoMutate = true elseif (choice > 1) then mode = "Shake" AFK.BounceWiggle.DoShake = true else mode = "NoShake" end print("AFK3(BounceWiggle"..mode..") started. ".. AFK.BounceWiggle.Iterations.. " consecutive Failed iterations before ending.") --jon end AFK.Helper.PrintEnd = function(gain) if (gain > 0) then print ("script complete: + ".. (current.GetEnergyScore() - AFK.StartScore).. " -- "..current.GetEnergyScore()) else print("script complete:"..current.GetEnergyScore()) end end AFK.Helper.SetCI = function(ci) ci = ci or math.random(50, 900) / 1000 behavior.SetClashImportance(ci) end AFK.Helper.SelectRandom = function() local shakeSelectionCount = math.random(1, structure.GetCount()) for n=1, shakeSelectionCount do local selectSegment = math.random(1, structure.GetCount()) selection.Select(selectSegment) end end AFK.Helper.PerformFunction = function(func, iters) local currentScore = current.GetEnergyScore() local newScore = currentScore behavior.SetFiltersDisabled(true) func(iters) behavior.SetFiltersDisabled(false) recentbest.Restore() newScore = current.GetEnergyScore() if (newScore > (currentScore + AFK.BounceWiggle.MinGain)) then currentScore = newScore save.Quicksave(AFK.SaveSlot) else save.Quickload(AFK.SaveSlot) end end AFK.Helper.UpdateIterations = function(gain) -- TODO: option to print, even on failure. (so we know Iterations) AFK.BounceWiggle.IterationCount=AFK.BounceWiggle.IterationCount+1 if gain > 0 then print (AFK.BounceWiggle.IterationCount .." iters. dogdays "..AFK.BounceWiggle.DogDays..": + ".. gain.." -- "..current.GetEnergyScore()) AFK.BounceWiggle.DogDays = 0 elseif (AFK.BounceWiggle.DogDays < AFK.BounceWiggle.Iterations) then if (AFK.BounceWiggle.PrintFailures == true) then print(AFK.BounceWiggle.IterationCount .." iters. dogdays "..AFK.BounceWiggle.DogDays..": "..gain.." -- "..current.GetEnergyScore()) end AFK.BounceWiggle.DogDays = AFK.BounceWiggle.DogDays+1 end end ----------------------- -- Create Dialog Box -- ----------------------- AFK.CreateBounceWiggleDialog = function() local currentDialog = dialog.CreateDialog("BounceWiggle") currentDialog.IterationsLabel = dialog.AddLabel( "Failed Iterations before ending") currentDialog.IterationsSlider = dialog.AddSlider( "Failure Iterations", AFK.BounceWiggle.Iterations, -1, 1000, 0) currentDialog.BlankLabel1 = dialog.AddLabel("") currentDialog.DiscardLabel = dialog.AddLabel( "(Sketchbook) Discard gains less than") currentDialog.DiscardSlider = dialog.AddSlider( "Discard <", AFK.BounceWiggle.MinGain, 0, 10, 1) currentDialog.BlankLabel2 = dialog.AddLabel("") currentDialog.SkipMaximization = dialog.AddCheckbox( "Skip CI=1 Maximization", AFK.BounceWiggle.SkipCIMaximization) currentDialog.PrintFailuresOption = dialog.AddCheckbox( "Print info for Failed Attempts", AFK.BounceWiggle.PrintFailures ) currentDialog.NoShakeButton = dialog.AddButton("Wiggle Only", 1) currentDialog.ShakeButton = dialog.AddButton("Shake", 2) if (AFK.IsMutable) then currentDialog.MutateButton = dialog.AddButton("Mutate", 3) end currentDialog.CancelButton = dialog.AddButton("Cancel", 0) local choice = dialog.Show(currentDialog) AFK.BounceWiggle.Iterations = currentDialog.IterationsSlider.value AFK.BounceWiggle.MinGain = currentDialog.DiscardSlider.value AFK.BounceWiggle.SkipCIMaximization = currentDialog.SkipMaximization.value AFK.BounceWiggle.PrintFailures = currentDialog.PrintFailuresOption.value if (AFK.BounceWiggle.Iterations < 1) then AFK.BounceWiggle.Iterations = -1 end if (choice > 0) then AFK.Helper.PrintStart(choice) end return choice end ------------------- -- The main dish -- ------------------- AFK.BounceWiggle.Main = function() AFK.Helper.IsMutable() local startScore = AFK.StartScore local choice = AFK.CreateBounceWiggleDialog() if (choice < 1) then print("Dialog cancelled.") return end save.Quicksave(AFK.SaveSlot) recentbest.Save() if (AFK.BounceWiggle.SkipCIMaximization == false) then AFK.Helper.PerformFunction(AFK.BounceWiggle.CIMaximization) startScore = current.GetEnergyScore() end print("Script started: "..startScore) while (AFK.BounceWiggle.DogDays < AFK.BounceWiggle.Iterations) do startScore = current.GetEnergyScore() AFK.Helper.PerformFunction(AFK.BounceWiggle.BounceWiggle) AFK.Helper.UpdateIterations(current.GetEnergyScore() - startScore) end AFK.Helper.PrintEnd(current.GetEnergyScore() - startScore) AFK.Cleanup() end ------------------------- -- The BounceWiggliest -- ------------------------- AFK.BounceWiggle.CIMaximization = function() local currentScore = AFK.StartScore local newScore = currentScore + AFK.BounceWiggle.MinGain + 0.01 print("Maximizing Wiggle Score at Clashing Importance = 1: "..currentScore) AFK.Helper.SetCI(1) while (currentScore + AFK.BounceWiggle.MinGain < newScore) do structure.WiggleAll(25) structure.LocalWiggleAll(25) recentbest.Restore() currentScore = newScore newScore = current.GetEnergyScore() end if (newScore > AFK.StartScore) then print ("CI Maximization: + "..(currentScore - AFK.StartScore).. " -- "..currentScore) end end AFK.BounceWiggle.WiggleAll = function(ci, wiggleIterations) AFK.Helper.SetCI(ci) wiggleIterations = wiggleIterations or math.random(1, 3) local wiggleType = math.random(1, 2) if (wiggleType > 1) then structure.WiggleAll(wiggleIterations) else structure.LocalWiggleAll(wiggleIterations) end end AFK.BounceWiggle.ShakeityShake = function() local shakeType = math.random(1, 3) local shakeIterations = math.random(1, 3) AFK.Helper.SetCI() -- 1/3 chance of whole protein if (shakeType > 2) then if (AFK.BounceWiggle.DoMutate == true) then -- When mutating all, we only do one iteration. -- This is to increase BounceWiggle speed, to explore more -- configurations faster. structure.MutateSidechainsAll(1) else structure.ShakeSidechainsAll(shakeIterations) end -- 2/3 chance of random selection else AFK.Helper.SelectRandom() if (AFK.BounceWiggle.DoMutate == true) then structure.MutateSidechainsSelected(shakeIterations) else structure.ShakeSidechainsSelected(shakeIterations) end selection.DeselectAll() end end AFK.BounceWiggle.BounceWiggle = function() AFK.BounceWiggle.WiggleAll() if (AFK.BounceWiggle.DoShake == true or AFK.BounceWiggle.DoMutate == true) then AFK.BounceWiggle.ShakeityShake() end AFK.BounceWiggle.WiggleAll(1, 25) end ------------- -- The end -- ------------- function AFK.Cleanup(errorMessage) behavior.SetClashImportance(AFK.StartCI) recentbest.Restore() selection.DeselectAll() -- Re enable all filters behavior.SetFiltersDisabled(false) end xpcall(AFK.BounceWiggle.Main, AFK.Cleanup) ----------------------------------------------------------------- ==jon copy --Banded Worm Pairs Infinite (& Filter) ------------------------------------------------------------------------------ -- Banded Worm ------------------------------------------------------------------------------ -- Modifies Worm LWS v2 by rav3n_pl -- -- by KarenCH ------------------------------------------------------------------------------ -- Made infinite and filters optimized by Bruno Kestemont 15/2/2015 -- v 1.1 corrected random contact map 20/9/2015 -- v 1.2 added random use of user bands (and random multiplier of their strength) -- v 1.2.1 undo.SetUndo -- v 1.3.0 BAND_TO_SIDECHAINS allowed -- v 1.3.1 Fixed unideal loop bug (thanks to gitwut) (band= true) -- v 1.3.2 Second attempt to fix it (added save.Quickload) -- v 1.4 Dialog for filters -- v 1.4.1 and tried again to fix GENERICFILTER on recentbest (see feedback discussion, Foldit Bug) -- replaced by FakeRecentBestSave() and FakeRecentBestRestore() 29/8/2017 -- v 1.4.2 added Ligand dialog -- v 1.4.3 systematic display of current score (Greg's suggestion), again fixing filter bug -- v 1.4.4 fixed detect bonusses -- v 1.4.5 fixed segMeanScore=(scoreboard.GetGroupScore()-8000)/segCnt --TO DO = probability otions in advanced dialog recipename= "Banded Worm Pairs Inf Filter 1.4.5" undo.SetUndo(false) -- interesting global variables that users might want to modify PROB_CHOOSE_USERBANDS = 0.10 -- don't put it too high PROB_CHOOSE_CONTACTMAP = 0.60 PROB_PUTBAND = 1.0 -- how often do we put bands in our wiggle steps? PROB_BIS_NOT_BETWEEN = 0.25 -- do we prefer BIS or bands between segs PROB_2ND_IS_BIS = 0.50 PROB_BETWEEN_USES_ATOM = 0.50 -- between: should wiggled seg have band from non-default atom BAND_STRENGTH_DEFAULT = 1.0 PROB_BAND_TO_LIGAND= 0 -- prob band to ligand if ligand -- less interesting global variables that users might consider modifying BIS_LENGTH = 5.0 -- max length of a BIS SCALE_MAXCI = 1.0 CONTACTMAP_THRESHOLD = 0.25 -- min heat of contacts USENORMALSCORE = true -- exploration puzzles would set false DEBUGRUN = false -- mostly goes with DebugPrint, but could get more use later -- atoms in an amino acid BETA_CARBON = 5 TERMINAL_BETA = 6 -- not used CENTER_CARBON = 2 --this is the default atom for bands to attach to BAND_TO_SIDECHAINS = true -- New BK, some bands to sidechains as well -- variables users probably don't want to play with (SLOTS) QS_Start = 1 QS_Best = 3 Qs_Recent = 5 -- for debugging recentbest bug Qs_Current = 6 -- for debugging recentbest score -- variables users really shouldn't play with PuzzleHasContactMap = false PuzzleHasLockedSegs = false EndCalled = false InitialScore = 0.0 -- not important: will be reinitialized in InitializePuzzleState( ) StartTime = 0 -- not important: will be reinitialized in InitializePuzzleState( ) CurrentBestScore = 0 -- not important: will be reinitialized in InitializePuzzleState( ) InitialClashImportance = behavior.GetClashImportance() NonLockedSegList = {} segCt = structure.GetCount() MinUnlockedSeg = 1 MaxUnlockedSeg = segCt segCnt2=segCt while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2=segCnt2-1 end FirstLigand= segCnt2 -- 0 if no ligand LastLigand= segCt InitialBandCount = 0 ubcount = 0 -- user bands ubandlist={} -- {band number, band strength, goal_length} USERBANDS=false PROBABLEFILTER=false --FILTERMANAGE=false -- default yes during wiggle (will always be activate when scoring) GENERICFILTER=false PROBABLELIGAND=false GENERICLIGAND=false --identifying explicitly (heavy) filtered puzzles (Contact with remain filter enabled, what is good) --START extraction of information from puzzle metadata --Extrait des infos function detectfilterandmut() -- Bruno Kestemont 10/10/2013; 13/2/2015; 5/1/2019 local descrTxt=puzzle.GetDescription() local puzzletitle=puzzle.GetName() local function SymetryFinder() -- by Bruno Kestemont 7/2/2013, 25/8/2013 local segMeanScore=(scoreboard.GetGroupScore()-8000)/segCnt2 -- top score pour eviter les debuts de puzzle --p("Score moyen par segment= "..segMeanScore) if PROBABLESYM then if segMeanScore<33.39 then sym=1 PROBABLESYM=false elseif segMeanScore<85 then sym=2 elseif segMeanScore<132 then sym=3 elseif segMeanScore<197 then sym=4 else sym=5 end else sym=1 end return end if #descrTxt>0 and (descrTxt:find("filter") or descrTxt:find("filters") or descrTxt:find("bonus") or descrTxt:find("bonuses") and not descrTxt:find("disabled"))then PROBABLEFILTER=true FILTERMANAGE=true -- default yes during wiggle (will always be activate when scoring) GENERICFILTER=false -- to be evaluated end if #descrTxt>0 and (descrTxt:find("H-bond networks") or descrTxt:find("Hydrogen Bond Networks") or descrTxt:find("H-bond Networks") or descrTxt:find("H-bond Network") and not descrTxt:find("disabled"))then PROBABLEFILTER=true FILTERMANAGE=false -- default no GENERICFILTER=false -- to be evaluated end if #descrTxt>0 and (descrTxt:find("design") or descrTxt:find("designs")) then HASMUTABLE=true IDEALCHECK=true HANDFOLD=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 HANDFOLD=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 SymetryFinder() 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") or descrTxt:find("C2 symmetry") or descrTxt:find("twoo symmetric")) and not (descrTxt:find("Dimer of Dimers") or descrTxt:find("dimer of dimers")) then sym=2 elseif descrTxt:find("Trimer") or descrTxt:find("trimer") or descrTxt:find("C3 symmetry") or descrTxt:find("three symmetric") then sym=3 elseif (descrTxt:find("Dimer of Dimers") or descrTxt:find("Tetramer") or descrTxt:find("C4 symmetry") or descrTxt:find("four symmetric")) and not (descrTxt:find("dimer of dimers") or descrTxt:find("tetramer"))then sym=4 elseif descrTxt:find("Pentamer") or descrTxt:find("pentamer") or descrTxt:find("C5 symmetry") or descrTxt:find("five symmetric") then sym=5 else SymetryFinder() 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 HANDFOLD=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 HANDFOLD=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() --END extraction of information from puzzle metadata --Extrait des infos function DialogForFilters() ask = dialog.CreateDialog(recipename) ask.l6 = dialog.AddLabel("Fast = filters off unless for score") ask.l8 = dialog.AddLabel("Slow = filters always on") ask.Fast = dialog.AddButton("Fast",1) ask.Slow = dialog.AddButton("Slow",2) askresult=dialog.Show(ask) if askresult < 2 then GENERICFILTER=true end end function DialogForLigand() ask = dialog.CreateDialog(recipename) ask.l6 = dialog.AddLabel("Ligand = move ligand") ask.l8 = dialog.AddLabel("All = move all") ask.Fast = dialog.AddButton("Ligand",1) ask.Slow = dialog.AddButton("All",2) askresult=dialog.Show(ask) if askresult> 1 then GENERICLIGAND=false else GENERICLIGAND=true end end if PROBABLEFILTER then DialogForFilters() end if PROBABLELIGAND then DialogForLigand() end if GENERICLIGAND and not FirstLigand == 0 then --there should be a ligand but who knows PROB_BAND_TO_LIGAND=1 end --START Generic Filter Management by BitSpawn 21/12/2014, updated by Bruno Kestemont 4/1/2019 --Source: http://fold.it/portal/node/1998917 --Note: GENERICFILTER must be defined elsewhere (otherwise, it will not do anything) -- GENERICFILTER=true -- 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 filter.AreAllEnabled()==false then filter.EnableAll() end end function FiltersOff() if filter.AreAllEnabled() then filter.DisableAll() end end -- function to overload a function 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) if GENERICFILTER then -- WARNING: TO VERIFY !! (may be it's irreversible for several funtions bellow) MutClass(structure, false) MutClass(band, true) -- if false, you have to enable filter just afterwards (otherwise unideal filter bug) MutClass(current, true) MutClass(recentbest, true) -- otherwise, it remembers cut solutions MutClass(save, true) -- better to save with full score end --STOP Generic Filter Management ------------------------------------------------------------------------------ -- FUNCTIONS ------------------------------------------------------------------------------ function BandedWorm( pattern ) --recentbest.Save( ) FakeRecentBestSave() SetCI( 1.0 ) SaveBest( ) local ss = getScore() local idx=1 for w = 1, #pattern do save.Quickload( QS_Best ) -- new for DEBUG len = pattern[ w ] local sw = getScore() local swCurr = sw print( "Starting BandedWormPairs of len " .. len .. ", score: ".. TrimNum( getScore() ) ) for s=MinUnlockedSeg, MaxUnlockedSeg - len + 1 do selection.DeselectAll() selection.SelectRange( s, s + len - 1 ) if random( ) < PROB_PUTBAND then if random( ) < PROB_BAND_TO_LIGAND then idx= random( Firstligand, LastLigand) else idx = random( s, s + len - 1 ) end PutSingleRandomBandToSeg( idx, PROB_BIS_NOT_BETWEEN ) if random( ) < 0.25 then local idx2 = random( s, s + len - 1 ) PutSingleRandomBandToSeg( idx2, PROB_2ND_IS_BIS ) end uBandEnabel() -- new v1.2 random adding one of the user bands structure.LocalWiggleSelected( random(2,4) ) ManageBands( ) structure.WiggleAll( 2 ) end structure.LocalWiggleSelected( 5 ) local swNew = getScore( ) local gain = swNew - swCurr if gain > 0 then structure.LocalWiggleSelected( 20 ) --recentbest.Restore( ) FakeRecentBestRestore() ManageBands( ) swNew = getScore( ) gain = swNew - swCurr if TrimNum( gain ) > 0 then print( ">>>> At " .. s .. ": Gained ".. TrimNum( gain ).." Score: "..TrimNum( swNew )) end SaveBest( ) swCurr = swNew else --recentbest.Restore( ) FakeRecentBestRestore() structure.LocalWiggleSelected( 4 ) end --recentbest.Restore( ) FakeRecentBestRestore() ManageBands( ) end print( "Pattern gain: ".. getScore( ) - sw ) SaveBest( ) end selection.DeselectAll() print( "Total BandedWormPairs gain: " .. TrimNum( getScore( ) - ss ) ) end function PutSingleRandomBandToSeg( idx, probBis ) changeSucceeded = false local strength = random( 0.5 * BAND_STRENGTH_DEFAULT, 1.5 * BAND_STRENGTH_DEFAULT, true ) local doBIS = random( ) < probBis if doBIS then changeSucceeded = PutBandInSpace( idx, BIS_LENGTH, strength ) else if SegHasContactData( idx, CONTACTMAP_THRESHOLD ) and random( ) < PROB_CHOOSE_CONTACTMAP -- changed > to < BK then local doSidechain = random( ) < PROB_BETWEEN_USES_ATOM changeSucceeded = PutSomeContactMapBands( CONTACTMAP_THRESHOLD, strength, 1, doSidechain ) else local atom = PickAtomNumberForBand( idx ) changeSucceeded = PutBandToRandomSeg( idx, 5, strength, atom ) end end return changeSucceeded end ---------------------------------------------------------------- -- ---------------- BOILERPLATE --------------------- -- ---------------------------------------------------------------- ---------------------------------------------------------------- -- BASIC FUNCTIONALITY ---------------------------------------------------------------- function DebugPrint( str ) if DEBUGRUN then print( str ) end end function TrimNum( val ) return val - val % 0.001 end -- Not for "external" use - call getScore. This could change if customers want -- something besides current or recentbest. function internalGetScore( wantRB ) if wantRB == nil then wantRB = false end local s=0.0 if not USENORMALSCORE then if wantRB then --s = recentbest.GetEnergyScore( ) s= FakeRecentBestGetEnergyScore() else s=current.GetEnergyScore( ) end else if wantRB then --s = recentbest.GetScore( ) s = FakeRecentBestGetScore() else s=current.GetScore( ) end end return s end function getScore( ) return internalGetScore( false ) end function getRBScore( ) return internalGetScore( true ) end function SaveBest( ) local score = getScore( ) if score > CurrentBestScore then save.Quicksave( QS_Best ) CurrentBestScore = score end -- CheckFullScore() -- for DEBUG only end --START Debugging Recentbest Foldit Bug Temporary solution of Foldit bug (BK 29/8/2017) function Score() -- for BWPIF only return current.GetScore() end function FakeRecentBestSave() if PROBABLEFILTER then -- trying to solve the Foldit bug save.Quicksave(Qs_Recent) else recentbest.Save() end end function FakeRecentBestRestore() if PROBABLEFILTER then -- trying to solve the Foldit bug local ss=Score() recentbest.Restore() -- filter disabled (bug) local se=Score() -- now with the filter if se > ss then save.Quicksave(Qs_Recent) end save.Quickload(Qs_Recent) else recentbest.Restore() end end function FakeRecentBestGetScore() if PROBABLEFILTER then -- trying to solve the Foldit bug save.Quicksave(Qs_Current) recentbest.Restore() -- filter disabled (bug) local se=Score() -- now with the filter save.Quickload(Qs_Current) return se else recentbest.GetScore( ) end end function FakeRecentBestGetEnergyScore() if PROBABLEFILTER then -- trying to solve the Foldit bug save.Quicksave(Qs_Current) recentbest.Restore() -- filter disabled (bug) local se=current.GetEnergyScore( ) -- now with the filter save.Quickload(Qs_Current) return se else recentbest.GetEnergyScore( ) end end --END Debugging Recentbest Foldit Bug --[[ function CheckFullScore() -- check without filter (only for DEBUG) if filter.AreAllEnabled()==false then DebugPrint ("DEBUG: filter is off, turning on") FiltersOn() end end ]]-- function SetCI( ci ) behavior.SetClashImportance( SCALE_MAXCI * ci ) end ------------- CONTACTMAP FUNCTIONS ------------ function CheckForContactMap( ) PuzzleHasContactMap = false local saveval = 0.0 for i=1, segCt-1 do for j=i+1, segCt do val = contactmap.GetHeat( i, j ) if saveval ~= 0.0 and val ~= saveval then PuzzleHasContactMap = true ContactMapScore = GetContactScore( ) return -- all we wanted to know was whether scores exist end if saveval == 0.0 then saveval = val end end end return end function SegHasContactData( segIn, heatThreshold ) for i = 1, segCt do if i < segIn - 1 or i > segIn + 1 then if contactmap.GetHeat( segIn, i ) >= heatThreshold then return true end end end return false end function InitializeContactMapSegList( heatThreshold ) HasContactMapSegList = {} for i = 1, segCt do if SegHasContactData( i, heatThreshold ) then HasContactMapSegList[ #HasContactMapSegList + 1 ] = i end end end function GetContactScore( ) if not PuzzleHasContactMap then return 0 end local sum = 0.0 local segCt = structure.GetCount( ) for i = 1,segCt-1 do for j = i + 1, segCt do if contactmap.IsContact( i, j ) then sum = sum + contactmap.GetHeat( i, j ) end end end return sum end ----------------------- MATHY STUFF ----------------------- function seedRandom() seed=os.time( )/math.abs( getScore( ) ) seed=seed%0.001 seed=1/seed while seed<10000000 do seed=seed*1000 end seed=seed-seed%1 DebugPrint( "Seed is: "..seed ) math.randomseed( seed ) -- throw away a couple of randoms math.random( ) math.random( ) end function random( n1,n2, forceFloat ) --random function returns int or float depends on input vars if forceFloat == nil then forceFloat = false end if n1==nil then return math.random() else if n2==nil then if n1 == 0 then return 0 end -- a random number between 0 and 0 is 0 if n1%1==0 then -- can't test for "forceFloat", so caller must beware return math.random( n1) --integer else return math.random( ) * n1 --float end else if n1%1==0 and n2%1==0 and not forceFloat then return math.random( n1, n2 ) --integer between else return math.random( ) * (n2 - n1) + n1 --float between end end end end function randomSeg( ) return random( segCt ) end function randomThetaPhi() return math.acos( random( -1.0, 1.0, true ) ), random( 2 * math.pi ) end function randomizeIndexList( idxList ) for i=1, #idxList do j = random( #idxList ) if j ~= i then idxList[i], idxList[j] = idxList[j], idxList[i] end end end -- for branched aas, simply picks one (longer, one with donor/acceptor tip, or if no difference then either) function GetAtomOfTip( aa ) if aa == "a" then return 10 elseif aa == "c" then return 10 elseif aa == "d" then return 8 elseif aa == "e" then return 9 elseif aa == "f" then return 20 elseif aa == "g" then return 0 -- glycine has no tip. just use a backbone atom elseif aa == "h" then return 17 elseif aa == "i" then return 18 elseif aa == "k" then return 9 elseif aa == "l" then return 16 elseif aa == "m" then return 17 elseif aa == "n" then return 14 elseif aa == "p" then return 13 elseif aa == "q" then return 9 elseif aa == "r" then return 22 elseif aa == "s" then return 11 elseif aa == "t" then return 6 elseif aa == "v" then return 13 elseif aa == "w" then return 24 elseif aa == "y" then return 12 else return 0 end end function GetTipAtomOfSeg( idx ) return GetAtomOfTip( structure.GetAminoAcid( idx )) end function PickAtomNumberForBand( idx ) if not BAND_TO_SIDECHAINS then return CENTER_CARBON end local r = random( 1, 4 ) -- consider adjusting probability? if r == 1 then return BETA_CARBON elseif r == 2 then return CENTER_CARBON else return GetTipAtomOfSeg( idx ) -- 50% of the cases end end function IsUnlockedSeg( seg1 ) return not structure.IsLocked( seg1 ) end function FindAllMovableSegs( ) for i=1, segCt do if structure.IsLocked( i ) then PuzzleHasLockedSegs = true else NonLockedSegList[ #NonLockedSegList + 1] = i end end if PuzzleHasLockedSegs then for i=1, segCt do if IsUnlockedSeg( i ) then MinUnlockedSeg = i break end end for i=segCt, 1, -1 do if IsUnlockedSeg( i ) then MaxUnlockedSeg = i break end end end return false end ----------------------- BANDY STUFF ----------------------- function uMakeBands() -- list of existing user bands, strength, goal length ubcount=band.GetCount() for i=1, ubcount do ubandlist[i]={i, band.GetStrength(i), band.GetGoalLength(i)} -- {band number, band strength, goal_length} end if #ubandlist==0 then USERBANDS=false else USERBANDS=true end return ubandlist end function uBandEnabel() -- random enable a user band if USERBANDS and PROB_CHOOSE_USERBANDS >= random(0.0,1.0) then local maxstrength= 5 local minstrength=0.1 local bandIndex= random(1,ubcount) local multiplier = random( 0.5,2) local bandstrength=band.GetStrength(bandIndex) bandstrength=ubandlist[bandIndex][2]*multiplier if bandstrength>maxstrength then bandstrength=maxstrength elseif bandstrength<minstrength then bandstrength=minstrength end band.SetStrength(bandIndex, bandstrength) -- to do: random length? band.Enable(bandIndex) end end function ManageBands() --delete recipe bands, disable user bands if ubcount==0 or ubcount==nil then band.DeleteAll() else local bands=band.GetCount() if bands>ubcount then for i=bands, ubcount+1, -1 do band.Delete(i) end -- TO DO: il reste peut etre une bande ici end end band.DisableAll() end function BandBetweenSegsWithParameters( seg1, seg2, strength, goalLength, atom1, atom2 ) if not ( IsUnlockedSeg( seg1 ) or IsUnlockedSeg( seg2 ) ) then return false end if atom1 == nil then atom1 = CENTER_CARBON end if atom2 == nil then atom2 = CENTER_CARBON end local bIdx = band.AddBetweenSegments( seg1, seg2, atom1, atom2 ) if bIdx ~= band.GetCount( ) then DebugPrint( "failed to add band from "..seg1.." to "..seg2) return false end if bIdx <= InitialBandCount then return true end -- don't change user-supplied bands if goalLength ~= nil then band.SetGoalLength( bIdx, goalLength ) end if strength ~= nil and strength > 0.0 then band.SetStrength( bIdx, strength ) end return true end function BandInSpaceWithParameters( seg, segFini, segInit, rho, theta, phi, strength, goalLength, atomIndexOrigin, atomIndexXAxis, atomIndexYAxis) if not ( IsUnlockedSeg( seg) ) then return false end local atomIndexOrigin, atomIndexXAxis, atomIndexYAxis = atomIndexOrigin or CENTER_CARBON, atomIndexXAxis or 0, atomIndexYAxis or 0 local bIdx = band.Add( seg, segFini, segInit, rho, theta, phi, atomIndexOrigin, atomIndexXAxis, atomIndexYAxis ) if bIdx ~= band.GetCount( ) then return false end if bIdx <= InitialBandCount then return true end -- don't change user-supplied bands if goalLength ~= nil then band.SetGoalLength( bIdx, goalLength ) end if strength ~= nil and strength ~= 0.0 then band.SetStrength( bIdx, strength ) end return true end function PutBandInSpace( idx, maxRho, strength ) local atomIndexOrigin, atomIndexXAxis, atomIndexYAxis = 0,0,0 -- x and y not used actually local idx2, idx3 if idx < segCt then idx2 = idx + 1 else idx2 = idx - 2 end if idx > 1 then idx3 = idx - 1 else idx3 = idx + 2 end -- random point in sphere of radius maxRho local theta, phi = randomThetaPhi( ) local rho = (maxRho * random()^(1/3)) + 0.001 -- random atom for the banded (BIS) segment local MaxatomIndexOrigin = PickAtomNumberForBand( idx ) -- it's the end of the sidechain atomIndexOrigin = random( 0 , MaxatomIndexOrigin ) return BandInSpaceWithParameters( idx, idx2, idx3, rho, theta, phi, strength, atomIndexOrigin, atomIndexXAxis, atomIndexYAxis ) end function PutBandToRandomSeg( idx, minGap, strength, atom ) needNew = true local failedTries = 0 while ( needNew and failedTries < 30 ) do idx2 = randomSeg( ) -- ok if this one isn't movable (we assume idx is movable) if idx2 > idx + minGap or idx2 < idx - minGap then needNew = false break else failedTries = failedTries + 1 end end if not needNew then return BandBetweenSegsWithParameters( idx, idx2, strength, nil, atom, nil ) end return false end function PutSomeContactMapBands( heatThreshold, strength, ctBands, doSidechains ) changeSucceeded = false local hotList = {} for i = 1, segCt-2 do for j = i+2, segCt do local heat = contactmap.GetHeat(i, j) if heat >= heatThreshold and not contactmap.IsContact( i , j ) then hotList[ #hotList + 1] = { i, j, heat } end end end randomizeIndexList( hotList ) for i=1, math.min( ctBands, #hotList ) do local atom1 = nil local atom2 = nil if BAND_TO_SIDECHAINS and doSidechains then atom1 = PickAtomNumberForBand( hotList[i][1] ) atom2 = PickAtomNumberForBand( hotList[i][2] ) end local ch = BandBetweenSegsWithParameters( hotList[i][1], hotList[i][2], strength, nil, doTip1, doTip2 ) changeSucceeded = ch or changeSucceeded end return changeSucceeded end -------------------------------------------------------------------------- -- SETUP, CLEANUP, and MAIN -------------------------------------------------------------------------- function CleanPuzzleState( ) SetCI( 1.0 ) selection.DeselectAll() ManageBands() end function PrintState( ) local gain = getScore() - InitialScore if gain < 0.001 then print( " No change" ) else print( " Startscore: "..TrimNum( InitialScore )) print( " Score: "..TrimNum( getScore() ) ) print( " Total gain: "..TrimNum( gain )) end print( " Run time: "..os.time() - StartTime) end function End( errstr ) undo.SetUndo(true) if EndCalled then return end -- no infinite recursion please EndCalled = true print( "" ) if errstr ~= nil then if string.find( errstr, "Cancelled" ) then print( "User cancel" ) else print( errstr ) end end save.Quickload( QS_Best ) PrintState( ) CleanPuzzleState( ) end function InitializePuzzleState( ) seedRandom( ) InitialScore = getScore( ) CurrentBestScore = InitialScore StartTime = os.time() save.Quicksave( QS_Start ) save.Quicksave( QS_Best ) InitialClashImportance = behavior.GetClashImportance() SCALE_MAXCI = InitialClashImportance uMakeBands() -- new v1.2 FindAllMovableSegs( ) CheckForContactMap() if PuzzleHasContactMap then InitializeContactMapSegList( CONTACTMAP_THRESHOLD ) end end function main( ) for i= 1, 1000 do InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 2,5,11,3,13,4,7,1,6 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 14,8,6,7,13,12,2,10,11 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 5,7,1,3,9,6,2,4,8 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 3,6,12,4,14,5,8,2,7 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 3,8,4,5,12,6,10,2,7} BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 end End( ) end xpcall( main, End )

Comments