Icon representing a recipe

Recipe: Banded Worm

created by KarenCH

Profile


Name
Banded Worm
ID
49704
Shared with
Public
Parent
Banded Wiggle
Children
Created on
July 26, 2014 at 13:11 PM UTC
Updated on
July 26, 2014 at 13:11 PM UTC
Description

Very late endgame script: worm wiggle with bands mixed in

Best for


Code


------------------------------------------------------------------------------ -- Banded Worm ------------------------------------------------------------------------------ -- Modifies Worm LWS v2 (and is thus a pure AD script) -- -- by KarenCH ------------------------------------------------------------------------------ USENORMALSCORE = true -- exploration puzzles would set false DEBUGRUN = true -- mostly goes with DebugPrint, but could get more use later BAND_STRENGTH_DEFAULT = 1.0 PROB_PUTBAND = 1.0 -- how often do we put bands in our wiggle steps? PROB_BIS_NOT_BETWEEN = 0.50 -- do we prefer BIS or bands between segs PROB_BETWEEN_USES_TIP = 0.50 -- between: should wiggled seg have band from aa tip BIS_LENGTH = 5.0 -- max length of a BIS SCALE_MAXCI = 1.0 QS_Start = 1 QS_Best = 3 EndCalled = false InitialScore = 0.0 StartTime = 0 CurrentBestScore = 0.0 InitialClashImportance = behavior.GetClashImportance() segCt = structure.GetCount() function BandedWorm( pattern ) recentbest.Save( ) SetCI( 1.0 ) SaveBest( ) local ss = getScore() for w = 1, #pattern do len = pattern[ w ] local sw = getScore() local swCurr = sw print( "Starting BandedWorm of len " .. len .. ", score: ".. TrimNum( getScore() ) ) for s=1, segCt - len + 1 do selection.DeselectAll() selection.SelectRange( s, s + len - 1 ) local idx = random( s, s + len - 1 ) if random( ) < PROB_PUTBAND then PutSingleBand( idx ) structure.LocalWiggleSelected( 2 ) DelBands( ) structure.WiggleAll( 2 ) end structure.LocalWiggleSelected( 2 ) local swNew = getScore( ) if swNew > swCurr then structure.LocalWiggleSelected( 20 ) recentbest.Restore( ) DelBands( ) print( ">>>> At " .. s .. ": Gained ".. swNew - swCurr ) SaveBest( ) swCurr = swNew end recentbest.Restore( ) DelBands( ) end print( "Pattern gain: ".. getScore( ) - sw ) SaveBest( ) end selection.DeselectAll() print( "Total Worm gain: " .. TrimNum( getScore( ) - ss ) ) end function PutSingleBand( idx ) changeSucceeded = false local strength = random( 0.5 * BAND_STRENGTH_DEFAULT, 1.5 * BAND_STRENGTH_DEFAULT, true ) local doBIS = random( ) < PROB_BIS_NOT_BETWEEN local doTip1 = random( ) < PROB_BETWEEN_USES_TIP if doBIS then changeSucceeded = PutBandInSpace( idx, BIS_LENGTH, strength ) else changeSucceeded = PutBandToRandomSeg( idx, strength, doTip1 ) 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( ) else s=current.GetEnergyScore( ) end else if wantRB then s = recentbest.GetScore( ) 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 end function SetCI( ci ) behavior.SetClashImportance( SCALE_MAXCI * ci ) 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 randomThetaPhi() return math.acos( random( -1.0, 1.0, true ) ), random( 2 * math.pi ) 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 11 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 DelBands() band.DeleteAll() end function BandBetweenSegsWithParameters( seg1, seg2, strength, goalLength, fromTip1, fromTip2 ) -- caller can set goalLength without setting strength by providing strength = 0.0 --if not ( IsMovableSeg( seg1) or IsMovableSeg( seg2) ) then return false end if fromTip1 == nil then fromTip1 = false end if fromTip2 == nil then fromTip2 = false end if fromTip1 then tip1 = GetTipAtomOfSeg(seg1) else tip1 = 0 end if fromTip2 then tip2 = GetTipAtomOfSeg(seg2) else tip2 = 0 end local bIdx = band.AddBetweenSegments( seg1, seg2, tip1, tip2 ) if bIdx ~= band.GetCount( ) then DebugPrint( "failed to add band from "..seg1.." to "..seg2) return false end 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 ) -- caller can set goalLength without setting strength by providing strength = 0.0 --if not ( IsMovableSeg( seg) ) then return false end local bIdx = band.Add( seg, segFini, segInit, rho, theta, phi ) if bIdx ~= band.GetCount( ) then return false end 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 ) -- trying to do tips is too weird, so we omit the capability 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 return BandInSpaceWithParameters( idx, idx2, idx3, rho, theta, phi, strength ) end function PutBandToRandomSeg( idx, strength, doTip ) needNew = true local failedTries = 0 while ( needNew and failedTries < 20 ) do idx2 = random( segCt ) -- ok if this one isn't movable (we assume idx is movable) if idx2 > idx + 1 or idx2 < idx - 1 then needNew = false break else failedTries = failedTries + 1 end end if not needNew then return BandBetweenSegsWithParameters( idx, idx2, strength, nil, doTip, false ) end return false end -------------------------------------------------------------------------- -- SETUP, CLEANUP, and MAIN -------------------------------------------------------------------------- function CleanPuzzleState( ) SetCI( 1.0 ) selection.DeselectAll() DelBands() 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 ) 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 main( ) seedRandom( ) InitialScore = getScore( ) CurrentBestScore = InitialScore StartTime = os.time() save.Quicksave( QS_Start ) save.Quicksave( QS_Best ) InitialClashImportance = behavior.GetClashImportance() SCALE_MAXCI = InitialClashImportance pattern={ 2,5,11,3,13,4,7,1,6 } BandedWorm( pattern ) End( ) end xpcall( main, End )

Comments