Code
--------------------------------------------------------------------
-- Code for Simulated Annealing Recipe
--------------------------------------------------------------------
-- Performs "modifications" of a protein and accepts or rejects them
-- depending on "temperature" and on how much they improved the score
-- (if + improvement, yes; if not too bad score drop and temperature
-- is "high", then maybe yes). Temperature starts high, but drops
-- gradually to 0 by end of run.
--
-- TODO:
-- 1. Future exploration/pose generation round - add a helixifier,
-- make a workable tailwhip. Create a cysteine guesser. Use the
-- sheet actions. Make a sheet flipper. Other actions: if two
-- non-tiny sheets are separated by 2-3 segs, create a tight turn
-- between them.
-- After an exploration set of actions, see if Stabilizer rounds
-- can sort out which poses are best. Use the multitry system to
-- do a run of actions + Stabilizer, saving in quickslots and
-- transferring best to qs 3/4-8.
-- 2. Replace XToY bands in Idealize, Rebuild, Remix actions with
-- something more local: fewer total bands, and only between
-- sufficiently "nearby" segs.
--
-- BUGFIX: I think sheet actions are sometimes miscalculating alignment by 1.
-- Still gives a good action, but align/shift are opposite...
-- Code ideas and/or thefts come from:
-- (tlaloc) tlaloc Random Tug 4.00
-- (spvincent) Helix Twister 1.0,
-- Loop rebuild 5.0 (NC),
-- Local Quake 1.0,
-- Quaking Rebuild V2 1.0
-- (susume2) Cut and Wiggle Everything v0.1
-- (MurloW) Shock v0.1, Fracture v1.6, QuakingRebuild
-- (MurloW, drjr) Idealize by 3+
-- (rav3n_pl) Rav3n_pl GAB BiS v2.0.1 w30 [NC],
-- Rav3n_pl Voids Killer v0.5 NC,
-- Rav3n_pl Push v3, LS Quake v1.1
-- (tlaloc, rav3n_pl, Seagat2011, thom001) ST - Glycine Hinge REPOST
-- (drjr) drjr - RandomizeR 1.20, Idealize by 3
-- (brow42) Bridge Wiggle
-- SheetAtomBander 1.0
-- SheetStraightener
-- (BitSpawn) Rebuilds, GentleComp actions, general "how to do low CI"
-- (robgee) multibander actions
-- (LociOiling) how-to for filters, dialogs, error messages, Ident, etc
-- (Bruno Kestemont) IdentPuzzleType (aka puzzleprop)
-- (Steven Pletch et al) AcidTweaker
-- (TvdL) deep rebuild and remix actions
--------------------------------------------------------------------------------
Recipe = "Simulated Annealing"
Version = "5.0"
ReVersion = Recipe .. " v" .. Version
----------------------------------------------------------------------
--
---- SIMULATED-ANNEALING-SPECIFIC STUFF
--
----------------------------------------------------------------------
-- SAStab combines STAB1&2, SAEarly combines EARLY1&2, SARebuild combines REBUILD&2.
-- Temperature functions:
-- Choices in order of activity level: "OneOverX" "MiddlingX" "LowX" "ColdX" "ZeroX"
-- basic info for various stages
SA_STEPSPERRUN_STAB1 = 12
SA_NUMSTARTS_STAB1 = 10
TEMPFUNCNAME_STAB1 = "OneOverX"
SA_FAILIFNOGAIN_STAB1 = 10
WIGGLEPOWER_STAB1 = 'l'
SA_STEPSPERRUN_STAB2 = 12
SA_NUMSTARTS_STAB2 = 30
TEMPFUNCNAME_STAB2 = "OneOverX"
SA_FAILIFNOGAIN_STAB2 = 15
WIGGLEPOWER_STAB2 = 'l'
SA_STEPSPERRUN_EARLY1 = 12
SA_NUMSTARTS_EARLY1 = 150
TEMPFUNCNAME_EARLY1 = "OneOverX"
SA_FAILIFNOGAIN_EARLY1 = 15
WIGGLEPOWER_EARLY1 = 'a'
MIN_TRIES_EARLY_OP = 3 -- minumum number of revisits for Early
MAX_TRIES_EARLY_OP = 5 -- maximum number of revisits for Early
PROB_QSTAB_EXTRA_EARLY1 = 0.5 -- affects whether MOVER actions get qstab fusing
SA_STEPSPERRUN_EARLY2 = 12
SA_NUMSTARTS_EARLY2 = 80
TEMPFUNCNAME_EARLY2 = "MiddlingX"
SA_FAILIFNOGAIN_EARLY2 = 12
WIGGLEPOWER_EARLY2 = 'a'
PROB_QSTAB_EXTRA_EARLY2 = 1.0 -- probably never used!
SA_STEPSPERRUN_REBUILD = 15
SA_NUMSTARTS_REBUILD = 80
TEMPFUNCNAME_REBUILD = "MiddlingX"
SA_FAILIFNOGAIN_REBUILD = 20
WIGGLEPOWER_REBUILD = 'a'
SA_STEPSPERRUN_DEEPREBUILD = 15
SA_NUMSTARTS_DEEPREBUILD = 40
TEMPFUNCNAME_DEEPREBUILD = "MiddlingX"
SA_FAILIFNOGAIN_DEEPREBUILD = 10
WIGGLEPOWER_DEEPREBUILD = 'a'
SA_STEPSPERRUN_MIDGAME = 12
SA_NUMSTARTS_MIDGAME = 80
TEMPFUNCNAME_MIDGAME = "OneOverX"
SA_FAILIFNOGAIN_MIDGAME = 20
WIGGLEPOWER_MIDGAME = 'a'
-- ENDGAME does not currently use SA strategy, it uses WALKER. However, just in case
-- SA is brought back, the constants last used are provided here.
SA_STEPSPERRUN_ENDGAME = 12
SA_NUMSTARTS_ENDGAME = 100
TEMPFUNCNAME_ENDGAME = "ColdX"
SA_FAILIFNOGAIN_ENDGAME = 20
MIN_TRIES_ENDGAME = 4
MAX_TRIES_ENDGAME = 12
MIN_GAIN_ENDGAME = 5.0
-- ENDGAME chooses between high and medium wiggle power because high is not always available
-- controllers for actions within SASequence option
SASEQ_SKIP_STABILIZER = false
SASEQ_SKIP_BASICREBUILD = false
SASEQ_SKIP_DEEPREBUILD = false
SASEQ_SKIP_ENDGAME = true
SASEQ_ENDGAME_SKIP_CW = false
SASEQ_DISABLE_UBAND_AFTER_STAB = false
SASEQ_DISABLE_UBAND_AFTER_EARLY= false
DISABLE_ALL_USER_BANDS = false
-- actions to perform between or in deciding upon Operations (as 1st Early and later ones)
INH_EXH_FOR_CRUSH_ATTEMPT = 5 -- Count of Inhale+Exhale to count as a mid-op crush action.
DECEMENT_MIN_GAIN_EARLY = 5.0 -- gain needed for another Early pass after MIN is reached
-- De-cement or terminate an operation that's having inadequate gains.
FIGHT_CEMENTING_EARLY1 = true -- sets FIGHT_CEMENTING for Early1
FIGHT_CEMENTING_EARLY2 = false -- sets FIGHT_CEMENTING for Early2
SA_STEPSPERRUN_DECEMENT = 15 -- runs with de-cementer actions at start need more time to recover
FailsToStartCementBreaking = SA_FAILIFNOGAIN_EARLY1 - 5 -- how many fails before we start fighting
StepsForCementBreaking = 5 -- how many initial steps in a run should be cementbreakers
SA_MINGAIN = 0.5 -- gain that must be exceeded to not count as a fail
-- NON-USER-CONTROLLED parameters in cementing-related actions
EXPAND_BEFORE_ACTION = false -- whether PickActionFromList should pre-expand.
SA_FAILIFNOGAIN_DEFAULT = 10 -- the default choice for failing if a run has too small gain
FIGHT_CEMENTING_DEFAULT = false -- the default choice for FIGHT_CEMENTING
FIGHT_CEMENTING = false -- OPERATION controls: Early* or LowCI might change this
PossibleCementingState = false -- PerformSA() controls: Sets when fails >= FailsToStartCementBreaking
WorthTryingCementBreaker = false -- SA() controls: sets during StepsForCementBreaking of a run
CountFails = {} -- PerformSA() stat tracker
--------------- Walker constants ---------------
ACTION_ORDERPROTOCOL_START_TO_END = 1
ACTION_ORDERPROTOCOL_END_TO_START = 2
ACTION_ORDERPROTOCOL_RANDOMIZE = 3
ACTION_ORDERPROTOCOL_WORST_TO_BEST = 4
MinIdxGainToRepeat = 0.5
------------ Useful "special" kinds of run ------------
-- The LunchBuffet
SA_STEPSPERRUN_BUFFET = 12
SA_NUMSTARTS_BUFFET = 60
TEMPFUNCNAME_BUFFET = "MiddlingX"
PROB_TARGETED_BUFFET = 0.0
DO_WALKER_BUFFET = false
ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_START_TO_END
LunchBuffetActions = {} -- Stores list of actions user chose
-- Test runs
SA_STEPSPERRUN_TEST = 12
SA_NUMSTARTS_TEST = 60
TEMPFUNCNAME_TEST = "MiddlingX"
PROB_TARGETED_TEST = 0.0
--------------- Actions ---------------
ACTION_TYPE_BANDER = 1
ACTION_TYPE_QUAKER = 2
ACTION_TYPE_REBUILD = 3
ACTION_TYPE_REMIXIDEAL = 4
ACTION_TYPE_CONTACTMAP = 5
ACTION_TYPE_ENDGAME = 6
ACTION_TYPE_DUBIOUS = 7
AllActionsList = { -- Filled by GenerateAllActionsList
nameStr = "",
actionFunc = nil,
testFunc = nil,
usesIdx = false,
actionType = ACTION_TYPE_BANDER
}
------------ LESS INTERESTING SA STUFF ------------
-- in case I ever want to overrule belief that some actions are too
-- slow for normal use (actions generally permitted for small puzzles):
ALLOW_SLOW_ACTIONS_DEFAULT = false
ALLOW_SLOW_ACTIONS = false
-- some defaults
ALLOW_EXPAND_FOR_ACTION = false
PROB_USE_EXPANDER = 0.00
PROB_USE_EXPANDER_DEFAULT = 0.00
-- constants for weird SA operations
SA_STEPSPERRUN_LOW20 = 15 -- CI <= 0.20 -- first half of "LowCI"
SA_NUMSTARTS_LOW20 = 100
TEMPFUNCNAME_LOW20 = "OneOverX"
SA_STEPSPERRUN_LOW50 = 15 -- CI <= 0.50 -- second half of "LowCI"
SA_NUMSTARTS_LOW50 = 100
TEMPFUNCNAME_LOW50 = "OneOverX"
FIGHT_CEMENTING_LOWCI = true
SA_STEPSPERRUN_CMAP = 15 -- special Contact map operations
SA_NUMSTARTS_CMAP = 100
TEMPFUNCNAME_CMAP = "OneOverX"
SA_STEPSPERRUN_LATE = 300 -- Does fuse. not useful at auto or high, maybe at medium?
SA_NUMSTARTS_LATE = 1
TEMPFUNCNAME_LATE = "ZeroX"
-- For neighbor generation (if "change" is less than this, we think action failed)
THRESHOLD_PROTEIN_CHANGED = 0.1
-- when to bail if a protein is mostly locked and therefore rebuilds always fail
MAX_REBUILD_FAILS = 20
CtRebuildFails = 0 -- Operation fails if MAX_REBUILD_FAILS reached.
-- values for controlling behavior of fusing during Late stage
ALLOW_FUSE = false -- true for "SALate"
FUSEWIGGLE_ITERS = 2
FUSEWIGGLE_GAIN = 0.10
PROB_FUSEWIGGLE_CUTFUSE = 0.70
PROB_FUSEWIGGLE_LOCAL = 0.00 -- very slow, very poor success rate
PROB_FUSEWIGGLE_BLUEFUSE = 0.30
--------------------------------------------------------
-- Options that exist but appear to give no benefit
--------------------------------------------------------
-- How often should we target good/bad indices? It seems this is not worthwhile.
PROB_TARGETED = 0.00
PROB_TARGETED_DEFAULT = 0.00
PROB_TARGETED_STAB2 = 0.00
PROB_TARGETED_EARLY1 = 0.00
PROB_TARGETED_EARLY2 = 0.00
PROB_TARGETED_REBUILD = 0.00
PROB_TARGETED_DEEPREBUILD = 0.00
PROB_TARGETED_MID = 0.00
-- Fancy Targeting games (not really useful, but ... maybe someday)
PROB_TARGETED_WANTS_WINNER = 0.75 -- how often to seek recently-good indices (instead of low-scorers)?
PROB_WINNER_WANTS_NEIGHBOR = 0.00 -- if picking winner, do we actually want one of its neighbors?
WINNER_CLOCK_TIMEOUT = 20 -- when to take an index off the RecentWinners list
WINNER_INDEX_MAX_RADIUS = 7.0 -- far enough to find non-adjacent aas that happen to be near
RecentWinners = { {idx=0, clock=0} }
-- probably RecentWinners needs to track the algorithm that got a win as well
-- but mostly I expect it's just not worth the effort.
--------------------------------------------------------
-- Specialty options for specific actions
--------------------------------------------------------
BWP_PROB_ADD_SECOND_BAND = 0.25 -- do we want two bands instead of one?
BWP_PROB_BIS_NOT_BETWEEN = 0.50 -- do we prefer BIS or bands between segs
BWP_PROB_2ND_IS_BIS = 0.50 -- how often should 2nd band be BIS instead of between
AT_SPHERE_RADIUS = 8
AT_MAXIMO = 10.0
AT_PROB_DO_REBUILD = 1.0
AT_PROB_PUT_FIX_BANDS = 0.5
AT_PROB_SPHERE_ADD_WORSTS = 0.5
--------------------------------------------------------
--
---------------- BOILERPLATE ---------------------
--
--------------------------------------------------------
------------------------------------------------------------------------------------------------
-- Standard variables/constants used in my foldit scripts. Some are intended to be changed
-- as part of setup of scripts, others are user settable, yet more are unlikely to be changed.
-- A separate group, indicated as such, are genuinely intended as constants or as program-
-- controlled variables.
------------------------------------------------------------------------------------------------
-- some oddballs that users might want to set
DEBUGRUN = false
SHOW_STATS_REPORT = true
USENORMALSCORE = true -- exploration puzzles would set false
-- what to do with user state (bands, cuts, filters) when running, and what cleanup is best at end
PRESERVE_USER_BANDS = true -- all actions change if user wants this; dialog changes either way
PRESERVE_USER_CUTS = false -- some actions change if user does want this
RESTORE_BEST_AT_END = true
PERFORM_CLEANUP_AT_END = true
KILLING_FILTERS = false
FORBID_WIGGLE_POWER_CHANGE = false
-- values for controlling wiggles
QUICKWIGGLE_ITERS = 2
QUICKWIGGLE_GAIN = 0.10 -- for iterative wiggles that happen in quickwiggle time
PROB_LOCALWIGGLE = 1.00 -- I currently believe "before" wiggles should always prefer LocalWiggle over Wiggle.
USE_LOWCI_WIGGLES = false -- set true by default in low-ci scripts
MAX_FALL_FOR_SHAKEOUT = 1000.0 -- whether to bother to finish an action with a good wiggler
-- values for controlling shaking
SHAKESIDECHAIN_ITERS = 1 -- default time to use in shaking
-- values for controlling mutating
MUTATE_NOT_SHAKE = false -- "mutate never" vs "mutate always" (cf MUTATE_ONCE) in mutable puzzles.
MUTATE_ONCE = false -- mutate only happens during first "real" shake/mutate action
MUTATESIMILAR_PROB = 0.25 -- Only used if LunchBuffet "SpotMutator" is chosen
-- cysteine bander constants
CYSTEINE_PERFORM_BANDING = false -- whether to have special cysteine bands modifying actions
CYSTEINE_BAND_STRENGTH = 5.0 -- >=9.0 is dicy; 8.0 is severe. 5.0 works fine
CYSTEINE_MAX_RI_SEPARATION = 15.0 -- if more, then pose is nuts. fail the action that did this
CYSTEINE_COUNT_BANDS_USED = 3 -- pick 1..4 or break your script (3 looks best)
CYSTEINE_TOTAL_BANDS = 0 -- NOT user controlled
CYSTEINE_GOT_MIXUP = false -- NOT user controlled
-- bander options
BAND_STRENGTH_DEFAULT = 1.0
BAND_STRENGTH_REGION = 1.0
BAND_MAXCOMPRESS = 0.80
BAND_MAXGENTLECOMPRESS = 0.90
BAND_MINCOMPRESS = 0.95
BAND_MINEXPAND = 1.05
BAND_MAXGENTLEEXPAND = 1.10
BAND_MAXEXPAND = 1.20
BANDEDWIGGLE_TARGET = 500.0
BAND_TO_SIDECHAINS = true
ZLB_DEFAULT_STRENGTH = 2.0
XTOY_REBUILD_STRENGTH = 0.5
XTOY_REMIX_STRENGTH = 0.5
XTOY_IDEALIZE_STRENGTH = 1.5
BIS_LENGTH = 5.0 -- max length of a normal BIS
BIS_LENGTH_LONG = 8.0 -- max length of a "long" BIS
BIS_MIN_STRENGTH = 0.3
BIS_MAX_STRENGTH = 1.1
BIS_MIN_GOALLENGTH = 0.2 -- almost a ZLB
BIS_MAX_GOALLENGTH = 6.9
-- qstab fusing options
FORBID_ALL_QSTAB_FUSE = false
PROB_QSTAB_EXTRA = 0.00
PROB_QSTAB_EXTRA_DEFAULT = 0.00
PROB_QSTAB_EXTRA_QUAKE = 0.50 -- Quakes and GentleComp*
PROB_QSTAB_EXTRA_MOVERBANDS = 0.50 -- TEST: Mover,Flexer,Pusher,Helix*,Sheet*,*Hinge
PROB_QSTAB_EXTRA_VOIDCRUSH = 0.25 -- TESTING: VoidCrusher, PushPull, TailGrab
PROB_QSTAB_EXTRA_IDEALIZE = 1.00 -- Idealize* likes qstab fusing
PROB_QSTAB_EXTRA_MULTIBAND = 0.00 -- Multi* doesn't benefit from qstab fusing
-- values associated with idealize
IDEALIZE_USE_CUTS = true
IDEALIZE_FORBID_UNHEALED_CUTS = true
IDEALIZE_ZLB_MAXTRIES = 5 -- fails if cuts not healed. up ZLBstrength, try again.
IDEALIZE_TUBE_SMALL_RADIUS = 4.0 -- the idealizing range for IdealizeZlb and IdealizeRegion
IDEALIZE_TUBE_BIG_RADIUS = 10.0 -- the idealizing range for IdealizeRegionXToY
IDEALIZE_MIN_SEGLEN = 3 -- See GetIdealizeRange for how it's used
IDEALIZE_MAX_SEGLEN = 5 -- See GetIdealizeRange for how it's used
-- values associated with rebuild
REBUILD_DEEP_MAXTRIES = 5 -- tries in a deep rebuild. also QuakingRebuild and RebuildBitspawn
REBUILD_ADDIDEALIZE = true -- Rebuilds that want to also idealize will do so if this is true
REBUILD_MIN_SEGLEN = 3 -- See GetRebuildRange for how it's used
REBUILD_MAX_SEGLEN = 10 -- See GetRebuildRange for how it's used
REBUILD_TUBE_SMALLEST_RADIUS = 9.0 -- quaking rebuild radius for shake/wiggle
REBUILD_TUBE_INNER_RADIUS = 12.0 -- deep rebuild quick-check radius for shake/wiggle
REBUILD_TUBE_OUTER_RADIUS = 18.0 -- deep rebuild serious radius for shake/wiggle
-- values associated with remix
REMIX_SLOTS_WANTED = 25 -- check REMIX_MAX_SLOTS_TO_USE before increasing!
REMIX_MAX_SLOTS_TO_WIGGLE = 5 -- how many to give real wiggles to
REMIX_ADDIDEALIZE = true -- RemixSimple will also idealize if this is true
REMIX_MIN_SEGLEN = 4 -- See GetRemixRange for how it's used
REMIX_MAX_SEGLEN = 8 -- See GetRemixRange for how it's used
REMIX_TUBE_INNER_RADIUS = 9.0 -- for quicker wiggles
REMIX_TUBE_OUTER_RADIUS = 12.0 -- for final check wiggles
-- Clash Importance
CI_MAXSCALE = 1.00
CI_REGIONMOD = 0.10
CI_MUTATE = 0.21
CI_MULTIBAND_SHAKE = 0.21
CI_COREPULLING = 0.70
CI_LOCALWIGGLER_SHAKE = 0.81
CI_MULTIBAND_PULL = 0.90
-- values for contact map actions
CONTACTMAP_THRESHOLD = 0.25
CONTACTMAP_TAKEDROPS = false -- allow drops if they improve contact map
CONTACTMAP_MAX_DROP = 25.0
CONTACTMAP_CONTACTING_GOAL = 0.90
CONTACTMAP_NONCONTACTING_GOAL = 0.70
CONTACTMAP_CONTACTING_STRENGTH = 0.50
CONTACTMAP_NONCONTACTING_STRENGTH = 1.50
CONTACTMAP_MAX_NOCONTACT = 10.0 -- longer means disbelieve it's a valid contact
CONTACTMAP_BAND_ADD_RANDOMS = true -- whether to add random bands
CONTACTMAP_RANDOMBAND_COUNT = 3 -- how many random bands to add
CONTACTMAP_REBUILD_TUBE_INNER_RADIUS = 8.0
CONTACTMAP_REBUILD_TUBE_OUTER_RADIUS = 16.0
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
------------ VALUES USERS SHOULD NOT BE TOUCHING ---------------------------------
----------------------------------------------------------------------------------
RandSeed = 0
-------------- CONSTANTS THAT PROBABLY SHOULD NEVER CHANGE --------------
-- atoms in an amino acid
BETA_CARBON = 5
TERMINAL_BETA = 6
CENTER_CARBON = 2 --this is the default atom for bands to attach to
AACount = 20 -- how many different AAs do we use?
AAPhilCount = 9 -- how many AAs are hydrophilic?
AAPhobCount = 11 -- how many AAs are hydrophobic?
-- ideal distances
HELIX_DISTANCE_SKIP4 = 6.3 -- for skips of 4
HELIX_DISTANCE_SKIP5 = 8.6 -- for skips of 5
DISTANCE_SHEET_TO_SHEET = 4.8
DISTANCE_HELIX_TO_THING = 8.2
DISTANCE_SHEET_SEG_TO_SEG = 6.8
DISTANCE_INSHEET_N_TO_NPLUS2 = 9.5
DISTANCE_CYSTEINE_BOND = 2.05
SCALE_CYSTEINE_OFF_1 = 1.8
DISTANCE_ARO_RING_TO_RING = 3.2 -- "only infrequently less than ~3.2A", sometimes as short as ~2.6
SHEET2SHEET_BONDING_BAND_LENGTH = 1.8
SHEET2SHEET_MAX_DIST_TO_BAND = 7.0
SHEET2SHEET_CENTER_BAND_LENGTH = 3.0
DISTANCE_AA_TO_AA = 3.5
-- QUICKSAVE slots used herein
QS_Start = 1
QS_CmBest = 2
QS_Best = 3
QS_Alternate1 = 4 -- these are for scripts offering alternate poses.
QS_Alternate2 = 5
QS_Alternate3 = 6
QS_Alternate4 = 7
QS_Alternate5 = 8
QS_SA_BestEarly = 4
QS_SA_BestRebuild = 5
QS_SA_BestMidgame = 6
QS_SA_BestEndgame = 7
-- a quickslot stack for any system that wants such (some rebuilder/remixer scripts want)
QS_Base = 9 -- the base of a stack of slots to operate with
QS_Top = QS_Base -- the current top of the stack
QS_MAX = 24 -- the max top point for the stack
-- A collection of slots dedicated to remix
QS_RemixSlot1 = 25 -- lots and lots of remix slots. the more the merrier
QS_RemixSlotLast = 74
REMIX_MAX_SLOTS_TO_USE = QS_RemixSlotLast - QS_RemixSlot1 + 1
-- A collection of slots dedicated to my multistart system
QS_MultiStartSave1 = 75 -- surely nobody will multistart more than 15 times!
QS_MultiStartSaveLast = 89
MULTISTART_MAX_SLOTS = QS_MultiStartSaveLast - QS_MultiStartSave1 + 1
-- following slots are intended for use by "actions". Use at will.
QS_Swapslot = 91 -- used by quickslot swapping functions. generally usable.
QS_Swapslot2 = 92 -- used by quickslot swapping functions. generally usable.
QS_ShortUseTemp1 = 93 -- used by low-level actions that stash state for short time
QS_ShortUseTemp2 = 94 -- used by low-level actions that stash state for short time
-- following slots are not safe to borrow if MultiTry or SA are in play
QS_NeighborTempM1 = 95 -- used by MultiTry's "Neighbor Generation" subroutines
QS_TopLevelTempMT = 96 -- used by MultiTry top-level manager
QS_TopLevelTempM2 = 97 -- used by MultiTry top-level manager
QS_NeighborTempSA = 98 -- used by SA's "Neighbor Generation" subroutines
QS_TopLevelTempSA = 99 -- used by SA top-level manager
--------------- THINGS THE PROGRAM LEARNS AND REMEMBERS --------------
-- why yes, I do wish I knew what aas/atoms bands connect to as well
InitialBandCount = 0
InitialBandStates = { {bIdx=0, isEnabled=false} }
InitialClashImportance = behavior.GetClashImportance()
IsFilterDisabled = behavior.GetFiltersDisabled( )
InitialWigglePower = behavior.GetWigglePower( )
SegCt = structure.GetCount( )
PuzzleAllowsMutate = false
PuzzleHasLockedSegs = false
PuzzleHasContactMap = false
PuzzleUsesFilters = false
PuzzleIsDesigner = false -- set but not used
PuzzleIsSepsis = false -- set but not used
PuzzleIsElectron = false -- set but not used
PuzzleIsCentroid = false -- used by acid tweaker
PuzzleIsSymmetry = false -- set but not used
PuzzleSymmetryLevel = 1 -- set but not used
StartTime = 0
InitialScore = 0.0
ContactMapScore = 0.0
HasContactMapSegList = {}
InitialFrozenTable = {}
-- weird globals controlled by program
ChangedSecondaryStructure = false
ChangedFrozenness = false
EndCalled = false
-- Usage of following tables: bounds = All*[i] use bounds.sIdx and bounds.eIdx
AllHelices = { {sIdx = 0, eIdx = 0} }
AllSheets = { {sIdx = 0, eIdx = 0} }
AllLoops = { {sIdx = 0, eIdx = 0} }
PossibleHelices = { {sIdx = 0, eIdx = 0} }
CysteineBandPairCount = 0
CysteineAaSegList = {}
CysteinePairList = {}
NonLockedSegList = {}
OriginalSecondaryStructures = {}
MinUnlockedSeg = 1
MaxUnlockedSeg = SegCt -- this line must come after setter of SegCt
NoMutateList = {}
ShakeAfterMutateList = {} -- generated from NoMutateList, depending on options wanted by user
AllowedActionIndices = {}
---------------- STATISTICS-TRACKING ---------------------
AlgName = "none" -- for tracking statistics about how successful an action is
AlgNameList = {}
AlgStats =
{
name = "none",
posScoreDelta = 0.0,
scoreDelta = 0.0,
runTime = 0,
callCount = 0,
failCount = 0,
}
TotalShakeTime = 0
TotalMutateTime = 0
----------------------------------------------------------------
-- STRING FUNCTIONS
----------------------------------------------------------------
function DebugPrint( str )
if DEBUGRUN then print( str ) end
end
function BoolStr( bval )
if bval then return "true" end
return "false"
end
function PadString( strIn, lenWanted )
local strOut = strIn
while string.len( strOut ) < lenWanted do
strOut = strOut .. " "
end
return strOut
end
function PadNumString( numIn, lenWanted )
local strOut = ""..numIn
while string.len( strOut ) < lenWanted do
strOut = strOut .. " "
end
return strOut
end
function TrimNum( val )
return val - val % 0.001
end
function printVector( vec, prefix, isFloat )
if isFloat == nil then isFloat = false end
local str=""
for i=1, #vec do
if isFloat then
str = str..TrimNum(vec[i])
else
str = str..vec[i]
end
if i < #vec then str = str.."," end
end
print(prefix.. ": "..str)
end
-- a function that parses a string of aa indices and returns them as a sorted array.
function ParseAaString( str, AaArray )
-- fancy parsing here: Input format is: idx1,idx2-idx3,idx4,idx5,idx6-idx7,...
for w in string.gmatch( str, "[^,]+" ) do
if string.find( w, "-" ) ~= nil then
local s, f = string.match( w, "(%d+)%-(%d+)" )
local start = tonumber( s )
local fin = tonumber( f )
for i=start,fin do
local okToAdd = true
for j=1,#AaArray do
if AaArray[ j ] == i then
okToAdd = false
break
end
end
if okToAdd then
AaArray[ #AaArray+1] = i
end
end
else
local seg = tonumber( w )
local okToAdd = true
for j=1,#AaArray do
if AaArray[ j ] == seg then
okToAdd = false
break
end
end
if okToAdd then
AaArray[ #AaArray+1] = seg
end
end
end
if #AaArray > 0 then table.sort(AaArray) end
end
-- expect a string of form "3,6-12,18-22,33,56-59"
function parseRangesStr( str )
local idxListOut = {}
local loc = 1
local len = 0
local sep = ""
local parseError = false
local notDone = true
while notDone do
loc,len,v1 = string.find( str, "(%d+)", loc )
if loc == nil then
notDone = false
break
end
loc = len
loc,len,sep = string.find( str, "([,;-])", loc )
if loc == nil then
notDone = false
idxListOut[#idxListOut+1] = v1+0
break -- must have been end of string
elseif sep == '-' then
loc = len
loc,len,v2 = string.find( str, "(%d+)", loc )
if loc == nil then
idxListOut = {}
parseError = true
notDone = false
break
end
loc = len
-- add range to list
for i=v1+0, v2+0 do
idxListOut[#idxListOut+1] = i
end
-- move past any following ',' or ';'
loc,len,sep = string.find( str, "([,;])", loc )
if loc == nil then
notDone = false
break -- must have been end of string
end
loc = len
else
-- add single number to list
idxListOut[#idxListOut+1] = v1+0
end
if len == string.len( str ) then break end
end
return idxListOut
end
function parseCysteineStr( ctPairsWanted, str )
local cysList = {}
-- v1, v2: '(%d+),(%d+)[; ]+'
for v1 in string.gfind(str, '-?(%d+)') do
v1 = tonumber( v1 )
if v1 < 1 or v1 > SegCt then return false end
if structure.GetAminoAcid(v1) ~= 'c' then return false end
cysList[#cysList+1] = v1
end
if #cysList ~= 2*ctPairsWanted then return false end
for i = 1, #cysList-1 do
val = cysList[i]
for j=i+1, #cysList do
if cysList[j+1] == val then return false end
end
end
-- ok, we believe the list is a correct number of distinct cysteines
CysteinePairList = {}
for i=1, ctPairsWanted do
CysteinePairList[#CysteinePairList+1] = {cysList[2*i-1], cysList[2*i]}
end
end
----------------------------------------------------------------
-- IDENTIFICATION FUNCTIONS
----------------------------------------------------------------
function Ident( slugline )
local function round ( ii )
return ii - ii % 0.001
end
print ( slugline )
print ( "Puzzle: " .. puzzle.GetName () .. " (" .. puzzle.GetPuzzleID () .. ")" )
print ( "Track: " .. ui.GetTrackName () )
local gname = user.GetGroupName()
if gname ~= nil then
gname = " (" .. gname .. ")"
else
gname = ""
end
print ( "User: " .. user.GetPlayerName () .. gname )
local scoretype = scoreboard.GetScoreType ()
local scort = ""
if scoretype == 0 then
scort = "soloist"
elseif scoretype == 1 then
scort = "evolver"
elseif scoretype == 2 then
scort = "all hands"
elseif scoretype == 3 then
scort = "no score"
else
scort = "unknown/error"
end
print ( "Rank: " .. scoreboard.GetRank ( scoretype ) .. " (" .. scort .. ")" )
local sGroup = scoreboard.GetGroupScore ()
if sGroup ~= nil then
print ( "Group rank / score: " .. scoreboard.GetGroupRank () .. " / " .. round ( 10 * ( 800 - sGroup ) ) )
end
print( "StartDate: "..os.date( ) )
end
function IdentPuzzleType( ) -- originally named puzzleprop, by Bruno Kestemont. some mods
local descrTxt = puzzle.GetDescription()
local puzzletitle = puzzle.GetName()
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
PuzzleIsSymmetry=true
if puzzletitle:find("Dimer") and not puzzletitle:find("Dimer of Dimers") then
PuzzleSymmetryLevel=2
elseif puzzletitle:find("Trimer") or puzzletitle:find("Tetramer") then
PuzzleSymmetryLevel=3
elseif puzzletitle:find("Dimer of Dimers") or puzzletitle:find("Tetramer") then
PuzzleSymmetryLevel=4
elseif puzzletitle:find("Pentamer") then
PuzzleSymmetryLevel=5
end
end
end
if not PuzzleIsSymmetry then
-- because sometimes the title doesn't tell us about symmetry, so try again here:
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
PuzzleIsSymmetry=true
if (descrTxt:find("Dimer") or descrTxt:find("dimer")) and not
(descrTxt:find("Dimer of Dimers") or descrTxt:find("dimer of dimers"))
then
PuzzleSymmetryLevel=2
elseif descrTxt:find("Trimer") or descrTxt:find("trimer") then
PuzzleSymmetryLevel=3
elseif (descrTxt:find("Dimer of Dimers") or descrTxt:find("Tetramer"))
and not (descrTxt:find("dimer of dimers") or descrTxt:find("tetramer"))
then
PuzzleSymmetryLevel=4
elseif descrTxt:find("Pentamer") or descrTxt:find("pentamer") then
PuzzleSymmetryLevel=5
end
end
end
if #puzzletitle>0 and puzzletitle:find("Sepsis") then -- new BK 17/6/2013
PuzzleIsSepsis=true
end
if #puzzletitle>0 and puzzletitle:find("Electron Density") then -- for Electron Density
PuzzleIsElectron=true
end
if #puzzletitle>0 and puzzletitle:find("Centroid") then -- New BK 20/10/2013
PuzzleIsCentroid=true
end
PuzzleAllowsMutate = isPuzzleMutable( )
if PuzzleAllowsMutate then PuzzleIsDesigner = checkDesigner( ) end
PuzzleUsesFilters = CheckForFilters( )
if PuzzleUsesFilters then ReportFilters( ) end
PuzzleHasContactMap = CheckForContactMap( )
if PuzzleHasContactMap then
ContactMapScore = GetContactScore( )
InitializeContactMapSegList( CONTACTMAP_THRESHOLD )
end
end
----------------------------------------------------------------
-- ACTION STATISTICS AND PREFERENCES
----------------------------------------------------------------
function whereIsStringInArray( array, str )
for i=1, #array do if str == array[ i ] then return i end end
return 0
end
function addActionToStats( scoreDelta, timeDelta )
if whereIsStringInArray( AlgNameList, AlgName ) == 0 then
AlgNameList[ #AlgNameList + 1] = AlgName
end
if AlgStats[ AlgName ] == nil then
AlgStats[ AlgName ] = {
posScoreDelta = 0.0,
scoreDelta = 0.0,
runTime = 0,
callCount = 0,
gainCount = 0,
failCount = 0,
}
end
if scoreDelta > 0.0 then
AlgStats[ AlgName ].posScoreDelta = AlgStats[ AlgName ].posScoreDelta + scoreDelta
AlgStats[ AlgName ].gainCount = AlgStats[ AlgName ].gainCount + 1
end
AlgStats[ AlgName ].scoreDelta = AlgStats[ AlgName ].scoreDelta + scoreDelta
AlgStats[ AlgName ].runTime = AlgStats[ AlgName ].runTime + timeDelta
AlgStats[ AlgName ].callCount = AlgStats[ AlgName ].callCount + 1
end
function addFailToStats( )
if whereIsStringInArray( AlgNameList, AlgName ) == 0 then
AlgNameList[ #AlgNameList + 1] = AlgName
end
if AlgStats[ AlgName ] == nil then
AlgStats[ AlgName ] = {
posScoreDelta = 0.0,
scoreDelta = 0.0,
runTime = 0,
callCount = 1,
gainCount = 0,
failCount = 1,
}
return
end
AlgStats[ AlgName ].callCount = AlgStats[ AlgName ].callCount + 1
AlgStats[ AlgName ].failCount = AlgStats[ AlgName ].failCount + 1
end
function sortStats(nameList, statsIn)
table.sort(nameList,
function(n1,n2)
return statsIn[n1].posScoreDelta / statsIn[n1].runTime >
statsIn[n2].posScoreDelta / statsIn[n2].runTime
end
)
end
function reportStats( )
-- scoreDelta turns out to be not very interesting to look at
sortStats( AlgNameList, AlgStats )
for i = 1, #AlgNameList do
local t = AlgNameList[ i ]
if AlgStats[ t ] ~= nil and AlgStats[ t ].callCount > 0 then
print( " " .. PadString(t, 20) .. ":" ..
" posScore=" .. TrimNum( AlgStats[ t ].posScoreDelta ) ..
" tmPerRun=" .. TrimNum( AlgStats[ t ].runTime / AlgStats[t].callCount) ..
" scPerTime=" .. TrimNum( AlgStats[ t ].posScoreDelta / AlgStats[ t ].runTime ) ..
" runs=" .. AlgStats[ t ].callCount ..
" gains=" .. AlgStats[ t ].gainCount ..
" fails=" .. AlgStats[ t ].failCount )
else
print("no info for "..t)
end
end
print( "Time so far: "..(os.time() - StartTime) )
end
function resetStats( )
for i = 1, #AlgNameList do
local t = AlgNameList[ i ]
if AlgStats[ t ] ~= nil then
AlgStats[ t ].scoreDelta = 0
AlgStats[ t ].posScoreDelta = 0
AlgStats[ t ].runTime = 0
AlgStats[ t ].callCount = 0
AlgStats[ t ].gainCount = 0
AlgStats[ t ].failCount = 0
end
end
end
----------------------------------------------------------------
-- BASIC SCORE FUNCTIONS
----------------------------------------------------------------
-- Not for "external" use - call getScore. This could change if customers want
-- something besides current or recentbest.
function internalGetScore( wantRB, useFilter )
if wantRB == nil then wantRB = false end
if useFilter and KILLING_FILTERS then
TurnOnFilters( )
end
local score=0.0
if not USENORMALSCORE then
if wantRB then
score = recentbest.GetEnergyScore( )
else
score = current.GetEnergyScore( )
end
if useFilter then score = score + filter.GetBonusTotal( ) end
else
if wantRB then score = recentbest.GetScore( )
else score=current.GetScore( )
end
end
if useFilter and KILLING_FILTERS then
TurnOffFilters( )
end
return score
end
function getScore( )
return internalGetScore( false, true )
end
function getQuickScore( )
return internalGetScore( false, false )
end
function getRBScore( )
return internalGetScore( true, true )
end
function GetTotalSegScore( )
local total=0.0
for i=1, SegCt do
total=total + current.GetSegmentEnergyScore(i)
end
return total
end
function getSlotScore( qs )
save.Quicksave( QS_Swapslot )
save.Quickload( qs )
local sc = getScore( )
save.Quickload( QS_Swapslot )
return sc
end
function SaveBest( forceBest, qs_best ) -- most callers will leave both as nil.
if qs_best == nil then qs_best = QS_Best end
if forceBest == nil then forceBest = false end
local score = getScore( )
local currentBestScore = getSlotScore( qs_best )
-- use "score >=" because same-with-unfrozen/unbanded is better
if forceBest or score >= currentBestScore then
save.Quicksave( qs_best )
currentBestScore = score
end
if PuzzleHasContactMap then
local currentBestCmScore = getSlotScore( QS_CmBest )
local cmScore = GetContactScore( )
if forceBest or (CONTACTMAP_TAKEDROPS and cmScore > currentBestCmScore)
then
save.Quicksave( QS_CmBest )
currentBestCmScore = score
end
if CONTACTMAP_TAKEDROPS and currentBestScore ~= currentBestCmScore then
DebugPrint(" In Best("..qs_best.."): score="..currentBestScore )
DebugPrint(" In CmBest("..QS_CmBest.. "): score="..currentBestCmScore )
end
end
end
function SaveBests( override, qs )
SaveBest( ) -- never allow an override for QS_Best
if qs ~= nil and qs ~= QS_Best then
SaveBest( override, qs )
end
end
function LoadBest( qs_best )
if qs_best == nil then qs_best = QS_Best end
local currentBestScore = getSlotScore( qs_best )
if PuzzleHasContactMap and CONTACTMAP_TAKEDROPS and qs_best == QS_Best then
local currentBestCmScore = getSlotScore( QS_CmBest )
if currentBestCmScore >= currentBestScore - CONTACTMAP_MAX_DROP
then
save.Quickload( QS_CmBest )
else
save.Quickload( qs_best )
end
else
save.Quickload( qs_best )
end
end
function GetBestScore( )
local currentBestScore = getSlotScore( qs_best )
if PuzzleHasContactMap and CONTACTMAP_ALLOWDROP then
local currentBestCmScore = getSlotScore( QS_CmBest )
if currentBestCmScore >= currentBestScore - CONTACTMAP_MAX_DROP
then
return currentBestCmScore
else
return currentBestScore
end
else
return currentBestScore
end
end
----------------------------------------------------------------
-- RANDOM FUNCTIONS
----------------------------------------------------------------
-- Using the java LCG random generator
function nextRand( )
-- keep 48 bits, so mod 2^48
RandSeed = (RandSeed * 0x5DEECE66D + 11) % 281474976710656
return RandSeed
end
function nextRandFloat01( )
local val = ( nextRand() + .0 ) / 100000000.0
local junk, valF = math.modf( val )
return valF
end
function nextRandIntRange( low, high )
if low == high then return low end
local val = (high + 1 - low) * nextRandFloat01( )
val = low + math.floor( val )
return val
end
function seedRandom( )
-- If someone wants to control the random sequence, they can manually set
-- RandSeed before run. Keep in mind that rebuild uses its own random,
-- so there's only so deterministic the run will end up being!
if RandSeed == 0 then
-- 79 is a random prime to spread time values out. True to Java would use 0x5DEECE66D
local seedI = os.time() * 79
local tmp = math.abs(getQuickScore( ))
local junk, seedF = math.modf( tmp ) -- want fractional part of score
local seed = math.floor( seedI * seedF) -- result: integer in [0..time*79)
RandSeed = seed % 281474976710656 -- mod 2^48: java LCG uses 48 bits
end
DebugPrint( "Seed is: "..RandSeed )
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 nextRandFloat01( )
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 -- caveat caller: can't test for "forceFloat"
return nextRandIntRange( 1, n1 ) --integer
else
return nextRandFloat01( ) * n1
end
else
if n1%1==0 and n2%1==0 and not forceFloat then
--integer between
return nextRandIntRange( n1, n2 )
else
--float between
return nextRandFloat01( ) * (n2 - n1) + n1
end
end
end
end
function randomBool( probTrue )
if probTrue == nil then probTrue = 0.5 end
if probTrue == 0.0 then
return false
elseif probTrue == 1.0 then
return true
else
return random() < probTrue
end
end
function randomDice( ctDice, minValPerDie, maxValPerDie ) -- distro that prefers "middle" values
local total = 0
for i=1, ctDice do
total = total + random( minValPerDie, maxValPerDie )
end
return total
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
local j = random( #idxList )
if j ~= i then
idxList[i], idxList[j] = idxList[j], idxList[i]
end
end
end
function randomSeg( )
return random( SegCt )
end
function randomUnlockedSeg( )
if not PuzzleHasLockedSegs then
return randomSeg( )
end
return NonLockedSegList[ random( #NonLockedSegList ) ]
end
function randomAASeg( whichAA )
local segs = {}
for i=1, #NonLockedSegList do
if structure.GetAminoAcid( i ) == whichAA then
segs[ #segs + 1 ] = i
end
end
if #segs == 0 then return 0 end
return segs[ random( #segs ) ]
end
function randomMovableSeg( )
for i=1, 20 do
local seg = randomUnlockedSeg( )
if seg == nil then break end
local bb, sc = freeze.IsFrozen( seg )
if not bb then return seg end
end
-- if we are here, then we had a hard time finding a nonfrozen seg.
-- make an array and search the hard way.
local movables = {}
for i=1, #NonLockedSegList do
local bb, sc = freeze.IsFrozen( seg )
if not bb then movables[ #movables + 1 ] = i end
end
if #movables == 0 then return 1 end -- nothing we can do
return movables[ random( #movables ) ]
end
function SegIsUsable( idx )
-- if it's locked, then it's not usable
local gotMatch = false
for i = 1, #NonLockedSegList do
if NonLockedSegList[ i ] == idx then
gotMatch = true
break
end
end
if not gotMatch then return false end
-- if it's frozen, then it's not usable
for i=1, #NonLockedSegList do
local bb, sc = freeze.IsFrozen( idx )
if bb then return false end
end
-- if we haven't made a restricted list, or if it's on that list, then it's usable
if #AllowedActionIndices == 0 then return true end
for i=1, #AllowedActionIndices do
if AllowedActionIndices[ i ] == idx then return true end
end
return false -- not usable
end
function randomMovableFarSeg( segOrigin, minSep, minDist, maxDist )
local segList = {}
for i=1, SegCt do
if IsMovableSeg( i ) and (i <= segOrigin - minSep or i >= segOrigin + minSep ) then
dist = structure.GetDistance( segOrigin, i )
if dist >= minDist and dist <= maxDist then segList[ #segList + 1 ] = i end
end
end
if #segList >= 1 then return segList[ random( #segList ) ]
else return 0
end
end
function randomLowScoringSeg( ctIndicesToChooseAmong, subscore )
local idxList = {}
getWorstScoringAAs( idxList, ctIndicesToChooseAmong, subscore )
return idxList[ random( #idxList ) ]
end
function randomContactableSeg( )
return HasContactMapSegList[ random( #HasContactMapSegList ) ]
end
function randomContactSeg( segIn, heatThreshold )
local segOpts = {}
for i = 1, SegCt do
if i < segIn - 1 or i > segIn + 1 then
if contactmap.GetHeat( segIn, i ) >= heatThreshold then
segOpts[ #segOpts + 1] = i
end
end
end
if #segOpts == 0 then return 0 end
return segOpts[ random( #segOpts ) ]
end
function randomPrimeNotMoreThan( max )
local primes = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101}
local lastIdx = #primes
for i=1, #primes do
if primes[ i ] > max then break end
lastIdx = i
end
return primes[ random( lastIdx ) ]
end
function getCoprime( n )
-- find the highest prime < 70% of "n" that is coprime with "n"
local primes = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101}
for i = #primes, 1, -1 do
if primes[ i ] < 0.70*n and n % primes[ i ] ~= 0 then
return primes[ i ]
end
end
return 1
end
----------------------------------------------------------------
-- SCORE-USING FUNCTIONS
----------------------------------------------------------------
function sortByScore(segs, scores)
table.sort(segs, function(n1,n2) return scores[n1] < scores[n2] end)
end
function sortByScoreDecr(segs, scores)
table.sort(segs, function(n1,n2) return scores[n1] > scores[n2] end)
end
function constructScoreMatrix( scmat )
-- TODO: Get the list of "active" subscores from puzzle info; use that info here.
for i=1, SegCt do
scmat[i] = {}
scmat[i][1] = current.GetSegmentEnergySubscore( i, "backbone" )
scmat[i][2] = current.GetSegmentEnergySubscore( i, "sidechain" )
scmat[i][3] = current.GetSegmentEnergySubscore( i, "clashing" )
scmat[i][4] = current.GetSegmentEnergySubscore( i, "packing" )
scmat[i][5] = current.GetSegmentEnergySubscore( i, "density" )
scmat[i][6] = current.GetSegmentEnergySubscore( i, "hiding" )
scmat[i][7] = current.GetSegmentEnergySubscore( i, "bonding" )
scmat[i][8] = current.GetSegmentEnergySubscore( i, "disulfides" )
scmat[i][9] = current.GetSegmentEnergySubscore( i, "ideality" )
scmat[i][10] = current.GetSegmentEnergySubscore( i, "pairwise" )
scmat[i][11] = current.GetSegmentEnergySubscore( i, "other" )
end
end
function getEuclideanDistanceVector( scmat1, scmat2, vecOut )
for j=1, #scmat1[1] do
vecOut[j] = 0.0
end
for i=1, SegCt do
for j=1, #scmat1[i] do
vecOut[j] = vecOut[j] + (scmat2[i][j] - scmat1[i][j]) * (scmat2[i][j] - scmat1[i][j])
end
end
for j=1, #vecOut do
vecOut[j] = math.sqrt( vecOut[j] )
end
end
function isNeighborDifferentFromOld( oldScoreMat, threshold )
local newScoreMat = {}
local scoreVector = {}
constructScoreMatrix( newScoreMat )
getEuclideanDistanceVector( oldScoreMat, newScoreMat, scoreVector )
for i=1, #scoreVector do
if scoreVector[i] > threshold then return true end
end
return false
end
function isProteinChanged( oldQuickScore, oldScoreMat, threshold )
if (not KILLING_FILTERS) and (not current.AreConditionsMet( )) then return false end
local currScore = getQuickScore( )
if currScore > oldQuickScore then return true end
return isNeighborDifferentFromOld( oldScoreMat, threshold )
end
-- returns all aas in order of score (if subscore is nil then does GetSegmentEnergyScore)
function getWorstScoringAAs( idxList, maxWanted, subscore )
local scoreList = {}
local idxes = {}
for i=1, SegCt do
idxes[i] = i
end
for i=1, SegCt do
if subscore == nil then
scoreList[i] = current.GetSegmentEnergyScore(i)
else
scoreList[i] = current.GetSegmentEnergySubscore( i, subscore )
end
end
sortByScore( idxes, scoreList )
for i = 1, math.min( maxWanted, SegCt ) do
idxList[i] = idxes[i]
end
end
function getBestScoringAAs( idxList, maxWanted, subscore )
local scoreList = {}
local idxes = {}
for i=1, SegCt do
idxes[i] = i
end
for i=1, SegCt do
if subscore == nil then
scoreList[i] = current.GetSegmentEnergyScore(i)
else
scoreList[i] = current.GetSegmentEnergySubscore( i, subscore )
end
end
sortByScoreDecr( idxList, scoreList )
end
function isBadScorer(idx, mustBeAtLeastThisBad)
local idxList = {}
getWorstScoringAAs( idxList, mustBeAtLeastThisBad)
for i=1, #idxList do
if idxList[i] == idx then return true end
end
return false
end
function SortIdxListBySubscore( idxList, subscoreName )
local subscoreList = {}
for i=1, #idxList do
subscoreList[ i ] = current.GetSegmentEnergySubscore( idxList[ i ], subscoreName )
end
sortByScore( idxList, subscoreList )
end
function GetWorstScoringRegions( idxList, len )
local scoreList = { }
for i=1, SegCt - len + 1 do
scoreList[ i ] = 0.0
idxList[ i ] = i
for j = 0, len - 1 do
scoreList[ i ] = scoreList[ i ] + current.GetSegmentEnergyScore( i + j )
end
end
sortByScore( idxList, scoreList )
end
----------------------------------------------------------------
-- DISTANCE FUNCTIONS
----------------------------------------------------------------
function computeDistanceSums(distList)
-- i-th entry is avg value of distances from every other aa to i-th aa.
for i=1, SegCt do
distList[i] = 0.0
end
for i=1, SegCt-1 do
for j=i+1, SegCt do
local x = structure.GetDistance( i, j ) / SegCt
distList[i] = distList[i] + x
distList[j] = distList[j] + x
end
end
end
function getCentralAAs( idxList )
local distList = {}
for i=1, SegCt do
idxList[i] = i
end
computeDistanceSums( distList )
sortByScore( idxList, distList )
end
function computeDistanceMatrix( distMat )
for i=1, SegCt do
distMat[i] = {}
end
for i=1, SegCt-1 do
for j=1, SegCt do
distMat[i][j] = structure.GetDistance( i, j )
end
end
end
function compareDistanceMatrices( mat1, mat2 )
for i=1, SegCt-1 do
for j=i+1, SegCt do
local val1 = mat1[ i ][ j ]
local val2 = mat2[ i ][ j ]
local diff = math.abs( val1 - val2 )
if diff > 2.5 then return false end
end
end
return true
end
-- returns all hydrophobics in order of "centralness"
function getCentralHydrophobics(idxList, ctWanted)
local idxListInternal = {}
getCentralAAs(idxListInternal)
for i=1, #idxListInternal do
if structure.IsHydrophobic( idxListInternal[ i ] ) then
idxList[ #idxList + 1 ] = idxListInternal[ i ]
if #idxList == ctWanted then return end
end
end
end
function isCentralHydrophobic( idx, mustBeAtLeastThisGood )
local idxList = {}
getCentralHydrophobics( idxList, mustBeAtLeastThisGood )
for i=1, #idxList do
if idxList[i] == idx then return true end
end
return false
end
function getSegsWithinSphere( idxList, centerIdx, radius, includeCenter )
if includeCenter then
idxList[ #idxList + 1 ] = centerIdx
end
for i=1, SegCt do
if i ~= centerIdx and structure.GetDistance( centerIdx, i ) <= radius then
idxList[ #idxList + 1 ] = i
end
end
end
function SelectSphere( centerIdx, radius )
for i=1, SegCt do
if i == centerIdx then
selection.Select( i )
elseif structure.GetDistance( centerIdx, i ) < radius then
selection.Select( i )
end
end
end
function getSegsOutsideSphere( idxList, centerIdx, radius )
for i=1, SegCt do
if i ~= centerIdx and structure.GetDistance( centerIdx, i ) > radius then
idxList[ #idxList + 1 ] = i
end
end
end
function getCMSegsWithinSphere( idxList, centerIdx, radius, includeCenter, heatThreshold )
if includeCenter then
idxList[ #idxList + 1 ] = centerIdx
end
for i=1, SegCt do
if i ~= centerIdx and structure.GetDistance( centerIdx, i ) <= radius and
contactmap.GetHeat( centerIdx, i ) >= heatThreshold
then
idxList[ #idxList + 1 ] = i
end
end
end
function getCMSegsOutsideSphere( idxList, centerIdx, radius, heatThreshold )
for i=1, SegCt do
if i ~= centerIdx and structure.GetDistance( centerIdx, i ) > radius and
contactmap.GetHeat( centerIdx, i ) >= heatThreshold
then
idxList[ #idxList + 1 ] = i
end
end
end
function getSegsWithinRangeOfTube( idxList, startSeg, endSeg, radius )
-- if a seg is "near" to one of the ones in our [startSeg, endSeg] range, then we want it
for i=1, SegCt do
for j=startSeg, endSeg do
if structure.GetDistance( i, j ) < radius then
idxList[ #idxList + 1] = i
break
end
end -- for j
end -- for i
end
-- produces a list of all AAs "near" the ones in a given inputList
function getSegsNearListed( inputList, radius)
local retval = {}
for i=1, SegCt do
for j=1, #inputList do
if structure.GetDistance(i,j)<radius then
retval[ #retval+1 ] = j
break
end
end
end
return retval
end
function isLocalMinimum( segCenter, segCheck )
if segCheck == segCenter then return false end -- exclude selfies
local ckDist = structure.GetDistance(segCenter, segCheck)
if segCheck > 1 then
local ckDist1 = structure.GetDistance( segCenter, segCheck - 1 )
if ckDist1 < ckDist then return false end
if segCheck > 2 then
local ckDist2 = structure.GetDistance( segCenter, segCheck - 2 )
if ckDist2 < ckDist then return false end
end
end
if segCheck < SegCt then
local ckDist1 = structure.GetDistance( segCenter, segCheck + 1 )
if ckDist1 < ckDist then return false end
if segCheck < SegCt - 1 then
local ckDist2 = structure.GetDistance( segCenter, segCheck + 2 )
if ckDist2 < ckDist then return false end
end
end
return true
end
function isLocalMaximum( segCenter, segCheck )
if segCheck == segCenter then return false end -- exclude selfies
local ckDist = structure.GetDistance(segCenter, segCheck)
if segCheck > 1 then
local ckDist1 = structure.GetDistance( segCenter, segCheck - 1 )
if ckDist1 > ckDist then return false end
if segCheck > 2 then
local ckDist2 = structure.GetDistance( segCenter, segCheck - 2 )
if ckDist2 > ckDist then return false end
end
end
if segCheck < SegCt then
local ckDist1 = structure.GetDistance( segCenter, segCheck + 1 )
if ckDist1 > ckDist then return false end
if segCheck < SegCt - 1 then
local ckDist2 = structure.GetDistance( segCenter, segCheck + 2 )
if ckDist2 > ckDist then return false end
end
end
return true
end
function getNearestPhobicsOutsideRange( seg, segExcludeStart, segExcludeEnd, nearPhobics, ctWanted )
local idxListInternal = {}
local distList = {}
for i=1, SegCt do idxListInternal[ #idxListInternal + 1 ] = i end
for i=1, segExcludeStart - 1 do
if structure.IsHydrophobic( i ) then
distList[ #distList + 1 ] = structure.GetDistance( seg, i )
else
distList[ #distList + 1 ] = 1000
end
end
for i=segExcludeStart, segExcludeEnd do
distList[ #distList + 1 ] = 10000
end
for i=segExcludeEnd + 1, SegCt do
if structure.IsHydrophobic( i ) then
distList[ #distList + 1 ] = structure.GetDistance( seg, i )
else
distList[ #distList + 1 ] = 1000
end
end
sortByScore( idxListInternal, distList )
for i=1, ctWanted do
if i > #idxListInternal then break end
nearPhobics[ #nearPhobics + 1 ] = idxListInternal[ i ]
end
end
function getSegsNotInList( list )
table.sort( list )
local result={ }
if #list > 0 then for j = 1, list[1]-1 do result[ #result+1 ] = j end end
for i = 1, #list-1 do
for j = list[ i ]+1, list[ i+1 ]-1 do result[ #result+1 ]=j end
end
for j = list[ #list ]+1, SegCt do result[ #result+1 ]=j end
return result
end
-- Returns a set of movable indices in a range, at least minLen long, no more than maxLen long
-- Perverse situations with unmovable segs interspersed with movable ones could cause trouble
function GetActionRange( idx, minLen, maxLen )
local len = random( minLen, maxLen )
if MaxUnlockedSeg - MinUnlockedSeg - 1 < len then
-- okay, we cannot succeed. flee the scene of the crime
return MinUnlockedSeg, MaxUnlockedSeg
end
local startIdx = math.max( MinUnlockedSeg, idx - random( 0, len-1) )
local endIdx = math.min( MaxUnlockedSeg, startIdx + len - 1 )
if endIdx == MaxUnlockedSeg then
startIdx = endIdx - len + 1
end
-- A pointless bit of writhing, but it shouldn't do any harm.
for i=idx+1, endIdx do
if not IsMovableSeg(i) then
endIdx = i - 1
startIdx = startIdx - 1
break
end
end
for i=idx-1, startIdx, -1 do
if not IsMovableSeg(i) then
startIdx = i + 1
endIdx = endIdx + 1
break
end
end
return startIdx, endIdx
end
----------------------------------------------------------------
-- SIDECHAIN AND ATOM FUNCTIONS
----------------------------------------------------------------
-- only customer for these 3 functions is the SpotMutator
function AA(idx)
-- hydrophilics
if idx == 1 then return "r"
elseif idx == 2 then return "s"
elseif idx == 3 then return "t"
elseif idx == 4 then return "n"
elseif idx == 5 then return "d"
elseif idx == 6 then return "q"
elseif idx == 7 then return "e"
elseif idx == 8 then return "h"
elseif idx == 9 then return "k"
-- hydrophobics
elseif idx == 10 then return "g"
elseif idx == 11 then return "a"
elseif idx == 12 then return "c"
elseif idx == 13 then return "v"
elseif idx == 14 then return "l"
elseif idx == 15 then return "i"
elseif idx == 16 then return "m"
elseif idx == 17 then return "p"
elseif idx == 18 then return "f"
elseif idx == 19 then return "y"
else return "w" -- idx == 20
end
end
function AAphilic(idx)
-- hydrophilics
if idx == 1 then return "r"
elseif idx == 2 then return "s"
elseif idx == 3 then return "t"
elseif idx == 4 then return "n"
elseif idx == 5 then return "d"
elseif idx == 6 then return "q"
elseif idx == 7 then return "e"
elseif idx == 8 then return "h"
else return "k" -- idx == 9
end
end
function AAphobic(idx)
-- hydrophobics
if idx == 1 then return "g"
elseif idx == 2 then return "a"
elseif idx == 3 then return "c"
elseif idx == 4 then return "v"
elseif idx == 5 then return "l"
elseif idx == 6 then return "i"
elseif idx == 7 then return "m"
elseif idx == 8 then return "p"
elseif idx == 9 then return "f"
elseif idx == 10 then return "y"
else return "w" -- idx == 11
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 -- real tip - 1 because maybe cysteine bridge
elseif aa == "d" then return 8
elseif aa == "e" then return 9
elseif aa == "f" then return 20
elseif aa == "g" then return CENTER_CARBON -- 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 getPolarAtoms( aa )
if aa == "a" then return {6}
elseif aa == "c" then return {7}
elseif aa == "d" then return {9}
elseif aa == "e" then return {10}
elseif aa == "f" then return {12}
elseif aa == "g" then return {5}
elseif aa == "h" then return {11,17}
elseif aa == "i" then return {9}
elseif aa == "k" then return {10,20,21,22}
elseif aa == "l" then return {9}
elseif aa == "m" then return {9}
elseif aa == "n" then return {9,13,14}
elseif aa == "p" then return nil
elseif aa == "q" then return {10,16,17}
elseif aa == "r" then return {12,20,21,22,23,24}
elseif aa == "s" then return {7,11}
elseif aa == "t" then return {8,11}
elseif aa == "v" then return {8}
elseif aa == "w" then return {15,20}
elseif aa == "y" then return {13,21}
else return nil
end
end
function GetTipAtomOfSeg( idx )
-- cysteine loses last atom if disulfide bridge
if structure.GetAminoAcid( idx ) == "c" then
return structure.GetAtomCount( idx )
else
return GetAtomOfTip( structure.GetAminoAcid( idx ))
end
end
function GetCysteineSulfurAtom( idx )
if structure.GetAminoAcid(idx) ~= "c" then
return 0
end
local totalAtoms = structure.GetAtomCount(idx)
if totalAtoms == 10 then
-- there is a cysteine bond, so things shifted
return 7
else
return 6
end
end
function GetBetaCarbonAtom( idx )
local lt = structure.GetAminoAcid( idx )
if isGlycine( idx ) then
return CENTER_CARBON
elseif idx == SegCt then
return TERMINAL_BETA
else
return BETA_CARBON
end
end
function isGlycine( seg )
local lt = structure.GetAminoAcid( seg )
return (lt == 'G' or lt == 'g')
end
function isGlycineOrAlanine( seg )
local lt = structure.GetAminoAcid( seg )
return (lt == 'G' or lt == 'g' or lt == 'a' or lt == 'A')
end
function isCysteine( seg )
local lt = structure.GetAminoAcid( seg )
return (lt == 'c' or lt == 'C')
end
function isProline( seg )
local lt = structure.GetAminoAcid( seg )
return (lt == 'p' or lt == 'P')
end
function GetFirstHydrogenAtom( idx )
local lt = structure.GetAminoAcid( idx )
local totalAtoms = structure.GetAtomCount(idx)
if lt == 'g' then return 5
elseif lt == 'p' then return 9
elseif lt == 'c' then
if totalAtoms == 10 then return 8 else return 7 end
else
local polarVec = getPolarAtoms( lt )
if polarVec == nil then return CENTER_CARBON end -- should not happen
return polarVec[1]
end
end
function PickAtomNumberForBand( idx, noTip )
if noTip == nil then noTip = false end
if not BAND_TO_SIDECHAINS then return CENTER_CARBON end
local r = 1
if noTip then
r = random( 1, 6 )
else
r = random( 1, 7 )
end
if r <= 3 then -- do for r = 1,2,3
return GetBetaCarbonAtom( idx )
elseif r <= 6 then -- do for r = 4,5,6
return CENTER_CARBON
else -- do rarely, because it's rarely good
return GetTipAtomOfSeg( idx )
end
end
function setCysteineSegList( )
CysteineAaSegList = {}
for i=1, SegCt do
local lt = structure.GetAminoAcid( i )
if lt == "c" or lt == "C" then
CysteineAaSegList[#CysteineAaSegList + 1] = i
end
end
end
function guessCysteinePairList( )
local ctPairsWanted = math.floor( #CysteineAaSegList / 2 )
CysteinePairList = {}
localCystList = {}
for i=1, #CysteineAaSegList do
localCystList[i] = CysteineAaSegList[i]
end
for ii = 1, ctPairsWanted do
local minDist = 1000000.0
local bestI = 0
local bestJ = 0
for i = 1, #localCystList - 1 do
local cyst1 = localCystList[i]
for j=i+1, #localCystList do
local cyst2 = localCystList[j]
-- don't try to match up "adjacent" cysteines.
if cyst2 - cyst1 > 2 then
distBetween = structure.GetDistance( cyst1, cyst2 )
if distBetween < minDist then
bestI = i
bestJ = j
minDist = distBetween
end
end
end
end
if bestI == 0 and bestJ == 0 then
bestI = 1
bestJ = 2
end
CysteinePairList[#CysteinePairList+1] = {localCystList[bestI], localCystList[bestJ]}
-- bestJ > bestI so remove in this order:
table.remove( localCystList, bestJ )
table.remove( localCystList, bestI )
end
return true
end
function doesCysteineBondExist( idx1, idx2)
-- NOTE: I have problems if two cysteine bonds exist involving the
-- two given segments but the bonds are not actually between
-- my two segments (eg a<->c and b<->d exist, I want a<->b).
--
-- My attempts to use distance are kludgy but I don't have
-- better (can't ask for distance between atoms), so I will
-- leave the problem in situ.
-- structure.GetAtomCount could also be checked (10 vs 11)
-- but that doesn't help the core problem here.
-- dist <= 6.996 seems to correspond to success.
local dist = structure.GetDistance(idx1, idx2 )
local dScore1 = current.GetSegmentEnergySubscore( idx1, "disulfides" )
local dScore2 = current.GetSegmentEnergySubscore( idx2, "disulfides" )
local bondExists = (dist < 7.5 and dScore1 ~= 0.0 and dScore2 ~= 0.0)
--if bondExists then
-- print( "CBond "..idx1.."-"..idx2..
-- " dist="..TrimNum(dist)..
-- " sc1="..TrimNum(dScore1)..
-- " sc2="..TrimNum(dScore2))
--end
return bondExists
end
function checkCysteineSanity()
if not CYSTEINE_PERFORM_BANDING then return true end
for i = 1, #CysteinePairList do
local pair = CysteinePairList[i]
local dist = structure.GetDistance( pair[1], pair[2] )
if dist > CYSTEINE_MAX_RI_SEPARATION then
print( "Rejected for cysteine insanity: "..pair[1].." far from "..pair[2])
return false
end
--print("distance "..pair[1].." to "..pair[2].." is "..dist)
end
return true
end
----------------------------------------------------------------
-- MUTATION-RELATED FUNCTIONS
----------------------------------------------------------------
function checkDesigner( )
local designAa=0
for n = 1, SegCt do
segType = structure.GetAminoAcid(n)
-- old design puzzles used alanine or glycine. new ones use isoleucine
if segType == 'a' or segType == 'g' or segType == 'i' then
designAa=designAa+1
end
end
return designAa == SegCt
end
function isPuzzleMutable( )
for i=1, SegCt do
if structure.IsMutable(i) then return true end
end
return false
end
function testIndexIsMutable( idx )
if not PuzzleAllowsMutate then return false end
if not structure.IsMutable(idx) then return false end
for i=1,#NoMutateList do
if idx == NoMutateList[i] then return false end
end
return true
end
----------------------------------------------------------------
-- FILTER FUNCTIONS
----------------------------------------------------------------
-- TODO: If the ability to individually manage filters comes about,
-- here is where to put such code. (see also internalGetScore)
function TurnOnFilters( )
if behavior.GetFiltersDisabled( ) then
--print("filters are now ON")
behavior.SetFiltersDisabled( false )
end
end
function TurnOffFilters( )
if not behavior.GetFiltersDisabled( ) then
--print("filters are now OFF")
behavior.SetFiltersDisabled( true )
end
end
function ResetFilterState( )
--if IsFilterDisabled then
-- print("filters are now ON")
--end
behavior.SetFiltersDisabled( IsFilterDisabled )
end
function ReportFilters( )
local fnames = filter.GetNames( )
if #fnames > 0 then
local filterz = {}
for i = 1, #fnames do
local fn = fnames[ i ]
local sat = filter.ConditionSatisfied( fn )
local bon = filter.HasBonus( fn )
local val = 0
if bon then
val = filter.GetBonus( fn )
end
filterz[ #filterz + 1 ] = { name = fn, satisfied = sat, hasbonus = bon, value = val }
end
for i = 1, #filterz do
print( " "..i..
": filter=" .. filterz[ i ].name ..
", satisfied=" .. BoolStr(filterz[ i ].satisfied) ..
", bonus=" .. BoolStr(filterz[ i ].hasbonus) ..
", value=" .. TrimNum( filterz[ i ].value )
)
end
end
end
function CheckForFilters( )
local retval = false
local fnames = filter.GetNames( )
if #fnames > 0 then retval = true end
print("Has filters? "..BoolStr(retval))
return retval
end
function GetFilters( fnames )
local filterTable = {}
for i = 1, #fnames do
local fhasbonus = filter.HasBonus( fnames[ i ] )
local fscore
if fhasbonus then
fscore = filter.GetBonus( fnames[ i ] )
else
fscore = nil
end
local fsatisfied = filter.ConditionSatisfied( fnames[ i ] )
filterTable[ #filterTable + 1 ] =
{ name = fnames[ i ], hasbonus = fhasbonus, score = fscore, satisfied = fsatisfied, }
end
return filterTable
end
----------------------------------------------------------------
-- LOCKED/FROZEN FUNCTIONS
----------------------------------------------------------------
function GenerateNonLockedSegList( )
for i=1, SegCt do
if structure.IsLocked( i ) then
PuzzleHasLockedSegs = true
else
NonLockedSegList[ #NonLockedSegList + 1] = i
end
end
end
function IsUnlockedSeg( seg )
return not structure.IsLocked( seg )
end
function FindAllMovableSegs( )
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
function IsMovableSeg( seg1 )
if seg1 == nil or seg1 < 1 or seg1 > SegCt then return false end
local BB, SC = freeze.IsFrozen( seg1 )
local sl = structure.IsLocked( seg1 )
return not (BB or SC or sl)
end
function IsAllMovableRange(seg1, seg2)
if seg1 == nil or seg2 == nil then return false end
if seg1 > seg2 then seg1, seg2 = seg2, seg1 end
if seg1 < 1 or seg2 > SegCt then return false end
for i=seg1, seg2 do
if not IsMovableSeg( i ) then return false end
end
return true
end
function SelectAllMovable( )
for i=1, SegCt do
if IsMovableSeg( i ) then selection.Select( i ) end
end
end
function selectNonFrozens( idxList )
local segs = { }
local segsToCheck = idxList
if segsToCheck == nil then
segsToCheck = { }
for i = 1, SegCt do
segsToCheck[ #segsToCheck + 1] = i
end
end
selection.DeselectAll( )
for i = 1, #segsToCheck do
local b,s = freeze.IsFrozen( segsToCheck[ i ] )
if not s then
segs[ #segs + 1 ] = segsToCheck[ i ]
end
end
for i = 1, #segs do
selection.Select( segs[ i ] )
end
end
function ResetFrozenness( )
freeze.UnfreezeAll( )
for i=1, SegCt do
local bFroz, sFroz = InitialFrozenTable[ i ]
if bFroz or sFroz then
freeze.Freeze( i, bFroz, sFroz )
end
end
ChangedFrozenness = false
end
function StoreFrozenness( )
for i=1, SegCt do -- save "frozenness"
local bFroz, sFroz = freeze.IsFrozen( i )
InitialFrozenTable[ i ] = bFroz, sFroz
end
end
----------------------------------------------------------------
-- CLASH IMPORTANCE
----------------------------------------------------------------
function SetCI( ci )
behavior.SetClashImportance( CI_MAXSCALE * ci )
end
function ExactSetCI( ci )
behavior.SetClashImportance( ci )
end
function GetCI( )
return behavior.GetClashImportance( )
end
----------------------------------------------------------------------
-- CUTTING FUNCTIONS
----------------------------------------------------------------------
function DeleteCutAtIndex( idx )
if idx == nil or idx < MinUnlockedSeg or idx > MaxUnlockedSeg then return true end
local sc = getQuickScore( )
structure.DeleteCut( idx )
return getQuickScore( ) ~= sc -- if no score change at all, then cut deletion didn't happen!
end
function CutEverywhereInRange( min, max )
if min == nil or min > MaxUnlockedSeg then min = MinUnlockedSeg end
if max == nil or max < min then max = MaxUnlockedSeg end
for i=min, max do
structure.InsertCut( i )
end
end
function DeleteAllCuts( min, max )
if min == nil or min > MaxUnlockedSeg then min = MinUnlockedSeg end
if max == nil or max < min then max = MaxUnlockedSeg end
for i=min, max do
structure.DeleteCut( i )
end
end
function AddRandomCuts( cutList, maxCuts )
for i=1, maxCuts do
local seg = randomMovableSeg( )
local gotMatch = false
for j=1, #cutList do
if cutList[ j ] == seg then gotMatch = true end
end
if not gotMatch then
structure.InsertCut( seg )
cutList[ #cutList + 1 ] = seg
end
end
end
function CleanCutsInList( cutList )
local changeSucceeded = true
for i=1, #cutList do
changeSucceeded = DeleteCutAtIndex( cutList[ i ] ) and changeSucceeded
end
return changeSucceeded
end
function ResetCuts( )
if not PRESERVE_USER_CUTS then
for i=MinUnlockedSeg, MaxUnlockedSeg do
DeleteCutAtIndex( i ) -- any cuts that appeared better go now, too
end
end
end
----------------------------------------------------------------
-- CONTACT MAP FUNCTIONS
----------------------------------------------------------------
function CheckForContactMap( )
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
return true -- all we wanted to know was whether scores exist
end
if saveval == 0.0 then saveval = val end
end
end
return false
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
function ActionDamagedContactMap( )
if PuzzleHasContactMap then
local sc = GetContactScore( )
if sc < ContactMapScore then return true end
ContactMapScore = sc -- now we have a "better" score, so keep that one
end
return false
end
----------------------------------------------------------------
-- SECONDARY STRUCTURES
----------------------------------------------------------------
function isExcellentHelixSeg( seg )
local aa = structure.GetAminoAcid( seg )
return aa == 'a' or aa == 'e' or aa == 'm' or aa == 'k'
end
function isGoodHelixSeg( seg )
local aa = structure.GetAminoAcid( seg )
return isExcellentHelixSeg(seg) or
aa == 'f' or aa == 'j' or aa == 'l' or aa == 'q' or aa == 'v' or aa == 'w'
end
function isOkHelixSeg( seg )
local aa = structure.GetAminoAcid( seg )
return isGoodHelixSeg(seg) or
aa == 'h' or aa == 'r' or aa == 's' or aa == 't'
end
function isHelixBreaker( seg )
return structure.GetAminoAcid( seg ) == 'p'
end
function isBadNonBreakerHelixSeg( seg )
local aa = structure.GetAminoAcid( seg )
return aa == 'g' or aa == 'd' or aa == 'n'
end
function LocateHelices( )
local inside = false
local helixStart = 0
AllHelices = {}
for i=1, SegCt do
if IsUnlockedSeg( i ) then lastUnlocked = i end
if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "H" ) then
if ( inside == false ) then
inside = true
helixStart = i
end
elseif inside == true then
inside = false
AllHelices[#AllHelices+1] = { sIdx = helixStart, eIdx = i-1 }
end
end
-- deal with "last seg is helix"
if ( inside == true ) then
AllHelices[#AllHelices+1] = {sIdx = helixStart, eIdx = lastUnlocked }
end
end
function LocateSheets( )
local inside = false
local sheetStart = 0
AllSheets = {}
for i=1, SegCt do
if IsUnlockedSeg( i ) then lastUnlocked = i end
if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "E" ) then
if ( inside == false ) then
inside = true
sheetStart = i
end
elseif inside == true then
inside = false
AllSheets[#AllSheets + 1] = {sIdx = sheetStart, eIdx = i - 1}
end -- if/else 'E'
end -- for (SegCt)
-- deal with "last seg is sheet"
if ( inside == true ) then
AllSheets[#AllSheets + 1] = {sIdx = sheetStart, eIdx = lastUnlocked}
end
end
function LocateLoops( )
local inside = false
local loopStart = 0
AllLoops = {}
for i=1, SegCt do
if IsUnlockedSeg( i ) then lastUnlocked = i end
if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "L" ) then
if ( inside == false ) then
inside = true
loopStart = i
end
elseif inside == true then
inside = false
AllLoops[ #AllLoops + 1 ] = {sIdx = loopStart, eIdx = i - 1}
end -- if/else 'L'
end -- for (SegCt)
-- deal with "last seg is loop"
if ( inside == true ) then
AllLoops[ #AllLoops + 1 ] = {sIdx = loopStart, eIdx = lastUnlocked}
end
end
function FindFirstProbableHelixInSeglist( sIdx, eIdx )
local startHelix = 0
local endHelix = 0
if eIdx - sIdx < 6 then -- not worth looking for one here
return 0, 0
end
for i = sIdx, eIdx - 5 do
startHelix = 0
endHelix = 0
if isGoodHelixSeg( i ) then
--print("Possible start at idx="..i.." aa="..structure.GetAminoAcid(i) )
startHelix = i
for j=i+1, eIdx do
endHelix = j
if isOkHelixSeg( j ) then
-- reset mediocre count because we don't mind
-- isolated mediocres, just don't want 2 in a row
--print("Saw good "..structure.GetAminoAcid(j).." at "..j)
elseif isHelixBreaker( j ) then
endHelix = j-1
--print("Saw proline at "..j)
break
elseif isBadNonBreakerHelixSeg( j ) then
endHelix = j-1
--print("Saw bad "..structure.GetAminoAcid(j).." at "..j)
break
else
--print( "Saw mediocre "..structure.GetAminoAcid(j).." at "..j )
nextOk = true
nextNextOk = true
if j < SegCt - 1 then
nextNextOk = isOkHelixSeg( j + 2 )
end
if j < SegCt then
nextOk = isOkHelixSeg( j + 1 )
end
if not (nextOk and nextNextOk) then
break
end
end
end
if endHelix - startHelix > 4 then
return startHelix, endHelix
end
end
end
return 0, 0
end
function LocateMissingHelices()
PossibleHelices = {}
for i = 1, #AllLoops do
local bounds = AllLoops[i]
--print( "looking at loop: "..bounds.sIdx.."-"..bounds.eIdx )
if bounds.eIdx - bounds.sIdx >= 7 then
local currStart = bounds.sIdx
while currStart < bounds.eIdx - 4 do
local startHelix, endHelix = FindFirstProbableHelixInSeglist( currStart, bounds.eIdx )
if startHelix == 0 then
break -- no more helices to find in this stretch of loopiness
else
--print("Found possible helix at s,e="..startHelix..","..endHelix)
PossibleHelices[#PossibleHelices + 1] = {sIdx = startHelix, eIdx = endHelix}
currStart = endHelix + 2
end
end
end
end
end
function isPossibleHelix( idx )
for i = 1, #PossibleHelices do
local bound = PossibleHelices[ i ]
if bound.sIdx <= idx and bound.eIdx >= idx then
--local s = bound.sIdx
--local e = bound.eIdx
return true
end
end
return false
end
function GetRegionStartAndEnd( idx )
local s = idx
local e = idx
if not IsUnlockedSeg( idx ) then return idx,idx end
local typeIdx = structure.GetSecondaryStructure( idx )
if idx > MinUnlockedSeg then
s = idx - 1
while s >= MinUnlockedSeg do
if structure.GetSecondaryStructure( s ) ~= typeIdx or not IsUnlockedSeg( s ) then break end
s = s - 1
end
s = s + 1
end
if idx < MaxUnlockedSeg then
e = idx + 1
while e <= MaxUnlockedSeg do
if structure.GetSecondaryStructure( e ) ~= typeIdx or not IsUnlockedSeg( e ) then break end
e = e + 1
end
e = e - 1
end
if typeIdx == 'L' then
-- if we think there's a helix hidden here, let's try to offer its boundaries
for i = 1, #PossibleHelices do
local bound = PossibleHelices[ i ]
if bound.sIdx <= idx and bound.eIdx >= idx then
s = bound.sIdx
e = bound.eIdx
return s, e
end
end
end
return s, e
end
function GetExtendedRegionForWiggle( idxStart, idxEnd )
local startExtendedSeg, endExtendedSeg, junk
if idxStart <= MinUnlockedSeg then
startExtendedSeg = idxStart
else
startExtendedSeg, junk = GetRegionStartAndEnd( idxStart - 1 )
end
if idxEnd >= MaxUnlockedSeg then
endExtendedSeg = idxEnd
else
junk, endExtendedSeg = GetRegionStartAndEnd( idxEnd + 1 )
end
-- try harder if we didn't get very much
if startExtendedSeg > idxStart - 4 then
startExtendedSeg = math.max( idxStart - 4, MinUnlockedSeg )
end
if endExtendedSeg < idxEnd + 4 then
endExtendedSeg = math.min( idxEnd + 4, MaxUnlockedSeg )
end
return startExtendedSeg, endExtendedSeg
end
-- uses GetRegionStartAndEnd, but tries to tune "loop" regions a bit
function GetRegionForOperation( idx )
-- try to find an acceptable region (really bizarre choices of SS can give trouble)
if not IsUnlockedSeg( idx ) then
return idx, idx
end
sIdx, eIdx = GetRegionStartAndEnd( idx )
-- Check: if our entire region is only 1 or 2 segs long, then see about expanding it
local regionType = structure.GetSecondaryStructure( idx )
if eIdx - sIdx <= 1 then
-- small range. Try to expand it...
local sIdx2, eIdx2
if sIdx > 2 then
if structure.GetSecondaryStructure(sIdx - 1) == regionType then
sIdx2, eIdx2 = GetRegionStartAndEnd( sIdx - 1)
sIdx = sIdx2
end
end
if eIdx < SegCt - 1 then
if structure.GetSecondaryStructure( eIdx + 1 ) == regionType then
sIdx2, eIdx2 = GetRegionStartAndEnd( eIdx + 1 )
eIdx = eIdx2
end
end
if eIdx - sIdx <= 1 then
-- last try: unless we're at an end, just give ourselves one before and after
if sIdx > 1 then sIdx = sIdx - 1 end
if eIdx < SegCt then eIdx = eIdx + 1 end
end
if eIdx - sIdx <= 1 then
return idx,idx
end -- failed, something is very wrong
end
-- Check: if loop and more than 30-long, then only take part of it
if regionType == 'L' and eIdx - sIdx > 30 and not isPossibleHelix( sIdx ) then
-- trim it; it is too long
if idx - sIdx < 15 then
eIdx = idx + 15 -- trim the other, longer side
elseif eIdx - idx < 15 then
sIdx = idx - 15 -- trim the other, longer side
else
-- more than 15 segs slop on both sides!
-- try to be random and "medium-long": 3d5 on each side should do
sIdx = idx - randomDice(3, 1, 5)
eIdx = idx + randomDice(3, 1, 5)
end
end
return sIdx, eIdx
end
function ResetSecondaryStructures( min, max )
selection.DeselectAll( )
for i=min, max do
if OriginalSecondaryStructures[ i ] == "l" then
selection.Select( i )
end
end
structure.SetSecondaryStructureSelected( "l" )
selection.DeselectAll( )
for i=min, max do
if OriginalSecondaryStructures[ i ] == "e" then
selection.Select( i )
end
end
structure.SetSecondaryStructureSelected( "e" )
selection.DeselectAll( )
for i=min, max do
if OriginalSecondaryStructures[ i ] == "h" then
selection.Select( i )
end
end
structure.SetSecondaryStructureSelected( "h" )
selection.DeselectAll( )
end
function StoreSecondaryStructure( )
for i=1, SegCt do
OriginalSecondaryStructures[ i ] = structure.GetSecondaryStructure( i )
end
end
function SetSS( min, max, type )
selection.DeselectAll( )
selection.SelectRange( min, max )
structure.SetSecondaryStructureSelected( type )
selection.DeselectAll( )
end
function SetAllLoop( min, max )
SetSS( min, max, "l" )
end
-------------- SHEET-SPECIFIC FUNCTIONS --------------
function GetBoundsOfSheet( seg )
local bounds = {sIdx = 0, eIdx = 0}
for i=1, #AllSheets do
bounds = AllSheets[ i ]
if bounds.sIdx <= seg and bounds.eIdx >= seg then
return bounds.sIdx, bounds.eIdx
end
end
return 0, 0
end
function GetBoundsOfSheetFromIndex( sheetIdx )
local bounds = {sIdx = 0, eIdx = 0}
if sheetIdx < 0 or sheetIdx > #AllSheets then return 0,0 end
bounds = AllSheets[ sheetIdx ]
return bounds.sIdx, bounds.eIdx
end
function GetIndexOfSheet( seg )
local bounds = {sIdx = 0, eIdx = 0}
for i=1, #AllSheets do
bounds = AllSheets[ i ]
if bounds.sIdx <= seg and bounds.eIdx >= seg then
return i
end
end
return 0
end
-- finds segment in sheet that's nearest to segIn
function GetNearestSegOfSheet( segIn, sheetIdxIn )
local sIdx, eIdx = GetBoundsOfSheetFromIndex( sheetIdxIn )
if sIdx == 0 or (sIdx <= segIn and eIdx >= segIn) then
return 0
end
local minDist = structure.GetDistance( segIn, sIdx )
local bestIdx = sIdx
for i=sIdx+1, eIdx do
dist = structure.GetDistance( segIn, i )
if dist < minDist then
minDist = dist
bestIdx = i
end
end
return bestIdx
end
-- much cleverer would be to build a table of all sheet indices that
-- aren't in our sheet, then build a distance chart versus segIn, then
-- find the shortest distance. we could even get clever and include only
-- the "non-satisfied" sheets - the ones that only have one neighbor.
function FindNearestSheetToSeg( segIn, maxDistance )
local sIdx, eIdx = GetBoundsOfSheet( segIn )
if sIdx == 0 then return false end
sheetLen = eIdx - sIdx + 1
foundSheet = false
foundMatch = false
local listIdx = {}
local sheetListOut = {}
listIdx = {}
getSegsWithinSphere( listIdx, segIn, maxDistance, false )
for j=1, #listIdx do
-- dont want segs from own sheet, so only act if "not" one of them
if listIdx[j] < sIdx or listIdx[j] > eIdx then
local sheetIdx = GetIndexOfSheet( listIdx[j] )
if sheetIdx > 0 then
-- found a sheet, it's not us. make sure we haven't already found it
for k=1, #sheetListOut do
if sheetIdx == sheetListOut[k] then
foundMatch = true
break
end
end
if not foundMatch then
sheetListOut[#sheetListOut+1] = sheetIdx
end
foundSheet = true
end
end
end
for j=1, #AllSheets do
-- ok, we have sheets that aren't far. now find the closest
if AllSheets[j].sIdx ~= sIdx then -- not us
end
end
return sheetListOut
end
function FindNearestSheetsToSheet( segIn, maxDistance )
local sIdx, eIdx = GetBoundsOfSheet( segIn )
if sIdx == 0 then return nil end
local listIdx = {}
local sheetListOut = {}
listIdx = {}
getSegsWithinRangeOfTube( listIdx, sIdx, eIdx, maxDistance )
for j=1, #listIdx do
-- dont want segs from own sheet, so only act if not one of them
if listIdx[j] < sIdx or listIdx[j] > eIdx then
local foundMatch = false
local sheetIdx = GetIndexOfSheet( listIdx[j] )
if sheetIdx > 0 then
-- found a sheet, it's not us. make sure we haven't already found it
for k=1, #sheetListOut do
if sheetIdx == sheetListOut[k] then
foundMatch = true
end
end
if not foundMatch then
sheetListOut[#sheetListOut+1] = sheetIdx
end
end
end
end
return sheetListOut
end
function IsStraySheet( segIn )
local nbrSheets = FindNearestSheetsToSheet( segIn, 6.0)
return #nbrSheets == 0
end
function FindNeighborSheets( segIn )
return FindNearestSheetsToSheet( segIn, 6.0)
end
function IsSheetPairAntiParallel( sheetIdx1, sheetIdx2 )
local sIdx1, eIdx1 = GetBoundsOfSheetFromIndex( sheetIdx1 )
local nearestSegs = {}
for i=sIdx1, eIdx1 do
nearestSegs[ i + 1 - sIdx1 ] = GetNearestSegOfSheet ( i, sheetIdx2 )
end
local countIncreases = 0
local countDecreases = 0
for i=1, #nearestSegs - 1 do
if nearestSegs[i+1] > nearestSegs[i] then countIncreases = countIncreases + 1 end
if nearestSegs[i+1] < nearestSegs[i] then countDecreases = countDecreases + 1 end
end
-- this is a rotten metric, but it's probably good enough for my needs
return countDecreases > countIncreases
end
function FindBestOffsetsForSheetMatching( sheetIdx1, sheetIdx2 )
local sIdx1, eIdx1 = GetBoundsOfSheetFromIndex( sheetIdx1 )
local sIdx2, eIdx2 = GetBoundsOfSheetFromIndex( sheetIdx2 )
local isAntiParallel = IsSheetPairAntiParallel( sheetIdx1, sheetIdx2 )
-- look for offsets for aligning the sheets.
local startFirst = sIdx1
local endFirst = eIdx1
local deltaFirst, deltaSecond
-- figure out what our endpoints are. Start with basics of boundaries of sheets we are matching
local nbrList = {}
local maxLen1 = eIdx1 - sIdx1 + 1
local maxLen2 = eIdx2 - sIdx2 + 1
local maxLenToTry = math.min( maxLen1, maxLen2 ) -- the length to walk along. too long for "right" answer
if maxLenToTry < 2 then
-- too short to be worth banding
return 0, 0, 0, false
end
for i=1, maxLenToTry do
nbrList[i] = GetNearestSegOfSheet( sIdx1 + i - 1, sheetIdx2 )
end
--printVector( nbrList, "Sheet 2 neighbors", false )
-- find the most believable startFirst
if nbrList[1] == nbrList[2] and nbrList[1] == nbrList[3] then
for i=2, maxLenToTry do
if nbrList[i] == nbrList[1] then
startFirst = startFirst + 1
--print("startFirst: ", startFirst )
else
break
end
end
end
maxLenToTry = maxLenToTry - (startFirst - sIdx1)
if maxLenToTry < 2 then
-- too short to be worth banding
return 0, 0, 0, false
end
deltaFirst = startFirst - sIdx1
-- find the most believable endFirst
if nbrList[#nbrList] == nbrList[#nbrList - 1] and nbrList[#nbrList] == nbrList[#nbrList - 2] then
for i=maxLenToTry-1, 1, -1 do
if nbrList[i] == nbrList[#nbrList] then
endFirst = endFirst - 1
--print("endFirst: ", endFirst )
else
break
end
end
end
local len = endFirst - startFirst + 1
--print( "len="..len.." endFirst="..endFirst.." startFirst="..startFirst )
-- OK, we have a startFirst and endFirst that we at least kind of believe
-- Now find the best alignment
local deltas = {}
for i=startFirst, endFirst do
local nearest = GetNearestSegOfSheet( i, sheetIdx2 )
--print("Nearest to "..i.." is "..nearest )
local delta1 = i - startFirst
local delta2
if isAntiParallel then
delta2 = eIdx2 - nearest - delta1
else
delta2 = nearest - sIdx2 - delta1
end
--print( "BestOffset: delta="..delta2 )
deltas[#deltas+1] = delta2
end
local avgDelta = 0.0
for i=1, #deltas do
avgDelta = avgDelta + deltas[ i ]
end
avgDelta = (avgDelta + 0.0) / #deltas
--print("avgDelta = "..avgDelta )
deltaSecond = math.floor(avgDelta)
return deltaFirst, deltaSecond, len, isAntiParallel
end
------------------------------------------------------------------------------
--
---- SHAKER MUTATOR AND WIGGLER FUNCTIONS
--
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- GENERAL-PURPOSE SHAKERS AND WIGGLERS
------------------------------------------------------------------------------
-- no recentbest here because sometimes we'd call while decreasing score
function ShakeSelected( iters, useLowerCi )
-- DO NOT OFFER mutate because we'd have to check NoMutateList and deselect
-- those indices, which would damage any follow-on use of the selected set
-- DO NOT DESELECT - someone else might want the selection
if iters == nil then iters = SHAKESIDECHAIN_ITERS end
if useLowerCi == nil then useLowerCi = false end
local sav_ci = GetCI( )
local startTime = os.time( )
if useLowerCi then SetCI( 0.31 ) end
structure.ShakeSidechainsSelected( iters )
if useLowerCi then SetCI( sav_ci ) end
TotalShakeTime = TotalShakeTime + ( os.time( ) - startTime )
end
function ShakeOrMutateSelected( iters )
if MUTATE_NOT_SHAKE then
structure.MutateSidechainsSelected(iters+1)
else
structure.ShakeSidechainsSelected(iters)
end
end
function ShakeOrMutate( iters, idxList, onlyShake ) -- "s" (idxList=nil for all)
local startTime
if iters == nil then iters = SHAKESIDECHAIN_ITERS end
if onlyShake == nil then onlyShake = false end
local origCI = GetCI( )
if (not onlyShake) and MUTATE_NOT_SHAKE then
selectNonFrozens( idxList )
if #NoMutateList > 0 then
-- deselect all no-mutate aas
for i = 1, #NoMutateList do
selection.Deselect( NoMutateList[ i ] )
end
end
startTime = os.time( )
SetCI( CI_MUTATE )
--print("Mutating")
structure.MutateSidechainsSelected( iters )
SetCI( origCI )
TotalMutateTime = TotalMutateTime + ( os.time( ) - startTime )
if #ShakeAfterMutateList > 0 then
selection.DeselectAll( )
for i = 1, #ShakeAfterMutateList do
local b,s = freeze.IsFrozen( ShakeAfterMutateList[ i ] )
if not s then selection.Select( ShakeAfterMutateList[ i ] ) end
end
startTime = os.time( )
structure.ShakeSidechainsSelected( iters )
TotalShakeTime = TotalShakeTime + ( os.time( ) - startTime )
end
else
startTime = os.time( )
selectNonFrozens( idxList )
structure.ShakeSidechainsSelected( iters )
TotalShakeTime = TotalShakeTime + ( os.time( ) - startTime )
end
selection.DeselectAll( )
end
function SimpleWiggleAll( iters ) -- "wa" on all
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.WiggleAll( iters, true, true )
end
function SimpleWiggleBackbone( iters ) -- "wb" on all
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.WiggleAll( iters, true, false )
end
function SimpleWiggleSidechains( iters ) -- "ws" on all
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.WiggleAll( iters, false, true )
end
function SimpleLocalWiggleAll( iters ) -- "lw" on all
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.LocalWiggleAll( iters, true, true )
end
function SimpleWiggleSelected( iters ) -- "wa" on selected
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.WiggleSelected( iters, true, true )
end
function SimpleWiggleBackboneSelected( ) -- "wb" on selected
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.WiggleSelected( iters, true, false )
end
function SimpleWiggleSidechainsSelected( ) -- "ws" on selected
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.WiggleSelected( iters, false, false )
end
function SimpleLocalWiggleSelected( iters ) -- "lw" on selected
if iters == nil then iters = QUICKWIGGLE_ITERS end
structure.LocalWiggleSelected( iters, true, true )
end
-- if anybody ever wants "lwb" or "lws", it's easy enough to see how to do them.
function LongWiggleAll( ) -- "wa" on all with gain
IterativeWiggleAll( true, true )
end
function LongWiggleBackbone( ) -- "wb" on all with gain
IterativeWiggleAll( true, false )
end
function LongWiggleSidechains( ) -- "ws" on all with gain
IterativeWiggleAll( false, true )
end
function LongWiggleAllLocal( ) -- "lw" on all with gain
IterativeLocalWiggleAll( true, true )
end
function LongWiggleSelected( ) -- "wa" on selected with gain
IterativeWiggleSelected( true, true )
end
function LongWiggleBackboneSelected( ) -- "wb" on selected with gain
IterativeWiggleSelected( true, false )
end
function LongWiggleSidechainsSelected( ) -- "ws" on selected with gain
IterativeWiggleSelected( false, true )
end
function LongWiggleSelectedLocal( ) -- "lw" on selected with gain
IterativeLocalWiggleSelected( true, true )
end
function IterativeLocalWiggleAll( doBackbone, doSidechain, minGain )
local lastScore = getQuickScore( )
if minGain == nil then minGain = QUICKWIGGLE_GAIN end
recentbest.Save( )
local gain = minGain
while gain >= minGain do
structure.LocalWiggleAll( QUICKWIGGLE_ITERS, doBackbone, doSidechain )
recentbest.Restore( )
gain = getQuickScore( ) - lastScore
lastScore = getQuickScore( )
end
end
function IterativeWiggleAll( doBackbone, doSidechain, minGain )
local lastScore = getQuickScore( )
if minGain == nil then minGain = QUICKWIGGLE_GAIN end
recentbest.Save( )
local gain = minGain
while gain >= minGain do
structure.WiggleAll( QUICKWIGGLE_ITERS, doBackbone, doSidechain )
recentbest.Restore( )
gain = getQuickScore( ) - lastScore
lastScore = getQuickScore( )
end
end
function IterativeWiggleSelected( doBackbone, doSidechain, minGain )
local lastScore = getQuickScore( )
if minGain == nil then minGain = QUICKWIGGLE_GAIN end
recentbest.Save( )
local gain = minGain
while gain >= minGain do
structure.WiggleSelected( QUICKWIGGLE_ITERS, doBackbone, doSidechain )
recentbest.Restore( )
gain = getQuickScore( ) - lastScore
lastScore = getQuickScore( )
end
end
function IterativeLocalWiggleSelected( doBackbone, doSidechain, minGain )
local lastScore = getQuickScore( )
if minGain == nil then minGain = QUICKWIGGLE_GAIN end
recentbest.Save( )
local gain = minGain
while gain >= minGain do
structure.LocalWiggleSelected( QUICKWIGGLE_ITERS, doBackbone, doSidechain )
recentbest.Restore( )
gain = getQuickScore( ) - lastScore
lastScore = getQuickScore( )
end
end
function WiggleRange( startSeg, endSeg, addFreeze, doGlobal )
if doGlobal == nil then doGlobal = randomBool() end
local firstSeg = math.max( MinUnlockedSeg, startSeg )
local lastSeg = math.min( endSeg, MaxUnlockedSeg )
if lastSeg < firstSeg then return end -- nothing to do
-- set up for the local wiggle
selection.DeselectAll( )
if addFreeze then
ChangedFrozenness = true
if firstSeg > MinUnlockedSeg then freeze.Freeze( firstSeg - 1, true, true ) end
if lastSeg < MaxUnlockedSeg then freeze.Freeze( lastSeg + 1, true, true ) end
end
-- actually perform the local wiggle
selection.SelectRange( firstSeg, lastSeg )
if doGlobal then
SimpleWiggleSelected( )
else
SimpleLocalWiggleSelected( )
end
-- clean up what we did
ResetFrozenness( )
selection.DeselectAll( )
end
---------------------------------------------
-- STABILIZER WIGGLES
---------------------------------------------
function WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, radius )
local idxList = {}
selection.DeselectAll( )
selection.SelectRange( idxStart, idxEnd )
SimpleWiggleSelected( )
selection.DeselectAll( )
getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, radius )
ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxList ) -- only shake the "nearby" segments
SimpleWiggleAll( ) -- just a short bit of time on this wiggle to settle things down a bit
end
function WiggleShakeListWiggleAll( idxList, onlyShake )
if onlyShake == nil then onlyShake = false end
recentbest.Save( )
local scoreInit = getQuickScore( )
selection.DeselectAll( )
for i=1, #idxList do
selection.Select( i )
end
LongWiggleSelected( )
selection.DeselectAll( )
recentbest.Restore( )
ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxList, onlyShake )
recentbest.Restore( )
if math.abs( getQuickScore( ) - scoreInit) > 0.1 then
-- save money if test fails: we apparently didn't do anything
LongWiggleAll( )
recentbest.Restore( )
end
end
function qStabWiggle( doFuse, shakeOnly )
if doFuse == nil then
doFuse = randomBool( PROB_QSTAB_EXTRA )
end
SetCI( 1.0 )
recentbest.Save( )
ShakeOrMutate( nil, nil, shakeOnly )
recentbest.Restore( )
if doFuse and not FORBID_ALL_QSTAB_FUSE then
SetCI( 0.4 )
LongWiggleAll( )
recentbest.Restore( )
SetCI( 1.0)
ShakeOrMutate( nil, nil, shakeOnly )
recentbest.Restore( )
end
SetCI( 1.0)
LongWiggleAll( )
recentbest.Restore( )
end
function ShakeWiggleTillStable( initScore, onlyShake )
if onlyShake == nil then onlyShake = false end
local count = 0
local currScore = getQuickScore()
if initScore == nil or initScore - currScore < 1000.0 then
recentbest.Save( )
ShakeOrMutate( nil, nil, onlyShake)
recentbest.Restore( )
local gainShake = getQuickScore() - currScore
while gainShake > 0.50 and count < 4 do
LongWiggleAll()
recentbest.Restore( )
currScore = getQuickScore()
ShakeOrMutate( nil, nil, MUTATE_ONCE )
recentbest.Restore( )
gainShake = getQuickScore() - currScore
count = count + 1
end
if count == 0 or gainShake > 0.10 then
LongWiggleAll()
recentbest.Restore( )
end
end
end
-- tends to produce transients. the only user is IdealizeRegionZlb
function WiggleZlbNicely( strength, skipLower, skipUpper )
if skipLower == nil then skipLower = MaxUnlockedSeg+1 end
if skipUpper == nil then skipUpper = MinUnlockedSeg-1 end
recentbest.Save( )
ZLB( strength, skipLower, skipUpper )
LongWiggleAll( )
recentbest.Restore( )
DelBands( )
recentbest.Save( )
ShakeOrMutate( )
recentbest.Restore( )
end
function SimpleRegionWiggle( idxLo, idxHi, pickGlobalWiggle, wiggleExpansion )
if wiggleExpansion == nil then
wiggleExpansion = 1 + random( math.floor( SegCt / 6 ))
end
local startIdx = math.max( MinUnlockedSeg, idxLo - wiggleExpansion )
local endIdx = math.min( MaxUnlockedSeg, idxHi + wiggleExpansion )
WiggleRange( startIdx, endIdx, false, pickGlobalWiggle )
end
function SimpleWiggleShake( )
recentbest.Save( )
local oldRbScore = getRBScore( )
SetCI( CI_COREPULLING )
if randomBool( PROB_LOCALWIGGLE ) then -- this is currently always
SimpleLocalWiggleAll( )
else
SimpleWiggleAll( )
end
ShakeOrMutate( )
local newRbScore = getRBScore( )
if newRbScore > oldRbScore then recentbest.Restore( ) end
end
---------------------------------------------------------
-- FAST RELAX WIGGLER
---------------------------------------------------------
function PerformFastRelaxWiggler( ctRuns )
if ctRuns == nil then ctRuns = 1 end
for i=1, ctRuns do
SetCI( 0.02 )
ShakeOrMutate( )
SimpleWiggleAll( )
SetCI( 0.25 )
ShakeOrMutate( )
SimpleWiggleAll( )
SetCI( 0.55 )
ShakeOrMutate( )
SimpleWiggleAll( )
SetCI( 1.00 )
ShakeOrMutate( )
structure.WiggleAll( 20, true, true )
SetCI( 0.07 )
ShakeOrMutate( )
SetCI( 1.00 )
structure.WiggleAll( 20, true, true )
end
end
---------------------------------------------------------
--CLEAN WRAPUP WIGGLERS
---------------------------------------------------------
function CleanQStabWiggleOut( qstabFuseWanted, initScore )
DelBands( )
ResetFrozenness( )
SetCI( 1.0 )
recentbest.Save( )
qStabWiggle( qstabFuseWanted, MUTATE_NOT_SHAKE )
ShakeWiggleTillStable( initScore, MUTATE_ONCE )
recentbest.Restore( )
end
function CleanShakeWiggleOut( onlyShake )
DelBands( )
ResetFrozenness( )
SetCI( 1.0 )
ShakeWiggleTillStable( nil, onlyShake)
end
function ShakeWiggleCleanShakeWiggle( )
recentbest.Save( )
local oldRbScore = getRBScore( )
ShakeOrMutate( )
if randomBool( PROB_LOCALWIGGLE) then -- currently this is always
SimpleLocalWiggleAll( 1 )
else
SimpleWiggleAll( 1 )
end
local newRbScore = getRBScore( )
if newRbScore > oldRbScore then recentbest.Restore( ) end
DelBands( )
ResetFrozenness( )
recentbest.Save( )
ShakeOrMutate( nil, nil, MUTATE_ONCE )
LongWiggleAll( )
recentbest.Restore( )
end
function WiggleBackboneThenWiggleOut( cutIdx, qstabFuseWanted )
SetCI( CI_MULTIBAND_PULL )
SimpleWiggleBackbone( )
DelBands()
if cutIdx ~= 0 then
DeleteCutAtIndex( cutIdx )
end
recentbest.Save( )
SetCI( CI_MULTIBAND_SHAKE )
ShakeOrMutate( )
SetCI( 1.0 )
qStabWiggle( qstabFuseWanted, MUTATE_ONCE )
ShakeWiggleTillStable( nil, MUTATE_ONCE )
end
function WiggleShakeCleanWiggleOut( )
SimpleWiggleShake( )
SetCI( 1.0 )
DelBands( ) -- if we had put in bands, they go now
ResetFrozenness( ) -- if we froze anything, clean that up now
selection.DeselectAll( ) -- just as a kindness
recentbest.Save( )
ShakeWiggleTillStable( nil, MUTATE_ONCE )
recentbest.Restore( )
end
function BandedWiggleUntilEnoughChange( scoreThreshold, pullingCI )
if scoreThreshold == nil then scoreThreshold = BANDEDWIGGLE_TARGET end
if pullingCI == nil then pullingCI = CI_COREPULLING end
SetCI( pullingCI )
local ss=getQuickScore( )
for str=0.30, 1.50, 0.11 do --search enough band strength to move
SetMyBandStrengths( str )
if randomBool( PROB_LOCALWIGGLE ) then
SimpleLocalWiggleAll( )
else
SimpleWiggleAll( )
end
if math.abs( ss-getQuickScore( ) ) > scoreThreshold then
-- we've changed the structure "enough", send it off
break
end
end
SetCI( 1.0 )
return math.abs( ss - getQuickScore( ) )
end
function SimpleBandedWiggleShakeWrapper( minChangeWanted, pullingCI, probQstab )
local initScore = getQuickScore( )
if minChangeWanted == nil then minChangeWanted = BANDEDWIGGLE_TARGET end
if pullingCI == nil then pullingCI = CI_COREPULLING end
if probQstab == nil then probQstab = PROB_QSTAB_EXTRA end
local scoreThreshold = math.min( minChangeWanted, initScore / 500.0)
recentbest.Save( )
local oldRbScore = getRBScore( )
BandedWiggleUntilEnoughChange( scoreThreshold, pullingCI )
local newRbScore = getRBScore( )
if newRbScore > oldRbScore then recentbest.Restore( ) end
CleanQStabWiggleOut( probQstab, initScore )
recentbest.Restore( )
end
-- not currently used, but just in case I change my mind...
function nudge( )
SetCI( 0.3 )
SimpleWiggleSelected( 1 )
SetCI( 1 )
SimpleWiggleSelected( 8 )
end
function WiggleAndShakeForRebuilder( idxStart, idxEnd, initScore, maxFall )
-- initScore is the score before our rebuild happened
recentbest.Save( )
local scoreA = getQuickScore( )
if initScore - scoreA > maxFall/2 then
ShakeOrMutate( )
end
scoreA = getQuickScore( )
if randomBool( PROB_LOCALWIGGLE ) then
LongWiggleAllLocal( )
else
LongWiggleAll( )
end
recentbest.Restore( )
local scoreB = getQuickScore( )
if scoreB - scoreA < 10.0 and initScore - scoreB > 30.0 then
-- The wiggle got stuck: try a nudge to see if that helps
nudge( )
recentbest.Restore( )
scoreB = getQuickScore( )
end
if initScore - scoreB <= 100.0 then
selection.SelectRange( idxStart, idxEnd )
ShakeOrMutate( ) -- should this restrict to range, too?
LongWiggleSelected( )
recentbest.Restore( )
nudge( )
recentbest.Restore( )
selection.DeselectAll()
end -- else not worth the effort
end
--------------------------------------------------
-- FUSES AND OTHER SLOW WIGGLERS
--------------------------------------------------
function BlueFuse( )
recentbest.Save( )
SetCI( .05 )
ShakeOrMutate( )
SetCI( 1 )
SimpleWiggleAll( 5 )
recentbest.Restore( )
SetCI( .07 )
ShakeOrMutate( )
SetCI( 1 )
SimpleWiggleAll( 5 )
recentbest.Restore( )
SetCI( .3 )
SimpleWiggleAll( 8 )
SetCI( 1 )
SimpleWiggleAll( 15 )
recentbest.Restore( )
end
function IterativeWiggleLocalByChunk(startSeg, endSeg, minGain, chunkSize, addFreeze)
recentbest.Save( )
local currOffset = 0
local lastScore = getQuickScore( )
local gain = minGain
while gain >= minGain do
if chunkSize == 1 then currOffset = 0
else currOffset = random( chunkSize - 1 )
end
ctBlocks = math.floor( (endSeg - startSeg + 1) / chunkSize )
for idx = 0,ctBlocks do
local score = getQuickScore( )
local startIdx = startSeg + currOffset + chunkSize*idx
WiggleRange( startIdx, math.min( startIdx + chunkSize, endSeg ), addFreeze, false )
recentbest.Restore( )
if addFreeze then ResetFrozenness( ) end
end
local currScore = getQuickScore( )
gain = currScore - lastScore
lastScore = currScore
end
recentbest.Restore( )
if addFreeze then ResetFrozenness( ) end
end
function BasicCutAndWiggleFuse( baseIters, shift, offset )
if shift == nil then shift = 3 end
if offset == nil then offset = MinUnlockedSeg else offset = MinUnlockedSeg + (offset % shift) end
for i = offset, MaxUnlockedSeg-1, shift do
structure.InsertCut( i )
end
WiggleWiggleSimpleFuse( 0.30, 1.0, baseIters, 2*baseIters )
ResetCuts( )
WiggleWiggleSimpleFuse( 0.30, 1.0, baseIters, 4*baseIters )
end
-- setting minGainAsked to 0.0 says to use failCt instead of gain.
function IterativeCutAndWiggle( baseIters, minGainAsked, shift )
local score = getQuickScore( )
local gain = minGainAsked
save.Quicksave( QS_ShortUseTemp1 )
local failCt = 0
repeat
save.Quickload( QS_ShortUseTemp1 )
recentbest.Save( )
BasicCutAndWiggleFuse( baseIters, shift, random( shift ) )
recentbest.Restore( )
local newscore = getQuickScore( )
gain = 0.0
if newscore >= score then
save.Quicksave( QS_ShortUseTemp1 )
gain = newscore - score
score = newscore
else
failCt = failCt + 1
end
until (minGainAsked > 0.0 and gain < minGain) or failCt >= shift
save.Quickload( QS_ShortUseTemp1 )
end
function IterativeCutAndWiggleFull( shift )
local baseIters = FUSEWIGGLE_ITERS
local score = getQuickScore( )
save.Quicksave( QS_ShortUseTemp1 )
local failCt = 0
local rIdx = {}
for i=1, shift do rIdx[ i ] = i end
randomizeIndexList( rIdx )
for i=1, shift do
save.Quickload( QS_ShortUseTemp1 )
BasicCutAndWiggleFuse( baseIters, shift, rIdx[i] )
ResetCuts()
local newscore = getQuickScore( )
if newscore >= score then
save.Quicksave( QS_ShortUseTemp1 )
score = newscore
end
end
save.Quickload( QS_ShortUseTemp1 )
end
-- BASIC FUSE WIGGLERS
function WiggleShakeSimpleFuse( ci )
SetCI( ci )
SimpleWiggleAll( )
ShakeOrMutate( )
end
function WiggleWiggleSimpleFuse( ci1, ci2, shortiter, longiter )
recentbest.Save( )
local oldRbScore = getRBScore( )
SetCI( ci1 )
SimpleWiggleAll( shortiter )
local newRbScore = getRBScore( )
if newRbScore > oldRbScore then recentbest.Restore( ) end
SetCI( ci2 )
recentbest.Save( )
SimpleWiggleAll( longiter ) -- "long" wiggle
recentbest.Restore( )
end
function ShakeWiggleFuse( ci1, ci2 ) -- aka Fuse1
SetCI( ci1 )
ShakeOrMutate( )
SetCI( ci2 )
LongWiggleAll( )
end
function WiggleWiggleWiggleFuse( ci1, ci2 ) -- aka Fuse2
SetCI( ci1 )
LongWiggleAll( )
SetCI( 1.00 )
LongWiggleAll( )
SetCI( ci2 )
LongWiggleAll( )
end
function WiggleShakeWiggleFuse( ) -- aka FuseEnd
SetCI( 1.00 )
LongWiggleAll( )
ShakeOrMutate( )
LongWiggleAll( )
end
----------------------------------------------------------------------
--
---- BANDER FUNCTIONS
--
----------------------------------------------------------------------
function StoreUserBands( )
InitialBandStates = {}
for i=1, InitialBandCount do
InitialBandStates[#InitialBandStates + 1 ] = {bidx = i, isEnabled = band.IsEnabled( i ) }
end
end
ToldUserAlreadyAboutBands = false
function ResetUserBands( wantOriginalState )
if #InitialBandStates == 0 then return end
if wantOriginalState == nil then wantOriginalState = false end
if band.GetCount() < #InitialBandStates then
-- we lost information and don't know what to do!
if wantOriginalState or not ToldUserAlreadyAboutBands then
print("!!!User band got lost - cannot set correctly; disabling")
ToldUserAlreadyAboutBands = true
end
for i=1, band.GetCount() do
band.Disable( InitialBandStates[i].bidx )
end
InitialBandCount = band.GetCount( )
return
end
for i=1, #InitialBandStates do
if InitialBandStates[i].isEnabled and
(wantOriginalState or not DISABLE_ALL_USER_BANDS)
then
band.Enable( InitialBandStates[i].bidx )
else
band.Disable( InitialBandStates[i].bidx )
end
end
end
function DelBands( alsoCysteine )
if alsoCysteine == nil then alsoCysteine = false end
if alsoCysteine and not PRESERVE_USER_BANDS then
print("Wiping all bands")
band.DeleteAll( )
else
local allBandCount = band.GetCount( )
local firstBandToDel = 1 + InitialBandCount
if not alsoCysteine then
firstBandToDel = firstBandToDel + CYSTEINE_TOTAL_BANDS
end
for i=allBandCount, firstBandToDel, -1 do
-- this *must* go in reverse order
band.Delete( i )
end
end
end
function EnableMyBands()
local allBandCount = band.GetCount( )
local firstActionBand = InitialBandCount + CYSTEINE_TOTAL_BANDS + 1
for i=firstActionBand, allBandCount do
band.Enable( i )
end
end
function SetMyBandStrengths( strength )
local allBandCount = band.GetCount( )
local firstActionBand = InitialBandCount + CYSTEINE_TOTAL_BANDS + 1
for i=firstActionBand, allBandCount do
band.SetStrength( i, strength )
end
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
print( "failed to add band from "..seg1.." to "..seg2)
return false
end
if bIdx <= InitialBandCount then
-- don't accidentally change user-supplied bands
return true
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 )
if not IsUnlockedSeg( seg ) then return false end
local bIdx = band.Add( seg, segFini, segInit, rho, theta, phi )
if bIdx ~= band.GetCount( ) then return 0 end
if bIdx <= InitialBandCount+CYSTEINE_TOTAL_BANDS then
-- don't change user-supplied bands
-- don't expect to hit our cysteine ones, but just to be safe...
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
-- fool with this some more
function BandInSpaceFromAtomWithParameters(
seg, segFini, segInit,
rho, theta, phi,
strength, goalLength, atom)
if not IsUnlockedSeg( seg ) then return false end
local bIdx = band.Add( seg, segFini, segInit, rho, theta, phi, atom)
if bIdx ~= band.GetCount( ) then return 0 end
if bIdx <= InitialBandCount+CYSTEINE_TOTAL_BANDS then
-- don't change special or prior bands
-- don't expect to hit them, but just to be safe...
return 0
end
if goalLength ~= nil then
band.SetGoalLength( bIdx, goalLength )
end
if strength ~= nil and strength ~= 0.0 then
band.SetStrength( bIdx, strength )
end
return bIdx
end
----------------------------------------------------------------------
-- SPECIAL BANDERS
----------------------------------------------------------------------
function ZLB( strength, lower, upper, bandGivenRange )
if lower == nil then lower = MaxUnlockedSeg + 1 end
if upper == nil then upper = MinUnlockedSeg - 1 end
if bandGivenRange == nil then bandGivenRange = false end -- default is exclude a range
if bandGivenRange then
for i=lower, upper do
if i == 1 then
BandInSpaceWithParameters( i, i+1, i+2, 0.01, 0.0, 0.0, strength, 0.01)
elseif i == SegCt then
BandInSpaceWithParameters( i, i-1, i-2, 0.01, 0.0, 0.0, strength, 0.01)
else
BandInSpaceWithParameters( i, i+1, i-1, 0.01, 0.0, 0.0, strength, 0.01)
end
end
else
for i=MinUnlockedSeg+1, MaxUnlockedSeg-1 do
if i < lower or i > upper then
BandInSpaceWithParameters( i, i+1, i-1, 0.01, 0.0, 0.0, strength, 0.01)
end
end
if lower > 1 then
BandInSpaceWithParameters( 1, 2, 3, 0.01, 0.0, 0.0, strength, 0.01)
end
if upper < SegCt then
BandInSpaceWithParameters( SegCt, SegCt-1, SegCt-2, 0.01, 0.0, 0.0, strength, 0.01)
end
end
end
function EnableAndDisableCysteineBands( )
if InitialBandCount + CYSTEINE_TOTAL_BANDS > band.GetCount() then
CYSTEINE_TOTAL_BANDS = band.GetCount() - InitialBandCount
CYSTEINE_GOT_MIXUP = true
end
if CYSTEINE_GOT_MIXUP then
-- somehow we've gotten confused. just disable the lot of them
local bIdx = InitialBandCount
print( "!!! Cannot manage cysteine bands - disabling all of them" )
for i=1, CYSTEINE_TOTAL_BANDS do
band.Disable( bIdx + i )
end
else
for i=1, CysteineBandPairCount do
local bIdx = InitialBandCount + CYSTEINE_COUNT_BANDS_USED*(i-1)
local pair = CysteinePairList[i]
local bondExists = doesCysteineBondExist( pair[1], pair[2] )
for j=1, CYSTEINE_COUNT_BANDS_USED do
if bondExists then
band.Disable( bIdx + j )
else
band.Enable( bIdx + j )
end
end
end
end
end
function PutCysteineBands( idx1, idx2 )
if idx1 < 1 or idx1 > SegCt or
idx2 < 1 or idx2 > SegCt or
idx1 == idx2 then
return false
end
if structure.GetAminoAcid( idx1 ) ~= 'c' or
structure.GetAminoAcid( idx2 ) ~= 'c'
then
return false
end
local at1 = GetTipAtomOfSeg( idx1 )
local at2 = GetTipAtomOfSeg( idx2 )
-- fancy is to put more than one band, going after the sulfur atom:
-- Put bands here:
-- atS1 -> atS2 dist=d1=DISTANCE_CYSTEINE_BOND
-- atS1 -> atS2-1 dist=d2=math.sqrt(d1*d1+1.8*1.8)
-- atS1-1 -> atS2 dist=d2
-- atS1-1 -> atS2-1 dist=d3=math.sqrt(d2*d2+1.8*1.8)
local atS1 = GetCysteineSulfurAtom( idx1 )
local atS2 = GetCysteineSulfurAtom( idx2 )
local strength = CYSTEINE_BAND_STRENGTH
local d1 = DISTANCE_CYSTEINE_BOND
if CYSTEINE_COUNT_BANDS_USED == 1 then
-- my old way of doing this
return BandBetweenSegsWithParameters( idx1, idx2, strength, d1, at1, at2 )
else
local d2 = math.sqrt(d1*d1 + SCALE_CYSTEINE_OFF_1*SCALE_CYSTEINE_OFF_1)
local d3 = math.sqrt(d2*d2 + SCALE_CYSTEINE_OFF_1*SCALE_CYSTEINE_OFF_1)
local chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d1, atS1, atS2 )
if not chSuc then
return false
end
chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d2, atS1, atS2-1 )
if not chSuc then
band.Delete( band.GetCount())
return false
end
if CYSTEINE_COUNT_BANDS_USED >= 3 then
chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d2, atS1-1, atS2 )
if not chSuc then
band.Delete( band.GetCount())
band.Delete( band.GetCount())
return false
end
end
if CYSTEINE_COUNT_BANDS_USED >= 4 then
chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d3, atS1-1, atS2-1 )
if not chSuc then
band.Delete( band.GetCount())
band.Delete( band.GetCount())
band.Delete( band.GetCount())
return false
end
end
end
return true
end
function PutCysteinePairBands( )
local changeSucceeded = false
CysteineBandPairCount = 0
CYSTEINE_TOTAL_BANDS = 0
for i=1, #CysteinePairList do
local pair = CysteinePairList[i]
local chSuc = PutCysteineBands( pair[1], pair[2] )
if chSuc then
-- will fail if user already has one of these in place
CysteineBandPairCount = CysteineBandPairCount + 1
CYSTEINE_TOTAL_BANDS = CYSTEINE_TOTAL_BANDS + CYSTEINE_COUNT_BANDS_USED
end
changeSucceeded = changeSucceeded or chSuc
end
return changeSucceeded
end
----------------------------------------------------------------------
-- SMALL-SCALE BANDERS
----------------------------------------------------------------------
function PutBandInSpace( idx, maxRho, strength, goalLength, atom ) -- ok goalLength, atom = nil
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
if goalLength == nil then goalLength = rho end
if atom == nil then atom = CENTER_CARBON end
return BandInSpaceFromAtomWithParameters(
idx, idx2, idx3, rho, theta, phi, strength, goalLength, atom )
end
function PutBandToRandomSeg( idx, strength, atom, bewareCysteine )
local needNew = true
local failedTries = 0
local idx2
local applyCaution = bewareCysteine and
CysteineBandPairCount > 0 and
structure.GetAminoAcid( idx ) == "c"
while ( needNew and failedTries < 20 ) do
idx2 = randomSeg( ) -- ok if this one isn't movable (we assume idx is movable)
if applyCaution and structure.GetAminoAcid( idx2 ) == "c" then
failedTries = failedTries + 1
elseif idx2 > idx + 3 or idx2 < idx - 3 then
needNew = false
break
else
failedTries = failedTries + 1
end
end
if not needNew then
return BandBetweenSegsWithParameters( idx, idx2, strength, nil, atom, nil )
else
return false
end
end
function PutSingleRandomBandToSeg( idx, probBis )
local changeSucceeded = false
local strength = random( 0.5 * BAND_STRENGTH_DEFAULT,
1.5 * BAND_STRENGTH_DEFAULT,
true )
local doBIS = randomBool( probBis )
if doBIS then
return PutBandInSpace( idx, BIS_LENGTH, strength )
else
local atom = PickAtomNumberForBand( idx, true )
return PutBandToRandomSeg( idx, strength, atom, false )
end
end
function PutRandomCompBands()
if not CONTACTMAP_BAND_ADD_RANDOMS then return end
if randomBool( ) then
local ctRandBands = random( CONTACTMAP_RANDOMBAND_COUNT - 2, CONTACTMAP_RANDOMBAND_COUNT + 2 )
local strength = random(0.5, 1.5) * BAND_STRENGTH_DEFAULT
PutGentleCompBands( ctRandBands, 14.0, 30.0, 5, strength, 0.7 ) -- 0.7 is compression
end
end
----------------------------------------------------------------------
-- MID-SCALE BANDERS
----------------------------------------------------------------------
function PutGlycineHingeBands( glycineIdx, strength )
if glycineIdx == MinUnlockedSeg or glycineIdx == MaxUnlockedSeg then return false end
local changeSucceeded = false
selection.DeselectAll ( )
-- construct the rods for the hinge (freeze before and after the glycine)
local sR, eR = GetRegionStartAndEnd( glycineIdx + 1 )
if eR < MaxUnlockedSeg and eR - glycineIdx < 3 then eR = eR + 1 end
selection.SelectRange( glycineIdx + 1 , eR )
local sL, eL = GetRegionStartAndEnd( glycineIdx - 1 )
if eL > MinUnlockedSeg and glycineIdx - eL < 3 then eL = eL - 1 end
selection.SelectRange ( sL, glycineIdx - 1 )
ChangedFrozenness = true
freeze.FreezeSelected ( true, true )
selection.DeselectAll ( )
-- put bands connecting the two rods
local maxLen = math.min( eR - sR + 1, eL - sL + 1 )
if maxLen > 4 or (glycineIdx >= 4 and glycineIdx <= MaxUnlockedSeg - 4) then
maxLen = 4 -- try very hard to have 4 instead of only 2 or 3, even if it means bands beyond end of rods
elseif maxLen < 1 then
return changeFailed -- should only happen if glycine at an end
end
for i=1, maxLen do
if BandBetweenSegsWithParameters(
math.max(MinUnlockedSeg, glycineIdx - i),
math.min(MaxUnlockedSeg, glycineIdx + i),
strength )
then
changeSucceeded = true
end
end
return changeSucceeded
end
function PutGeneralHingeBands( startHinge, endHinge, strength )
if startHinge > endHinge then startHinge, endHinge = endHinge, startHinge end
if startHinge == MinUnlockedSeg or endHinge == MaxUnlockedSeg then return false end
local changeSucceeded = false
selection.DeselectAll( )
-- construct the rods for the hinge (freeze before and after the region)
local sR, eR = GetRegionStartAndEnd( endHinge + 1 )
if eR < MaxUnlockedSeg and eR - endHinge < 3 then eR = eR + 1 end
selection.SelectRange( endHinge + 1 , eR )
local sL, eL = GetRegionStartAndEnd( startHinge - 1 )
if eL > MinUnlockedSeg and startHinge - eL < 3 then eL = eL - 1 end
selection.SelectRange( sL, startHinge - 1 )
ChangedFrozenness = true
freeze.FreezeSelected( true, true )
selection.DeselectAll( )
-- put bands connecting the two rods
local maxLen = math.min( eR - sR + 1, eL - sL + 1 )
if maxLen > 4 then maxLen = 4 -- we will surely have it be at least 2 by choice of eR and eL
elseif maxLen < 1 then
-- should only happen if startHinge or endHinge is too close to an end
return changeFailed
end
for i=1, maxLen do
if BandBetweenSegsWithParameters(
math.max(MinUnlockedSeg, startHinge - i),
math.min(MaxUnlockedSeg, endHinge + i),
strength )
then
changeSucceeded = true
end
end
if not changeSucceeded then
ResetFrozenness( )
end
return changeSucceeded
end
function BandableSheetSeg( seg )
return not isGlycine( seg ) and not isProline( seg )
end
function PutAntiParallelSheetBandsBetweenSegs( seg1, seg2, strength )
local changeSucceeded = false
local chSuc = false
local atom1 = 4
local atom1Vec = getPolarAtoms( seg1 )
if atom1Vec ~= nil then atom1 = atom1Vec[1] end
local atom2 = 4
local atom2Vec = getPolarAtoms( seg2 )
if atom2Vec ~= nil then atom2 = atom2Vec[1] end
if BandableSheetSeg(seg1) and BandableSheetSeg(seg2) then
chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength,
SHEET2SHEET_BONDING_BAND_LENGTH,
4, atom2 )
local iBand = band.GetCount()
if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then
band.Delete(iBand)
end
changeSucceeded = changeSucceeded or chSuc
chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength,
SHEET2SHEET_BONDING_BAND_LENGTH,
atom1, 4 )
iBand = band.GetCount()
if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then
band.Delete(iBand)
end
changeSucceeded = changeSucceeded or chSuc
end
chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength,
SHEET2SHEET_CENTER_BAND_LENGTH)
changeSucceeded = changeSucceeded or chSuc
return changeSucceeded
end
function PutParallelSheetBandsBetweenSegs( seg1, seg2, strength )
local changeSucceeded = false
local chSuc = false
local seg3 = seg2+1
local seg4 = seg2-1
local atom1 = 4
local atom1Vec = getPolarAtoms( seg1 )
if atom1Vec ~= nil then atom1 = atom1Vec[1] end
local atom3 = 4
local atom3Vec = getPolarAtoms( seg3 )
if atom3Vec ~= nil then atom3 = atom3Vec[1] end
if BandableSheetSeg(seg1) then
if seg3 <= MaxUnlockedSeg and BandableSheetSeg(seg3) then
chSuc = BandBetweenSegsWithParameters( seg1, seg3, strength,
SHEET2SHEET_BONDING_BAND_LENGTH,
4, atom3 )
local iBand = band.GetCount()
if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then
band.Delete(iBand)
end
changeSucceeded = changeSucceeded or chSuc
end
if seg4 >= MinUnlockedSeg and BandableSheetSeg(seg4) then
chSuc = BandBetweenSegsWithParameters( seg1, seg4, strength,
SHEET2SHEET_BONDING_BAND_LENGTH,
atom1, 4 )
local iBand = band.GetCount()
if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then
band.Delete(iBand)
end
changeSucceeded = changeSucceeded or chSuc
end
end
chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength,
SHEET2SHEET_CENTER_BAND_LENGTH)
changeSucceeded = changeSucceeded or chSuc
return changeSucceeded
end
function PutSheetBands( idxStart1, idxStart2, goForward2, len, strengthBkb, strengthSide )
local idx1, idx2
local changeSucceeded = false
local chSuc = false
for i=1, len do
idx1 = idxStart1 + i - 1
if goForward2 then
idx2 = idxStart2 + i - 1
else
idx2 = idxStart2 + len - i + 1
end
if idx1 < 1 or idx1 > SegCt or idx2 < 1 or idx2 > SegCt
then
-- we can't put bands here!
chSuc = false
else
if goForward2 then -- PARALLEL
chSuc = PutParallelSheetBandsBetweenSegs( idx1, idx2, strengthBkb )
else -- ANTIPARALLEL
chSuc = PutAntiParallelSheetBandsBetweenSegs( idx1, idx2, strengthBkb )
end
changeSucceeded = changeSucceeded or chSuc
if strengthSide > 0.0 and not (isGlycine( idx1 ) or isGlycine( idx2 )) then
-- sidechain band
chSuc = BandBetweenSegsWithParameters( idx1, idx2,
strengthSide, goalLength,
GetBetaCarbonAtom(idx1),
GetBetaCarbonAtom(idx2) )
changeSucceeded = changeSucceeded or chSuc
end
end
end
return changeSucceeded
end
function PutFlipSheetBands( startSeg, endSeg, length, strength )
local changeSucceeded = false
for i = math.max( startSeg, MinUnlockedSeg+1 ), math.min( endSeg, MaxUnlockedSeg - 1 ) do
local atom = GetBetaCarbonAtom( i )
local theta = math.rad( 180 ) -- math.pi / 2
local phi = math.rad( 270 ) -- math.rad( 315 )
if BandInSpaceFromAtomWithParameters( i, i + 1, i - 1, length, theta, phi, strength, length, atom ) then
changeSucceeded = true
end
end
return changeSucceeded
end
function BandAdjacentSheets( sheetIdx1, sheetIdx2, deltaToAdd )
local sIdx1, eIdx1 = GetBoundsOfSheetFromIndex( sheetIdx1 )
local sIdx2, eIdx2 = GetBoundsOfSheetFromIndex( sheetIdx2 )
if sIdx1 == 0 or sidx2 == 0 then return false end
local strength = 1.0
local goalLength = DISTANCE_SHEET_TO_SHEET
local sheetLen = 0
local deltaFirst, deltaSecond, len, isAntiParallel =
FindBestOffsetsForSheetMatching( sheetIdx1, sheetIdx2 )
--print( "deltaFirst="..deltaFirst.." deltaSecond="..deltaSecond.." len="..len )
--print( "start1="..(sIdx1 + deltaFirst).." start2="..(sIdx2 + deltaSecond + deltaToAdd) )
return PutSheetBands( sIdx1 + deltaFirst, sIdx2 + deltaSecond + deltaToAdd,
not isAntiParallel, len, strength, strength )
end
function BandStraySheetToNearestSheet( sheetIdx1 )
local s1,e1 = GetBoundsOfSheetFromIndex( sheetIdx1 )
local lenFirst = e1 - s1 + 1
local sheetIdxList = {}
local changeSucceeded = false
local strength = 1.0
sheetIdxList = FindNearestSheetToSeg( s1, 25.0 ) -- faraway
--print( "Ct Nearest sheets: "..#sheetIdxList )
if #sheetIdxList >= 1 then
for i=1, #sheetIdxList do
local s,e = GetBoundsOfSheetFromIndex( sheetIdxList[i] )
--print(" #"..sheetIdxList[i]..": "..s.."-"..e )
end
local r = random( #sheetIdxList )
local idxFar = GetNearestSegOfSheet( s1, sheetIdxList[r] )
local sIdx2, eIdx2 = GetBoundsOfSheetFromIndex( sheetIdxList[r] )
local maxDelta = idxFar - sIdx2 - lenFirst
local idxStartSecondSheet = idxFar - lenFirst - random(0, maxDelta)
if idxFar - sIdx2 >= lenFirst then
-- we always try to do anti-parallel here
changeSucceeded = PutSheetBands( s1, idxStartSecondSheet, false, lenFirst,
strength, strength )
end
end
return changeSucceeded
end
function PutSheetStraightenerBand( startSeg, endSeg, strength )
local changeSucceeded = BandBetweenSegsWithParameters(
startSeg, endSeg, strength,
(endSeg-startSeg)*DISTANCE_AA_TO_AA )
return changeSucceeded
end
function PutHelixUniformDistanceBands( startSeg, endSeg, shift, strength )
if startSeg < MinUnlockedSeg or endSeg > MaxUnlockedSeg or shift < 2 then
return false
end
local changeSucceeded = false
local sumDist = 0.0
for i=startSeg, endSeg-shift do
sumDist = sumDist + structure.GetDistance( i, i+shift )
end
length = sumDist/( endSeg - shift - startSeg + 1 )
for i=startSeg,endSeg-shift do
if BandBetweenSegsWithParameters( i, i+shift, strength, length ) then changeSucceeded = true end
end
return changeSucceeded
end
function PutHelixFixerBands( startSeg, endSeg, strength, do4 )
if endSeg < startSeg + 4 then return false end
if (not do4) and endSeg < startSeg + 5 then return false end
local changeSucceeded = false
if do4 then
for i=startSeg,endSeg-4 do
if BandBetweenSegsWithParameters( i, i+4, strength, HELIX_DISTANCE_SKIP4 ) then
changeSucceeded = true
end
end
else
for i=startSeg,endSeg-5 do
if BandBetweenSegsWithParameters( i, i+5, strength, HELIX_DISTANCE_SKIP5 ) then
changeSucceeded = true
end
end
end
return changeSucceeded
end
function PutHelixCompressorBands( startSeg, endSeg, shift, strength, stretch )
if startSeg < MinUnlockedSeg or endSeg > MaxUnlockedSeg or shift < 2 then
return false
end
local changeSucceeded = false
for i=startSeg,endSeg-shift do
dist = structure.GetDistance( i, i+shift )
if BandBetweenSegsWithParameters( i, i+shift, strength, dist*stretch ) then changeSucceeded = true end
end
return changeSucceeded
end
function PutHelixRotatorBands( startSeg, endSeg, length, strength, wantClockwise )
local changeSucceeded = false
for i = math.max( startSeg, MinUnlockedSeg+1 ), math.min( endSeg, MaxUnlockedSeg - 1 ) do
if wantClockwise then
if BandInSpaceWithParameters( i, i + 1, i - 1, length, math.pi/2, math.rad ( 315 ), strength ) then
changeSucceeded = true
end
else
if BandInSpaceWithParameters( i, i - 1, i + 1, length, math.pi/2, math.rad ( 315 ), strength ) then
changeSucceeded = true
end
end
end
return changeSucceeded
end
function PutPusherBands( startSeg, endSeg, length, strength, doForward )
local changeSucceeded = false
local init = math.max( MinUnlockedSeg, startSeg - 1 )
local fini = math.min( MaxUnlockedSeg, endSeg + 1 )
if doForward then
for i = init + 1, fini - 1 do
if BandInSpaceWithParameters( i, fini, init, length, math.pi/2, 0.0, strength ) then
changeSucceeded = true
end
end
else
for i = fini - 1, init + 1, -1 do
if BandInSpaceWithParameters( i, fini, init, length, math.pi/2, 0.0, strength ) then
changeSucceeded = true
end
end
end
return changeSucceeded
end
function PutMoverBands( startSeg, endSeg, length, strength )
local changeSucceeded = false
local init, fini
if startSeg > MinUnlockedSeg then
init = startSeg - 1
else
init = startSeg
end
if endSeg < MaxUnlockedSeg then
fini = endSeg + 1
else
fini = endSeg
end
local theta, phi = randomThetaPhi( )
for i = init + 1, fini - 1 do
if BandInSpaceWithParameters( i, fini, init, length, theta, phi, strength ) then
changeSucceeded = true
end
end
return changeSucceeded
end
-- TODO consider putting more bands in "between" segments, with lengths that increase
-- as they head towards the midpoint
function PutFlexerBands( startSeg, endSeg, length, strength )
if endSeg - startSeg < 3 then return false end
local changeSucceeded = false
local init, first, fini, last, midpt
if startSeg > MinUnlockedSeg then
init = startSeg - 1
first = startSeg
else
init = startSeg
first = startSeg + 1
end
if endSeg < MaxUnlockedSeg then
fini = endSeg + 1
last = endSeg
else
fini = endSeg
last = endSeg - 1
end
midpt = (startSeg + endSeg + 1) / 2
-- initial band points inwards
if BandInSpaceWithParameters( first, fini, init, 1.0, math.pi/2.0, 0.0, strength ) then
changeSucceeded = true
end
--final band points inwards, too
if BandInSpaceWithParameters( last, init, fini, 1.0, math.pi/2.0, 0.0, strength ) then
changeSucceeded = true
end
-- middle one is longer and points perpendicularly to init-fini line. Consider
-- replacing with ramping-up lengths over all "interior" segments.
local theta, phi = randomThetaPhi( ) -- ignoring phi, because we just want to use 0
if BandInSpaceWithParameters( midpt, fini, init, length, theta, 0.0, strength ) then
changeSucceeded = true
end
return changeSucceeded
end
function PutPushPullBands( badSeg, bandsWanted, center, strength, wantPushNotPull )
local changeSucceeded = false
local okSegList = {}
local SC = structure.GetDistance( badSeg, center )
local SR
for i=1, SegCt do
local RC=structure.GetDistance( i, center )
SR=structure.GetDistance( i, badSeg )
if SR<15
and RC<SC-3
and math.abs( i - badSeg ) > 5
and math.abs( i - center ) > 3
then
okSegList[#okSegList + 1] = i
end
end
if #okSegList == 0 then
print( "No suitable segs for idx="..badSeg.." with center="..center)
return false
end
randomizeIndexList( okSegList )
local bandsAdded = 0
for i=1, #okSegList do
SR=structure.GetDistance( i, badSeg )
if wantPushNotPull then
SR=SR + 4
else
SR=SR - 4
end
if SR>20 then SR=20 end
if SR<3 then SR=3 end
if BandBetweenSegsWithParameters( badSeg, okSegList[i], strength, SR ) then
changeSucceeded = true
bandsAdded = bandsAdded + 1
end
if bandsAdded >= bandsWanted then break end
end -- FOR(i)
return changeSucceeded
end
function PutVoidCrusherBands( idx, strength ) --make band if found void in area of segment "idx"
local changeSucceeded = false
local t={} -- store possible segments
for b=1,SegCt do --test all segments
if math.abs(idx-b) >= 15 then -- else idx,b too near each other count-wise
local ab = structure.GetDistance(idx, b)
if ab > 10.0 then --no void if less
local void=true
for c=1,SegCt do --searching for any segment between them
if c ~= idx and c ~= b then -- don't want c = idx or b
local ac = structure.GetDistance(idx,c)
local bc = structure.GetDistance(b,c)
if ac<ab and bc<ab and ac>4 and bc>4 then
if ac+bc<ab+1.5
then void=false break --no void there for sure
end
end
end
end -- END for c
if void==true then
t[#t+1]={idx,b}
end
end -- END if idx and b are spatially at least 10 apart
end -- END if idx and b are count-wise at least 15 apart
end -- LOOP over candidate b's
if #t>0 then
for i=1,#t do
local s=t[i][1]
local e=t[i][2]
local d=structure.GetDistance( s, e )
d = d - 3.0 -- try to compress this much...
if d<3 then d=3 end
if d>20 then d=20 end
if BandBetweenSegsWithParameters( s, e, strength, d ) then changeSucceeded = true end
end
end
return changeSucceeded
end
-- bandToNearest=false means "band to farthest"
function PutManyBandsToSeg( idx, maxBandCount, strength, compression, bandToNearest )
local changeSucceeded = false
local segsToBand = {}
local idxList = {}
local distList = {}
local totalDistance = 0.0
local dist = 0.0
-- we will construct segsToBand first, summing totalDistance as we go
for i = MinUnlockedSeg + 2, MaxUnlockedSeg - 3 do
if i ~= idx and IsUnlockedSeg( i ) then
if bandToNearest then
if isLocalMinimum( idx, i ) then
segsToBand[ #segsToBand + 1 ] = i
totalDistance = totalDistance + structure.GetDistance( idx, i )
end
else
if isLocalMaximum( idx, i ) then
segsToBand[ #segsToBand + 1 ] = i
totalDistance = totalDistance + structure.GetDistance( idx, i )
end
end
end
end
-- now sort them so we can take only the "best" segments...
for i=1, #segsToBand do idxList[ i ] = i end
for i=1, #segsToBand do distList[ i ] = structure.GetDistance( idx, i ) end
sortByScore( idxList, distList )
-- now put the bands, preferring the "nearest" ones
for i=1, math.min( #segsToBand, maxBandCount ) do
local dist = structure.GetDistance( idx, segsToBand[ idxList[ i ]] )
if BandBetweenSegsWithParameters( idx, segsToBand[ idxList[ i ]], strength, compression*dist ) then
changeSucceeded = true
end
end
return changeSucceeded
end
function PutTailDetacherBands( fromStart, length )
local s, e, rel, goalLen, phi, theta
if fromStart then
s = MinUnlockedSeg
e = MinUnlockedSeg + length
rel = MinUnlockedSeg + 1 + length
else
s = MaxUnlockedSeg - length - 1
e = MaxUnlockedSeg
rel = MaxUnlockedSeg - length - 2
end
if rel < MinUnlockedSeg or rel > MaxUnlockedSeg then return 0 end
goalLen = 0
phi = random( 0.5 * math.pi )
theta = math.pi/2.0 + random( -0.5 * math.pi, 0.5 * math.pi )
if fromStart then
for i=e,s+1,-1 do
goalLen = goalLen + 3.5
BandInSpaceWithParameters( i, e+1, e+2, length, theta, phi, 1.0, goalLen )
end
else
goalLen = goalLen + 3.5
for i=s,e do
BandInSpaceWithParameters( i, s-1, s-2, length, theta, phi, 1.0, goalLen )
end
end
return true
end
function PutTailAttacherBands( fromStart, length )
local s, e
if fromStart then
s = MinUnlockedSeg
e = MinUnlockedSeg + length
else
s = MaxUnlockedSeg - length - 1
e = MaxUnlockedSeg
end
-- Idea is to find hydrophobics between s and e and attach bands
-- from some of them to a "randomly" chosen nearby hydrophobic
-- not between s and e.
local hookAas = { }
for i=s, e do
if structure.IsHydrophobic( i ) then hookAas[ #hookAas + 1] = i end
end
if #hookAas == 0 then return false end -- if we have no hydrophobics then give up for now
randomizeIndexList( hookAas)
local ctToHook = random(1, #hookAas )
for i=1, ctToHook do
local nearPhobics = {}
local toHook = hookAas[ i ]
getNearestPhobicsOutsideRange( toHook, s, e, nearPhobics, 5 )
which = random( 1, #nearPhobics )
BandBetweenSegsWithParameters( toHook, nearPhobics[which], 1.0, 2.0, BETA_CARBON, BETA_CARBON )
end
return true
end
----------------------------------------------------------------------
-- LARGE-SCALE BANDERS
----------------------------------------------------------------------
function PutSheetSewerBandsAllOver( maxDist, strength )
local changeSucceeded = false
for seg1 = MinUnlockedSeg+1, MaxUnlockedSeg - 4 do
for seg2 = seg1 + 3, MaxUnlockedSeg do
if IsUnlockedSeg( seg1 ) or IsUnlockedSeg( seg2 ) then
if structure.GetDistance( seg1, seg2 ) < maxDist and
structure.GetSecondaryStructure( seg1 ) == 'E' and
structure.GetSecondaryStructure( seg2 ) == 'E'
then
local changeSuc = BandBetweenSegsWithParameters(seg1, seg2, strength )
changeSucceeded = changeSucceeded or changeSuc
end
end
end
end
return changeSucceeded
end
function PutCoreCompressBands(coreList, skipCt, startOffset, strength, compression, pullPhilics, doSidechains )
if doSidechains == nil then doSidechains = false end
if pullPhilics == nil then pullPhilics = false end
local maxToBand = #coreList
local bandList = {}
local added = 0
local goalLength
-- first put bands between all of our central segs
-- notice: there's no protection from some of them being adjacent, but it's ok
-- if one or more of these bands fail to be created.
for i=1, maxToBand-1 do
for j=i+1, maxToBand do
if coreList[i] < coreList[j] - 1 or coreList[i] > coreList[j] + 1 then
goalLength = compression * structure.GetDistance( coreList[ i ], coreList[ j ] )
if BandBetweenSegsWithParameters( coreList[ i ], coreList[ j ], strength, goalLength ) then
added = added + 1
end
end
end
end
-- now put bands between the "rest" of the protein and our chosen ones
for i=startOffset, SegCt, skipCt do
local skipThisI = false
for j=1, maxToBand do
if coreList [ j ] == i then
skipThisI = true
break
end
end
if not skipThisI then
for j=1, maxToBand do
if i < coreList[ j ] - 1 or i > coreList[ j ] + 1 then
goalLength= compression * structure.GetDistance( i, coreList[ j ] )
if pullPhilics and not structure.IsHydrophobic( i ) then
goalLength= goalLength + 1.0
end
atom = nil
if doSidechains then
atom = PickAtomNumberForBand( i )
end
if BandBetweenSegsWithParameters( i, coreList[ j ], strength, goalLength, atom, nil ) then
added = added + 1
end
end
end
end
end
return added > 0
end
function PutBandsEveryXToEveryY( xRange, xInit, yRange, yInit, strength, compression )
local length = 0
local added = 0
for i=xInit, MaxUnlockedSeg, xRange do
for j=yInit, MaxUnlockedSeg, yRange do
if (i < j - 1 or i > j + 1) then
if compression == nil then length = nil
else length = compression * structure.GetDistance( i, j )
end
if BandBetweenSegsWithParameters( i, j, strength, length ) then
added = added + 1
end
end
end
end
return added > 0
end
function AddRandomXToYBands( strength )
if strenth == nil then strength = XTOY_DEFAULT_STRENGTH end
local length = 0
local added = 0
local validRange = (MaxUnlockedSeg - MinUnlockedSeg + 1)
local xInterval = random( math.floor( validRange / 9 ), math.floor( validRange / 5 ))
local yInterval = random( 2 + xInterval, 2 + math.floor( validRange / 5 ))
local xInit = MinUnlockedSeg + random( xInterval-1 ) - 1
local yInit = MinUnlockedSeg + random( yInterval-1 ) - 1
return PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, 1.0 )
end
function PutGentleCompBands( bandsWanted, minLength, maxLength, minSeparation, strength, compression )
local bandsAdded = 0
local failCount = 0
repeat
local s = randomMovableSeg( )
local e = randomMovableFarSeg( s, minSeparation, minLength, maxLength )
if e == 0 then
failCount = failCount + 1
else
-- yes, this would try to add the same segment twice, but that will fail simply...
local dist = structure.GetDistance( s, e )
changeSucceeded = BandBetweenSegsWithParameters( s,e, strength, dist * compression )
if changeSucceeded then
bandsAdded = bandsAdded + 1
else
failCount = failCount + 1
end
end
until bandsAdded == bandsWanted or failCount >= 100
return true
end
----------------------------------------------------------------------
-- CONTACT-MAP BANDERS
----------------------------------------------------------------------
function PutAllContactMapBands( heatThreshold, madeStrength, madeLengthScale,
unmadeStrength, unmadeLengthScale,
doSidechains, ditherValues, omitLongBands )
local changeSucceeded = false
local baseStrength = BAND_STRENGTH_DEFAULT
for i = 1, SegCt-2 do
for j = i+2, SegCt do
if contactmap.GetHeat(i, j) >= heatThreshold then
local goalLength = structure.GetDistance( i, j )
if contactmap.IsContact( i, j ) then
goalLength = madeLengthScale * goalLength
strength = madeStrength
else
goalLength = unmadeLengthScale * goalLength
strength = unmadeStrength
end
if not omitLongBands or goalLength < CONTACTMAP_MAX_NOCONTACT then
if ditherValues then
goalLength = random( 0.95, 1.05, true ) * goalLength
strength = random( 0.95, 1.05, true ) * strength
end
local atom1 = nil
local atom2 = nil
if BAND_TO_SIDECHAINS and doSidechains then
atom1 = BETA_CARBON
atom2 = BETA_CARBON
end
local chSuc = BandBetweenSegsWithParameters(
i, j, strength, goalLength, atom1, atom2 )
changeSucceeded = changeSucceeded or chSuc
end
end
end
end
return changeSucceeded
end
function PutContactMapBands( )
local threshold = CONTACTMAP_THRESHOLD
local madeStrength = random( 0.96, 1.04, true ) * CONTACTMAP_CONTACTING_STRENGTH
local madeLenScale = random( 0.96, 1.04, true ) * CONTACTMAP_CONTACTING_GOAL
local unmadeStrength = random( 0.96, 1.04, true ) * CONTACTMAP_NONCONTACTING_STRENGTH
local unmadeLenScale = random( 0.96, 1.04, true ) * CONTACTMAP_NONCONTACTING_GOAL
local doSidechains = randomBool( )
local wantDither = randomBool( )
local doVariableStrength = false
return PutAllContactMapBands( threshold, madeStrength, madeLenScale,
unmadeStrength, unmadeLenScale,
doSidechains, wantDither, true )
end
function PutSomeContactMapBands( heatThreshold, strength, ctBands, doSidechains, omitLongBands )
local 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
if not omitLongBands or structure.GetDistance( i, j ) < CONTACTMAP_MAX_NOCONTACT then
hotList[ #hotList + 1] = { i, j, heat }
end
end
end
end
randomizeIndexList( hotList )
for i=1, math.min( ctBands, #hotList ) do
local atom1 = nil
local atom2 = nil
if doSidechains then
atom1 = PickAtomNumberForBand( hotList[i][1] )
atom2 = PickAtomNumberForBand( hotList[i][2] )
end
local ch = BandBetweenSegsWithParameters( hotList[i][1], hotList[i][2], strength, nil, atom1, atom2 )
changeSucceeded = ch or changeSucceeded
end
return changeSucceeded
end
function PutAllContactMapBandsToSeg( idx, heatThreshold, strength, doComp, doSidechain, omitLongBands )
local changeSucceeded = false
local baseStrength = strength
if doComp then
-- COMP-style bands
for i=1, SegCt do
if i < idx - 1 or i > idx + 1 then
local heat = contactmap.GetHeat( i, idx )
if heat >= heatThreshold then
local goalLength = structure.GetDistance( i, idx )
if contactmap.IsContact( i, idx ) then
strength = CONTACTMAP_CONTACTING_STRENGTH * baseStrength
goalLength = CONTACTMAP_CONTACTING_GOAL * goalLength
else
strength = CONTACTMAP_NONCONTACTING_STRENGTH * baseStrength
goalLength = CONTACTMAP_NONCONTACTING_GOAL * goalLength
end
if not omitLongBands or goalLength < CONTACTMAP_MAX_NOCONTACT then
local atom = nil
if doSidechain then
atom = PickAtomNumberForBand( i )
end
local changeSuc = BandBetweenSegsWithParameters(
idx, i, strength, goalLength,
nil, atom )
changeSucceeded = changeSuc or changeSucceeded
end
end
end
end
else
-- only bands to non-contacting segs
local hotList = {}
for i = 1, SegCt do
if i < idx - 1 or i > idx + 1 then
local heat = contactmap.GetHeat( i, idx )
if heat >= heatThreshold and not contactmap.IsContact( i , idx ) then
if not omitLongBands or structure.GetDistance( i, idx ) < CONTACTMAP_MAX_NOCONTACT then
hotList[ #hotList + 1] = i
end
end
end
end
for i=1, #hotList do
if hotList[ i ] ~= idx then -- not supposed to happen!
local atom = nil
if doSidechain then
atom = PickAtomNumberForBand( hotList[i] )
end
local changeSuc = BandBetweenSegsWithParameters(
idx, hotList[i], strength * contactmap.GetHeat( i, idx ),
nil, nil, atom )
changeSucceeded = changeSuc or changeSucceeded
end
end
end
return changeSucceeded
end
function PutContactMapBandsBetweenRegions(
heatThreshold,
startIdx1, endIdx1, startIdx2, endIdx2,
strength, doComp, doBetaCarbons, ditherValues, omitLongBands )
local changeSucceeded = false
local baseStrength = strength
local atom1 = CENTER_CARBON
local atom2 = CENTER_CARBON
if BAND_TO_SIDECHAINS and doBetaCarbons then
atom1 = BETA_CARBON
atom2 = BETA_CARBON
end
for i = startIdx1, endIdx1 do
for j = startIdx2, endIdx2 do
if contactmap.GetHeat( i, j ) >= heatThreshold then
local goalLength = nil
if doComp then
goalLength = structure.GetDistance( i, j )
if contactmap.IsContact( i, j ) then
strength = CONTACTMAP_CONTACTING_STRENGTH * baseStrength
goalLength = CONTACTMAP_CONTACTING_GOAL * goalLength
else
strength = CONTACTMAP_NONCONTACTING_STRENGTH * baseStrength
goalLength = CONTACTMAP_NONCONTACTING_GOAL* goalLength
end
end
if not omitLongBands or goalLength < CONTACTMAP_MAX_NOCONTACT then
if ditherValues then
strength = random( 0.95, 1.05, true ) * strength
goalLength = random( 0.95, 1.05, true ) * goalLength
end
changeSucceeded = BandBetweenSegsWithParameters( i, j, strength, goalLength, atom1, atom2 )
or changeSucceeded
end
end
end
end
return changeSucceeded
end
function PutPushPullContactMapBands(
badSeg, bandsWanted,
center, strength, heatThreshold,
wantPushNotPull )
local changeSucceeded = false
local okSegList = {}
local SC = structure.GetDistance( badSeg, center )
local SR
for i=1, SegCt do
local RC=structure.GetDistance( i, center )
SR=structure.GetDistance( i, badSeg )
if SR<15
and RC<SC-3
and math.abs( i - badSeg ) > 5
and math.abs( i - center ) > 3
then
okSegList[#okSegList + 1] = i
end
end
randomizeIndexList( okSegList )
local bandsAdded = 0
for i=1, #okSegList do
SR=structure.GetDistance( i, badSeg )
if wantPushNotPull then
SR=SR + 4
else
SR=SR - 4
end
if SR>20 then SR=20 end
if SR<3 then SR=3 end
if BandBetweenSegsWithParameters( badSeg, okSegList[i], strength, SR ) then
changeSucceeded = true
bandsAdded = bandsAdded + 1
end
if bandsAdded >= bandsWanted then break end
end -- FOR(i)
return changeSucceeded
end
function PutVoidCrusherContactMapBands( idx, strength, heatThreshold )
local changeSucceeded = false
local t={} -- store possible segments
for b=1,SegCt do --test all segments
if math.abs(idx-b) >= 15 and contactmap.GetHeat( idx, b ) >= heatThreshold then
local ab = structure.GetDistance(idx, b)
if ab > 10.0 then --no void if less
local void=true
for c=1,SegCt do --searching for any segment between them
if c ~= idx and c ~= b then -- don't want c = idx or b
local ac = structure.GetDistance(idx,c)
local bc = structure.GetDistance(b,c)
if ac<ab and bc<ab and ac>4 and bc>4 then
if ac+bc<ab+1.5
then void=false break --no void there for sure
end
end
end
end -- END for c
if void==true then
t[#t+1]={ idx, b }
end
end -- END if idx and b are spatially at least 10 apart
end -- END if idx and b are count-wise at least 15 apart
end -- LOOP over candidate b's
if #t>0 then
for i=1,#t do
local s=t[i][1]
local e=t[i][2]
local d=structure.GetDistance( s, e )
d = d - 3.0 -- try to compress this much...
if d<3 then d=3 end
if d>20 then d=20 end
if BandBetweenSegsWithParameters( s, e, strength, d ) then changeSucceeded = true end
end
end
return changeSucceeded
end
--------------------------------------------------------------
--
---- MUTATOR ACTION FUNCTIONS
--
-- Very Similar AAs:
-- leucine/isoleucine (L/I), glycine/alanine (G/A), serine/threonine (S/T),
-- glutamine/glutamate (Q/E), asparagine/aspartate (D/N),
-- Maybe also aromatics: histidine/phenylalanine/tyrosine/tryptophan (H/F/Y/W)
-- Maybe aliphatic = valine/leucine/isoleucine (V/L/I)
-- Maybe cysteine/methionine (C/M)
-- Possibly arginine/lysine (R/K)
-- Proline (P) isn't similar to anything!
--------------------------------------------------------------
-- this one doesn't care what amino used to be at idx
function MutateToAny( idx )
local aa = structure.GetAminoAcid( idx )
local aanew = aa
local i = 0
while ( aanew == aa ) do
i = random( AACount )
aanew = AA( i )
end
print( "mutating " .. aa .. " at " .. idx .. " to " .. aanew )
structure.SetAminoAcid( idx, aanew )
return true
end
-- this one preserves hydrophob/hydrophil
function MutateToSimilar( idx )
local aa = structure.GetAminoAcid( idx )
local i = 0
local aanew = aa
while (aanew == aa) do
if structure.IsHydrophobic( idx ) then
i = random( AAPhobCount )
aanew = AAphobic( i )
else
i = random( AAPhilCount )
aanew = AAphilic( i )
end
end
print( "mutating " .. aa .. " at " .. idx .. " to " .. aanew )
structure.SetAminoAcid( idx, aanew )
return true
end
function MutateToVerySimilar( idx )
local aa = structure.GetAminoAcid( idx )
local i = 0
local aanew = aa
if aa == "a" then aanew = "g"
elseif aa == "c" then aanew = "m"
elseif aa == "d" then aanew = "n"
elseif aa == "e" then aanew = "q"
elseif aa == "g" then aanew = "a"
elseif aa == "h" then
local r = random(1,3)
if r == 1 then aanew = "f"
elseif r == 2 then aanew = "y"
else aanew = "w"
end
elseif aa == "i" then
local r = random(1,2)
if r == 1 then aanew = "l"
else aanew = "v"
end
elseif aa == "k" then aanew = "r"
elseif aa == "l" then
local r = random(1,2)
if r == 1 then aanew = "i"
else aanew = "v"
end
elseif aa == "m" then aanew = "c"
elseif aa == "n" then aanew = "d"
elseif aa == "p" then aanew = "p" -- proline isn't similar to anything
elseif aa == "q" then aanew = "e"
elseif aa == "r" then aanew = "k"
elseif aa == "s" then aanew = "t"
elseif aa == "t" then aanew = "s"
elseif aa == "v" then
local r = random(1,2)
if r == 1 then aanew = "i"
else aanew = "l"
end
elseif aa == "w" then
local r = random(1,3)
if r == 1 then aanew = "f"
elseif r == 2 then aanew = "y"
else aanew = "h"
end
elseif aa == "y" then
local r = random(1,3)
if r == 1 then aanew = "f"
elseif r == 2 then aanew = "h"
else aanew = "w"
end
else aanew = aa -- dunno what it is, but we can't play with it
end
print( "mutating " .. aa .. " at " .. idx .. " to " .. aanew )
structure.SetAminoAcid( idx, aanew )
return true
end
----------------------------------------------------------------------
-- SPECIALTY ACTION HELPER FUNCTIONS
----------------------------------------------------------------------
function BandedWormPairAction( segStart, len, idxFirst, wantGlobalWiggle )
local initScore = getScore( )
selection.DeselectAll( )
selection.SelectRange( segStart, segStart + len - 1 )
PutSingleRandomBandToSeg( idxFirst, BWP_PROB_BIS_NOT_BETWEEN )
if randomBool( BWP_PROB_ADD_SECOND_BAND ) then
local idx2 = random( segStart, segStart + len - 1 )
PutSingleRandomBandToSeg( idx2, BWP_PROB_2ND_IS_BIS )
end
if wantGlobalWiggle then
structure.WiggleSelected( random(2,4) )
else
structure.LocalWiggleSelected( random(2,4) )
end
DelBands( )
structure.WiggleAll( 2 )
structure.LocalWiggleSelected( 5 )
if getScore( ) - initScore > 0 then
structure.LocalWiggleSelected( 20 )
else
recentbest.Restore( )
structure.LocalWiggleSelected( 4 )
end
recentbest.Restore( )
DelBands( )
return true
end
function WiggleRangeAction( startIdx, endIdx, wantGlobalWiggle, minGain )
selection.SelectRange( startIdx, endIdx )
local iters = QUICKWIGGLE_ITERS
local startScore = getScore( )
gain = minGain
while gain >= minGain do
local lastScore = getScore()
if wantGlobalWiggle then
structure.WiggleSelected( iters, true, true)
else
structure.LocalWiggleSelected( iters, true, true )
end
gain = getScore( ) - lastScore
end
selection.DeselectAll( )
return true
end
function AT_SelectWorsts( )
for i=1, SegCt do
if current.GetSegmentEnergyScore(i) < 0.0 then
selection.Select(i)
end
end
end
function AT_IsSegScoreAcceptable( seg )
local ss = current.GetSegmentEnergyScore( seg )
if ss < AT_MAXIMO or ss > 600.0 then return false end
return true
end
function AT_Fix( seg )
for i = 1, SegCt do
if i ~= seg then
local dist=structure.GetDistance(seg, i)
if dist<12.0 and dist>6.0 then
local bidx = band.AddBetweenSegments(seg, i)
band.SetGoalLength(bidx, dist)
end
end
end
SimpleWiggleSelected( 1 )
DelBands()
end
function AT_IterativeWiggleSelected( minGain )
-- DO NOT CALL recentbest.Save() !!!
if minGain == nil then minGain = 0.001 end
local iters
if GetCI( ) < 1.0 then
iters = 1
else
iters = QUICKWIGGLE_ITERS
end
local lastScore = getQuickScore( )
local ctLoop = 0
local gain = minGain
while gain >= minGain and ctLoop < 6 do
structure.WiggleSelected( QUICKWIGGLE_ITERS, true, true )
gain = getQuickScore( ) - lastScore
lastScore = getQuickScore( )
ctLoop = ctLoop + 1
end
end
function AT_wiggle_out( )
SetCI( 0.6 )
SimpleWiggleSelected( 2 )
SetCI( 1.0 )
AT_IterativeWiggleSelected( )
ShakeSelected( 1 )
SetCI( 0.6 )
AT_IterativeWiggleSelected( )
SetCI( 1.0 )
AT_IterativeWiggleSelected( )
recentbest.Restore( )
end
function AT_getNear(seg, fixBand, checkScore)
if checkScore == nil or getScore() < checkScore - 1000.0 then
selection.Deselect( seg )
SetCI( 0.75 )
ShakeSelected( 1 )
SimpleWiggleSidechains( 1 )
selection.Select( seg )
SetCI( 1.0 )
end
if checkScore == nil or getScore() < checkScore - 1000.0 then
if fixBand then
AT_Fix( seg )
else
-- this might pick up a transient!
recentbest.Restore()
return getScore() > checkScore
end
end
return true
end
function AT_MiniRebuild( seg )
selection.DeselectAll()
selection.Select( seg )
--RebuildSelected(2)
RebuildSelectedGetBest( 5 )
selection.DeselectAll()
end
function AT_IsUsableAA( i )
if not SegIsUsable( seg ) then return false end
if not AT_IsSegScoreAcceptable( seg ) then return false end
if forbidTinySidechains and isGlycineOrAlanine( seg ) then return false end
return true
end
function ATSidechainTweakAction( idx, radius, wantRebuild, includeWorsts, fixBand )
if wantRebuild then
AT_MiniRebuild( idx )
end
recentbest.Save( )
local checkScore = getScore()
selection.DeselectAll( )
selection.Select( idx )
SetCI( 0.0 )
ShakeSelected( 1 )
SetCI( 1.0 )
selection.DeselectAll()
SelectSphere( idx, radius )
if includeWorsts then
AT_SelectWorsts( )
end
if AT_getNear( idx, fixBand, checkScore ) then
AT_wiggle_out( )
end
selection.DeselectAll()
return true
end
function ATSidechainTweakAroundAction( idx, radius, wantRebuild, includeWorsts, fixBand )
if wantRebuild then
AT_MiniRebuild( idx )
end
recentbest.Save( )
local g_score = {}
for n=1, SegCt do
g_score[n] = current.GetSegmentEnergyScore(n)
end
selection.DeselectAll()
selection.Select(idx)
local checkScore = getScore()
SetCI( 0 )
ShakeSelected( 1 )
SetCI( 1.0 )
SelectSphere(idx, radius)
if includeWorsts then
AT_SelectWorsts( )
end
if getScore() > checkScore - 30.0 then
-- good enough, just do a wiggle
AT_wiggle_out( )
else
-- try harder
selection.DeselectAll()
for n=1, SegCt do
if (current.GetSegmentEnergyScore(n) < g_score[n] - 1) then
selection.Select(n)
end
end
selection.Deselect(idx)
SetCI( 0.1 )
ShakeSelected( 1 )
SelectSphere(idx, radius, true)
if includeWorsts then
AT_SelectWorsts( )
end
SetCI( 1.0 )
if AT_getNear( idx, fixBand, checkScore ) then
AT_wiggle_out( )
end
end
selection.DeselectAll()
return true
end
function ATSidechainManipulateAction( idx, radius, wantRebuild )
if wantRebuild then
AT_MiniRebuild( idx )
end
recentbest.Save( )
selection.DeselectAll()
rotamers = rotamer.GetCount(idx)
save.Quicksave( QS_ShortUseTemp1 )
save.Quicksave( QS_ShortUseTemp2 )
if rotamers > 1 then
for r=1, rotamers do
save.Quickload(QS_ShortUseTemp1)
local checkScore = getScore()
rotamer.SetRotamer(idx,r)
SetCI(1.0)
if getScore() > checkScore - 30.0 then
selection.DeselectAll()
SelectSphere( idx, radius )
AT_wiggle_out( ) -- this can change the number of rotamers
SaveBest( false, QS_ShortUseTemp2 )
end
if rotamers > rotamer.GetCount(idx) then break end
end
end
selection.DeselectAll()
save.Quickload( QS_ShortUseTemp2 )
return true
end
----------------------------------------------------------------------
--
---- IDEALIZERS AND REBUILDERS
--
----------------------------------------------------------------------
----------------------------------------------------------------------
-- IDEALIZERS
----------------------------------------------------------------------
function IdealizeSelected( )
recentbest.Save()
band.DisableAll( )
structure.IdealizeSelected( )
ResetUserBands( )
EnableMyBands()
EnableAndDisableCysteineBands( )
if not checkCysteineSanity() then
recentbest.Restore()
return false
end
return true
end
-- no customers
function IdealizeRange( startSeg, endSeg )
selection.DeselectAll()
selection.SelectRange( startSeg, endSeg )
return IdealizeSelected( )
end
function GetIdealizeRange( idx )
return GetActionRange( idx, IDEALIZE_MIN_SEGLEN, IDEALIZE_MAX_SEGLEN )
end
function IdealizeRangeSimple( startSeg, endSeg, useCuts )
local idxList = { }
save.Quicksave( QS_ShortUseTemp1 )
local changeFailed = false
if startSeg > endSeg then startSeg, endSeg = endSeg, startSeg end
if useCuts then
if startSeg > MinUnlockedSeg + 1 then structure.InsertCut( startSeg - 1 ) end
if endSeg < MaxUnlockedSeg then structure.InsertCut( endSeg ) end
end
selection.DeselectAll( )
selection.SelectRange( startSeg, endSeg )
local changeSucceeded = IdealizeSelected( )
if not changeSucceeded then
save.Quickload( QS_ShortUseTemp1 )
return false
end
selection.DeselectAll( )
recentbest.Save( )
getSegsWithinRangeOfTube( idxList, startSeg, endSeg, IDEALIZE_TUBE_BIG_RADIUS )
ShakeOrMutate( 1, idxList )
for i=1, #idxList do
selection.Select( idxList[i] )
end
LongWiggleSelected( )
SimpleWiggleAll( ) -- a short wiggle of everything
recentbest.Restore( )
selection.DeselectAll( )
if useCuts then
if startSeg > MinUnlockedSeg + 1 then
if not DeleteCutAtIndex( startSeg - 1 ) then
changeFailed = true
end
end
if endSeg < MaxUnlockedSeg then
if not DeleteCutAtIndex( endSeg ) then
changeFailed = true
end
end
end
if changeFailed then
save.Quickload( QS_ShortUseTemp1 )
return false -- just give up
end
return true
end
function IdealizeRegionZlb( startSeg, endSeg, useCuts )
if useCuts == nil then useCuts = true end
local idxList = { }
changeFailed = false
if startSeg > endSeg then startSeg, endSeg = endSeg, startSeg end
if startSeg < MinUnlockedSeg then startSeg = MinUnlockedSeg end
if endSeg > MaxUnlockedSeg then endSeg = MaxUnlockedSeg end
local tries = 0
save.Quicksave( QS_ShortUseTemp1 )
local delta = 0.0
repeat
save.Quickload( QS_ShortUseTemp1 )
changeFailed = false
if IDEALIZE_ZLB_MAXTRIES > 1 and tries == IDEALIZE_ZLB_MAXTRIES - 1 then
delta = 0.0
useCuts = false -- overrule the user's request for use of cuts (should always succeed)
end
if useCuts then
if startSeg - 2 > MinUnlockedSeg then
structure.InsertCut( startSeg - 2 )
end
if endSeg + 1 < MaxUnlockedSeg then
structure.InsertCut( endSeg + 1 )
end
if startSeg - 3 >= MinUnlockedSeg then
BandBetweenSegsWithParameters( startSeg-3, startSeg, 1.0 + delta,
structure.GetDistance( startSeg-3, startSeg ) )
end
if endSeg + 3 <= MaxUnlockedSeg then
BandBetweenSegsWithParameters( endSeg, endSeg + 3, 1.0 + delta,
structure.GetDistance( endSeg, endSeg+3 ) )
end
end
selection.DeselectAll( )
getSegsWithinRangeOfTube( idxList, startSeg, endSeg, IDEALIZE_TUBE_SMALL_RADIUS )
for i=1, #idxList do selection.Select( idxList[i] ) end
changeSucceeded = IdealizeSelected( )
selection.DeselectAll( )
if changeSucceeded then
if useCuts then
-- get some wiggling happening
WiggleZlbNicely( ZLB_DEFAULT_STRENGTH + delta,
math.max( 1, startSeg-2 ),
math.min( SegCt, endSeg+2 ))
DebugPrint( "WiggleZlbNicely")
-- now put the protein back in its proper shape
if startSeg - 2 > MinUnlockedSeg then
if not DeleteCutAtIndex(startSeg - 2 ) and IDEALIZE_FORBID_UNHEALED_CUTS then
changeFailed = true
end
end
if changeFailed == false and endSeg + 1 < MaxUnlockedSeg then
if not DeleteCutAtIndex(endSeg + 1 ) and IDEALIZE_FORBID_UNHEALED_CUTS then
changeFailed = true
end
end
else -- since we didn't put in any cuts, we can try simple wiggling to see how we did
recentbest.Save( )
DebugPrint( "SimpleRegionWiggle")
SimpleRegionWiggle( startSeg, endSeg )
ShakeOrMutate( )
recentbest.Restore( )
end
end
if changeSucceeded and not changeFailed then
DelBands( )
return true
end
tries = tries + 1
delta = delta + 0.25
until tries >= IDEALIZE_ZLB_MAXTRIES
DelBands( ) -- we have failed. make sure the bands are gone and flee.
return false
end
function lowCiIdealizer( idealizeMin, idealizeMax )
if idealizeMin == nil then idealizeMin = 1 end
if idealizeMax == nil then idealizeMax = SegCt end
local old_ci = GetCI()
ExactSetCI( 0.05 )
ZLB( IDEALIZEALL_ZLB_STRENGTH )
selection.SelectRange( idealizeMin, idealizeMax )
local changeSucceeded = IdealizeSelected( )
if changeSucceeded then
LongWiggleAll( ) -- was structure.WiggleAll( 30 )
ShakeOrMutate( )
LongWiggleAll( true, true ) -- was structure.WiggleAll( 30 )
selection.DeselectAll( )
end
DelBands( )
print( "After Initial Idealizer = "..TrimNum( getScore( )))
ExactSetCI( old_ci )
return changeSucceeded
end
----------------------------------------------------------------------
-- REBUILDERS
----------------------------------------------------------------------
function RebuildSelected( iters )
recentbest.Save( )
band.DisableAll( )
structure.RebuildSelected( iters )
ResetUserBands( )
EnableMyBands( )
EnableAndDisableCysteineBands( )
if not checkCysteineSanity() then
recentbest.Restore()
return false
end
return getQuickScore( ) ~= initscore
end
function RebuildSelectedGetBest( iters )
if iters == 1 then return RebuildSelected( 1 ) end
local changeSucceeded = false
local initscore = getQuickScore( )
local newScore = initscore
local tries = 0
repeat
tries = tries + 1
local chSuc = RebuildSelected( 1 )
changeSucceeded = changeSucceeded or chSuc
newScore = getQuickScore( )
until newScore ~= initScore or tries > iters
if changeSucceeded then
-- N.B. this set of commands does the "get best of iters" attempts
recentbest.Save( )
RebuildSelected( iters - 1 )
recentbest.Restore( )
-- recentbest's restore can lose our enabled-ness!
ResetUserBands( )
EnableMyBands( )
EnableAndDisableCysteineBands( )
if not checkCysteineSanity() then
return false
end
end
return changeSucceeded
end
function GetRebuildRange( idx )
return GetActionRange( idx, REBUILD_MIN_SEGLEN, REBUILD_MAX_SEGLEN )
end
function DeepRebuildRange( idxStart, idxEnd, maxTries )
if maxTries == nil then maxTries = REBUILD_DEEP_MAXTRIES end
local wantHelix = isPossibleHelix( idxStart )
local changeSucceeded = false
local locss = {}
local changedSS = false
local startScore = getQuickScore( )
local currScore = startScore
local timeStart = os.time()
for i=idxStart, idxEnd do
locss[i] = structure.GetSecondaryStructure( i )
end
for i=idxStart, idxEnd do
if wantHelix then
-- we think there's a helix, so tell rebuild to go with it
changedSS = true
structure.SetSecondaryStructure( i, 'H' )
elseif structure.GetSecondaryStructure( i ) == 'E' then
-- sheet isn't worth telling rebuild about
changedSS = true
structure.SetSecondaryStructure( i, 'L' )
end
end
selection.DeselectAll( )
save.Quicksave( QS_ShortUseTemp1 ) -- holds our "running" pose
save.Quicksave( QS_ShortUseTemp2 ) -- holds our "best so far" result
bestRescore = -100000.0
for i=1, maxTries do
local idxListInner = { }
save.Quickload( QS_ShortUseTemp1 ) -- bring up our "running" pose
selection.SelectRange( idxStart, idxEnd )
changeSucceeded = RebuildSelected( 1 )
selection.DeselectAll( )
if changeSucceeded then
-- give the whole thing a little bit of shake-and-wiggle-time
timeStart = os.time()
WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REBUILD_TUBE_INNER_RADIUS )
rescore = getQuickScore( )
print("Try "..i..": time="..(os.time() - timeStart).." Score="..rescore)
if rescore > bestRescore then
save.Quicksave( QS_ShortUseTemp2 ) -- our best-so-far is better
bestRescore = rescore
if rescore > currScore then -- we have a real improvement!
-- cheat: use the better result as our base for future rebuilds
-- instead of original pose
save.Quicksave( QS_ShortUseTemp1 )
currScore = rescore
end
end
end
end
save.Quickload( QS_ShortUseTemp2 )
if changedSS then
for i=idxStart, idxEnd do structure.SetSecondaryStructure( i, locss[ i ] ) end
end
return changeSucceeded
end
function DeepRebuildRangeAction( idxStart, idxEnd, wantBands )
local changeSucceeded = false
local timeStart = os.time()
local didIdealize = false
local idxList = {}
if wantBands then
AddRandomXToYBands( XTOY_REBUILD_STRENGTH )
end
timeStart = os.time()
-- use a rebuilder that wiggles all the ones it sees and gives back the very best
changeSucceeded = DeepRebuildRange( idxStart, idxEnd )
if wantBands then
DelBands( )
end
if changeSucceeded then
-- used to offer idealize, but only 1-2% of tries got benefit.
-- we did a tiny bit of WSW in DeepRebuildRange, close out with a better wiggler
idxList = {}
getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, REBUILD_TUBE_OUTER_RADIUS )
DebugPrint( "WiggleShakeListWiggleAll-SWTillStable" )
WiggleShakeListWiggleAll( idxList, MUTATE_ONCE )
ShakeWiggleTillStable( nil, MUTATE_ONCE )
end
return changeSucceeded
end
function RebuildRangeFromQuaker( idxStart, idxEnd, maxTries )
local changeSucceeded = false
local initScore = getQuickScore( )
selection.DeselectAll( )
selection.SelectRange( idxStart, idxEnd )
changeSucceeded = RebuildSelectedGetBest( maxTries )
if changeSucceeded then
DebugPrint( "WiggleRangeShakeTubeWiggleAll-SWTillStable")
WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REBUILD_TUBE_OUTER_RADIUS )
ShakeWiggleTillStable( nil, MUTATE_ONCE )
end
return changeSucceeded
end
-- this one actually does a quake if it thinks it's worth doing
function QuakingRebuild( idxStart, idxEnd, maxTries )
local changeSucceeded = false
local initScore = getQuickScore( )
local tries = 0
selection.DeselectAll( )
selection.SelectRange( idxStart, idxEnd )
changeSucceeded = RebuildSelectedGetBest( maxTries )
if changeSucceeded then
DebugPrint( "WiggleRangeShakeTubeWiggleAll")
WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REBUILD_TUBE_SMALLEST_RADIUS )
ShakeOrMutate( nil, nil, MUTATE_ONCE )
LongWiggleAll( )
currScore = getScore()
if currScore < initScore and currScore > initScore - 50.0 then
-- LSQuake is the only not-too-slow quake that cares what idxStart/End are
whichIdx = math.floor( (idxStart + idxEnd) / 2 )
PerformLSQuakeAction( whichIdx )
else
DebugPrint( "ShakeWiggleTillStable" )
ShakeWiggleTillStable( nil, MUTATE_ONCE )
end
end
return changeSucceeded
end
-- does a single rebuild, try to make it good
function RebuildSimpleCore( idxStart, idxEnd, addIdealize, wantBands, wantRemix )
if idxEnd < MinUnlockedSeg or idxStart > MaxUnlockedSeg then return false end
if idxStart < MinUnlockedSeg then idxStart = MinUnlockedSeg end
if idxEnd > MaxUnlockedSeg then idxEnd = MaxUnlockedSeg end
if addIdealize == nil then addIdealize = REBUILD_ADDIDEALIZE end
if wantBands then
DebugPrint("Adding X-Y bands")
AddRandomXToYBands( XTOY_REBUILD_STRENGTH )
end
local initscore = getQuickScore( )
local idxList = { }
for i=idxStart, idxEnd do
idxList[ #idxList + 1 ] = i
end
selection.DeselectAll( )
selection.SelectRange( idxStart, idxEnd )
if wantRemix then
changeSucceeded = RemixSelectedOnce( )
else
changeSucceeded = RebuildSelected( 1 )
end
if changeSucceeded then
DebugPrint( "RS-Wiggler")
recentbest.Save( )
ShakeOrMutate( nil, idxList )
recentbest.Restore( )
if addIdealize then
local chSuc = IdealizeSelected( )
if chSuc then
recentbest.Restore( )
ShakeOrMutate( nil, idxList, MUTATE_ONCE )
recentbest.Restore( )
structure.WiggleAll( 25 )
recentbest.Restore( )
ShakeOrMutate( nil, nil, MUTATE_ONCE )
end
end
LongWiggleAll( )
recentbest.Restore( )
DelBands( )
ShakeWiggleTillStable( nil, MUTATE_ONCE )
else
DelBands( )
end
return changeSucceeded
end
function RebuildSimple( idxStart, idxEnd, addIdealize )
return RebuildSimpleCore( idxStart, idxEnd, addIdealize, false, false )
end
function RebuildSimpleXToY( idxStart, idxEnd, addIdealize )
return RebuildSimpleCore( idxStart, idxEnd, addIdealize, true, false )
end
function RemixSimple( idxStart, idxEnd, addIdealize )
return RebuildSimpleCore( idxStart, idxEnd, addIdealize, false, true )
end
function RemixSimpleXToY( idxStart, idxEnd, addIdealize )
return RebuildSimpleCore( idxStart, idxEnd, addIdealize, true, true )
end
-- Get best scorer of several rebuilds, do good wiggle/shake action
function RebuildBitspawn( idxStart, idxEnd, useLowCIRules )
selection.DeselectAll( )
selection.SelectRange( idxStart, idxEnd )
local changeSucceeded = RebuildSelectedGetBest( REBUILD_DEEP_MAXTRIES )
selection.DeselectAll( )
if changeSucceeded then
DebugPrint( "RBits-Wiggler")
if useLowCIRules then
local ciOld = GetCI( )
ExactSetCI( 0.05 )
ShakeOrMutate( )
ExactSetCI( ciOld )
else
ShakeOrMutate( nil, nil, MUTATE_NOT_SHAKE )
SimpleWiggleAll( )
ShakeOrMutate( nil, nil, MUTATE_ONCE )
end
structure.WiggleAll( 16 ) -- leave it like this.
ShakeWiggleTillStable( nil, MUTATE_ONCE )
return true
end
return changeSucceeded
end
function PerformWiskyRebuildAllAction( )
print("WiskyRebuildAll")
SelectAllMovable( )
local changeSucceeded = RebuildSelected( 1 )
if changeSucceeded then
ShakeWiggleTillStable( )
end
return changeSucceeded
end
function PerformRebuildAllWithIdealizeAction( )
print("RebuildAllWithIdealize")
SelectAllMovable( )
local changeSucceeded = RebuildSelected( 1 )
if changeSucceeded then
ShakeWiggleTillStable( )
lowCiIdealizer()
end
return changeSucceeded
end
----------------------------------------------------------------------
-- REMIX HELPER FUNCTIONS
----------------------------------------------------------------------
function GetRemixRange( idx )
return GetActionRange( idx, REMIX_MIN_SEGLEN, REMIX_MAX_SEGLEN )
end
function RemixSelectedOnce( )
local remixCt = structure.RemixSelected( QS_RemixSlot1, REMIX_MAX_SLOTS_TO_USE)
if remixCt == 0 then return false end
local scMax = -999999.9
local qsBest = QS_RemixSlot1
for i=1, remixCt do
local qs = QS_RemixSlot1 + i - 1
local curScore = getSlotScore( qs )
if curScore > scMax or scMax == -999999.9 then
scMax = curScore
qsBest = qs
end
end
save.Quickload( qsBest )
return true
end
function RemixAction( idxStart, idxEnd, wantBands )
if wantBands then
DebugPrint("Adding X-Y bands")
-- I think XToY's default strength is too strong for remix.
AddRandomXToYBands( XTOY_REMIX_STRENGTH )
end
local initScore = getScore()
local bestScore = -10000.0
local bestSlot = 0
local remixesToTry = math.min( REMIX_SLOTS_WANTED, REMIX_MAX_SLOTS_TO_USE )
local minToDoReTry = REMIX_MAX_SLOTS_TO_WIGGLE + math.floor(REMIX_MAX_SLOTS_TO_WIGGLE/2)
local actualToRetry = 2*REMIX_MAX_SLOTS_TO_WIGGLE
local slotsToDoFullWiggleCheck = REMIX_MAX_SLOTS_TO_WIGGLE
selection.SelectRange( idxStart, idxEnd )
local remixCt = structure.RemixSelected( QS_RemixSlot1, remixesToTry )
if remixCt == 0 then
print("no remixes found")
if wantBands then
DelBands()
end
return false
end
-- 1st-level Pass - go through all the returned answers, doing a simple shake
local slotList = {}
local slotIdxes = {}
local scoreList = {}
local idxList = {}
local timeStart = os.time()
for i=1, remixCt do
-- load an answer
save.Quickload( QS_RemixSlot1 + i - 1 )
if checkCysteineSanity() then
-- some pre-shaking to help decide which rebuilds are "best"
-- NOTE: adding more actions serve only to greatly increase the
-- time spent in this phase. Expanding to a tube similarly
-- makes actions too expensive.
selection.DeselectAll()
selection.SelectRange( idxStart, idxEnd )
ShakeSelected( 1, false )
-- Track what we did
save.Quicksave( QS_RemixSlot1 + i - 1 )
slotList[ #slotList + 1 ] = QS_RemixSlot1 + i - 1
scoreList[ #scoreList + 1] = getScore( )
slotIdxes[ #slotIdxes + 1] = #slotIdxes + 1
end
end
if #slotIdxes == 0 then
print("no sane remixes found")
if wantBands then
DelBands()
end
return false
end
if #slotIdxes > slotsToDoFullWiggleCheck then
print("Check of "..#slotIdxes.." answers took "..(os.time() - timeStart).." seconds")
end
sortByScoreDecr( slotIdxes, scoreList )
-- 2nd-level Pass - go through the top "actualToRetry", do very simple wiggling
timeStart = os.time()
if #slotList >= minToDoReTry then
local slotList2 = {}
local scoreList2 = {}
local slotIdxes2 = {}
for i=1, math.min( #slotList, actualToRetry) do
slotList2[ #slotList2 + 1 ] = slotList[ slotIdxes[i] ]
slotIdxes2[ #slotIdxes2 + 1] = #slotIdxes2 + 1
end
for i=1, math.min( #slotList, actualToRetry) do -- give top ones extra jiggling
local idxList = {}
save.Quickload( slotList2[ slotIdxes2[i] ] )
-- try some very simple wiggle action. this time spend money on a tube
selection.DeselectAll()
getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, REMIX_TUBE_INNER_RADIUS )
for j=1, #idxList do selection.Select(idxList[j]) end
SimpleWiggleSidechainsSelected( 1 )
SimpleLocalWiggleSelected( 1 )
scoreList2[ i ] = getScore( )
end
slotIdxes = slotIdxes2
scoreList = scoreList2
slotList = slotList2
print("Check of top "..math.min( #slotList, actualToRetry)..
" answers took "..(os.time() - timeStart).." seconds")
sortByScoreDecr( slotIdxes, scoreList )
end
-- 3rd-level Pass - collect the best few and do "real" wiggle+shake/mutate on them
local bestI = 0
for i=1, math.min( #slotList, slotsToDoFullWiggleCheck) do
selection.DeselectAll()
-- load an answer
save.Quickload( slotList[ slotIdxes[i] ] )
-- wiggle the result enough to decide which is best
local currScore = getScore()
local timeStart = os.time()
-- TODO: Decide argument: should I mutate here and spend lots of money for more accuracy,
-- or do it at the very end instead?
WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REMIX_TUBE_OUTER_RADIUS )
timeEnd = os.time()
print( "RMWiggle["..slotList[slotIdxes[i]].."] score: "..TrimNum(currScore)..
" -> "..TrimNum(getScore())..
" time:"..(timeEnd - timeStart))
-- save it so we can reload when we know which one we love best
save.Quicksave( slotList[ slotIdxes[i] ] )
-- Pick the highest scoring result
local currScore = getScore()
if currScore > bestScore then
bestScore = currScore
bestSlot = slotList[ slotIdxes[i] ]
bestI = i
end
end
-- get the best one, do a cleanup wiggle, and flee.
if bestSlot == 0 then return false end
save.Quickload( bestSlot )
-- finish up the wiggle for our winner!
ShakeWiggleTillStable( nil, MUTATE_ONCE )
return true
end
----------------------------------------------------------------------
-- FUNCTIONS TO PERFORM SOME SPECIFIC ACTION
----------------------------------------------------------------------
function PerformRemixAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local startIdx, endIdx = GetRemixRange( idx )
print( "Remix for "..startIdx..","..endIdx )
return RemixAction( startIdx, endIdx, false )
end
function PerformRemixXToYAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local startIdx, endIdx = GetRemixRange( idx )
print( "RemixXToY for "..startIdx..","..endIdx )
return RemixAction( startIdx, endIdx, true )
end
function PerformRemixSimpleAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "RemixSimple for " ..idxStart.. "," ..idxEnd )
return RemixSimple( idxStart, idxEnd, REMIX_ADDIDEALIZE )
end
function PerformRemixSimpleXToYAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "RemixSimpleXToY for " ..idxStart.. "," ..idxEnd )
return RemixSimpleXToY( idxStart, idxEnd, REMIX_ADDIDEALIZE )
end
function PerformDeepRebuildAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "DeepRebuildRange for "..idxStart..","..idxEnd)
return DeepRebuildRangeAction( idxStart, idxEnd, false )
end
function PerformDeepRebuildXToYAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "DeepRebuildRangeXToY for "..idxStart..","..idxEnd)
return DeepRebuildRangeAction( idxStart, idxEnd, true )
end
function PerformDeepRebuildSSAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
-- This uses a range (mostly) matching some Secondary Structure:
local idxStart, idxEnd = GetRegionForOperation( idx )
print( "DeepRebuildSS for " ..idxStart.. "," ..idxEnd )
return DeepRebuildRangeAction( idxStart, idxEnd, false )
end
function PerformDeepRebuildSSXToYAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
-- This uses a range (mostly) matching some Secondary Structure:
local idxStart, idxEnd = GetRegionForOperation( idx )
print( "DeepRebuildSSXToY for " ..idxStart.. "," ..idxEnd )
return DeepRebuildRangeAction( idxStart, idxEnd, true )
end
function PerformRebuildSimplePointAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
print( "RebuildSimplePoint for "..idx )
return RebuildSimple( idx, idx, REBUILD_ADDIDEALIZE )
end
function PerformRebuildSimpleAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "RebuildSimple for " ..idxStart.. "," ..idxEnd )
return RebuildSimple( idxStart, idxEnd, REBUILD_ADDIDEALIZE )
end
function PerformRebuildSimpleXToYAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "RebuildSimpleXToY for " ..idxStart.. "," ..idxEnd )
return RebuildSimpleXToY( idxStart, idxEnd, REBUILD_ADDIDEALIZE )
end
function PerformRebuildFromQuakerAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "RebuildFromQuaker for " ..idxStart.. "," ..idxEnd )
return RebuildRangeFromQuaker( idxStart, idxEnd, REBUILD_DEEP_MAXTRIES )
end
function PerformRebuildBitspawnAction( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "RebuildBitspawn for " ..idxStart.. "," ..idxEnd )
return RebuildBitspawn( idxStart, idxEnd, false )
end
function PerformRebuildBitspawnLowCI( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "RebuildBitspawnLowCI for " ..idxStart.. "," ..idxEnd )
return RebuildBitspawn( idxStart, idxEnd, true )
end
function PerformQuakingRebuild( idx )
if idx == nil or idx == 0 then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "QuakingRebuild for " ..idxStart.. "," ..idxEnd )
return QuakingRebuild( idxStart, idxEnd, REBUILD_DEEP_MAXTRIES )
end
function PerformIdealizeZlbAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetIdealizeRange( idx )
print( "IdealizeZlb for ".. idxStart..","..idxEnd )
local changeSucceeded = IdealizeRegionZlb( idxStart, idxEnd, IDEALIZE_USE_CUTS )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_IDEALIZE )
return changeSucceeded
end
function PerformIdealizeRegionAction( idx )
local idxList = { }
if idx == nil then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetIdealizeRange( idx )
print( "IdealizeRegion for ".. idxStart..","..idxEnd )
-- idealize everything in smaller vicinity of idxStart .. idxEnd
-- TODO: try IDEALIZE_TUBE_BIG_RADIUS, see how things change
getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, IDEALIZE_TUBE_SMALL_RADIUS )
selection.DeselectAll( )
for i=1, #idxList do selection.Select( idxList[i] ) end
local changeSucceeded = IdealizeSelected( )
selection.DeselectAll( )
WiggleShakeListWiggleAll( idxList )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_IDEALIZE )
return changeSucceeded
end
function PerformIdealizeRegionXToYAction( idx )
local idxList = { }
if idx == nil then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetIdealizeRange( idx )
print( "IdealizeXToY for ".. idxStart..","..idxEnd )
DebugPrint("Adding X-Y bands")
AddRandomXToYBands( XTOY_IDEALIZE_STRENGTH )
-- idealize everything in larger vicinity of idxStart .. idxEnd
-- TODO: try IDEALIZE_TUBE_SMALL_RADIUS, see how things change
getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, IDEALIZE_TUBE_BIG_RADIUS )
selection.DeselectAll( )
for i=1, #idxList do selection.Select( idxList[i] ) end
local changeSucceeded = IdealizeSelected( )
selection.DeselectAll( )
WiggleShakeListWiggleAll( idxList )
DelBands( )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_IDEALIZE )
return changeSucceeded
end
function PerformIdealizePointAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
print( "IdealizePoint for ".. idx )
local changeSucceeded = IdealizeRangeSimple( idx, idx, IDEALIZE_USE_CUTS )
DebugPrint( "ShakeWiggleTillStable" )
ShakeWiggleTillStable( nil, MUTATE_ONCE )
return changeSucceeded
end
function PerformSpotMutatorAction( idx )
if idx == nil then idx = randomMovableSeg( ) end -- better would be random mutable seg
print( "SpotMutator for " .. idx )
local changeSucceeded = false
if randomBool( MUTATESIMILAR_PROB ) then
if randomBool() then
changeSucceeded = MutateToVerySimilar( idx)
else
changeSucceeded = MutateToSimilar( idx )
end
else
changeSucceeded = MutateToAny( idx )
end
if changeSucceeded then
DebugPrint( "WiggleShakeCleanWiggleOut" )
WiggleShakeCleanWiggleOut( )
end
return changeSucceeded
end
function PerformSingleBandInSpaceAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = random( BAND_STRENGTH_DEFAULT / 2, BAND_STRENGTH_DEFAULT, true )
local atom = PickAtomNumberForBand( idx )
local goalLength = random( BIS_MIN_GOALLENGTH, BIS_MAX_GOALLENGTH )
print( "BIS for " .. idx.." with strength "..TrimNum( strength ) )
local changeSucceeded = PutBandInSpace( idx, BIS_LENGTH, strength, goalLength, atom )
if changeSucceeded then
DebugPrint( "WiggleShakeCleanWiggleOut" )
WiggleShakeCleanWiggleOut( )
end
return changeSucceeded
end
function PerformBandToRandomSegAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_DEFAULT
local atom = PickAtomNumberForBand( idx )
print( "BandBetween for " .. idx.." with strength "..TrimNum( strength ) )
local changeSucceeded = PutBandToRandomSeg( idx, strength, atom )
if changeSucceeded then
DebugPrint( "WiggleShakeCleanWiggleOut" )
WiggleShakeCleanWiggleOut( )
end
return changeSucceeded
end
function PerformPushPullAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local segList = {}
local wantPushNotPull = randomBool( )
local ctBands = 5
local strength = BAND_STRENGTH_DEFAULT
print( "PushPull for " .. idx )
getSegsOutsideSphere( segList, idx, 8 )
if #segList == 0 then
-- nothing we can do!
print(" PushPull failed due to lack of distant segs")
return false
end
local centerSeg = segList[ random( #segList) ]
local changeSucceeded = PutPushPullBands( idx, ctBands, centerSeg, strength, wantPushNotPull )
if changeSucceeded then
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH )
end
return changeSucceeded
end
function PerformVoidCrusherAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_DEFAULT
print( "VoidCrusher for " .. idx )
changeSucceeded = PutVoidCrusherBands( idx, strength )
if changeSucceeded then
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH )
end
return changeSucceeded
end
function PerformGlycineHingeAction( idx )
if idx == nil then idx = randomAASeg( ) end
if idx == 0 then return false end
local strength = random( 0.25, BAND_STRENGTH_DEFAULT, true )
print( "GlycineHinge for "..idx)
local startSeg = math.max( 1, idx - 4 - random( 0, 2 ))
local endSeg = math.min( SegCt, idx + 4 + random( 0, 2 ))
local changeSucceeded = PutGlycineHingeBands( idx, strength )
if changeSucceeded then
beginSeg = math.max( 1, startSeg - 3)
finalSeg = math.min( SegCt, endSeg + 3)
SetCI( CI_REGIONMOD )
SimpleRegionWiggle( beginSeg, finalSeg, false, 2 + random( 4 ))
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformGeneralHingeAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local bisLen = BIS_LENGTH
local startSeg, endSeg = GetRegionForOperation( idx )
if endSeg - startSeg <= 1 then return false end -- something's very wrong
if startSeg < idx - 2 then startSeg = idx - random( 0, 2 ) end
if endSeg > idx + 2 then endSeg = idx + random( 0, 2 ) end
print( "GeneralHinge for "..startSeg..","..endSeg)
local changeSucceeded = PutGeneralHingeBands( startSeg, endSeg, strength )
if changeSucceeded then
beginSeg = math.max( 1, startSeg - 3)
finalSeg = math.min( SegCt, endSeg + 3)
SetCI( CI_REGIONMOD )
SimpleRegionWiggle( beginSeg, finalSeg, false, 2 + random( 4 ))
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformPusherAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local bisLen = BIS_LENGTH_LONG
local goForward = randomBool()
local doublePush = randomBool()
local startSeg, endSeg = GetRegionForOperation( idx )
print( "Pusher for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
local changeSucceeded = PutPusherBands( startSeg, endSeg, bisLen, strength, goForward )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
end
DelBands( )
if doublePush then
changeSucceeded = PutPusherBands( startSeg, endSeg, bisLen, strength, goForward )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle-2" )
SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) )
end
end
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS )
return changeSucceeded
end
function PerformMoverAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local bisLen = BIS_LENGTH_LONG
local doubleMove = randomBool()
local startSeg, endSeg = GetRegionForOperation( idx )
print( "Mover for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
local changeSucceeded = PutMoverBands( startSeg, endSeg, bisLen, strength )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
end
DelBands( )
if doubleMove then
changeSucceeded = PutMoverBands( startSeg, endSeg, bisLen, strength )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle-2" )
SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) )
end
end
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS )
return changeSucceeded
end
function PerformFlexerAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local bisLen = BIS_LENGTH
local doubleFlex = randomBool()
local startSeg, endSeg = GetRegionForOperation( idx )
print( "Flexer for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
local changeSucceeded = PutFlexerBands( startSeg, endSeg, bisLen, strength )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
end
DelBands( )
if doubleFlex then
changeSucceeded = PutFlexerBands( startSeg, endSeg, bisLen, strength )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle-2" )
SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) )
end
end
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS )
return changeSucceeded
end
function PerformSheetAlignerAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local sheetIdxFirst = GetIndexOfSheet( idx )
local nbrSheets = {}
local changeSucceeded = false
local gotTwoSheet = false
local gotStraySheet = false
local startSeg, endSeg = GetRegionForOperation( idx )
print( "SheetAligner for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
nbrSheets = FindNeighborSheets( idx )
if #nbrSheets > 0 then
if #nbrSheets ==1 or #nbrSheets > 2 then
-- just pick one if there's only one or if it's confusing
sheetIdxSecond = nbrSheets[random(1, #nbrSheets)]
changeSucceeded = BandAdjacentSheets( sheetIdxFirst, sheetIdxSecond, 0 )
else
-- if exactly 2 neighbors, try to make them both play nice
changeSucceeded = BandAdjacentSheets( sheetIdxFirst, nbrSheets[1], 0 )
local chSuc = BandAdjacentSheets( sheetIdxFirst, nbrSheets[2], 0 )
changeSucceeded = changeSucceeded or chSuc
gotTwoSheet = true
end
else
changeSucceeded = BandStraySheetToNearestSheet( sheetIdxFirst )
gotStraySheet = true
end
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleLocalWiggleAll" )
SimpleLocalWiggleAll( 2 ) -- fancier games did less well.
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformSheetShifterAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local sheetIdxFirst = GetIndexOfSheet( idx )
local startSeg, endSeg = GetRegionForOperation( idx )
print( "SheetShifter for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
nbrSheets = FindNeighborSheets( idx )
if #nbrSheets > 0 then
local r = random( #nbrSheets )
sheetIdxSecond = nbrSheets[ r ]
local delta
r = random( 2 )
if r == 1 then delta = 1 else delta = -1 end
changeSucceeded = BandAdjacentSheets( sheetIdxFirst, sheetIdxSecond, delta )
else
-- no point shifting if there isn't a neighbor!
changeSucceeded = false
end
if changeSucceeded then
local startWiggleSeg, endWiggleSeg
SetCI( CI_REGIONMOD )
SimpleLocalWiggleAll( 2 )
--DebugPrint( "WiggleRange" )
--startWiggleSeg, endWiggleSeg = GetExtendedRegionForWiggle( startSeg, endSeg )
--WiggleRange( startWiggleSeg, endWiggleSeg, false, false )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
else
ResetFrozenness( )
DelBands( )
selection.DeselectAll()
end
return changeSucceeded
end
function PerformSheetFlipperAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local sheetIdxFirst = GetIndexOfSheet( idx )
local startSeg, endSeg = GetRegionForOperation( idx )
print( "SheetFlipper for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
nbrSheets = FindNeighborSheets( idx )
if #nbrSheets > 0 then
DebugPrint("There are "..(#nbrSheets).." neighboring sheets")
sheetIdxSecond = nbrSheets[random(1, #nbrSheets)]
-- give it some help with the rotation part!
ZLB( 8.0, startSeg, endSeg, true )
selection.DeselectAll()
selection.SelectRange( startSeg, endSeg )
freeze.FreezeSelected( true, false )
changeSucceeded = PutFlipSheetBands( startSeg, endSeg, BIS_LENGTH, BAND_STRENGTH_REGION )
if changeSucceeded then
SetCI( 0 )
DebugPrint( "SimpleRegionWiggle" )
WiggleRange( startSeg, endSeg, false, false )
DelBands( )
ZLB( 8.0, startSeg, endSeg, true )
changeSucceeded = PutFlipSheetBands( startSeg, endSeg, BIS_LENGTH, BAND_STRENGTH_REGION )
WiggleRange( startSeg, endSeg, false, false )
end
ResetFrozenness( )
DelBands( )
changeSucceeded = BandAdjacentSheets( sheetIdxFirst, sheetIdxSecond, 1 )
else
-- no point flipping if there isn't a neighbor!
changeSucceeded = false
end
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleLocalWiggleAll" )
SimpleLocalWiggleAll( 2 )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
end
ResetFrozenness( )
DelBands( )
selection.DeselectAll()
return changeSucceeded
end
function PerformSheetSewerAction( )
-- original: always 8.0. More recent: 4-12
local maxSheetDistance = random( 4.0, 10.0, true )
local strength = BAND_STRENGTH_DEFAULT
local startScore = getQuickScore()
print( "SheetSewer")
local changeSucceeded = PutSheetSewerBandsAllOver( maxSheetDistance, strength )
if changeSucceeded then
SetCI( CI_REGIONMOD )
SimpleLocalWiggleAll( 2 )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformSheetStraightenerAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = 3.0
local startSeg, endSeg = GetRegionForOperation( idx )
print( "SheetStraightener for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
local changeSucceeded = PutSheetStraightenerBand( startSeg, endSeg, strength )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformHelixUniformAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local startSeg, endSeg = GetRegionForOperation( idx )
print( "HelixUniform for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
local regionLength = endSeg - startSeg + 1
local hShift = 4
if randomBool( 0.25 ) then
hShift = math.min( regionLength - 3, random(5,7))
end
if startSeg > idx - 2 then startSeg = math.max( 1, idx - random( 2, 4 )) end
if endSeg < idx + 2 then endSeg = math.min( SegCt, idx + random( 2, 4 )) end
changeSucceeded = PutHelixUniformDistanceBands( startSeg, endSeg, hShift, strength )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformHelixCompressorAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local hComp = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND )
local startSeg, endSeg = GetRegionForOperation( idx )
print( "HelixCompressor for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
local regionLength = endSeg - startSeg + 1
local hShift = 4
if randomBool( 0.25 ) then
hShift = math.min(regionLength - 2, randomDice(4, 1, 2)) -- a number 4 - 8, preferring 6ish
end
local changeSucceeded = PutHelixCompressorBands( startSeg, endSeg, hShift, strength, hComp )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformHelixFixerAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local do4 = randomBool( )
local startSeg, endSeg = GetRegionForOperation( idx )
print( "HelixFixer for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
local changeSucceeded = PutHelixFixerBands( startSeg, endSeg, strength, do4 )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
end
return changeSucceeded
end
function PerformHelixRotatorAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local strength = BAND_STRENGTH_REGION
local bisLen = BIS_LENGTH
local goClockwise = randomBool()
local doubleRotate = randomBool()
local startSeg, endSeg = GetRegionForOperation( idx )
print( "HelixRotator for "..startSeg..","..endSeg)
if endSeg - startSeg <= 1 then return false end -- something's very wrong
-- Put the bands, use wiggle to do a rotation
local changeSucceeded = PutHelixRotatorBands( startSeg, endSeg, bisLen, strength, goClockwise )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) )
end
DelBands( )
if doubleRotate then
changeSucceeded = PutHelixRotatorBands( startSeg, endSeg, bisLen, strength, goClockwise )
if changeSucceeded then
SetCI( CI_REGIONMOD )
DebugPrint( "SimpleRegionWiggle-2" )
SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) )
end
end
DebugPrint( "CleanQStabWiggleOut" )
CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS )
return changeSucceeded
end
function PerformMultiBisAction( )
local ctBandsToMake = random(3, 7)
local bandCt = 0
local cutIdx = 0
local changeSucceeded = false
local startScore = getQuickScore()
print( "MultiBis ctbands="..ctBandsToMake )
if randomBool() and not PRESERVE_USER_CUTS then
recentbest.Save( )
cutIdx = randomMovableSeg( )
structure.InsertCut( cutIdx )
end
while bandCt < ctBandsToMake do
local strength = random( BIS_MIN_STRENGTH, BIS_MAX_STRENGTH, true )
local idx = randomMovableSeg( )
local atom = PickAtomNumberForBand( idx, true )
local maxRho = BIS_LENGTH
local goalLength = random( BIS_MIN_GOALLENGTH, BIS_MAX_GOALLENGTH )
if PutBandInSpace( idx, maxRho, strength, goalLength, atom ) then
changeSucceeded = true
bandCt = bandCt + 1
end
end
if changeSucceeded then
DebugPrint( "WiggleBackboneThenWiggleOut" )
WiggleBackboneThenWiggleOut( cutIdx, PROB_QSTAB_EXTRA_MULTIBAND )
end
return changeSucceeded
end
function PerformMultiSegBandAction( )
local ctBandsToMake = random(3, 7)
local bandCt = 0
local cutIdx = 0
local changeSucceeded = false
local startScore = getQuickScore()
print( "MultiSegBand ctbands="..ctBandsToMake )
if randomBool() and not PRESERVE_USER_CUTS then
recentbest.Save( )
cutIdx = randomMovableSeg( )
structure.InsertCut( cutIdx )
end
while bandCt < ctBandsToMake do
local strength = random( BIS_MIN_STRENGTH, BIS_MAX_STRENGTH, true )
local idx = randomMovableSeg( )
local atom = PickAtomNumberForBand( idx, true )
if PutBandToRandomSeg( idx, strength, atom, true ) then
bandCt = bandCt + 1
changeSucceeded = true
end
end
if changeSucceeded then
DebugPrint( "WiggleBackboneThenWiggleOut" )
WiggleBackboneThenWiggleOut( cutIdx, PROB_QSTAB_EXTRA_MULTIBAND )
end
return changeSucceeded
end
function PerformMultiBanderAction( )
local ctBandsToMake = random(3, 7)
local bandCt = 0
local cutIdx = 0
local bandType = random( 1, 4 ) -- 1=all-bis, 2=all-segband, else mixed.
local changeSucceeded = false
local startScore = getQuickScore()
print( "MultiBander ctbands="..ctBandsToMake )
if randomBool() and not PRESERVE_USER_CUTS then
recentbest.Save( )
cutIdx = randomMovableSeg( )
structure.InsertCut( cutIdx )
end
while bandCt < ctBandsToMake do
local strength = random( BIS_MIN_STRENGTH, BIS_MAX_STRENGTH, true )
local idx = randomMovableSeg( )
local atom = PickAtomNumberForBand( idx, true )
local which = random( 2 )
if which == 1 then
local maxRho = BIS_LENGTH
local goalLength = random( BIS_MIN_GOALLENGTH, BIS_MAX_GOALLENGTH )
if PutBandInSpace( idx, maxRho, strength, goalLength, atom ) then
changeSucceeded = true
bandCt = bandCt + 1
end
else
if PutBandToRandomSeg( idx, strength, atom, true ) then
changeSucceeded = true
bandCt = bandCt + 1
end
end
end
if changeSucceeded then
DebugPrint( "WiggleBackboneThenWiggleOut" )
WiggleBackboneThenWiggleOut( cutIdx, PROB_QSTAB_EXTRA_MULTIBAND )
end
return changeSucceeded
end
function PerformCentralBanderAction( )
local strength = BAND_STRENGTH_DEFAULT
local maxCenters = randomDice( 2, 1, 3)
local changeSucceeded = false
local coreSegs = {}
getCentralHydrophobics( coreSegs, maxCenters)
local compression = randomDice( 2, BAND_MAXCOMPRESS/2, BAND_MAXEXPAND/2 )
local skipCt = random(4, 10)
local startOffset = random(1, skipCt)
print( "CentralBander with centers="..maxCenters )
changeSucceeded = PutCoreCompressBands( coreSegs, skipCt, startOffset, strength,
compression, randomBool( ), randomBool( ) )
if changeSucceeded then
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( )
end
return changeSucceeded
end
-- THIS one is the normal action: puts bands, wiggles, deletes bands, then wiggles out
function PerformEveryXToEveryYBandAction( )
local compr = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND, true )
local xInterval = random( math.floor( SegCt / 9), math.floor( SegCt / 5 ))
local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 ))
local xInit = random( xInterval-1 )
local yInit = random( yInterval-1 )
local strength = random( 0.01, BAND_STRENGTH_DEFAULT, true )
local startScore = getQuickScore()
print( "BandEveryXToY for X,Y=" ..xInterval.. "," ..yInterval..
" starting " ..xInit.. "," ..yInit )
local changeSucceeded = PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, compr )
if changeSucceeded then
DebugPrint( "BandedWiggleUntilEnoughChange" )
BandedWiggleUntilEnoughChange( BANDEDWIGGLE_TARGET, CI_COREPULLING )
end
DelBands( )
ShakeWiggleTillStable( startScore )
return changeSucceeded
end
-- THIS ONE IS SPECIAL: it is called whenever we want to pre-expand our protein
function PerformEveryXToEveryYExpansion( )
local compr = random( BAND_MINEXPAND, BAND_MAXEXPAND, true )
local xInterval = random( math.floor( SegCt / 9), math.floor( SegCt / 5 ))
local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 ))
local xInit = random( xInterval-1 )
local yInit = random( yInterval-1 )
local strength = random( 0.5, 1.50, true ) -- FIND OUT: is always strong good?
print("XToYExpander: " ..xInterval.. "x" ..yInterval..
" expand="..TrimNum(compr)..
" strength="..TrimNum(strength))
local initScore = getScore()
local changeSucceeded = PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, compr )
if changeSucceeded then
SimpleWiggleShake( )
end
DelBands( )
local endScore = getScore()
DebugPrint("Expander Score drop = "..TrimNum(endScore-initScore))
return changeSucceeded
end
function PerformInhaleAndExhaleAction( ctBreaths )
local fightingCementing = FIGHT_CEMENTING and PossibleCementingState and WorthTryingCementBreaker
if ctBreaths == nil then ctBreaths = 1 end
print("InhaleAndExhale for "..ctBreaths.." breaths")
local bestScore = getScore()
local foundImprovement = false
for i=1,ctBreaths do
local compr
local xInterval = random( math.floor( SegCt / 9 ), math.floor( SegCt / 5 ))
local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 ))
local xInit = random( xInterval-1 )
local yInit = random( yInterval-1 )
local strength = random( BAND_STRENGTH_DEFAULT - 0.25, BAND_STRENGTH_DEFAULT + 0.25 )
local wantCompress = (i==1 and fightingCementing) or randomBool()
if wantCompress then
compr = random( BAND_MAXGENTLECOMPRESS, BAND_MINCOMPRESS, true )
print( "Breathe out "..TrimNum(compr).." then in..." )
else
compr = random( BAND_MINEXPAND, BAND_MAXGENTLEEXPAND, true )
print( "Breathe in "..TrimNum(compr).." then out..." )
end
local changeSucceeded = PutBandsEveryXToEveryY(
xInterval, xInit, yInterval, yInit, strength, compr )
if changeSucceeded then
SimpleLocalWiggleAll( )
ShakeOrMutate( )
CleanShakeWiggleOut( MUTATE_ONCE )
local currScore = getScore()
if currScore > bestScore then
save.Quicksave( QS_ShortUseTemp1 )
bestScore = currScore
foundImprovement = true
end
end
end
if foundImprovement then
save.Quickload( QS_ShortUseTemp1 )
end
return true
end
function PerformInAndOutAction( ctBreaths )
local fightingCementing = FIGHT_CEMENTING and PossibleCementingState and WorthTryingCementBreaker
if ctBreaths == nil then
if fightingCementing then ctBreaths = 5 else ctBreaths = 3 end
end
print("InAndOut for "..ctBreaths.." breaths")
local bestScore = getScore()
local changeSucceeded = false
for i=1,ctBreaths do
local compr
local xInterval = random( math.floor( SegCt / 9 ), math.floor( SegCt / 5 ))
local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 ))
local xInit = random( xInterval-1 )
local yInit = random( yInterval-1 )
local strength = random( BAND_STRENGTH_DEFAULT - 0.25, BAND_STRENGTH_DEFAULT + 0.25 )
if fightingCementing and i == 1 then
-- we already did an expander. so start with a compression
compr = random( BAND_MAXCOMPRESS, BAND_MINCOMPRESS, true )
else
compr = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND, true )
end
if compr < 1.0 then
print( "Breathe out "..compr.." then in..." )
else
print( "Breathe in "..compr.." then out..." )
end
local chSuc = PutBandsEveryXToEveryY(
xInterval, xInit, yInterval, yInit, strength, compr )
changeSucceeded = changeSucceeded or chSuc
if chSuc then
SimpleLocalWiggleAll( )
ShakeOrMutate( )
DelBands( )
xInterval = random( math.floor( SegCt / 9 ), math.floor( SegCt / 5 ))
yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 ))
xInit = random( xInterval-1 )
yInit = random( yInterval-1 )
strength = random( BAND_STRENGTH_DEFAULT - 0.25, BAND_STRENGTH_DEFAULT + 0.25 )
compr = 1 / compr
chSuc = PutBandsEveryXToEveryY(
xInterval, xInit, yInterval, yInit, strength, compr )
changeSucceeded = changeSucceeded or chSuc
if chSuc then
SimpleLocalWiggleAll( )
ShakeOrMutate( )
DelBands( )
end
end
end
LongWiggleAll( )
CleanShakeWiggleOut( MUTATE_ONCE )
return changeSucceeded
end
function PerformGentleCompAction( )
local minLength = random( 9.0, 16.0, true ) -- 10 and 14 seen in scripts
local maxLength = random( 18.0, 32.0, true ) -- 20 and 30 seen in scripts; tempting to do ~2*minLength
local minSeparation = random( 4, 12 ) -- 5 and 10 seen in scripts
local compression = random( BAND_MAXCOMPRESS, BAND_MINCOMPRESS, true ) -- 0.70 seen in scripts
local bandsWanted = randomDice( 3, 2, 5 ) -- usually tunable; 7-9 for standalone is typical; 3-5 when added
local strength = random( 0.50, 1.50) * BAND_STRENGTH_DEFAULT
print( "GentleComp for " ..bandsWanted.. " bands" )
local changeSucceeded = PutGentleCompBands(
bandsWanted, minLength, maxLength,
minSeparation, strength, compression )
if changeSucceeded then
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE )
end
return changeSucceeded
end
function PerformGentleCompLowCIAction( )
local minLength = random( 9.0, 16.0, true ) -- 10 and 14 seen in scripts
local maxLength = random( 18.0, 32.0, true ) -- 20 and 30 seen in scripts; tempting to do ~2*minLength
local minSeparation = 15
local compression = 1.0
if randomBool() then
compression = random( BAND_MAXCOMPRESS, BAND_MINCOMPRESS, true )
else
compression = random( 1.10, BAND_MAXEXPAND, true )
end
local bandsWanted = 3
local strength = BAND_STRENGTH_DEFAULT
print( "GentleCompLowCI for " ..bandsWanted.. " bands" )
local changeSucceeded = PutGentleCompBands(
bandsWanted, minLength, maxLength,
minSeparation, strength, compression )
if changeSucceeded then
if USE_LOWCI_WIGGLES then
DebugPrint( "ShakeWiggleCleanShakeWiggle" )
ShakeWiggleCleanShakeWiggle( )
else
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE )
end
end
return changeSucceeded
end
function PerformLSQuakeAction( idx )
-- ok for idx to be not movable, but silly to put it in locked region
if idx == nil then idx = random( MinUnlockedSeg, MaxUnlockedSeg) end
local wantFreeze = randomBool( )
local ctBands = randomDice( 2, 2, 4 ) -- was 6
local strength = BAND_STRENGTH_DEFAULT
local compression = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND ) -- was MINCOMPRESS
local changeSucceeded = false
ResetFrozenness( )
local startIdx, endIdx = GetRegionForOperation( idx )
print( "LSQuake over range "..startIdx..", "..endIdx )
for i=startIdx, endIdx do
local changeSuc = PutManyBandsToSeg( i, ctBands, strength, compression, true)
changeSucceeded = changeSucceeded or changeSuc
end
if changeSucceeded then
if wantFreeze then
selection.DeselectAll( )
selection.SelectRange( startIdx, endIdx )
ChangedFrozenness = true
freeze.FreezeSelected( true, true )
selection.DeselectAll( )
end
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE )
end
return changeSucceeded
end
function PerformSimpleQuakeAction( )
print( "SimpleQuake" )
local changeSucceeded = false
for i=1,2 do
local ctBands = random( 1, 19 )
local bloat = randomBool( )
for j=1, ctBands do
local strength = BAND_STRENGTH_DEFAULT
local seg1 = randomMovableSeg( )
local seg2 = seg1
local tryCt = 0
while math.abs( seg2 - seg1 ) < 3 do
seg2 = randomMovableSeg( )
tryCt = tryCt + 1
if tryCt > 20 then
DelBands()
return false
end
end
local leng = structure.GetDistance( seg1, seg2 )
if bloat then
leng = leng+4
else
local perc=random(50,80)
leng = (perc*leng) / 100.0
end
local chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, leng )
changeSucceeded = changeSucceeded or chSuc
end
if changeSucceeded then
SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE )
end
end
return changeSucceeded
end
-- just like SimpleQuake, but 4 runs and add up to 10 Bis's each time. Too pricy
function PerformBisQuakeAction( )
print( "BisQuake" )
local changeSucceeded = false
for i=1,4 do
local ctBands = random( 1, 19 )
local bloat = randomBool( )
for j=1, ctBands do
local strength = BAND_STRENGTH_DEFAULT
local seg1 = randomMovableSeg( )
local seg2 = seg1
local tryCt = 0
while math.abs( seg2 - seg1 ) < 3 do
seg2 = randomMovableSeg( )
tryCt = tryCt + 1
if tryCt > 20 then
DelBands()
return false
end
end
local leng = structure.GetDistance( seg1, seg2 )
if bloat then
leng = leng+4
else
local perc=random(50,80)
leng = (perc*leng) / 100
end
chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, leng )
changeSucceeded = changeSucceeded or chSuc
end
local ctBisBands = random( 1, 10 )
for j=1, ctBisBands do
local idx = randomMovableSeg( )
PutBandInSpace(idx, 10.0, strength )
end
if changeSucceeded then
SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE )
end
end
return changeSucceeded
end
-- too pricy to use in normal sequences
function PerformLocalQuakeAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
print( "LocalQuake at ".. idx )
local ctBands = randomDice( 2, 2, 4 ) -- 2 dice each 2-4; was just 6
local compression = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND )
local strength = BAND_STRENGTH_DEFAULT
save.Quicksave( QS_ShortUseTemp1 )
local bestScore = getQuickScore( )
local changeSucceeded = false
local changeSuc = false
local lqIdx = idx
for i=1, 10 do
save.Quickload( QS_ShortUseTemp1 )
local currScore = getQuickScore( )
DelBands( )
changeSuc = PutManyBandsToSeg( lqIdx, ctBands, strength, compression, true )
if changeSuc then
local idx2 = math.min( SegCt, lqIdx + 3 )
local changeSuc2 = PutManyBandsToSeg( idx2, ctBands, strength, compression, true )
changeSuc = changeSuc or changeSuc2
end
if changeSuc then
if USE_LOWCI_WIGGLES then
ShakeWiggleCleanShakeWiggle( )
else
SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE )
end
newScore = getQuickScore( )
if newScore > currScore then save.Quicksave( QS_ShortUseTemp1 ) end
changeSucceeded = true -- we only have to succeed once to count as a success
end
lqIdx = SegCt - 2
while lqIdx > SegCt - 3 do
lqIdx = randomSeg( )
end
end
save.Quickload( QS_ShortUseTemp1 )
return changeSucceeded
end
function PerformTailWhipAction( idx )
if idx == nil then fromStart = randomBool( ) end
if idx < SegCt / 2 then fromStart = true else fromStart = false end
local length = 0
local r = randomBool()
if r then
if fromStart then idx = 1 else idx = SegCt end
local st,ed = GetRegionForOperation( idx )
length = ed - st + 1
end
if length < 5 then
length = random( 5,15 )
end
if fromStart then
str = "start"
else
str = "end"
end
print( "TailWhip at " .. str .. " length="..length )
selection.DeselectAll( )
local s = 1
local e = length
if fromStart then
changeSucceeded = PutTailDetacherBands( true, length )
else
s = SegCt - length + 1
e = SegCt
changeSucceeded = PutTailDetacherBands( false, length )
end
selection.SelectRange( s, e )
if not changeSucceeded then return false end
DebugPrint( "SimpleRegionWiggle" )
SimpleRegionWiggle( s, e, false, random(4) ) -- pull the tail away from the main body
DelBands( )
selection.DeselectAll( )
if fromStart then
changeSucceeded = PutTailAttacherBands( true, length )
else
changeSucceeded = PutTailAttacherBands( false, length )
end
selection.SelectRange( s, e )
if not changeSucceeded then return false end
DebugPrint( "SimpleRegionWiggle - 2" )
SimpleRegionWiggle( s, e, false, random(4) ) -- bring the tail back to the main body
selection.DeselectAll( )
DelBands( )
-- do our own "after" wiggle
recentbest.Save( )
ShakeOrMutate( )
DebugPrint( "LongWiggleAll" )
LongWiggleAll( )
recentbest.Restore( )
return true
end
-- somewhat pricy, but worthwhile
function PerformTailGrabAction()
print("TailGrab")
local strength = BAND_STRENGTH_DEFAULT
local first = MinUnlockedSeg
local last = MaxUnlockedSeg
local middle = math.floor(SegCt/2)
local compr=random(0.50,0.80)
local leng= compr * structure.GetDistance( first, last )
local changeSucceeded = BandBetweenSegsWithParameters( first, last, strength, leng )
if not changeSucceeded then return false end
SetCI(CI_COREPULLING)
SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH )
DelBands()
LongWiggleAll()
local bloat = randomBool()
leng=structure.GetDistance( first, middle )
if bloat then
leng = leng + 4.0
else
local compr=random(0.50,0.80)
leng = compr*leng
end
local chSuc1 = BandBetweenSegsWithParameters( first, middle, strength, leng )
leng=structure.GetDistance( middle, last )
if bloat then
leng = leng + 4.0
else
local compr=random(0.50,0.80)
leng = compr*leng
end
local chSuc2 = BandBetweenSegsWithParameters( middle, last, strength, leng )
if chSuc1 or chSuc2 then
DebugPrint("SimpleBandedWiggleShakeWrapper")
SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH )
DelBands()
end
DebugPrint("LongWiggleAll")
LongWiggleAll()
return changeSucceeded
end
function PerformBandedWormPairAction( idx )
local startIdx, endIdx = GetActionRange( idx, 1, 15 )
local len = endIdx - startIdx + 1
local wantGlobalWiggle = randomBool( )
print("BandedWormPair for "..idx.." with len="..len)
return BandedWormPairAction( startIdx, len, idx, wantGlobalWiggle )
end
function PerformLocalWiggleAction( idx )
local startIdx, endIdx = GetActionRange( idx, 1, 4 )
local wantGlobalWiggle = randomBool( )
local minGain = 0.001
print("LocalWiggle for "..idx)
--SetCI( CI_LOCALWIGGLER_SHAKE )
--structure.ShakeSidechainsSelected(1)
--SetCI( 1.00 )
return WiggleRangeAction( startIdx, endIdx, false, minGain )
end
function PerformLocalFreezeWiggleAction( idx )
local startIdx, endIdx = GetActionRange( idx, 1, 4 )
local wantGlobalWiggle = randomBool( )
local minGain = 0.001
print("LocalFreezeWiggle for "..idx)
if startIdx > MinUnlockedSeg then freeze.Freeze( startIdx - 1, true, true ) end
if endIdx < MaxUnlockedSeg then freeze.Freeze( endIdx + 1, true, true ) end
SetCI( CI_LOCALWIGGLER_SHAKE )
structure.ShakeSidechainsSelected(1)
SetCI( 1.00 )
local changeSucceeded = WiggleRangeAction( startIdx, endIdx, false, minGain )
ResetFrozenness( )
return changeSucceeded
end
function PerformATSidechainTweakAction( idx )
local radius = AT_SPHERE_RADIUS
local wantRebuild = randomBool( AT_PROB_DO_REBUILD )
local includeWorsts = randomBool( AT_PROB_SPHERE_ADD_WORSTS )
local fixBand = randomBool( AT_PROB_PUT_FIX_BANDS )
print("ATSidechainTweak for "..idx)
return ATSidechainTweakAction( idx, radius, wantRebuild, includeWorsts, fixBand )
end
function PerformATSidechainTweakAroundAction( idx )
local radius = AT_SPHERE_RADIUS
local wantRebuild = randomBool( AT_PROB_DO_REBUILD )
local includeWorsts = randomBool( AT_PROB_SPHERE_ADD_WORSTS )
local fixBand = randomBool( AT_PROB_PUT_FIX_BANDS )
print("ATSidechainTweakAround for "..idx)
return ATSidechainTweakAroundAction( idx, radius, wantRebuild, includeWorsts, fixBand )
end
function PerformATSidechainManipulateAction( idx )
local radius = AT_SPHERE_RADIUS
local wantRebuild = randomBool( AT_PROB_DO_REBUILD )
print("ATSidechainManipulate for "..idx)
return ATSidechainManipulateAction( idx, radius, wantRebuild )
end
function PerformSingleContactMapAction( idx )
if idx == nil then idx = randomContactableSeg( ) end
print( "SingleContactMapBand at ".. idx )
local changeSucceeded = false
local heatThreshold = CONTACTMAP_THRESHOLD
local strength = 1.5 * BAND_STRENGTH_DEFAULT
changeSucceeded = PutSomeContactMapBands( heatThreshold, strength, 1, randomBool( ), true )
if changeSucceeded then
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( )
end
return changeSucceeded
end
function PerformSomeContactMapBandsAction( )
print( "SomeContactMapBands" )
local changeSucceeded = false
local heatThreshold = CONTACTMAP_THRESHOLD
local strength = BAND_STRENGTH_DEFAULT
local ctWanted = random( 5, 10 )
changeSucceeded = PutSomeContactMapBands( heatThreshold, strength, ctWanted, randomBool( ), true )
if changeSucceeded then
PutRandomCompBands()
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( )
end
return changeSucceeded
end
function PerformContactMapBandsForSegAction( idx )
print( "ContactMapBandsForSeg for idx " ..idx )
if idx == nil then idx = randomContactableSeg( ) end
local changeSucceeded = false
local heatThreshold = CONTACTMAP_THRESHOLD
local strength = BAND_STRENGTH_DEFAULT
local doSidechain = false
if BAND_TO_SIDECHAINS then
doSidechain = randomBool( )
end
changeSucceeded = PutAllContactMapBandsToSeg( idx, heatThreshold, strength, true, doSidechain, true )
if changeSucceeded then
PutRandomCompBands()
DebugPrint( "WiggleShakeCleanWiggleOut" )
WiggleShakeCleanWiggleOut( )
end
return changeSucceeded
end
function PerformCMTwoRegionBandAction( idx1 )
print( "CMTwoRegionBander for idx " ..idx1 )
if idx1 == nil then idx1 = randomContactableSeg( ) end
local strength = BAND_STRENGTH_DEFAULT
local heatThreshold = CONTACTMAP_THRESHOLD
local startIdx1, endIdx1 = GetRegionStartAndEnd( idx1 )
if startIdx1 == 1 and endIdx1 == SegCt then return false end -- we just can't deal with this
local idx2 = startIdx1
local tryCount = 0
while idx2 >= startIdx1 and idx2 <= endIdx1 and tryCount < 50 do
for i=startIdx1, endIdx1 do
idx2 = randomContactSeg( i, CONTACTMAP_THRESHOLD )
if idx2 ~= 0 and (idx2 < startIdx1 or idx2 > endIdx1) then break end -- got one
end
tryCount = tryCount + 1
end
if idx2 == 0 then return false end -- we have failed
if tryCount == 50 then return false end
local startIdx2, endIdx2 = GetRegionStartAndEnd( idx2 )
local changeSucceeded = PutContactMapBandsBetweenRegions( heatThreshold,
startIdx1, endIdx1, startIdx2, endIdx2,
strength, true, randomBool( ), randomBool( ),
true )
if changeSucceeded then
PutRandomCompBands()
DebugPrint( "WiggleShakeCleanWiggleOut" )
WiggleShakeCleanWiggleOut( )
end
return changeSucceeded
end
function PerformContactMapperAction( )
print("ContactMapper" )
local changeSucceeded = PutContactMapBands( )
if changeSucceeded then
PutRandomCompBands()
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( )
end
return changeSucceeded
end
function PerformPushPullContactMapAction( badSeg )
if badSeg == nil then badSeg = randomContactableSeg( ) end
local segList = {}
local wantPushNotPull = randomBool( )
local ctBands = 5
local strength = BAND_STRENGTH_DEFAULT
print("PushPullCM at seg "..badSeg )
getCMSegsOutsideSphere( segList, badSeg, 8, CONTACTMAP_THRESHOLD )
if #segList == 0 then
-- nothing we can do!
print( " PushPull failed due to lack of distant 'center' segs" )
return false
end
local centerSeg = segList[ random( #segList ) ]
local changeSucceeded = PutPushPullContactMapBands(
badSeg, ctBands, centerSeg, strength,
CONTACTMAP_THRESHOLD, wantPushNotPull )
if changeSucceeded then
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( )
end
return changeSucceeded
end
function PerformVoidCrusherContactMapAction( idx )
if idx == nil then idx = randomContactableSeg( ) end
local strength = BAND_STRENGTH_DEFAULT
print("VoidCrusherCM at seg "..idx )
local changeSucceeded = PutVoidCrusherContactMapBands( idx, strength, CONTACTMAP_THRESHOLD )
if changeSucceeded then
DebugPrint( "SimpleBandedWiggleShakeWrapper" )
SimpleBandedWiggleShakeWrapper( )
end
return changeSucceeded
end
function PerformContactMapRebuildRangeAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRebuildRange( idx )
print( "ContactMapRebuildRange on range ".. idxStart, idxEnd )
local changeSucceeded = PutContactMapBands( )
if changeSucceeded then
if USE_LOWCI_WIGGLES then
changeSucceeded = RebuildBitspawn( idxStart, idxEnd, true )
else
changeSucceeded = RebuildSimple( idxStart, idxEnd )
end
end
DebugPrint( "CleanShakeWiggleOut" )
CleanShakeWiggleOut( )
return changeSucceeded
end
-- think about all-loop and restoring secondary structure and such
function PerformContactMapRebuildSSAction( idx )
if idx == nil then idx = randomMovableSeg( ) end
local idxStart, idxEnd = GetRegionForOperation( idx )
print( "ContactMapRebuildSS for range "..idxStart..","..idxEnd )
local oldInnerTube = REBUILD_TUBE_INNER_RADIUS
local oldOuterTube = REBUILD_TUBE_OUTER_RADIUS
REBUILD_TUBE_INNER_RADIUS = CONTACTMAP_REBUILD_TUBE_INNER_RADIUS
REBUILD_TUBE_OUTER_RADIUS = CONTACTMAP_REBUILD_TUBE_OUTER_RADIUS
local changeSucceeded = PutContactMapBands( )
if changeSucceeded then
if randomBool( ) then
changeSucceeded = DeepRebuildRange(
idxStart, idxEnd,
REBUILD_DEEP_MAXTRIES )
else
changeSucceeded = RebuildRangeFromQuaker(
idxStart, idxEnd,
REBUILD_DEEP_MAXTRIES )
end
end
REBUILD_TUBE_INNER_RADIUS = oldInnerTube
REBUILD_TUBE_OUTER_RADIUS = oldOuterTube
DebugPrint( "CleanShakeWiggleOut" )
CleanShakeWiggleOut()
return changeSucceeded
end
function PerformContactMapRebuildAllAction( )
print( "ContactMapRebuildAll" )
local changeSucceeded = PutContactMapBands( )
if changeSucceeded then
PerformWiskyRebuildAllAction( )
end
DebugPrint( "CleanShakeWiggleOut" )
CleanShakeWiggleOut()
return changeSucceeded
end
--------------------------------------------------------------------------------------------------------
-- PERFORMING OF ACTIONS
--------------------------------------------------------------------------------------------------------
function GenerateAllActionsList( )
AllActionsList = {}
-- idealize, remix, rebuild
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "IdealizeZlb", actionFunc=PerformIdealizeZlbAction,
testFunc=testSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "IdealizeRegion", actionFunc=PerformIdealizeRegionAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "IdealizeXToY", actionFunc=PerformIdealizeRegionXToYAction,
testFunc=testSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} -- testSmallPuzzleOk
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "Remix", actionFunc=PerformRemixAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RemixSimple", actionFunc=PerformRemixSimpleAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RemixSimpleXToY", actionFunc=PerformRemixSimpleXToYAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RemixXToY", actionFunc=PerformRemixXToYAction,
testFunc=testSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "DeepRebuildSS", actionFunc=PerformDeepRebuildSSAction,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "DeepRebuildSSXToY", actionFunc=PerformDeepRebuildSSXToYAction,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "DeepRebuildRange", actionFunc=PerformDeepRebuildAction,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "DeepRebuildRangeXToY", actionFunc=PerformDeepRebuildXToYAction,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RebuildSimple", actionFunc=PerformRebuildSimpleAction,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RebuildSimpleXToY", actionFunc=PerformRebuildSimpleXToYAction,
testFunc=testRebuildSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RebuildFromQuaker", actionFunc=PerformRebuildFromQuakerAction,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RebuildBitspawn", actionFunc=PerformRebuildBitspawnAction,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RebuildBitspawnLowCI", actionFunc=PerformRebuildBitspawnLowCI,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "QuakingRebuild", actionFunc=PerformQuakingRebuild,
testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD}
-- banders
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "PushPull", actionFunc=PerformPushPullAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "VoidCrusher", actionFunc=PerformVoidCrusherAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "PusherBands", actionFunc=PerformPusherAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "MoverBands", actionFunc=PerformMoverAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "FlexerBands", actionFunc=PerformFlexerAction,
testFunc=testFlexerOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SheetStraightener", actionFunc=PerformSheetStraightenerAction,
testFunc=testSheetActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SheetAligner", actionFunc=PerformSheetAlignerAction,
testFunc=testSheetActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SheetShifter", actionFunc=PerformSheetShifterAction,
testFunc=testNonstraySheetsActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SheetFlipper", actionFunc=PerformSheetFlipperAction,
testFunc=testNonstraySheetsActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SheetSewer", actionFunc=PerformSheetSewerAction,
testFunc=testSheetActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "HelixRotator", actionFunc=PerformHelixRotatorAction,
testFunc=testSimpleHelixOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "HelixUniform", actionFunc=PerformHelixUniformAction,
testFunc=testLargishHelixActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "HelixCompressor", actionFunc=PerformHelixCompressorAction,
testFunc=testLargishHelixActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "HelixFixer", actionFunc=PerformHelixFixerAction,
testFunc=testLargishHelixActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "GeneralHinge", actionFunc=PerformGeneralHingeAction,
testFunc=testGeneralHingeOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "GlycineHinge", actionFunc=PerformGlycineHingeAction,
testFunc=testGlycineHingeOk, usesIdx=true, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "LocalQuake", actionFunc=PerformLocalQuakeAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "LSQuake", actionFunc=PerformLSQuakeAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "BisQuake", actionFunc=PerformBisQuakeAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_QUAKER}
-- non-index-using banders
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "GentleComp", actionFunc=PerformGentleCompAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "GentleCompLowCI", actionFunc=PerformGentleCompLowCIAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "TailGrab", actionFunc=PerformTailGrabAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_BANDER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "InhaleAndExhale", actionFunc=PerformInhaleAndExhaleAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "InAndOut", actionFunc=PerformInAndOutAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SimpleQuake", actionFunc=PerformSimpleQuakeAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "MultiBander", actionFunc=PerformMultiBanderAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "MultiBis", actionFunc=PerformMultiBisAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "MultiSegBand", actionFunc=PerformMultiSegBandAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "EveryXToY", actionFunc=PerformEveryXToEveryYBandAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER}
-- contact map collection (we just assume rebuild doesn't need safety checks here)
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ContactMapper", actionFunc=PerformContactMapperAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SomeContactMapBands", actionFunc=PerformSomeContactMapBandsAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ContactMapRebuildAll", actionFunc=PerformContactMapRebuildAllAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ContactMapRebuildRange", actionFunc=PerformContactMapRebuildRangeAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ContactMapRebuildSS", actionFunc=PerformContactMapRebuildSSAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ContactMapTwoRegions", actionFunc=PerformCMTwoRegionBandAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ContactTwoSegs", actionFunc=PerformSingleContactMapAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ContactMapForSeg", actionFunc=PerformContactMapBandsForSegAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "PushPullContactMap", actionFunc=PerformPushPullContactMapAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "VoidCrusherContactMap", actionFunc=PerformVoidCrusherContactMapAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP}
-- oddball endgame actions deserve some love, too
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "IdealizePoint", actionFunc=PerformIdealizePointAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
-- NOTE: by calling this endgame, I lose rebuild sanity check ability
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RebuildSimplePoint", actionFunc=PerformRebuildSimplePointAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "BandedWormPair", actionFunc=PerformBandedWormPairAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "LocalWiggle", actionFunc=PerformLocalWiggleAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "LocalFreezeWiggle", actionFunc=PerformLocalFreezeWiggleAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ATSidechainTweak", actionFunc=PerformATSidechainTweakAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ATSidechainTweakAround", actionFunc=PerformATSidechainTweakAroundAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "ATSidechainManipulate", actionFunc=PerformATSidechainManipulateAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME}
-- the dubious actions come last
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "TailWhip", actionFunc=PerformTailWhipAction,
testFunc=testTailWhipOk, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "SpotMutator", actionFunc=PerformSpotMutatorAction,
testFunc=testIndexIsMutable, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "BIS", actionFunc=PerformSingleBandInSpaceAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "BandBetween", actionFunc=PerformBandToRandomSegAction,
testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "CentralBander", actionFunc=PerformCentralBanderAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_DUBIOUS}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "WiskyRebuildAll", actionFunc=PerformWiskyRebuildAllAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_DUBIOUS}
AllActionsList[ #AllActionsList + 1 ] =
{nameStr = "RebuildAllWithIdealize", actionFunc=PerformRebuildAllWithIdealizeAction,
testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_DUBIOUS}
end
function GetActionMatchingName( name )
for i=1, #AllActionsList do
if name == AllActionsList[ i ].nameStr then
return AllActionsList[ i ]
end
end
print( "No matching action for "..name )
end
function indexIsAllowed( idx )
if #AllowedActionIndices == 0 then return true end
for i = 1, #AllowedActionIndices do
if idx == AllowedActionIndices[ i ] then return true end
end
return false
end
function GenerateAcceptableIndexList( )
local idxList = {}
for i = 1, #NonLockedSegList do
if indexIsAllowed( NonLockedSegList[i] ) then
idxList[ #idxList + 1 ] = NonLockedSegList[i]
end
end
if #idxList == 0 then return nil end
randomizeIndexList( idxList )
-- IF TARGETED IS WANTED, THEN PLAY ITS GAMES HERE
if randomBool( PROB_TARGETED ) then
print("Trying to target")
-- winners: put one winner list entry at top
if randomBool( PROB_TARGETED_WANTS_WINNER ) then
-- get the most recent winner, move it to the top of the list
local idx = RecentWinners[ random( #RecentWinners ) ].idx
for j=1, #idxList do
if idxList[ j ] == idx then
idxList[ j ], idxList[ 1 ] = idxList[ 1 ], idxList[ j ]
break
end
end
else
-- worst: move the five worst-scoring indices to the top of the list
local idxBads = {}
getWorstScoringAAs( idxBads, 5, subscore )
randomizeIndexList( idxBads )
for i=1, #idxBads do
for j=1, #idxList do
if idxList[ j ] == idxBads[ i ] then
idxList[ j ], idxList[ i ] = idxList[ i ], idxList[ j ]
break
end
end
end
end
end
return idxList
end
function GenerateActionChoice( actionNamesList )
-- Generate a list of usable indices in an appropriate order
local idxList = GenerateAcceptableIndexList( )
if actionNamesList == nil or #actionNamesList == 0 or #idxList == 0 then
return nil, nil
end
-- Generate an ordering for the list of actions
-- IF WANT TO SUPPORT SOME KIND OF RANKED ORDERING OF ACTIONS, DO IT HERE
local actionIdxes = {}
for i=1, #actionNamesList do
actionIdxes[ i ] = i
end
randomizeIndexList( actionIdxes )
-- walk through the indices and actions looking for workable combinations
for i=1, #idxList do
for j = 1, #actionIdxes do
local idx = idxList[ i ]
local actionToConsider = GetActionMatchingName( actionNamesList[ actionIdxes[ j ] ] )
if actionToConsider ~= nil then
if actionToConsider.actionType ~= ACTION_TYPE_REBUILD or #NonLockedSegList > 0 then
if actionToConsider.usesIdx == false or
actionToConsider.testFunc == nil
then
if actionToConsider.usesIdx == false then
return nil, actionToConsider
else
return idx, actionToConsider
end
else
if actionToConsider.testFunc(idx) then
return idx, actionToConsider
end
end
end
end
end
end
-- we has faileded
return nil, nil
end
function PerformAction( action, idx )
AlgName = action.nameStr
local initScore = getQuickScore() -- winner circle silliness
-- SETUP FOR THE ACTION
if CYSTEINE_PERFORM_BANDING then
EnableAndDisableCysteineBands( ) -- get cysteine bands just right
end
ResetUserBands( ) -- enable/disable as user originally had them
-- decide whether to perform pre-expansion (used by decementing actions)
local likeExpanders = EXPAND_BEFORE_ACTION and WorthTryingCementBreaker
if likeExpanders and randomBool( PROB_USE_EXPANDER ) then
PerformEveryXToEveryYExpansion()
AlgName = "Exp" .. AlgName -- to help stats tracking
end
-- PERFORM THE ACTION
if not action.usesIdx then idx = nil end
changeSucceeded = action.actionFunc( idx )
-- WRAPUP AFTER THE ACTION
-- cleanup on aisle 6 (not supposed to be needed, but just in case)
ResetFrozenness( )
DelBands( )
--ResetCuts( ) -- too pricy, rather risk missing out
selection.DeselectAll( )
SetCI( 1.0 )
-- stats and final fuse if user wants such a thing
if not changeSucceeded then
if action.actionType == ACTION_TYPE_REBUILD then
CtRebuildFails = CtRebuildFails + 1
print( "CHANGE FAILED - RB(" .. CtRebuildFails .. ")" )
else
print( "CHANGE FAILED - " .. AlgName )
end
else
if action.actionType == ACTION_TYPE_REBUILD then CtRebuildFails = 0 end
-- THE FUSER for those who want such
if USE_FUSEWIGGLE then
DoFuseWiggle( )
end
-- winner's circle tracking (currently useless, but who knows?)
-- a better version of this would also track action.
if idx ~= nil then UpdateWinners( idx, getScore() > initScore ) end
end
return changeSucceeded
end
function PickActionFromList( actionNamesList )
local idx, action = GenerateActionChoice( actionNamesList )
if action == nil then
print("!!! No selectable actions")
return false
end
return PerformAction( action, idx )
end
----------------------------------------------------------------
-- WALKER FUNCTIONS
----------------------------------------------------------------
function PerformWalker( orderProtocol, actionNamesList, qs_best, abbr )
if qs_best == nil then qs_best = QS_Best end
if abbr == nil then abbr = "WALK" end
if actionNamesList == nil or #actionNamesList == 0 then
print("no actions to perform")
return 0, 0, 0
end
local stepCt = 0
local startTime = os.time()
local initScore = getScore()
-- which indices should we act upon?
local idxList = {}
local idxIndexer = {}
for i = 1, #NonLockedSegList do
if indexIsAllowed( NonLockedSegList[i] ) then
idxList[ #idxList + 1 ] = NonLockedSegList[i]
idxIndexer[ #idxIndexer + 1 ] = #idxIndexer + 1
end
end
if #idxList == 0 then
print("no aas to act upon")
return 0, 0, 0
end
if orderProtocol == ACTION_ORDERPROTOCOL_START_TO_END then
abbr = abbr.."_SE"
elseif orderProtocol == ACTION_ORDERPROTOCOL_END_TO_START then
abbr = abbr.."_ES"
for i=1, math.floor( #idxIndexer/2 ) do
local tmp = idxIndexer[ #idxIndexer - i ]
idxIndexer[ #idxIndexer - i ] = idxIndexer[ i ]
idxIndexer[ i ] = tmp
end
elseif orderProtocol == ACTION_ORDERPROTOCOL_RANDOMIZE then
abbr = abbr.."_R"
randomizeIndexList( idxIndexer )
elseif orderProtocol == ACTION_ORDERPROTOCOL_WORST_TO_BEST then
abbr = abbr.."_WB"
local idxScores = {}
for i = 1, #NonLockedSegList do
if indexIsAllowed( NonLockedSegList[i] ) then
idxScores[ #idxScores + 1 ] = current.GetSegmentEnergyScore( i )
end
end
sortByScore( idxIndexer, idxScores )
else
print("no such protocol")
return 0,0,0
end
for i = 1, #idxList do
LoadBest( qs_best )
-- which index should we act upon?
local idx = idxList[ idxIndexer[ i ] ]
print( abbr..":"..i.." score="..TrimNum(getScore()) )
local gainForIdx = MinIdxGainToRepeat
while gainForIdx >= MinIdxGainToRepeat do
local actionIdxes = {}
for j=1, #actionNamesList do
actionIdxes[ j ] = j
end
randomizeIndexList( actionIdxes )
local initIdxScore = getScore()
for j=1, #actionNamesList do
-- what action should we take?
LoadBest( qs_best )
local oldScore = getScore()
local oldTime = os.time()
action = GetActionMatchingName( actionNamesList[actionIdxes[ j ]])
if action == nil then
print("No action - wanted: "..actionNamesList[actionIdxes[ j ]])
else
if action.testFunc == nil or action.testFunc(idx) then
local changeSucceeded = PerformAction( action, idx )
if changeSucceeded then
local newScore = getScore( )
local deltaScore = newScore - oldScore
local deltaTime = os.time() - oldTime
addActionToStats( deltaScore, deltaTime )
if deltaScore > 0.0 then
print("+ Action gain: "..deltaScore)
SaveBests( false, qs_best )
end
else
addFailToStats( )
end
stepCt = stepCt + 1
end
end
end
LoadBest( qs_best )
gainForIdx = getScore() - initIdxScore
if gainForIdx > 0.0 then
print("+++ Gain for idx="..idx..": "..gainForIdx.." score="..TrimNum(getScore()))
else
print("--- No gain for idx="..idx)
end
end
end
local endScore = getScore()
local endTime = os.time()-startTime
return stepCt, endTime, endScore
end
----------------------------------------------------------------
-- MULTITRY FUNCTIONS
----------------------------------------------------------------
function FindAlreadyStoredPoseSimilarToCurrentOne( qs_slots )
local currDistMat = {}
computeDistanceMatrix( currDistMat )
local currScore = getScore( )
save.Quicksave( QS_Swapslot )
for i=1, #qs_slots do
save.Quickload( qs_slots[i] )
local savDistMat = {}
computeDistanceMatrix( savDistMat )
local savScore = getScore()
if compareDistanceMatrices( savDistMat, currDistMat ) then
return qs_slots[i], savScore
end
end
save.Quickload( QS_Swapslot )
return 0, 0
end
function SaveTopBests( TopBestSlots )
currScore = getScore()
local slot, slotScore = FindAlreadyStoredPoseSimilarToCurrentOne( TopBestSlots )
if slot > 0 then
-- ok, we have a slot with extremely similar entry. Decide whether to keep it
if slotScore < currScore then
print("Saving pose - replacing similar less-scoring pose")
save.Quicksave( slot )
else
print("Not saving - already have a similar and better pose")
end
else
-- ok, we don't have a slot with extremely similar entry. Put it in score order.
save.Quicksave( QS_Swapslot )
for i = 1, #TopBestSlots do
save.Quickload( TopBestSlots[ i ] )
savScore = getScore()
if currScore > savScore then
for j=#TopBestSlots-1, i, -1 do
save.Quickload( TopBestSlots[j] )
save.Quicksave( TopBestSlots[j+1] )
end
save.Quickload( QS_Swapslot )
print("Storing new pose in slot "..i)
save.Quicksave( TopBestSlots[ i ] ) -- save new pose
break
end
end
save.Quickload( QS_Swapslot )
end
end
function GetBestFromList( topBests, wantReport )
-- it's already sorted, so we'll load the first one
if wantReport then
for i=1, #topBests do
save.Quickload( topBests[ i ] )
print( "Score #" .. i .. " = " .. getScore() )
end
end
save.Quickload( topBests[1] )
end
function SetupTopBests( topBests, numberOfSlotsWanted )
if numberOfSlotsWanted > QS_MultiStartSaveLast - QS_MultiStartSave1 + 1 then
print( "!!! Asked for more slots than allowed max" )
return false
end
for i=1, numberOfSlotsWanted do
topBests[#topBests+1] = QS_MultiStartSave1 + i - 1
save.Quicksave( QS_MultiStartSave1 + i - 1)
end
return true
end
function PerformMultiTryOperation(
numberOfStarts, numberOfActionsPerTry,
startIdx, endIdx, actionFunction, abbrBase )
if abbrBase == nil then abbrBase = "" end
print( "PerformMultiTryOperation for "..numberOfStarts.." starts with "..
numberOfActionsPerTry.." actions per try" )
BestScore=getScore( )
LoadBest( )
local bests = {}
local topBests = {}
if not SetupTopBests( topBests, numberOfStarts ) then return false end
save.Quicksave( QS_TopLevelTempMT )
save.Quicksave( QS_TopLevelTempM2 )
for k=1, numberOfStarts do
save.Quickload( QS_TopLevelTempMT ) -- always start over from initial state
SaveBest( true, QS_TopLevelTempM2 ) -- make this be best so far
--print( "Starting try " .. k.. " of " .. numberOfStarts .. ": Score="..TrimNum(getScore( )))
local initscore = getScore( )
for j=1, numberOfActionsPerTry do
if numberOfActionsPerTry > 1 then
abbr = abbrBase .. "-MT" .. numberOfStarts .. "." .. numberOfActionsPerTry.. ":" .. k .. "." .. j
else
abbr = abbrBase .. "-MT" .. numberOfStarts .. ":" .. k
end
save.Quickload( QS_TopLevelTempM2 )
local currScore = getScore( )
actionFunction( startIdx, endIdx, QS_TopLevelTempM2, abbr )
-- I expect actionFunction to store its best result in QS..M2,
-- but I do not expect it to load that result for me.
save.Quickload( QS_TopLevelTempM2 )
local endScore = getScore( )
if endScore > currScore then
save.Quicksave( QS_TopLevelTempM2 )
currScore = endScore
end
if endScore > BestScore then
BestScore = endScore
end
SaveBests( false, QS_TopLevelTempM2 )
end -- FOR j
save.Quickload( QS_TopLevelTempM2 )
print( abbr .. ": Finishing - Score: "..getScore( ) )
SaveTopBests( topBests )
end -- FOR k
GetBestFromList( topBests, true )
print( "Taking result with score " .. TrimNum( getScore() ))
return true
end
----------------------------------------------------------------------
-- SCRIPT-SPECIFIC FUNCTIONS
----------------------------------------------------------------------
----------------------------------------------------------------
-- SA's Neighbor generator
----------------------------------------------------------------
function CreateNeighborPose( NeighborGenerationFunction )
-- creditbest code removed because starting from shares runs into foldit bug
--local oldCreditBest = creditbest.GetScore( ) -- to find out if we've missed transients
local oldScoreMat = {}
local oldQuickScore = getQuickScore( )
local oldScore = getScore( )
constructScoreMatrix( oldScoreMat )
SetCI( 1.0 )
DelBands( )
selection.DeselectAll( )
ResetFrozenness( )
recentbest.Save( )
local rbscore = getRBScore( )
save.Quicksave( QS_NeighborTempSA )
local goodNeighbor = false
while not goodNeighbor do
local oldTime = os.time( )
local changeSucceeded = false
goodNeighbor = false
save.Quickload( QS_NeighborTempSA )
local changeSucceeded = NeighborGenerationFunction( )
if changeSucceeded then
local newScore = getScore( )
goodNeighbor = isProteinChanged( oldQuickScore, oldScoreMat, THRESHOLD_PROTEIN_CHANGED )
if not goodNeighbor then
addFailToStats( )
print( "NEIGHBOR REJECTED (score:"..newScore..")")
else
local deltaScore = newScore - oldScore
local deltaTime = os.time() - oldTime
addActionToStats( deltaScore, deltaTime )
end
else
addFailToStats( )
end
if CtRebuildFails > MAX_REBUILD_FAILS then
-- sometimes there are no successful ways to do a rebuild, we must bail
CtRebuildFails = 0
return false
end
end -- END while not goodNeighbor
-- Look over the result
local newScore = getScore( )
--local newCreditBest = creditbest.GetScore( )
--if newCreditBest ~= oldCreditBest and newCreditBest ~= newScore then
-- -- we missed a transient
-- -- trying to regain it can be problematic for some wigglers
-- -- (eg WiggleZlbNicely) because the creditbest pose may have bands.
-- print( "!!! CreditBest changed: old="..oldCreditBest.." new="..newCreditBest )
--end
print( "Neighbor Score: " .. newScore)
return true
end
function DoFuseWiggle( )
local oldScore = getQuickScore( )
local oldTime = os.time( )
local r = random( )
if r < PROB_FUSEWIGGLE_LOCAL then
print( "IterativeWiggleLocalByChunk" )
AlgName = "IterativeWiggleLocalByChunk"
IterativeWiggleLocalByChunk( 1, SegCt, FUSEWIGGLE_GAIN, random( 3, 6 ), false )
elseif r < PROB_FUSEWIGGLE_LOCAL + PROB_FUSEWIGGLE_BLUEFUSE then
print( "BlueFuse" )
AlgName = "BlueFuse"
BlueFuse( )
else -- PROB_FUSEWIGGLE_CUTFUSE
print( "IterativeCutAndWiggle")
AlgName = "IterativeCutAndWiggle"
IterativeCutAndWiggle( FUSEWIGGLE_ITERS, FUSEWIGGLE_GAIN, random( 3,11 ) )
for i=1, SegCt do -- deliberate non-use of ResetCuts
DeleteCutAtIndex( i )
end
end
local deltaScore = getQuickScore( ) - oldScore
local deltaTime = os.time( ) - oldTime
addActionToStats( deltaScore, deltaTime )
end
----------------------------------------------------------------------
--
---- SIMULATED ANNEALING ALGORITHM FUNCTIONS
--
----------------------------------------------------------------------
-- Real research could be done (rosetta folks have done) on what a "good"
-- Temperature function is for these purposes.
-- Note that "num" = i/n and goes from 0 to 1 over the life of the SA function.
--
-- FOR COMPARISON PURPOSES
-- Rosetta pose generation uses:
-- ts1 = (t0-tn)/cosh(5.0*i/n) + t0 -- below: num = i/n
-- ts2 = (t0-tn)*i/n + t0
-- stage1: t0=5.0, tn=0.5 ts1 -- runs from 9.0-epsilon to 5.0
-- stage2: t0=5.0, tn=0.5 ts1
-- stage3: t0=5.0, tn=0.5 ts1
-- stage4: t0=5.0, tn=0.0 ts2 -- runs backwards from 0.0 to 5.0
-- stage5: t0=1.0, tn=0.2 ts2 -- runs backwards from 0.2 to 0.8
--
-- Rosetta scoring:
-- stage1: only repulsive force of sidechain centroids
-- stage2: "score1" = stage1 score + vanderwaals+SS+disulfide
-- stage3: interchange "score2" and "score5", similar except for weighting
-- stages4&5: use "score3" = stage2 + compactness+solvent accessibility+position of sidechain centroids
--
-- Rosetta neighbor generation:
-- stage1: operates on 9-mers
-- stage2,3: 9-mers and 3-mers
-- stage4: 3-mers at start, pairs of 3-mers later
-- place 1st at random, 2nd minimizes disruption of 1st location.
-- stage5: play with dihedral angles of randomly chosen aa
-- repacking: checks a rotamer database for sidechains.
--
function T_OneOverX( num )
return ( 1.0 / (num + 0.01) ) - ( 1.0 / 1.01 )
end
function T_OneOverX2( num )
x = ( 1.0 / (num + 0.001) ) - 1.0
return x * x
end
function T_MiddlingX( num )
return 10.0 * (1.0 - num)
end
function T_LowX( num )
return 1.0 - num
end
function T_ColdX( num )
return 0.1 * (1.0 - num)
end
function T_Zero( num )
return 0.0 -- causes SA to drop to normal march-forward behavior.
end
function PickTempFuncByName( tempName )
if tempName == "OneOverX" then return T_OneOverX
elseif tempName == "MiddlingX" then return T_MiddlingX
elseif tempName == "LowX" then return T_LowX
elseif tempName == "ColdX" then return T_ColdX
elseif tempName == "ZeroX" then return T_Zero
else return T_OneOverX -- the default temp function
end
end
function PickTempStringByNumber( tempNumber )
if tempNumber == 0 then return "ZeroX"
elseif tempNumber == 1 then return "ColdX"
elseif tempNumber == 2 then return "LowX"
elseif tempNumber == 3 then return "MiddlingX"
else return "OneOverX"
end
end
-- this is the standard probability function in Simulated Annealing algorithms
function P( ecurr, enew, T )
if enew < ecurr then return 1.0 end -- always accept increased scores
if T == 0.0 then return 0.0 end -- always reject decreased scores if temp = 0
return math.exp( (ecurr - enew)/T )
end
-- must negate score to function as a Simulated Annealing energy function
function E( )
return 8000.0 - getScore( ) -- 8000 is irrelevant, just for scaling
end
function SA( kmax, NeighborGenerationFunction, TempFunc,
qs_best, abbr )
-- emax is expected to "never happen"
if TempFunc == nil then TempFunc = T_OneOverX end
local estart = E( )
local ecurr = estart
save.Quicksave( QS_TopLevelTempSA ) -- a private slot
local ebest = ecurr
local startTime = os.time( )
local emax = -999999.0
local k = 0.0
while k < kmax and ecurr > emax do
WorthTryingCementBreaker = (k < StepsForCementBreaking)
save.Quickload( QS_TopLevelTempSA )
local T = TempFunc( k / kmax )
print("#" ..abbr .. k+1 ..
" T=" .. TrimNum( T )..
" s=" .. TrimNum( getScore( ) )..
" tm=" .. os.time( )-startTime )
local succeeded = CreateNeighborPose( NeighborGenerationFunction )
if not succeeded then return k end
local enew = E( )
local p = P(ecurr, enew, T)
local r = random( )
if p > r or enew < ecurr then
if enew < ecurr then
print( "++++ accepting state: score " ..TrimNum( getScore()))
if enew < ebest then
ebest = enew
SaveBests( false, qs_best )
end
elseif enew > ecurr then
print( "++++ overriding state: score " ..TrimNum( getScore()))
else
print( "++++ same-score state: score " ..TrimNum( getScore()))
end
save.Quicksave( QS_TopLevelTempSA )
ecurr = enew
end
k = k + 1.0
end
LoadBest( qs_best )
return k
end
function PerformSA( ctRestarts, stepsPerRun,
quitIfTooManyFails, minGainPerRun, ctTooManyFails,
NeighborGenerationFunction, TempFuncName,
qs_best, abbr )
if minGainPerRun == nil then minGainPerRun = 0 end
local saInitialTime = os.time( )
local saInitialScore = getScore( )
local bestScore = saInitialScore
local newscore = 0.0
local stepCount = 0
SaveBests( false, qs_best )
local sav_useExpander = EXPAND_BEFORE_ACTION
local sav_probExpander = PROB_USE_EXPANDER
local sav_stepsPerRun = stepsPerRun
-- contruct the heiroglyphics
if abbr == nil then
abbr = "SA"
else
abbr = abbr .. "-SA"
end
if ctRestarts > 1 then
abbr = abbr .. ctRestarts .. "."
end
abbr = abbr .. stepsPerRun .. ":"
-- reset the stat tracking info
for i=1, #CountFails do CountFails[i]=0 end
-- change temp func string into actual function
TempFunc = PickTempFuncByName( TempFuncName )
-- start playing the game!
local ctFailedRuns = 0
for i=1, ctRestarts do
LoadBest( qs_best )
local saRunStartScore = getScore( )
local saRunStartTime = os.time( )
print( "START: SA score=" ..TrimNum( saRunStartScore )..
" time=" ..saRunStartTime - saInitialTime )
local abbrOut = abbr
if ctRestarts > 1 then
abbrOut = abbrOut .. i .. "."
end
stepCount = stepCount + SA( stepsPerRun,
NeighborGenerationFunction, TempFunc,
qs_best, abbrOut )
LoadBest( qs_best )
newscore = getScore( )
local gain = newscore - bestScore
if newscore > bestScore then
bestScore = newscore
end
local str = "FINISH: SA score=" ..TrimNum( bestScore )..
" gain=" ..TrimNum( gain )..
" time=" ..(os.time( ) - saRunStartTime)
if quitIfTooManyFails and gain < minGainPerRun then
str = str .. " fails="..(ctFailedRuns + 1)
end
print( str )
if quitIfTooManyFails and gain < minGainPerRun then
-- this run wasn't profitable...
ctFailedRuns = ctFailedRuns + 1
if #CountFails < ctFailedRuns then
CountFails[ctFailedRuns] = 0
end
CountFails[ ctFailedRuns ] = CountFails[ ctFailedRuns ] + 1
if i < ctRestarts and ctFailedRuns >= ctTooManyFails then
-- ok, it was fun while it lasted, but this is getting silly
print( "!!! Too many failed runs - bailing" )
break
end
elseif gain >= minGainPerRun then
-- reset the failure clock
ctFailedRuns = 0
end
PossibleCementingState = (ctFailedRuns >= FailsToStartCementBreaking)
if i < ctRestarts and PossibleCementingState and FIGHT_CEMENTING then
-- we fear it's cemented: haul out the badass actions.
EXPAND_BEFORE_ACTION = true
PROB_USE_EXPANDER = 1.0
stepsPerRun = SA_STEPSPERRUN_DECEMENT
print("---Decementing---" )
else
-- if all is well, then stop fighting!
EXPAND_BEFORE_ACTION = sav_useExpander
PROB_USE_EXPANDER = sav_probExpander
stepsPerRun = sav_stepsPerRun
end
end
LoadBest( qs_best )
if ctRestarts > 1 then
print( "FINAL SA: steps=" ..stepCount..
" gain=" ..TrimNum( getScore( ) - saInitialScore)..
" time=" ..os.time( ) - saInitialTime )
end
EXPAND_BEFORE_ACTION = sav_useExpander
PossibleCementingState = false
WorthTryingCementBreaker = false
return stepCount
end
----------------------------------------------------------------------
-- SA ROUTINES FOR CHOOSING INDICES
----------------------------------------------------------------------
function UpdateWinners( idx, hadGain )
-- everybody's clock gets updated, clean out too-old entries
--print( "UW: idx="..idx.." gain? "..BoolStr( hadGain ) )
for i=#RecentWinners, 1, -1 do
if RecentWinners[ i ].clock > WINNER_CLOCK_TIMEOUT or
RecentWinners[ i ].idx == 0
then
table.remove( RecentWinners, i )
else
RecentWinners[ i ].clock = RecentWinners[ i ].clock + 1
end
end
-- if we have a new success, add it (don't mind repeats)
if idx > 0 and hadGain then
local entry = {}
entry.idx = idx
entry.clock = 1
table.insert( RecentWinners, 1, entry )
end
--for i=1, #RecentWinners do
-- print("RW: idx="..(RecentWinners[i].idx).." clock="..(RecentWinners[i].clock) )
--end
end
function GetWinnerIdx( )
if #RecentWinners == 0 then return 0 end
local idx = RecentWinners[ random( #RecentWinners ) ].idx
--print( "GetWinnerIdx start with winner idx = "..idx )
if randomBool( PROB_WINNER_WANTS_NEIGHBOR ) then
idxNeighbors = {}
getSegsWithinSphere( idxNeighbors, idx, WINNER_INDEX_MAX_RADIUS, true)
--print( "Picking Neighbor: there are "..#idxNeighbors )
idx = idxNeighbors[ random( #idxNeighbors ) ]
end
--print( "GetWinnerIdx return idx = "..idx )
return idx
end
function PickIdxForAction( idx )
-- I currently believe targeted is never worth the effort (both kinds of targeting)
if randomBool( PROB_TARGETED ) then
-- overrule whatever we may have been given
idx = 0
if randomBool( PROB_TARGETED_WANTS_WINNER ) then
idx = GetWinnerIdx( )
end
if idx == 0 then
idx = randomLowScoringSeg( random( #NonLockedSegList / 5 ))
end
else
-- we always end up here of late!
if idx == nil or idx == 0 then
if #AllowedActionIndices > 0 then
local r = random( #AllowedActionIndices )
idx = AllowedActionIndices[ r ]
else
idx = randomMovableSeg( )
end
end
end
return idx
end
----------------------------------------------------------------------
-- SA ROUTINES FOR CHOOSING ACTION COLLECTIONS
----------------------------------------------------------------------
function testSheetActionsOk( idx )
local isSheetRegion = structure.GetSecondaryStructure( idx ) == 'E'
return isSheetRegion and #AllSheets > 1
end
function testNonstraySheetsActionsOk( idx )
local isSheetRegion = structure.GetSecondaryStructure( idx ) == 'E'
return isSheetRegion and #AllSheets > 1 and not IsStraySheet( idx )
end
function testSimpleHelixOk( idx )
local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or
isPossibleHelix( idx )
return isHelixRegion
end
function testGlycineHingeOk( idx )
local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or
isPossibleHelix( idx )
return isGlycine( idx ) and (not isHelixRegion) and idx >= 5 and idx <= SegCt - 5
end
function testGeneralHingeOk( idx )
local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or
isPossibleHelix( idx )
return (not isHelixRegion) and idx >= MinUnlockedSeg + 5 and idx <= MaxUnlockedSeg - 5
end
function testLargishHelixActionsOk( idx )
local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or
isPossibleHelix( idx )
local startSeg, endSeg = GetRegionForOperation( idx )
local regionLength = endSeg - startSeg + 1
return isHelixRegion and regionLength > 6
end
function testFlexerOk( idx )
local startSeg, endSeg = GetRegionForOperation( idx )
local regionLength = endSeg - startSeg + 1
return regionLength >= 5 and idx >= MinUnlockedSeg + 4 and idx <= MaxUnlockedSeg - 4
end
function testTailWhipOk( idx )
return idx <= MinUnlockedSeg + 5 or idx >= MaxUnlockedSeg - 5
end
function testSmallPuzzleOk( idx )
if ALLOW_SLOW_ACTIONS then return true end
return MaxUnlockedSeg - MinUnlockedSeg < 100
end
function testRebuildOk( idx )
return CtRebuildFails < MAX_REBUILD_FAILS
end
function testRebuildSmallPuzzleOk( idx )
if CtRebuildFails < MAX_REBUILD_FAILS then return false end
if ALLOW_SLOW_ACTIONS then return true end
return MaxUnlockedSeg - MinUnlockedSeg < 100
end
function PickStab1Action( )
-- Actions that don't change the "shape" except in controllable ways.
allowedActions = {
"GentleComp",
"GentleCompLowCI",
"SheetShifter",
"SheetAligner",
"SheetSewer",
"SheetStraightener",
"HelixRotator",
"HelixUniform",
"HelixCompressor",
"HelixFixer",
}
return PickActionFromList( allowedActions )
end
function PickStab2Action( )
allowedActions = {
"GentleComp",
"GentleCompLowCI",
"PushPull",
"VoidCrusher",
"TailGrab",
"BisQuake",
"LSQuake",
"SimpleQuake",
"GeneralHinge",
"GlycineHinge",
"SheetAligner",
"SheetShifter",
"SheetSewer",
"SheetStraightener",
"HelixRotator",
"HelixUniform",
"HelixCompressor",
"HelixFixer",
--"RebuildSimple",
--"RebuildBitspawn",
--"RebuildBitspawnLowCI"
--"QuakingRebuild",
}
return PickActionFromList( allowedActions )
end
function PickEarly1Action( )
local allowedActions = { }
local onlyCementBreakers = PossibleCementingState and WorthTryingCementBreaker and FIGHT_CEMENTING
if onlyCementBreakers then
allowedActions = {
"GentleComp",
"GentleCompLowCI",
"QuakingRebuild",
"LSQuake",
"SimpleQuake",
"InhaleAndExhale",
}
else
-- the cementbreakers have "normal" uses, too
allowedActions = {
"GentleComp",
"GentleCompLowCI",
"LSQuake",
"SimpleQuake",
"InhaleAndExhale",
"PushPull",
"VoidCrusher",
"TailGrab",
"PusherBands",
"MoverBands",
"FlexerBands",
"GeneralHinge",
"GlycineHinge",
"SheetAligner",
"SheetSewer",
"SheetShifter",
"HelixRotator",
"HelixUniform",
"HelixCompressor",
"HelixFixer",
"QuakingRebuild",
"RebuildSimple",
"RebuildBitspawn",
"RebuildBitspawnLowCI",
}
end
return PickActionFromList( allowedActions )
end
function PickEarly2Action( )
local onlyCementBreakers = FIGHT_CEMENTING and PossibleCementingState and WorthTryingCementBreaker
local allowedActions = { }
if onlyCementBreakers then
allowedActions = {
"GentleComp",
"LSQuake",
"SimpleQuake",
"InhaleAndExhale",
}
else
allowedActions = {
"PushPull",
"VoidCrusher",
"TailGrab",
"RebuildSimple",
"RebuildBitspawn",
"RebuildBitspawnLowCI",
"RebuildFromQuaker",
"IdealizeRegion",
"IdealizeXToY",
"IdealizeZlb",
"RemixSimple",
}
end
return PickActionFromList( allowedActions )
end
function PickRebuildAction( )
local allowedActions = {
-- DON'T do expensive ones
"RebuildFromQuaker",
"RebuildSimple",
"RebuildBitspawn",
"RebuildBitspawnLowCI",
"RebuildSimpleXToY",
"QuakingRebuild",
"RemixSimple",
"RemixSimpleXToY",
"IdealizeRegion",
"IdealizeZlb",
"IdealizeXToY",
}
return PickActionFromList( allowedActions )
end
function PickDeepRebuildAction( )
local allowedActions = {
-- NOW do expensive ones
"DeepRebuildRange",
"DeepRebuildRangeXToY",
"DeepRebuildSS",
"DeepRebuildSSXToY",
"Remix",
"RemixXToY",
}
return PickActionFromList( allowedActions )
end
function PickMidgameAction( )
local allowedActions = {
"MultiBander",
"MultiBis",
"MultiSegBand",
"BandedWormPair",
"LocalWiggle",
"LocalFreezeWiggle",
}
return PickActionFromList( allowedActions )
end
function PickEndgameAction( )
local allowedActions = {
"IdealizePoint",
"RebuildSimplePoint",
"BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair",
"LocalWiggle",
"LocalFreezeWiggle",
"ATSidechainTweak",
"ATSidechainTweakAround",
"ATSidechainManipulate",
}
return PickActionFromList( allowedActions )
end
function PickLowCIAction( )
local allowedActions = {
"GentleCompLowCI",
"VoidCrusher",
"RebuildSimple",
"RebuildBitspawnLowCI",
"GeneralHinge",
"GlycineHinge",
"SheetAligner",
"SheetSewer",
"SheetShifter",
"HelixRotator",
"HelixUniform",
"HelixCompressor",
"HelixFixer",
"PusherBands",
"MoverBands",
"FlexerBands",
}
return PickActionFromList( allowedActions )
end
function PickLateAction( )
local allowedActions = {
"MultiBander",
"MultiBis",
"MultiSegBand",
"EveryXToY",
"DeepRebuildRange",
"DeepRebuildRangeXToY",
"IdealizeZlb",
"IdealizeRegion",
"IdealizeXToY",
"IdealizePoint",
"RebuildSimplePoint"
}
return PickActionFromList( allowedActions )
end
function PickContactMapAction( )
local allowedActions = {
"ContactMapper",
"SomeContactMapBands",
"ContactMapForSeg",
"ContactTwoSegs",
"PushPullContactMap",
"VoidCrusherContactMap",
"ContactMapTwoRegions",
"ContactMapRebuildRange",
"ContactMapRebuildSS",
"ContactMapRebuildAll",
}
return PickActionFromList( allowedActions )
end
----------------------------------------------------------------
-- SA OPERATION PERFORMING FUNCTIONS
----------------------------------------------------------------
function SetSAParamDefaults()
ALLOW_FUSE = false
USE_FUSEWIGGLE = false
EXPAND_BEFORE_ACTION = false
PROB_QSTAB_EXTRA = PROB_QSTAB_EXTRA_DEFAULT
PROB_USE_EXPANDER = PROB_USE_EXPANDER_DEFAULT
PROB_TARGETED = PROB_TARGETED_DEFAULT
FIGHT_CEMENTING = FIGHT_CEMENTING_DEFAULT
ALLOW_SLOW_ACTIONS = ALLOW_SLOW_ACTIONS_DEFAULT
behavior.SetWigglePower( InitialWigglePower )
recentbest.Save()
end
function PerformStab1Operation( allowFailOut, abbr )
SetSAParamDefaults()
if abbr == nil then abbr = "STAB1" end
if allowFailOut == nil then allowFailOut = true end
if not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( WIGGLEPOWER_STAB1 )
end
local initScore = getScore()
local startTime = os.time()
local failNoGain = SA_FAILIFNOGAIN_STAB1
local tempFunc = TEMPFUNCNAME_STAB1
local runcount = SA_NUMSTARTS_STAB1
local numSteps = SA_STEPSPERRUN_STAB1
local actionPicker = PickStab1Action
print( "SA-Stabilize for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
local stepCt = PerformSA(
runcount, numSteps,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
local gain = getScore() - initScore
local endScore = getScore()
local endTime = os.time() - startTime
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function PerformStab2Operation( allowFailOut, abbr )
SetSAParamDefaults()
if abbr == nil then abbr = "STAB2" end
if allowFailOut == nil then allowFailOut = true end
if not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( WIGGLEPOWER_STAB2 )
end
local initScore = getScore()
local startTime = os.time()
local failNoGain = SA_FAILIFNOGAIN_STAB2
local tempFunc = TEMPFUNCNAME_STAB2
local runcount = SA_NUMSTARTS_STAB2
local numSteps = SA_STEPSPERRUN_STAB2
local actionPicker = PickStab2Action
print( "SA-Stabilize for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
local stepCt = PerformSA(
runcount, numSteps,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
local gain = getScore() - initScore
local endScore = getScore()
local endTime = os.time() - startTime
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function SimpleStabSA( startIdx, endIdx, qs_best, abbrIn )
-- A single run of SA for use by a MultiTry caller.
-- unused: startIdx, endIdx
local numSteps = SA_STEPSPERRUN_STAB1
PerformSA( 1, numSteps,
false, SA_MINGAIN, SA_FAILIFNOGAIN_STAB1,
PickStab1Action, TEMPFUNCNAME_STAB1, qs_best, abbrIn )
end
function PerformStab1MultiTry( iters, depthOfMultiTry )
SetSAParamDefaults()
local stepCt = 0
for i=1, iters do
local currScore = getScore()
local abbr = "STABp"..iters..":" .. i
PerformMultiTryOperation( depthOfMultiTry, 1, 1, SegCt, SimpleStabSA, abbr )
stepCt = stepCt + depthOfMultiTry*SA_STEPSPERRUN_STAB1
end
return stepCt
end
function PerformStabilizerOperation( )
-- INIT WSWSW
local initScore = getScore()
local timeStart = os.time()
print( "before WSWSW: score="..TrimNum(initScore) )
-- first relax it some, then do swsw...
if not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( WIGGLEPOWER_STAB1 )
end
recentbest.Save()
PerformFastRelaxWiggler( 5 )
recentbest.Restore()
EnableAndDisableCysteineBands( )
ShakeWiggleTillStable()
local scoreWswsw = getScore()
local gainWswsw = scoreWswsw - initScore
local timeWswsw = os.time( ) - timeStart
DelBands( ) -- in case of cysteine bands...
SaveBest( )
print( "WSWSW finished: time="..timeWswsw.." gain="..TrimNum(gainWswsw) )
behavior.SetWigglePower( InitialWigglePower )
-- Don't bother with multitry, it buys nothing
--stepCt1 = PerformStab1MultiTry( 3, 5 )
-- PERFORM OUR FIRST SA run: Stab1
LoadBest( )
local abbr = "STAB:2.1"
local stepsStab1,timeStab1,scoreStab1 = PerformStab1Operation( true, abbr )
print( "Stabilizer1 finished: time="..timeStab1 )
-- PERFORM OUR SECOND SA run: Stab2
abbr = "STAB:2.2"
local stepsStab2,timeStab2,scoreStab2 = PerformStab2Operation( true, abbr )
print( "Stabilizer2 finished: time="..timeStab2 )
print( "Finished Stabilizer run" )
print( "Times: wswsw="..timeWswsw.." stab1="..timeStab1.." stab2="..timeStab2)
print( "Steps: wswsw="..(1).." stab1="..stepsStab1.." stab2="..stepsStab2)
print( "Scores: wswsw="..TrimNum(scoreWswsw).." stab1="..TrimNum(scoreStab1).." stab2="..TrimNum(scoreStab2))
return 1, stepsStab1, stepsStab2,
timeWswsw, timeStab1, timeStab2,
scoreWswsw, scoreStab1, scoreStab2
end
function PerformEarly1Operation( allowFailOut, abbr )
SetSAParamDefaults()
if abbr == nil then abbr = "EA1" end
if allowFailOut == nil then allowFailOut = true end
if not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( WIGGLEPOWER_EARLY1 )
end
local failNoGain = SA_FAILIFNOGAIN_EARLY1
FIGHT_CEMENTING = FIGHT_CEMENTING_EARLY1
PROB_QSTAB_EXTRA = PROB_QSTAB_EXTRA_EARLY1
local tempFunc = TEMPFUNCNAME_EARLY1
local runcount = SA_NUMSTARTS_EARLY1
local stepcount = SA_STEPSPERRUN_EARLY1
local actionPicker = PickEarly1Action
print( "SA-Mover for " .. runcount .. " runs of " .. stepcount .. " steps using "..tempFunc )
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, stepcount,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_SA_BestEarly, abbr )
local endScore = getScore()
local gain = endScore - initScore
local endTime = os.time() - startTime
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function PerformEarly2Operation( allowFailOut, abbr )
SetSAParamDefaults()
if abbr == nil then abbr = "EA2" end
if allowFailOut == nil then allowFailOut = true end
if not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( WIGGLEPOWER_EARLY2 )
end
local initScore = getScore()
local startTime = os.time()
FIGHT_CEMENTING = FIGHT_CEMENTING_EARLY2
local failNoGain = SA_FAILIFNOGAIN_EARLY2
PROB_QSTAB_EXTRA = PROB_QSTAB_EXTRA_EARLY2
local tempFunc = TEMPFUNCNAME_EARLY2
local runcount = SA_NUMSTARTS_EARLY2
local stepcount = SA_STEPSPERRUN_EARLY2
local actionPicker = PickEarly2Action
print( "SA-Idealize for " .. runcount .. " runs of " .. stepcount .. " steps using "..tempFunc )
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
local stepCt = PerformSA(
runcount, stepcount,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_SA_BestEarly, abbr )
local endScore = getScore()
local endTime = os.time() - startTime
local gain = endScore - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function PerformEarlyOperation()
SaveBests( true, QS_SA_BestEarly )
local bestScoreSoFar = getScore()
local scoresInhaleVector = { 0.0 } -- want same #entries as Early1/2
local scoresEarly1Vector = {}
local scoresEarly2Vector = {}
local stepsEarly1Vector = {}
local stepsEarly2Vector = {}
local timesEarly1Vector = {}
local timesEarly2Vector = {}
local stepCt1 = 0
local stepCt2 = 0
local timeEarly1 = 0
local timeEarly2 = 0
local gainEarly1 = 0.0
local gainEarly2 = 0.0
local gain = DECEMENT_MIN_GAIN_EARLY
local ct = 1
while (ct <= MIN_TRIES_EARLY_OP) or
(ct <= MAX_TRIES_EARLY_OP and gain >= DECEMENT_MIN_GAIN_EARLY)
do
local postExhScore = 0.0
local loopStartScore = getScore()
LoadBest()
if ct > 1 then
-- First do InhaleAndExhale cement-breaker.
PerformInhaleAndExhaleAction( INH_EXH_FOR_CRUSH_ATTEMPT )
local postScore = getScore()
if postScore > bestScoreSoFar then bestScoreSoFar = postScore end
SaveBests( true, QS_SA_BestEarly )
postExhScore = getScore()
print("Finish inhale/exhale: score="..TrimNum( postExhScore ))
scoresInhaleVector[ct] = postExhScore
end
-- Next do Early1
abbr = "EAv.2:"..ct..".1"
local steps,time1,score1 = PerformEarly1Operation( true, abbr )
SaveBests( true, QS_SA_BestEarly )
stepCt1 = stepCt1 + steps
scoresEarly1Vector[ct] = score1
stepsEarly1Vector[ct] = steps
timesEarly1Vector[ct] = time1
timeEarly1 = timeEarly1 + time1
gainEarly1 = gainEarly1 + score1 - postExhScore
-- Last do Early2
abbr = "EAv.2:"..ct..".2"
local steps,time2,score2 = PerformEarly2Operation( true, abbr )
SaveBests( false, QS_SA_BestEarly )
stepCt2 = stepCt2 + steps
scoresEarly2Vector[ct] = score2
stepsEarly2Vector[ct] = steps
timesEarly2Vector[ct] = time2
timeEarly2 = timeEarly2 + time2
gainEarly2 = gainEarly2 + score2 - score1
-- figure out what we accomplished
LoadBest( QS_SA_BestEarly )
local endScore = getScore()
print("Finish #"..ct.." round: gain="..TrimNum( endScore - postExhScore ))
-- calculate our true gain: if none, get back our best-so-far
gain = endScore - loopStartScore
if gain < 0.0 then
local priorBestScore = getSlotScore( QS_Best )
print( "No gain from run. Revert to prior best: "..TrimNum(priorBestScore) )
save.Quickload( QS_Best )
else
print( "Got gain from run: new best="..TrimNum(endScore))
save.Quicksave( QS_Best )
end
ct = ct + 1
end
LoadBest( )
-- REPORT THE RESULTS
scoreEarly1 = scoresEarly1Vector[ 1 ]
for i=2, #scoresEarly1Vector do
if scoresEarly1Vector[i] > scoreEarly1 then scoreEarly1 = scoresEarly1Vector[i] end
end
scoreEarly2 = scoresEarly2Vector[ 1 ]
for i=2, #scoresEarly2Vector do
if scoresEarly2Vector[i] > scoreEarly2 then scoreEarly2 = scoresEarly2Vector[i] end
end
print( "Finished Early run" )
printVector( scoresEarly1Vector, "EA1 scores", true)
printVector( stepsEarly1Vector, "EA1 steps")
printVector( timesEarly1Vector, "EA1 times")
printVector( scoresEarly2Vector, "EA2 scores", true)
printVector( stepsEarly2Vector, "EA2 steps")
printVector( timesEarly2Vector, "EA2 times")
printVector( scoresInhaleVector, "Inhale scores", true)
-- Return lots of stuff because SASequence wants to report on it all.
return stepCt1, stepCt2,
timeEarly1, timeEarly2,
scoreEarly1,scoreEarly2
end
function PerformBasicRebuildOperation( allowFailOut, abbr )
SetSAParamDefaults()
if abbr == nil then abbr = "RB" end
if allowFailOut == nil then allowFailOut = true end
if #NonLockedSegList == 0 then
print( "Cannot do rebuild with no movable segments" )
return 0
end
if not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( WIGGLEPOWER_REBUILD )
end
PROB_TARGETED = PROB_TARGETED_REBUILD
local tempFunc = TEMPFUNCNAME_REBUILD
local runcount = SA_NUMSTARTS_REBUILD
local numSteps = SA_STEPSPERRUN_REBUILD
local actionPicker = PickRebuildAction
local failNoGain = SA_FAILIFNOGAIN_REBUILD
print( "SA-RebuildBasic for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if allowFailOut then
print("Move on on if "..failNoGain.." rounds have too little gain")
end
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_SA_BestRebuild, abbr )
local endScore = getScore()
local endTime = os.time()-startTime
local gain = endScore - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function PerformDeepRebuildOperation( allowFailOut, abbr )
SetSAParamDefaults()
if abbr == nil then abbr = "DPRB" end
if allowFailOut == nil then allowFailOut = true end
if #NonLockedSegList == 0 then
print( "Cannot do rebuild with no movable segments" )
return 0
end
if not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( WIGGLEPOWER_DEEPREBUILD )
end
PROB_TARGETED = PROB_TARGETED_DEEPREBUILD
local tempFunc = TEMPFUNCNAME_DEEPREBUILD
local runcount = SA_NUMSTARTS_DEEPREBUILD
local numSteps = SA_STEPSPERRUN_DEEPREBUILD
local actionPicker = PickDeepRebuildAction
local failNoGain = SA_FAILIFNOGAIN_DEEPREBUILD
print( "SA-DeepRebuild for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_SA_BestRebuild, abbr )
local endScore = getScore()
local gain = endScore - initScore
local endTime = os.time()-startTime
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function PerformRebuildOperation( )
-- Do Rebuild
SaveBests( true, QS_SA_BestRebuild )
local initScore = getScore()
local stepCt1,timeRebuild1,scoreRebuild1
if not SASEQ_SKIP_BASICREBUILD then
local abbr = "RB"
stepCt1,timeRebuild1,scoreRebuild1 = PerformBasicRebuildOperation( true, abbr )
else
stepCt1,timeRebuild1,scoreRebuild1 = 0,0,0.0
end
local stepCt2,timeRebuild2,scoreRebuild2
if not SASEQ_SKIP_DEEPREBUILD then
abbr = "DPRB"
stepCt2,timeRebuild2,scoreRebuild2 = PerformDeepRebuildOperation( true, abbr )
else
stepCt2,timeRebuild2,scoreRebuild2 = 0,0,0.0
end
LoadBest( )
print("Finish round: gain="..TrimNum( scoreRebuild2 - initScore )..
" score="..scoreRebuild2)
return stepCt1, stepCt2, timeRebuild1, timeRebuild2, scoreRebuild1, scoreRebuild2
end
function PerformMidgameOperation()
SaveBests( true, QS_SA_BestMidgame )
SetSAParamDefaults()
local abbr = "MID"
local failNoGain = SA_FAILIFNOGAIN_MIDGAME
local tempFunc = TEMPFUNCNAME_MIDGAME
local runcount = SA_NUMSTARTS_MIDGAME
local numSteps = SA_STEPSPERRUN_MIDGAME
local actionPicker = PickMidgameAction
local allowFailOut = true
print( "SA-Midgame for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_SA_BestMidgame, abbr )
local endScore = getScore()
local endTime = os.time() - startTime
local gain = endScore - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function PerformEndgame_SA( allowFailOut, abbr )
SaveBests( true, QS_SA_BestEndgame )
SetSAParamDefaults()
if abbr == nil then abbr = "ENDGAME" end
if allowFailOut == nil then allowFailOut = true end
local tempFunc = TEMPFUNCNAME_ENDGAME
local runcount = SA_NUMSTARTS_ENDGAME
local numSteps = SA_STEPSPERRUN_ENDGAME
local actionPicker = PickEndgameAction
local failNoGain = SA_FAILIFNOGAIN_ENDGAME
print( "SA-End for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
initScore = getScore()
startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_SA_BestEndgame, abbr )
local endScore = getScore()
local endTime = os.time()-startTime
local gain = endScore - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
return stepCt, endTime, endScore
end
function PerformEndgame_W( orderProtocol )
SaveBests( true, QS_SA_BestEndgame )
SetSAParamDefaults()
local actionNames = {
"IdealizePoint",
"RebuildSimplePoint",
"BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair",
"LocalWiggle",
"LocalFreezeWiggle",
"ATSidechainTweak",
"ATSidechainTweakAround",
--"ATSidechainManipulate",
}
local stepCt, endTime, endScore = PerformWalker( orderProtocol,
actionNames,
QS_SA_BestEndgame,
"ENDGAME" )
return stepCt, endTime, endScore
end
function PerformEndgameOperation( )
if behavior.HighPowerAllowed( ) and not FORBID_WIGGLE_POWER_CHANGE then
behavior.SetWigglePower( 'h' )
else
behavior.SetWigglePower( 'm' )
end
local initScore = getScore()
local startTime = os.time()
local cwScore = getScore()
local cwTime = 0
local stepCW = 0
if not SASEQ_ENDGAME_SKIP_CW then
print("Init score = "..TrimNum(initScore))
print("Performing CutAndWiggle fuse")
local lens = {2,3,5,7,11,13,15,17}
local lIdx = {1,2,3,4,5, 6, 7, 8 }
randomizeIndexList( lIdx )
for i=1, #lIdx/2 do -- TODO decide whether to do all or only some r values
IterativeCutAndWiggleFull( lens[ lIdx[i] ] )
print("CW Score (len=" .. lens[ lIdx[i] ] .. "): " ..TrimNum(getScore()))
end
cwScore = getScore()
cwTime = os.time()-startTime
stepCW = 1
SaveBests( false, QS_SA_BestEndgame )
print("Finished CutAndWiggle, gain="..TrimNum(cwScore - initScore))
end
local stepEnd = 0
local endTime = 0
local endScore = 0
local scoresEndVector = {}
local scoresInhaleVector = { 0 }
local bestScoreSoFar = getScore()
local ct = 0
local gain = MIN_GAIN_ENDGAME
while ct < MIN_TRIES_ENDGAME or (ct < MAX_TRIES_ENDGAME and gain >= MIN_GAIN_ENDGAME) do
LoadBest( )
local beginScore = getScore()
-- CRUSH with InhaleAndExhale
if ct > 0 then
PerformInhaleAndExhaleAction( INH_EXH_FOR_CRUSH_ATTEMPT )
local postScore = getScore()
if postScore > bestScoreSoFar then bestScoreSoFar = postScore end
SaveBests( true, QS_SA_BestEndgame )
local postExhScore = getScore()
print("Finish inhale/exhale: score="..TrimNum( postExhScore ))
scoresInhaleVector[#scoresInhaleVector+1] = postExhScore
stepCW = stepCW + 1
end
if ct%4 == 0 then
print("Do start to end")
orderProtocol = ACTION_ORDERPROTOCOL_START_TO_END
elseif ct%4 == 1 then
print("Do random")
orderProtocol = ACTION_ORDERPROTOCOL_RANDOMIZE
elseif ct%4 == 2 then
print("Do end to start")
orderProtocol = ACTION_ORDERPROTOCOL_END_TO_START
else
print("Do worst to best")
orderProtocol = ACTION_ORDERPROTOCOL_WORST_TO_BEST
end
-- DO IT ALREADY!
local stepCt, saTime, saScore = PerformEndgame_W( orderProtocol )
scoresEndVector[ #scoresEndVector ] = saScore
gain = saScore - beginScore
ct = ct + 1
end
LoadBest( )
print( "Finished Endgame run" )
printVector( scoresInhaleVector, "Inhale scores", true)
printVector( scoresEndVector, "Inhale scores", true)
return stepCW,stepEnd,cwTime,endTime,cwScore,endScore
end
function PerformLateOperation( )
SetSAParamDefaults()
local qwg = QUICKWIGGLE_GAIN
local swg = FUSEWIGGLE_GAIN
QUICKWIGGLE_GAIN = 0.05
FUSEWIGGLE_GAIN = 0.01
-- I could track the fuse score increase, but this operation just isn't
-- that interesting to me
USE_FUSEWIGGLE = true
IterativeCutAndWiggle( FUSEWIGGLE_ITERS, FUSEWIGGLE_GAIN, random( 3,11 ))
local abbr = "LATE"
local tempFunc = TEMPFUNCNAME_LATE
local runcount = SA_NUMSTARTS_LATE
local numSteps = SA_STEPSPERRUN_LATE
local actionPicker = PickLateAction
local failNoGain = SA_FAILIFNOGAIN_DEFAULT
print( "SA-Late for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
false, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
local endScore = getScore()
local endTime = os.time()-startTime
local gain = endScore - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" fails="..str )
QUICKWIGGLE_GAIN = qwg
FUSEWIGGLE_GAIN = swg
return stepCt,endTime,endScore
end
function PerformLowCIOperation( )
-- Does not seem worth the time it takes for "stable" poses
SetSAParamDefaults()
USE_LOWCI_WIGGLES = true
savCI = GetCI( )
local abbr = "20CI"
FIGHT_CEMENTING = FIGHT_CEMENTING_LOWCI
local tempFunc = TEMPFUNCNAME_LOW20
local runcount = SA_NUMSTARTS_LOW20
local numSteps = SA_STEPSPERRUN_LOW20
local actionPicker = PickLowCIAction
local failNoGain = SA_FAILIFNOGAIN_DEFAULT
print( "SA-LowCI20 for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
ExactSetCI( 0.20 )
CI_MAXSCALE = 0.20
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
false, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
local gain = getScore() - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..(os.time()-startTime)..
" fails="..str )
SetSAParamDefaults()
abbr = "50CI"
tempFunc = TEMPFUNCNAME_LOW50
runcount = SA_NUMSTARTS_LOW50
numSteps = SA_STEPSPERRUN_LOW50
actionPicker = PickLowCIAction
failNoGain = SA_FAILIFNOGAIN_DEFAULT
print( "SA-LowCI50 for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
ExactSetCI( 0.50 )
CI_MAXSCALE = 0.50
initScore = getScore()
startTime = os.time()
stepCt2 = PerformSA(
runcount, numSteps,
false, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
local gain = getScore() - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt2..
" time="..(os.time()-startTime)..
" fails="..str )
USE_LOWCI_WIGGLES = false
ExactSetCI( savCI )
CI_MAXSCALE = savCI
return stepCt + stepCt2
end
function PerformContactMapOperation( )
SetSAParamDefaults()
local abbr = "CMAP"
local tempFunc = TEMPFUNCNAME_CMAP
local runcount = SA_NUMSTARTS_CMAP
local numSteps = SA_STEPSPERRUN_CMAP
local actionPicker = PickContactMapAction
local failNoGain = SA_FAILIFNOGAIN_DEFAULT
print( "SA-Contact for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
false, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
local gain = getScore() - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..(os.time()-startTime)..
" fails="..str )
return stepCt
end
function PickLunchBuffetAction( )
local idx = PickIdxForAction( )
return PickActionFromList( LunchBuffetActions, idx )
end
function PerformLunchBuffetOperation( )
SetSAParamDefaults()
local abbr = "LUNCH"
local initScore = getScore()
local stepCt, endTime, endScore
if DO_WALKER_BUFFET then
stepCt, endTime, endScore = PerformWalker(
ACTION_ORDERPROTOCOL_BUFFET,
LunchBuffetActions,
QS_Best, abbr )
else
PROB_TARGETED = PROB_TARGETED_BUFFET
local tempFunc = TEMPFUNCNAME_BUFFET
local runcount = SA_NUMSTARTS_BUFFET
local numSteps = SA_STEPSPERRUN_BUFFET
local actionPicker = PickLunchBuffetAction
failNoGain = SA_FAILIFNOGAIN_DEFAULT
print( "SA-Buffet for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if #LunchBuffetActions == 0 then
print("No actions provided to perform - bailing")
return 0
end
local startTime = os.time()
stepCt = PerformSA(
runcount, numSteps,
false, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
endTime = os.time()-startTime
endScore = getScore()
end
local gain = endScore - initScore
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..endTime..
" score="..TrimNum(endScore))
return stepCt
end
function PickTestAction( )
local idx = PickIdxForAction( )
-- idx = SOMETHING USER WANTS TO FORCE?
allowedActions = { }
-- put the action to test here!
allowedActions[ #allowedActions + 1] = "Remix"
allowedActions[ #allowedActions + 1] = "RemixXToY"
return PickActionFromList( allowedActions, idx )
end
function PerformTestSA( )
SetSAParamDefaults()
local abbr = "TEST"
PROB_TARGETED = PROB_TARGETED_TEST
local tempFunc = TEMPFUNCNAME_TEST
local runcount = SA_NUMSTARTS_TEST
local numSteps = SA_STEPSPERRUN_TEST
local actionPicker = PickTestAction
local failNoGain = SA_FAILIFNOGAIN_DEFAULT
local allowFailOut = true
print( "SA-Test for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc)
if allowFailOut then
print("Move on if "..failNoGain.." rounds have too little gain")
end
local initScore = getScore()
local startTime = os.time()
local stepCt = PerformSA(
runcount, numSteps,
allowFailOut, SA_MINGAIN, failNoGain,
actionPicker, tempFunc, QS_Best, abbr )
local gain = getScore() - initScore
local str = "{"
for i=1,#CountFails do
str = str..CountFails[i]
if i < #CountFails then str = str.."," else str = str .."}" end
end
print( abbr..": gain="..TrimNum(gain)..
" steps="..stepCt..
" time="..(os.time()-startTime)..
" fails="..str )
return stepCt
end
function PerformTestOperation( )
-- Options offered so far:
-- 1. Pick "Test" operation: Adjust PickTestAction
-- 2. Pick a still-being-tested operation that isn't directly offered
-- 3. Loop over calls to CreateNeighborPose: Adjust PickTestAction
--local steps = PerformTestSA( )
local steps = PerformDeepRebuildOperation( true, "TEST" )
-- for i=1,50 do CreateNeighborPose( PickTestAction ) end
return steps
end
function PerformSASequence( )
SaveBest( )
print( "Begin SA Sequence" )
local scoreInit = getScore( )
timeInit = os.time( )
local stepsLate = 0
local timeLate = 0
local gainLate = 0.0
local stepsWswsw,stepsStab1,stepsStab2,timeWswsw, timeStab1, timeStab2,scoreWswsw,scoreStab1,scoreStab2
if not SASEQ_SKIP_STABILIZER then
stepsWswsw, stepsStab1,stepsStab2,
timeWswsw, timeStab1, timeStab2,
scoreWswsw,scoreStab1,scoreStab2 = PerformStabilizerOperation( )
save.Quicksave( QS_SA_BestEarly )
print( "SASEQ-Stab finished - qs "..QS_SA_BestEarly..
": time="..timeWswsw+timeStab1+timeStab2 )
else
stepsWswsw,stepsStab1,stepsStab2,timeWswsw,timeStab1,timeStab2,scoreWswsw,scoreStab1,scoreStab2 =
0,0,0, 0,0,0, 0.0,0.0,0.0
end
if SASEQ_DISABLE_UBAND_AFTER_STAB then
DISABLE_ALL_USER_BANDS = true
end
-- EARLY
local stepsEarly1,stepsEarly2,
timeEarly1,timeEarly2,
scoreEarly1,scoreEarly2 = PerformEarlyOperation()
save.Quicksave( QS_SA_BestEarly )
print( "SASEQ-Early finished - qs "..QS_SA_BestEarly..
": time="..timeEarly1+timeEarly2 )
if SASEQ_DISABLE_UBAND_AFTER_EARLY then
DISABLE_ALL_USER_BANDS = true
end
-- REBUILD
local stepsRebuild1,stepsRebuild2,
timeRebuild1,timeRebuild2,
scoreRebuild1,scoreRebuild2 = PerformRebuildOperation()
save.Quicksave( QS_SA_BestRebuild )
print( "SARebuild finished - qs "..QS_SA_BestRebuild..
": time="..timeRebuild1+timeRebuild2 )
-- MIDGAME
local stepsMid,timeMid,scoreMid = PerformMidgameOperation()
print( "SAMidgame finished: time="..timeMid )
-- LATE -- I question caller's wisdom, but do as they asked...
if ALLOW_FUSE then
save.Quicksave( QS_SA_BestMidgame )
print( "SAMidgame result stored in qs "..QS_SA_BestMidgame )
stepsLate,timeLate,scoreLate = PerformLateOperation( )
print( "SALate finished: time="..timeLate )
end
-- ENDGAME
local stepsCW,stepsEnd,timeCW,timeEnd,scoreCW,scoreEnd
if not SASEQ_SKIP_ENDGAME then
stepsCW,stepsEnd,timeCW,timeEnd,scoreCW,scoreEnd = PerformEndgameOperation()
print( "SAEndgame finished: time="..timeEnd )
else
stepsCW,stepsEnd,timeCW,timeEnd,scoreCW,scoreEnd = 0,0, 0,0, 0.0,0.0
end
-- GIVE REPORT TO USER
local timeEarly = timeEarly1+timeEarly2
local stepsEarly = stepsEarly1+stepsEarly2
local scoreEarly = math.max( scoreEarly1, scoreEarly2 )
print( "End SASequence: initScore=" ..TrimNum(scoreInit)..
" gain="..(getScore( ) - scoreInit)..
" time="..(os.time( ) - timeInit ))
print("Early steps: Early1="..stepsEarly1.." Early2="..stepsEarly2)
print("Early times: Early1="..timeEarly1.. " Early2="..timeEarly2)
print( " Stage Time Steps Score" )
if not SASEQ_SKIP_STABILIZER then
print( " Wswsw: " ..PadNumString(timeWswsw,7).. " " ..PadNumString(stepsWswsw,5).. " " .. TrimNum(scoreWswsw))
print( " Stab1: " ..PadNumString(timeStab1,7).. " " ..PadNumString(stepsStab1,5).. " " .. TrimNum(scoreStab1))
print( " Stab2: " ..PadNumString(timeStab2,7).. " " ..PadNumString(stepsStab2,5).. " " .. TrimNum(scoreStab2))
end
print( " Early1/2: " ..PadNumString(timeEarly,7).. " " ..PadNumString(stepsEarly,5).. " " .. TrimNum(scoreEarly))
print( " Rebuild1: " ..PadNumString(timeRebuild1,7).." " ..PadNumString(stepsRebuild1,5).. " " .. TrimNum(scoreRebuild1))
print( " Rebuild2: " ..PadNumString(timeRebuild2,7).." " ..PadNumString(stepsRebuild2,5).. " " .. TrimNum(scoreRebuild2))
print( " Midgame: " ..PadNumString(timeMid,7).. " " ..PadNumString(stepsMid,5).. " " .. TrimNum(scoreMid))
if ALLOW_FUSE then
print( " Late: " ..PadNumString(timeLate,7).." " ..PadNumString(stepsLate,5).. " " .. TrimNum(scoreLate))
end
if not SASEQ_SKIP_ENDGAME then
print( " CW : " ..PadNumString(timeCW,7).. " " ..PadNumString(stepsCW,5).. " " .. TrimNum(scoreCW))
print( " Endgame: " ..PadNumString(timeEnd,7).. " " ..PadNumString(stepsEnd,5).. " " .. TrimNum(scoreEnd))
end
print( "Time so far: "..(os.time() - StartTime))
end
function PerformOperation( operation )
local moInitialScore = getScore( )
local moInitialTime = os.time( )
local numSteps = 0
local failNoGain = 0
local stepCt = 0
local stepCt2 = 0
CtRebuildFails = 0 -- global that gets incremented when a rebuild fails
SaveBest( )
if CtRebuildFails >= MAX_REBUILD_FAILS then
print( "rebuild fail count exceeded in PerformOperation")
CtRebuildFails = 0
return
end
if operation == "SASequence" then
PerformSASequence( )
elseif operation == "SAStab" then
stepCt, stepCt2 = PerformStabilizerOperation( )
stepCt = stepCt + stepCt2
print( "SA-Stabilizer finished" )
elseif operation == "SAEarly" then
stepCt, stepCt2 = PerformEarlyOperation( )
stepCt = stepCt + stepCt2
print( "SA-Early finished" )
elseif operation == "SARebuild" then
stepCt, stepCt2 = PerformRebuildOperation( )
stepCt = stepCt + stepCt2
print( "SARebuild finished" )
elseif operation == "SAMidgame" then
stepCt = PerformMidgameOperation()
print( "SA-Midgame finished" )
elseif operation == "SAEndgame" then
stepCt, stepCt2 = PerformEndgameOperation()
stepCt = stepCt + stepCt2
print( "SA-Endgame finished" )
elseif operation == "SAShortStab" then
stepCt = PerformStab1Operation( )
print( "SA-Stab1 finished" )
elseif operation == "SALongStab" then
stepCt = PerformStab2Operation( )
print( "SA-Stab2 finished" )
elseif operation == "SAEarlyMove" then
stepCt = PerformEarly1Operation( )
print( "SA-EarlyMove finished" )
elseif operation == "SAEarlyIdeal" then
stepCt = PerformEarly2Operation( )
print( "SA-EarlyIdeal finished" )
elseif operation == "SARebuildBasic" then
stepCt = PerformRebuildOperation( )
print( "SA-RebuildBasic finished" )
elseif operation == "SARebuildDeep" then
stepCt = PerformDeepRebuildOperation( )
print( "SA-RebuildDeep finished" )
elseif operation == "SALowCI" then
stepCt = PerformLowCIOperation( )
print( "SA-LowCI finished" )
elseif operation == "SALate" then
stepCt = PerformLateOperation( )
print( "SA-Late finished" )
elseif operation == "SAContact" then
stepCt = PerformContactMapOperation( )
print( "SA-Contact finished" )
elseif operation == "SATest" then
stepCt = PerformTestOperation( )
print( "SA-Test finished" )
elseif operation == "SALunchBuffet" then
stepCt = PerformLunchBuffetOperation( )
print( "SA-Buffet finished" )
else
if operation == nil then print("!! No operation given")
else print( "!! Unknown operation: ".. operation )
end
end
LoadBest( )
return stepCt
end
-----------------------------------------------------------------------------
-- DIALOG BOX SEQUENCE FROM THE NETHERWORLD
-----------------------------------------------------------------------------
function PutMutateOptionsInBox( dlg )
dlg.MutateCI = dialog.AddSlider( "Mutate CI", CI_MUTATE, 0, 1, 2 )
dlg.noMutateAas = dialog.AddTextbox( "No-mutate AAs", "" )
end
function SetMutateOptions( dlg )
CI_MUTATE = dlg.MutateCI.value
DebugPrint("MutateCI="..CI_MUTATE)
if dlg.noMutateAas.value ~= nil and dlg.noMutateAas.value ~= "" then
NoMutateList = parseRangesStr( dlg.noMutateAas.value )
DebugPrint("NoMutateList has "..(#NoMutateList).." segs" )
if DEBUGRUN and #NoMutateList > 0 then
printVector( NoMutateList, "NoMutate", false )
else
DebugPrint("Error Parsing: No ranges selected")
end
end
end
function PutSlowWiggleOptionsInBox( dlg )
dlg.swgain = dialog.AddSlider( "Fuse-WiggleGain", FUSEWIGGLE_GAIN, 0, 0.50, 2 )
dlg.swCmt = dialog.AddLabel( "Values will be scaled to sum to 1" )
dlg.wloc = dialog.AddSlider( "LocalWiggler", PROB_FUSEWIGGLE_LOCAL, 0, 1, 2 ) -- slow, poor
dlg.wbfuse= dialog.AddSlider( "BlueFuse", PROB_FUSEWIGGLE_BLUEFUSE, 0, 1, 2 ) -- less slow, moderately good
dlg.wcwfuse= dialog.AddSlider( "C&WFuse", PROB_FUSEWIGGLE_CUTFUSE, 0, 1, 2 ) -- slow, moderately good
end
function SetSlowWiggleOptions( dlg )
FUSEWIGGLE_GAIN = dlg.swgain.value
local t1 = dlg.wloc.value
local t2 = dlg.wbfuse.value
local t3 = dlg.wcwfuse.value
if t1 + t2 + t3 == 0 then
t1 = .25 -- not a problem that these don't sum to 1: they'll be scaled
t2 = .25
t3 = .25
end
PROB_FUSEWIGGLE_LOCAL = t1 / ( t1 + t2 + t3 )
PROB_FUSEWIGGLE_BLUEFUSE = t2 / ( t1 + t2 + t3 )
PROB_FUSEWIGGLE_CUTFUSE = t3 / ( t1 + t2 + t3 )
DebugPrint( "SlowGain="..FUSEWIGGLE_GAIN )
DebugPrint( "Prob_slowwiggle-local="..PROB_FUSEWIGGLE_LOCAL )
DebugPrint( "Prob_slowwiggle-bluefuse="..PROB_FUSEWIGGLE_BLUEFUSE )
DebugPrint( "Prob_slowwiggle-cutfuse="..PROB_FUSEWIGGLE_CUTFUSE )
end
function PutBanderOptionsInBox( dlg )
dlg.bdrbci = dialog.AddSlider( "RegionBandCI", CI_REGIONMOD, 0.01, 1.0, 2 )
dlg.mbshakeci = dialog.AddSlider( "MultiBandShakeCI", CI_MULTIBAND_SHAKE, 0.01, 1.0, 2 )
dlg.mbpullci = dialog.AddSlider( "MultiBandPullCI", CI_MULTIBAND_PULL, 0.01, 1.0, 2 )
dlg.bdcpci = dialog.AddSlider( "CorePullingCI", CI_COREPULLING, 0.01, 1.0, 2 )
dlg.bdwigtargdelta = dialog.AddSlider( "BWig ScoreDelta", BANDEDWIGGLE_TARGET, 50, 1000, 0 )
dlg.bdwigmincompr = dialog.AddSlider( "MinCompress", BAND_MINCOMPRESS, BAND_MINCOMPRESS/2, 1.00, 2 )
dlg.maxgentlecompr = dialog.AddSlider( "MaxGentCompr", BAND_MAXGENTLECOMPRESS, BAND_MAXGENTLECOMPRESS/2, 1.00, 2 )
dlg.bdwigmaxcompr = dialog.AddSlider( "MaxCompress", BAND_MAXCOMPRESS, BAND_MAXCOMPRESS/2, 1.00, 2 )
dlg.bdwigminexpand = dialog.AddSlider( "MinExpand", BAND_MINEXPAND, 1.00, 1.10, 2 )
dlg.maxgentleexpand = dialog.AddSlider( "MaxGentExpand", BAND_MAXGENTLEEXPAND, 1.0, 2.0, 2 )
dlg.bdwigmaxexpand = dialog.AddSlider( "MaxExpand", BAND_MAXEXPAND, 1.00, 3.00, 2 )
end
function SetBanderOptions( dlg )
CI_REGIONMOD = dlg.bdrbci.value
CI_MULTIBAND_SHAKE = dlg.mbshakeci.value
CI_MULTIBAND_PULL = dlg.mbpullci.value
CI_COREPULLING = dlg.bdcpci.value
BANDEDWIGGLE_TARGET = dlg.bdwigtargdelta.value
BAND_MINCOMPRESS = dlg.bdwigmincompr.value
BAND_MAXGENTLECOMPRESS = dlg.maxgentlecompr.value
BAND_MAXCOMPRESS = dlg.bdwigmaxcompr.value
BAND_MINEXPAND = dlg.bdwigminexpand.value
BAND_MAXGENTLEEXPAND = dlg.maxgentleexpand.value
BAND_MAXEXPAND = dlg.bdwigmaxexpand.value
DebugPrint("ReginmBander CI="..CI_REGIONMOD )
DebugPrint("MultiBand Pull CI="..CI_MULTIBAND_SHAKE )
DebugPrint("MultiBand Shake CI="..CI_MULTIBAND_PULL )
DebugPrint("Core-pulling CI="..CI_COREPULLING )
DebugPrint("Banded Wiggler Target Delta="..BANDEDWIGGLE_TARGET )
DebugPrint("Max Compress="..BAND_MAXCOMPRESS)
DebugPrint("Max Gentle Compress="..BAND_MAXGENTLECOMPRESS)
DebugPrint("Min Compress="..BAND_MINCOMPRESS)
DebugPrint("Min Expand="..BAND_MINEXPAND )
DebugPrint("Max Gentle Expand="..BAND_MAXGENTLEEXPAND )
DebugPrint("Max Expand="..BAND_MAXEXPAND )
end
function PutIdealizeOptionsInBox( dlg )
dlg.sepIdealizer = dialog.AddLabel( "--------------Idealize Options--------------------" )
dlg.idMinRange = dialog.AddSlider( "MinIdealizeLen", IDEALIZE_MIN_SEGLEN, 1, 20, 0 )
dlg.idMaxRange = dialog.AddSlider( "MaxIdealizeLen", IDEALIZE_MAX_SEGLEN, 1, 20, 0 )
dlg.idradius = dialog.AddSlider( "IdealizeRadius", IDEALIZE_TUBE_SMALL_RADIUS, 1.0, 20.0, 2 )
dlg.idradshake = dialog.AddSlider( "WiggleShakeRadius", IDEALIZE_TUBE_BIG_RADIUS, 1.0, 20.0, 2 )
dlg.idusecuts = dialog.AddCheckbox( "Allow cuts during idealize", IDEALIZE_USE_CUTS )
dlg.idmusthealcuts = dialog.AddCheckbox( "Forbid unhealed cuts after idealize", IDEALIZE_FORBID_UNHEALED_CUTS )
end
function SetIdealizeOptions( dlg )
IDEALIZE_MIN_SEGLEN = dlg.idMinRange.value
IDEALIZE_MAX_SEGLEN = dlg.idMaxRange.value
IDEALIZE_TUBE_SMALL_RADIUS = dlg.idradius.value
IDEALIZE_TUBE_BIG_RADIUS = dlg.idradshake.value
IDEALIZE_USE_CUTS = dlg.idusecuts.value
IDEALIZE_FORBID_UNHEALED_CUTS = dlg.idmusthealcuts.value
DebugPrint("Idealize range: "..IDEALIZE_MIN_SEGLEN.."-"..IDEALIZE_MAX_SEGLEN )
if IDEALIZE_USE_CUTS then DebugPrint("Cuts will be made") else DebugPrint("Cuts are forbidden") end
if IDEALIZE_FORBID_UNHEALED_CUTS then DebugPrint("Cuts must heal to be accepted") else DebugPrint("Cuts permitted to survive") end
DebugPrint("Radius of idealization: "..IDEALIZE_TUBE_SMALL_RADIUS)
DebugPrint("Radius of shake/wiggle: "..IDEALIZE_TUBE_BIG_RADIUS)
end
function PutlRebuildSubOptionsInBox( dlg )
dlg.sepRb = dialog.AddLabel( "--------------Rebuild Options--------------------" )
dlg.rebDeepMaxTries = dialog.AddSlider( "Deep Rebuild tries", REBUILD_DEEP_MAXTRIES, 1, 20, 0 )
dlg.rebuildMinRange = dialog.AddSlider( "MinRebuildLength", REBUILD_MIN_SEGLEN, 1, 20, 0 )
dlg.rebuildMaxRange = dialog.AddSlider( "MaxRebuildLength", REBUILD_MAX_SEGLEN, 1, 20, 0 )
dlg.rebDeepInnerRad = dialog.AddSlider( "DeepRebShortRadius", REBUILD_TUBE_INNER_RADIUS, 5.0, 20.0, 2 )
dlg.rebDeepOuterRad = dialog.AddSlider( "DeepRebLongRadius", REBUILD_TUBE_OUTER_RADIUS, 5.0, 25.0, 2 )
dlg.rebQuakingRad = dialog.AddSlider( "QuakeReb radius", REBUILD_TUBE_SMALLEST_RADIUS, 5.0, 20.0, 2 )
dlg.rebWantIdealize = dialog.AddCheckbox( "Idealize with rebuilds?", REBUILD_ADDIDEALIZE )
end
function SetRebuildSubOptions( dlg )
REBUILD_DEEP_MAXTRIES = dlg.rebDeepMaxTries.value
REBUILD_MIN_SEGLEN = dlg.rebuildMinRange.value
REBUILD_MAX_SEGLEN = dlg.rebuildMaxRange.value
REBUILD_ADDIDEALIZE = dlg.rebWantIdealize.value
REBUILD_TUBE_INNER_RADIUS = dlg.rebDeepInnerRad.value
REBUILD_TUBE_OUTER_RADIUS = dlg.rebDeepOuterRad.value
REBUILD_TUBE_SMALLEST_RADIUS = dlg.rebQuakingRad.value
DebugPrint( "TriesPerStep="..REBUILD_DEEP_MAXTRIES )
DebugPrint( "Rebuild range="..REBUILD_MIN_SEGLEN.."-"..REBUILD_MAX_SEGLEN )
DebugPrint( "Rebuilds can idealize? "..BoolStr( REBUILD_ADDIDEALIZE))
DebugPrint( "DeepReb short radius: "..REBUILD_TUBE_INNER_RADIUS )
DebugPrint( "DeepReb long radius: "..REBUILD_TUBE_OUTER_RADIUS )
DebugPrint( "Quaking Rebuild radius: "..REBUILD_TUBE_SMALLEST_RADIUS )
end
function PutRemixOptionsInBox( dlg )
dlg.sepRemix = dialog.AddLabel( "--------------Remix Options--------------------" )
dlg.remixMaxSlots = dialog.AddSlider( "Remix slots", REMIX_SLOTS_WANTED, 1, REMIX_MAX_SLOTS_TO_USE, 0 )
dlg.remixMaxSlotsToWiggle = dialog.AddSlider( "#SlotsToDeepTest", REMIX_MAX_SLOTS_TO_WIGGLE, 1, REMIX_MAX_SLOTS_TO_USE, 0 )
dlg.remixMinRange = dialog.AddSlider( "MinRemixLength", REMIX_MIN_SEGLEN, 1, 20, 0 )
dlg.remixMaxRange = dialog.AddSlider( "MaxRemixLength", REMIX_MAX_SEGLEN, 1, 20, 0 )
dlg.remixInnerRad = dialog.AddSlider( "RemixShortRadius", REMIX_TUBE_INNER_RADIUS, 5.0, 20.0, 2 )
dlg.remixOuterRad = dialog.AddSlider( "RemixLongRadius", REMIX_TUBE_OUTER_RADIUS, 5.0, 25.0, 2 )
end
function SetRemixOptions( dlg )
REMIX_SLOTS_WANTED = dlg.remixMaxSlots.value
REMIX_MAX_SLOTS_TO_WIGGLE = dlg.remixMaxSlotsToWiggle.value
REMIX_MIN_SEGLEN = dlg.remixMinRange.value
REMIX_MAX_SEGLEN = dlg.remixMaxRange.value
REMIX_TUBE_INNER_RADIUS = dlg.remixInnerRad.value
REMIX_TUBE_OUTER_RADIUS = dlg.remixOuterRad.value
DebugPrint( "Slots to use="..REMIX_SLOTS_WANTED )
DebugPrint( "Slots to wiggle="..REMIX_MAX_SLOTS_TO_WIGGLE )
DebugPrint( "Remix range="..REBUILD_MIN_SEGLEN.."-"..REBUILD_MAX_SEGLEN )
DebugPrint( "Remix short radius: "..REMIX_TUBE_INNER_RADIUS )
DebugPrint( "Remix long radius: "..REMIX_TUBE_OUTER_RADIUS )
end
function PutDecementingOptionsInBox( dlg )
dlg.fightCementEa1 = dialog.AddCheckbox( "Do decement runs in EarlyMover", FIGHT_CEMENTING_EARLY1 )
dlg.fightCementEa2 = dialog.AddCheckbox( "Do decement runs in EarlyIdeal", FIGHT_CEMENTING_EARLY2 )
dlg.whenStartDecem = dialog.AddSlider("Fails till start", FailsToStartCementBreaking, 1, 2*FailsToStartCementBreaking, 0 )
dlg.ctDecement = dialog.AddSlider("Decement steps", StepsForCementBreaking, 1, 2*StepsForCementBreaking, 0 )
dlg.stepsperCem = dialog.AddSlider("Run steps", SA_STEPSPERRUN_DECEMENT, 1, 10*SA_STEPSPERRUN_DECEMENT, 0 )
end
function SetDecementingOptions( dlg )
FIGHT_CEMENTING_EARLY1 = dlg.fightCementEa1.value
FIGHT_CEMENTING_EARLY2 = dlg.fightCementEa2.value
SA_STEPSPERRUN_DECEMENT = dlg.ctDecement.value
FailsToStartCementBreaking = dlg.stepsperCem.value
StepsForCementBreaking = dlg.whenStartDecem.value
DebugPrint("Decement in Early1? "..BoolStr( FIGHT_CEMENTING_EARLY1 ))
DebugPrint("Decement in Early2? "..BoolStr( FIGHT_CEMENTING_EARLY2 ))
DebugPrint("Decement steps,fails,ctDecement="..SA_STEPSPERRUN_DECEMENT..","..FailsToStartCementBreaking..
","..StepsForCementBreaking )
end
function PutLowCI20OptionsInBox( dlg )
dlg.stepsperLCI20 = dialog.AddSlider( "Steps20CI", SA_STEPSPERRUN_LOW20, 1, 3*SA_STEPSPERRUN_LOW20, 0 )
dlg.startsLCI20 = dialog.AddSlider( "Runs20CI", SA_NUMSTARTS_LOW20, 1, 10*SA_NUMSTARTS_LOW20, 0 )
end
function SetLowCI20Options( dlg )
SA_STEPSPERRUN_LOW20 = dlg.stepsperLCI20.value
SA_NUMSTARTS_LOW20 = dlg.startsLCI20.value
DebugPrint("LowCI steps,starts="..SA_STEPSPERRUN_LOW20..","..SA_NUMSTARTS_LOW20 )
return true
end
function PutLowCI50OptionsInBox( dlg )
dlg.stepsperLCI50 = dialog.AddSlider( "Steps50CI", SA_STEPSPERRUN_LOW50, 1, 3*SA_STEPSPERRUN_LOW50, 0 )
dlg.startsLCI50 = dialog.AddSlider( "Runs50CI", SA_NUMSTARTS_LOW50, 1, 10*SA_NUMSTARTS_LOW50, 0 )
end
function SetLowCI50Options( dlg )
SA_STEPSPERRUN_LOW50 = dlg.stepsperLCI50.value
SA_NUMSTARTS_LOW50 = dlg.startsLCI50.value
DebugPrint("LowCI steps,starts="..SA_STEPSPERRUN_LOW50..","..SA_NUMSTARTS_LOW50 )
return true
end
function PutLowCIOptionsInBox( dlg )
PutLowCI20OptionsInBox( dlg )
PutLowCI50OptionsInBox( dlg )
end
function SetLowCIOptions( dlg )
SetLowCI20Options( dlg )
SetLowCI50Options( dlg )
return true
end
function PutStab1OptionsInBox( dlg )
dlg.stepsperSt1 = dialog.AddSlider( "StepsStab1", SA_STEPSPERRUN_STAB1, 1, 3*SA_STEPSPERRUN_STAB1, 0 )
dlg.startsSt1 = dialog.AddSlider( "RunsStab1", SA_NUMSTARTS_STAB1, 1, 10*SA_NUMSTARTS_STAB1, 0 )
dlg.quitnogainSt1 = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_STAB1, 1, 5*SA_FAILIFNOGAIN_STAB1, 0 )
end
function SetStab1Options( dlg )
SA_STEPSPERRUN_STAB1 = dlg.stepsperSt1.value
SA_NUMSTARTS_STAB1 = dlg.startsSt1.value
SA_FAILIFNOGAIN_STAB1 = dlg.quitnogainSt1.value
DebugPrint("EarlyStab1 steps,starts,quit="..SA_STEPSPERRUN_STAB1..","..SA_NUMSTARTS_STAB1..","..SA_FAILIFNOGAIN_STAB1 )
return true
end
function PutStab2OptionsInBox( dlg )
dlg.stepsperSt2 = dialog.AddSlider( "StepsStab2", SA_STEPSPERRUN_STAB2, 1, 3*SA_STEPSPERRUN_STAB2, 0 )
dlg.startsSt2 = dialog.AddSlider( "RunsStab2", SA_NUMSTARTS_STAB2, 1, 10*SA_NUMSTARTS_STAB2, 0 )
dlg.quitnogainSt2 = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_STAB2, 1, 5*SA_FAILIFNOGAIN_STAB2, 0 )
end
function SetStab2Options( dlg )
SA_STEPSPERRUN_STAB2 = dlg.stepsperSt2.value
SA_NUMSTARTS_STAB2 = dlg.startsSt2.value
SA_FAILIFNOGAIN_STAB2 = dlg.quitnogainSt2.value
DebugPrint("EarlyStab2 steps,starts,quit="..SA_STEPSPERRUN_STAB2..","..SA_NUMSTARTS_STAB2..","..SA_FAILIFNOGAIN_STAB2 )
return true
end
function PutEarly1OptionsInBox( dlg )
dlg.stepsperEa1 = dialog.AddSlider( "StepsEarlyMove", SA_STEPSPERRUN_EARLY1, 1, 3*SA_STEPSPERRUN_EARLY1, 0 )
dlg.startsEa1 = dialog.AddSlider( "RunsEarlyMove", SA_NUMSTARTS_EARLY1, 1, 10*SA_NUMSTARTS_EARLY1, 0 )
dlg.quitnogainEa1 = dialog.AddSlider("Stop at N fails", SA_FAILIFNOGAIN_EARLY1, 1, 5*SA_FAILIFNOGAIN_EARLY1, 0 )
end
function SetEarly1Options( dlg )
SA_STEPSPERRUN_EARLY1 = dlg.stepsperEa1.value
SA_NUMSTARTS_EARLY1 = dlg.startsEa1.value
SA_FAILIFNOGAIN_EARLY1 = dlg.quitnogainEa1.value
DebugPrint("EarlyMove steps,starts,quit="..SA_STEPSPERRUN_EARLY1..","..SA_NUMSTARTS_EARLY1..","..SA_FAILIFNOGAIN_EARLY1 )
return true
end
function PutEarly2OptionsInBox( dlg )
dlg.stepsperEa2 = dialog.AddSlider( "StepsEarlyIdeal", SA_STEPSPERRUN_EARLY2, 1, 3*SA_STEPSPERRUN_EARLY2, 0 )
dlg.startsEa2 = dialog.AddSlider( "RunsEarlyIdeal", SA_NUMSTARTS_EARLY2, 1, 10*SA_NUMSTARTS_EARLY2, 0 )
dlg.quitnogainEa2 = dialog.AddSlider("Stop at N fails", SA_FAILIFNOGAIN_EARLY2, 1, 5*SA_FAILIFNOGAIN_EARLY2, 0 )
end
function SetEarly2Options( dlg )
SA_STEPSPERRUN_EARLY2 = dlg.stepsperEa2.value
SA_NUMSTARTS_EARLY2 = dlg.startsEa2.value
SA_FAILIFNOGAIN_EARLY2 = dlg.quitnogainEa2.value
DebugPrint("EarlyIdeal steps,starts,quit="..SA_STEPSPERRUN_EARLY2..","..SA_NUMSTARTS_EARLY2..","..SA_FAILIFNOGAIN_EARLY2 )
return true
end
function PutStabOptionsInBox( dlg )
PutStab1OptionsInBox( dlg )
PutStab2OptionsInBox( dlg )
end
function SetStabOptions( dlg )
SetStab1Options( dlg )
SetStab2Options( dlg )
return true
end
function PutEarlyOptionsInBox( dlg )
PutEarly1OptionsInBox( dlg )
PutEarly2OptionsInBox( dlg )
dlg.minEarly = dialog.AddSlider("Min runs of Early", MIN_TRIES_EARLY_OP, 1, 2*MIN_TRIES_EARLY_OP, 0)
dlg.maxEarly = dialog.AddSlider("Max runs of Early", MAX_TRIES_EARLY_OP, 1, 2*MAX_TRIES_EARLY_OP, 0)
end
function SetEarlyOptions( dlg )
SetEarly1Options( dlg )
SetEarly2Options( dlg )
MIN_TRIES_EARLY_OP = dlg.minEarly.value
MAX_TRIES_EARLY_OP = dlg.maxEarly.value
DebugPrint("MinTries, MaxTries = "..MIN_TRIES_EARLY_OP..","..MAX_TRIES_EARLY_OP)
return true
end
function PutRebuild1OptionsInBox( dlg )
dlg.stepsperRb = dialog.AddSlider( "StepsRebuild1", SA_STEPSPERRUN_REBUILD, 1, 3*SA_STEPSPERRUN_REBUILD, 0 )
dlg.startsRb = dialog.AddSlider( "RunsRebuild1", SA_NUMSTARTS_REBUILD, 1, 10*SA_NUMSTARTS_REBUILD, 0 )
dlg.quitnogainRb = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_REBUILD, 1, 5*SA_FAILIFNOGAIN_REBUILD, 0 )
end
function SetRebuild1Options( dlg )
SA_STEPSPERRUN_REBUILD = dlg.stepsperRb.value
SA_NUMSTARTS_REBUILD = dlg.startsRb.value
SA_FAILIFNOGAIN_REBUILD = dlg.quitnogainRb.value
DebugPrint("RebuildBasic steps,starts,quit="..SA_STEPSPERRUN_REBUILD..","..SA_NUMSTARTS_REBUILD..","..SA_FAILIFNOGAIN_REBUILD )
return true
end
function PutRebuild2OptionsInBox( dlg )
dlg.stepsperRb2 = dialog.AddSlider( "StepsRebuild2", SA_STEPSPERRUN_DEEPREBUILD, 1, 3*SA_STEPSPERRUN_DEEPREBUILD, 0 )
dlg.startsRb2 = dialog.AddSlider( "RunsRebuild2", SA_NUMSTARTS_DEEPREBUILD, 1, 10*SA_NUMSTARTS_DEEPREBUILD, 0 )
dlg.quitnogainRb2 = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_DEEPREBUILD, 1, 5*SA_FAILIFNOGAIN_DEEPREBUILD, 0 )
end
function SetRebuild2Options( dlg )
SA_STEPSPERRUN_DEEPREBUILD = dlg.stepsperRb2.value
SA_NUMSTARTS_DEEPREBUILD = dlg.startsRb2.value
SA_FAILIFNOGAIN_DEEPREBUILD = dlg.quitnogainRb2.value
DebugPrint("RebuildDeep steps,starts,quit="..SA_STEPSPERRUN_DEEPREBUILD..","..SA_NUMSTARTS_DEEPREBUILD..","..SA_FAILIFNOGAIN_DEEPREBUILD )
return true
end
function PutRebuildOptionsInBox( dlg )
dlg.skipBasicRebuild = dialog.AddCheckbox( "Skip basic rebuild", false )
PutRebuild1OptionsInBox( dlg )
dlg.skipDeepRebuild = dialog.AddCheckbox( "Skip deep rebuild", false )
PutRebuild2OptionsInBox( dlg )
end
function SetRebuildOptions( dlg )
SASEQ_SKIP_BASICREBUILD = dlg.skipBasicRebuild.value
SASEQ_SKIP_DEEPREBUILD = dlg.skipDeepRebuild.value
if not SASEQ_SKIP_BASICREBUILD then
SetRebuild1Options( dlg )
end
if not SASEQ_SKIP_DEEPREBUILD then
SetRebuild2Options( dlg )
end
return true
end
function PutMidOptionsInBox( dlg )
dlg.stepsperMid = dialog.AddSlider( "StepsMid", SA_STEPSPERRUN_MIDGAME, 1, 3*SA_STEPSPERRUN_MIDGAME, 0 )
dlg.startsMid = dialog.AddSlider( "RunsMid", SA_NUMSTARTS_MIDGAME, 1, 10*SA_NUMSTARTS_MIDGAME, 0 )
dlg.quitnogainMid = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_MIDGAME, 1, 5*SA_FAILIFNOGAIN_MIDGAME, 0 )
end
function SetMidOptions( dlg )
SA_STEPSPERRUN_MIDGAME = dlg.stepsperMid.value
SA_NUMSTARTS_MIDGAME = dlg.startsMid.value
SA_FAILIFNOGAIN_MIDGAME = dlg.quitnogainMid.value
DebugPrint("Mid steps,starts,quit="..SA_STEPSPERRUN_MIDGAME..","..SA_NUMSTARTS_MIDGAME..","..SA_FAILIFNOGAIN_MIDGAME )
return true
end
function PutLateOptionsInBox( dlg )
dlg.stepsperLt = dialog.AddSlider( "StepsFuser", SA_STEPSPERRUN_LATE, 1, 3*SA_STEPSPERRUN_LATE, 0 )
dlg.startsLt = dialog.AddSlider( "RunsFuser", SA_NUMSTARTS_LATE, 1, 10*SA_NUMSTARTS_LATE, 0 )
end
function SetLateOptions( dlg )
SA_STEPSPERRUN_LATE = dlg.stepsperLt.value
SA_NUMSTARTS_LATE = dlg.startsLt.value
DebugPrint("Late steps,starts="..SA_STEPSPERRUN_LATE..","..SA_NUMSTARTS_LATE )
return true
end
function PutEndgameOptionsInBox( dlg )
dlg.endgameSkipCW = dialog.AddCheckbox( "Skip endgame CutAndWiggle start", SASEQ_ENDGAME_SKIP_CW )
dlg.minEnd = dialog.AddSlider("Min tries", MIN_TRIES_ENDGAME, 1, 3*MIN_TRIES_ENDGAME, 0)
dlg.maxEnd = dialog.AddSlider("Max tries", MAX_TRIES_ENDGAME, 1, 4*MAX_TRIES_ENDGAME, 0)
end
function SetEndgameOptions( dlg )
SASEQ_ENDGAME_SKIP_CW = dlg.endgameSkipCW.value
MIN_TRIES_ENDGAME = dlg.minEnd.value
MAX_TRIES_ENDGAME = dlg.maxEnd.value
DebugPrint("Skip CW fuse? "..BoolStr( SASEQ_ENDGAME_SKIP_CW ))
DebugPrint("Min Tries Endgame"..MIN_TRIES_ENDGAME)
DebugPrint("Max Tries Endgame"..MAX_TRIES_ENDGAME)
return true
end
function PutContactMapOptionsInBox( dlg )
dlg.CmapLabel = dialog.AddLabel( "---------- ContactMap Run Options ----------")
dlg.stepsperCMap = dialog.AddSlider( "StepsCMap", SA_STEPSPERRUN_CMAP, 1, 3*SA_STEPSPERRUN_CMAP, 0 )
dlg.startsCMap = dialog.AddSlider( "RunsLowCMap", SA_NUMSTARTS_CMAP, 1, 10*SA_NUMSTARTS_CMAP, 0 )
end
function SetContactMapOptions( dlg )
SA_STEPSPERRUN_CMAP = dlg.stepsperCMap.value
SA_NUMSTARTS_CMAP = dlg.startsCMap.value
DebugPrint("CMap steps,starts="..SA_STEPSPERRUN_CMAP..","..SA_NUMSTARTS_CMAP )
return true
end
function PutLunchBuffetEconomyOptionsInBox( dlg )
dlg.actGentCom = dialog.AddCheckbox( "GentleComp", false )
dlg.actGentComLo = dialog.AddCheckbox( "GentleCompLowCI", false )
dlg.actInhExh = dialog.AddCheckbox( "InhaleAndExhale", false )
dlg.actTailG = dialog.AddCheckbox( "TailGrab", false )
dlg.actVoidC = dialog.AddCheckbox( "VoidCrusher", false )
dlg.actPushP = dialog.AddCheckbox( "PushPull", false )
dlg.actGenrHin = dialog.AddCheckbox( "GeneralHinge", false )
dlg.actIdealR = dialog.AddCheckbox( "IdealizeRegion", false )
dlg.actIdealX = dialog.AddCheckbox( "IdealizeXToY", false )
dlg.actIdealizePt = dialog.AddCheckbox( "IdealizePoint", false )
dlg.actRbBits = dialog.AddCheckbox( "RebuildBitspawn", false )
dlg.actRbBitsLo = dialog.AddCheckbox( "RebuildBitspawnLowCI", false )
dlg.actQuakeRb = dialog.AddCheckbox( "QuakingRebuild", false )
dlg.actRebSimpPt = dialog.AddCheckbox( "RebuildSimplePoint", false )
dlg.actBWP = dialog.AddCheckbox( "BandedWormPair", false )
dlg.actLocalWiggle = dialog.AddCheckbox( "LocalWiggle", false )
dlg.actATSide = dialog.AddCheckbox( "ATSidechainTweak", false )
dlg.actATSideAround = dialog.AddCheckbox( "ATSidechainTweakAround", false )
dlg.cmtBlankBuffet = dialog.AddLabel("")
dlg.cmtBuffet = dialog.AddLabel("--- Expensive but useful ---")
dlg.actRemix = dialog.AddCheckbox( "Remix", false )
dlg.actATSideManipulate = dialog.AddCheckbox( "ATSidechainManipulate", false )
end
function SetLunchBuffetEconomyOptions( dlg )
if dlg.actGentCom.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "GentleComp" end
if dlg.actGentComLo.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "GentleCompLowCI" end
if dlg.actInhExh.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "InhaleAndExhale" end
if dlg.actTailG.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "TailGrab" end
if dlg.actVoidC.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "VoidCrusher" end
if dlg.actPushP.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "PushPull" end
if dlg.actGenrHin.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "GeneralHinge" end
if dlg.actIdealR.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "IdealizeRegion" end
if dlg.actIdealX.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "IdealizeXToY" end
if dlg.actIdealizePt.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "IdealizePoint" end
if dlg.actRbBits.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "RebuildBitspawn" end
if dlg.actRbBitsLo.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "RebuildBitspawnLowCI" end
if dlg.actQuakeRb.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "QuakingRebuild" end
if dlg.actRebSimpPt.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "RebuildSimplePoint" end
if dlg.actBWP.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "BandedWormPair" end
if dlg.actLocalWiggle.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "LocalWiggle" end
if dlg.actATSide.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "ATSidechainTweak" end
if dlg.actATSideAround.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "ATSidechainTweakAround" end
if dlg.actRemix.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "Remix" end
if dlg.actATSideManipulate.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "ATSidechainManipulate" end
end
function PutLunchBuffetBanderOptionsInBox( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_BANDER then
dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false )
end
end
end
function SetLunchBuffetBanderOptions( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_BANDER then
if dlg[ AllActionsList[i].nameStr].value then
LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr
end
end
end
end
function PutLunchBuffetRebuilderOptionsInBox( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_REBUILD or
AllActionsList[i].actionType == ACTION_TYPE_REMIXIDEAL
then
dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false )
end
end
end
function SetLunchBuffetRebuilderOptions( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_REBUILD or
AllActionsList[i].actionType == ACTION_TYPE_REMIXIDEAL
then
if dlg[ AllActionsList[i].nameStr].value then
LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr
end
end
end
end
function PutLunchBuffetQuakerOptionsInBox( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_QUAKER then
dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false )
end
end
end
function SetLunchBuffetQuakerOptions( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_QUAKER then
if dlg[ AllActionsList[i].nameStr].value then
LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr
end
end
end
end
function PutLunchBuffetEndgameOptionsInBox( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_ENDGAME then
dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false )
end
end
end
function SetLunchBuffetEndgameOptions( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_ENDGAME then
if dlg[ AllActionsList[i].nameStr].value then
LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr
end
end
end
end
function PutLunchBuffetDubiousOptionsInBox( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_DUBIOUS then
dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false )
end
end
end
function SetLunchBuffetDubiousOptions( dlg )
for i = 1, #AllActionsList do
if AllActionsList[i].actionType == ACTION_TYPE_DUBIOUS then
if dlg[ AllActionsList[i].nameStr].value then
LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr
end
end
end
end
function PutLunchBuffetRunOptionsInBox( dlg )
dlg.wantWalker = dialog.AddCheckbox( "Walker instead of SA?", DO_WALKER_BUFFET )
dlg.LBblankWSA = dialog.AddLabel( "" )
dlg.sepWalkerRunOpt = dialog.AddLabel( "---------- Walker Options ------------")
dlg.sepWalkerInfo = dialog.AddLabel( "For walker, pick order (topmost checked will be taken)")
dlg.walkerSE = dialog.AddCheckbox( "Start to End", true )
dlg.walkerES = dialog.AddCheckbox( "End to Start", false )
dlg.walkerR = dialog.AddCheckbox( "Random order", false )
dlg.walkerWB = dialog.AddCheckbox( "Worst to best", false )
dlg.sepBuffetRunOpt = dialog.AddLabel( "---------- SA Run Options ------------")
dlg.stepsperBuffet = dialog.AddSlider( "Steps", SA_STEPSPERRUN_BUFFET, 1, 3*SA_STEPSPERRUN_BUFFET, 0 )
dlg.startsBuffet = dialog.AddSlider( "Runs", SA_NUMSTARTS_BUFFET, 1, 10*SA_NUMSTARTS_BUFFET, 0 )
dlg.sepsaTempInfo = dialog.AddLabel( "For temp, slider is level of activity, 4=highest, 0=none")
dlg.sepsaTempInfo2 = dialog.AddLabel( " (4=T_OneOverX 3=T_MiddlingX 2=T_LowX 1=T_ColdX 0=T_Zero)")
dlg.tempControl = dialog.AddSlider( "Temp", 4, 0, 4, 0 )
end
function SetLunchBuffetRunOptions( dlg )
if dlg.wantWalker.value then
DO_WALKER_BUFFET = true
if dlg.walkerSE.value then
ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_START_TO_END
elseif dlg.walkerES.value then
ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_END_TO_START
elseif dlg.walkerR.value then
ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_RANDOMIZE
elseif dlg.walkerWB.value then
ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_WORST_TO_BEST
else
print("no order chosen: will default to Start-to-end")
ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_START_TO_END
end
DebugPrint("LunchBuffet walker: order="..ACTION_ORDERPROTOCOL_BUFFET)
else
DO_WALKER_BUFFET = false
SA_STEPSPERRUN_BUFFET = dlg.stepsperBuffet.value
SA_NUMSTARTS_BUFFET = dlg.startsBuffet.value
TEMPFUNCNAME_BUFFET = PickTempStringByNumber( dlg.tempControl.value )
DebugPrint("LunchBuffet SA steps,starts="..SA_STEPSPERRUN_BUFFET..","..SA_NUMSTARTS_BUFFET )
DebugPrint("LunchBuffet SA temp="..TEMPFUNCNAME_BUFFET)
end
return true
end
function PutLunchBuffetOptionsInBox( dlg )
dlg.cmtLB1 = dialog.AddLabel( "-------- Lunch Buffet Actions --------" )
dlg.cmtLB11 = dialog.AddLabel( " Here be food: Please pick at least one" )
dlg.wantEconomyPlatter = dialog.AddCheckbox( "Pick Economy Platter", false )
dlg.wantBanders = dialog.AddCheckbox( "Pick banders", false )
dlg.wantQuakes = dialog.AddCheckbox( "Pick quakes", false )
dlg.wantRebuilders = dialog.AddCheckbox( "Pick rebuild/remix/idealize", false )
dlg.wantEndgameActs = dialog.AddCheckbox( "Pick endgame actions", false )
dlg.wantDubiousActs = dialog.AddCheckbox( "Pick dubious foods", false )
dlg.cmtLBSpacer1 = dialog.AddLabel( "" )
end
function SetLunchBuffetOptions( dlg )
LunchBuffetActions = {}
if dlg.wantEconomyPlatter.value then
dlg2 = dialog.CreateDialog( "Economy Platter Actions" )
PutLunchBuffetEconomyOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
if dialog.Show( dlg2 ) == 0 then return false end
SetLunchBuffetEconomyOptions( dlg2 )
end
if dlg.wantBanders.value then
dlg2 = dialog.CreateDialog( "Bander Actions" )
PutLunchBuffetBanderOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
if dialog.Show( dlg2 ) == 0 then return false end
SetLunchBuffetBanderOptions( dlg2 )
end
if dlg.wantQuakes.value then
dlg2 = dialog.CreateDialog( "Quaker Actions" )
PutLunchBuffetQuakerOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
if dialog.Show( dlg2 ) == 0 then return false end
SetLunchBuffetQuakerOptions( dlg2 )
end
if dlg.wantRebuilders.value then
dlg2 = dialog.CreateDialog( "Rebuilder Actions" )
PutLunchBuffetRebuilderOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
if dialog.Show( dlg2 ) == 0 then return false end
SetLunchBuffetRebuilderOptions( dlg2 )
end
if dlg.wantEndgameActs.value then
dlg2 = dialog.CreateDialog( "Endgame Actions" )
PutLunchBuffetEndgameOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
if dialog.Show( dlg2 ) == 0 then return false end
SetLunchBuffetEndgameOptions( dlg2 )
end
if dlg.wantDubiousActs.value then
dlg2 = dialog.CreateDialog( "Dubious Actions" )
PutLunchBuffetDubiousOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
if dialog.Show( dlg2 ) == 0 then return false end
SetLunchBuffetDubiousOptions( dlg2 )
end
for i=1, #LunchBuffetActions do
DebugPrint("Will perform "..LunchBuffetActions[i])
end
return #LunchBuffetActions >= 1
end
function PutSASequenceOptionsInBox( dlg )
dlg.cmtSASeq = dialog.AddLabel( "------ SA Sequence Options -----" )
dlg.wantToChangeRuns = dialog.AddCheckbox( "SA run options", false )
dlg.skipStab = dialog.AddCheckbox( "Skip initial stabilizer runs", SASEQ_SKIP_STABILIZER )
dlg.skipRebuild = dialog.AddCheckbox( "Skip rebuild run", false )
dlg.wantFuses = dialog.AddCheckbox( "Add post-midgame fuse run", ALLOW_FUSE )
dlg.wantEndgame = dialog.AddCheckbox( "Add HWP endgame run", not SASEQ_SKIP_ENDGAME )
if InitialBandCount > 0 then
dlg.cmtUserBandsBlank = dialog.AddLabel( "" )
dlg.cmtUserBands = dialog.AddLabel( "------ User Band options ------" )
dlg.nobandAfterStab = dialog.AddCheckbox( "Disable user bands after stabilizer", SASEQ_DISABLE_UBAND_AFTER_STAB )
dlg.nobandAfterEarly = dialog.AddCheckbox( "Disable user bands after early", SASEQ_DISABLE_UBAND_AFTER_EARLY )
end
end
function SetSASequenceOptions( dlg )
ALLOW_FUSE = dlg.wantFuses.value
SASEQ_SKIP_STABILIZER = dlg.skipStab.value
SASEQ_SKIP_DEEPREBUILD = dlg.skipRebuild.value
SASEQ_SKIP_BASICREBUILD = dlg.skipRebuild.value
SASEQ_SKIP_ENDGAME = not dlg.wantEndgame.value
if InitialBandCount > 0 then
SASEQ_DISABLE_UBAND_AFTER_STAB = dlg.nobandAfterStab.value
SASEQ_DISABLE_UBAND_AFTER_EARLY = dlg.nobandAfterEarly.value
DebugPrint("Disable user bands after Stab? "..BoolStr(SASEQ_DISABLE_UBAND_AFTER_STAB))
DebugPrint("Disable user bands after Early? "..BoolStr(SASEQ_DISABLE_UBAND_AFTER_EARLY))
end
DebugPrint("skip Stab? "..BoolStr(SASEQ_SKIP_STABILIZER))
DebugPrint("skip DeepR? "..BoolStr(SASEQ_SKIP_DEEPREBUILD))
DebugPrint("skip BasicR? "..BoolStr(SASEQ_SKIP_BASICREBUILD))
DebugPrint("add Late/Fuse run? "..BoolStr(ALLOW_FUSE))
DebugPrint("skip End? "..BoolStr(SASEQ_SKIP_ENDGAME))
if dlg.wantToChangeRuns.value == true then
local doStab,doEarly,doRebuild,doMidgame,doLate,doEnd =
false, false, false, false, false, false
dlg2 = dialog.CreateDialog( "SA Run Options" )
if not SASEQ_SKIP_STABILIZER then
dlg2.SeeStabilizer = dialog.AddCheckbox( "Change Stabilizer?", false )
end
dlg2.SeeEarly = dialog.AddCheckbox( "Change Early?", false )
if not (SASEQ_SKIP_DEEPREBUILD and SASEQ_SKIP_BASICREBUILD) then
dlg2.SeeRebuild = dialog.AddCheckbox( "Change Rebuild?", false )
end
dlg2.SeeMidgame = dialog.AddCheckbox( "Change Midgame?", false )
if ALLOW_FUSE then
dlg2.SeeLate = dialog.AddCheckbox( "Change Fuse run?", false )
end
if not SASEQ_SKIP_ENDGAME then
dlg2.SeeEndgame = dialog.AddCheckbox( "Change Endgame?", false )
end
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then return false end
if (not SASEQ_SKIP_STABILIZER) and dlg2.SeeStabilizer.value then
local dlg3 = dialog.CreateDialog( "Stabilizer Run Options" )
PutStabOptionsInBox( dlg3 )
dlg3.ok = dialog.AddButton( "OK", 1 )
dlg3.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg3 ) == 0 then return false end
SetStabOptions( dlg3 )
end
if dlg2.SeeEarly.value then
local dlg3 = dialog.CreateDialog( "Early Run Options" )
PutEarlyOptionsInBox( dlg3 )
dlg3.ok = dialog.AddButton( "OK", 1 )
dlg3.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg3 ) == 0 then return false end
SetEarlyOptions( dlg3 )
end
if (not (SASEQ_SKIP_DEEPREBUILD and SASEQ_SKIP_BASICREBUILD)) and
dlg2.SeeRebuild.value
then
local dlg3 = dialog.CreateDialog( "Rebuild Run Options" )
PutRebuildOptionsInBox( dlg3 )
dlg3.ok = dialog.AddButton( "OK", 1 )
dlg3.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg3 ) == 0 then return false end
SetRebuildOptions( dlg3 )
end
if dlg2.SeeMidgame.value then
local dlg3 = dialog.CreateDialog( "Midgame Run Options" )
PutMidOptionsInBox( dlg3 )
dlg3.ok = dialog.AddButton( "OK", 1 )
dlg3.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg3 ) == 0 then return false end
SetMidOptions( dlg3 )
end
if ALLOW_FUSE and dlg2.SeeLate.value then
local dlg3 = dialog.CreateDialog( "Fuse Run Options" )
PutLateOptionsInBox( dlg3 )
dlg3.ok = dialog.AddButton( "OK", 1 )
dlg3.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg3 ) == 0 then return false end
SetLateOptions( dlg3 )
end
if not SASEQ_SKIP_ENDGAME then
local dlg3 = dialog.CreateDialog( "Endgame Run Options" )
PutEndgameOptionsInBox( dlg3 )
dlg3.ok = dialog.AddButton( "OK", 1 )
dlg3.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg3 ) == 0 then return false end
SetEndgameOptions( dlg3 )
end
end
return true
end
function PutCysteineOptionsInBox( dlg )
str = ""
for i=1, #CysteineAaSegList do
str = str..CysteineAaSegList[i]
if i < #CysteineAaSegList then
str = str.. ","
end
end
dlg.cmtCy = dialog.AddLabel( "Cysteines: "..str )
str = ""
for i=1, #CysteinePairList do
local pair = CysteinePairList[i]
str = str..pair[1]..","..pair[2]
if i < #CysteinePairList then
str = str .. "; "
end
end
dlg.cmtCy2 = dialog.AddLabel( "Guessed pairs: "..str )
dlg.cyPairsWanted = dialog.AddSlider( "Pair count", #CysteinePairList, 0, #CysteinePairList, 0 )
dlg.cyPairings = dialog.AddTextbox( "Pairings", str)
if InitialBandCount > 0 then
dlg.cmtCy3 = dialog.AddLabel( "Cysteine-bander cannot honor user bands" )
end
dlg.cyBandStrength = dialog.AddSlider( "Band strength", CYSTEINE_BAND_STRENGTH, 0.0, 8.0, 1 )
dlg.cyBandsPer = dialog.AddSlider( "Ct Bands", CYSTEINE_COUNT_BANDS_USED, 1, 4, 0 )
end
function SetCysteineOptions( dlg )
ctCysPairs = dlg.cyPairsWanted.value
if dlg.cyPairings.value ~= nil then
parseCysteineStr( ctCysPairs, dlg.cyPairings.value)
else
-- this happens if user puts empty comment,
-- but says they want a number of pairs smaller than expected
-- we interpret this as request to truncate accepted list
while ctCysPairs < #CysteinePairList do
table.remove(CysteinePairList, #CysteinePairList)
end
end
if ctCysPairs > 0 then
str = ""
for i=1, #CysteinePairList do
pair = CysteinePairList[i]
str = str..pair[1]..","..pair[2]
if i < #CysteinePairList then
str = str .. "; "
end
end
DebugPrint( "CysteinePairList: "..str )
DebugPrint( "Try to add "..ctCysPairs.." cysteine band groups" )
else
DebugPrint( "No cysteine bands wanted, none made" )
end
CYSTEINE_BAND_STRENGTH = dlg.cyBandStrength.value
CYSTEINE_COUNT_BANDS_USED = dlg.cyBandsPer.value
DebugPrint( "Use cysteine band strength = "..CYSTEINE_BAND_STRENGTH )
DebugPrint( "Use "..CYSTEINE_COUNT_BANDS_USED.." bands per cysteine bond wanted" )
end
-- THE BIG 2ND DIALOG AFTER TYPE OF RUN HAS BEEN CHOSEN
function DoDialogParamChooser( opMsg, operationPutter, operationSetter, wantFuse, wantDecement, wantLunchPickers)
local dlg = dialog.CreateDialog( opMsg )
-- Lunch Buffet if relevant (note: I might want a submenu putter and setter pair. SASequence might benefit)
if wantLunchPickers then PutLunchBuffetOptionsInBox( dlg ) end
-- Basic parameters
dlg.cmtBO1 = dialog.AddLabel( "-------- Basic SA Parameters --------" )
dlg.cmtBO11 = dialog.AddLabel( " Here be baby dragons" )
dlg.preserveCuts = dialog.AddCheckbox( "Preserve user cuts", PRESERVE_USER_CUTS )
if InitialBandCount > 0 then
dlg.preserveBands = dialog.AddCheckbox( "Preserve user bands", true )
end
if #CysteineAaSegList >= 2 then
dlg.playCysteineGames = dialog.AddCheckbox( "Bond cysteine pairs", false )
end
dlg.forbidQstab = dialog.AddCheckbox( "Forbid qstab fuzing", FORBID_ALL_QSTAB_FUSE )
dlg.forbidWPChange = dialog.AddCheckbox( "Forbid wiggle power changes", FORBID_WIGGLE_POWER_CHANGE )
if PuzzleHasContactMap then
dlg.cmForceContactBettering = dialog.AddCheckbox( "Contact map tries to improve", CONTACTMAP_TAKEDROPS )
dlg.cmInfo = dialog.AddLabel( "If tries to improve: Max score drop allowed" )
dlg.cmMaxDrop = dialog.AddSlider( " Drop", CONTACTMAP_MAX_DROP, 5, 100, 0 )
end
if PuzzleUsesFilters then
dlg.cmKillFilters = dialog.AddCheckbox( "DisableFilters", KILLING_FILTERS )
end
if PuzzleAllowsMutate then
dlg.MutateCmt = dialog.AddLabel("Mutate: 0=never, 1=once, 2=always")
dlg.whenToMutate = dialog.AddSlider( " Mutate", 1, 0, 2, 0 ) -- default to "once"
end
-- Advanced parameters
dlg.cmtSpacer2 = dialog.AddLabel( "" )
dlg.cmtAO1 = dialog.AddLabel( "-------- Advanced SA Parameters --------" )
dlg.cmtAO11 = dialog.AddLabel( " Here be big dragons" )
dlg.wantRunParams = dialog.AddCheckbox( "Change run params", false )
if PuzzleAllowsMutate then
dlg.setMutate = dialog.AddCheckbox( "Change Mutate options", false )
end
dlg.IdRAdvancedPars= dialog.AddCheckbox( "Change Idealize/Rebuild/Remix", false )
--dlg.BanderPars= dialog.AddCheckbox( "Change Bander options", false )
if wantFuse then
dlg.WigglerPars= dialog.AddCheckbox( "Change Fuser options", false )
end
if wantDecement then
dlg.DecementPars = dialog.AddCheckbox( "Change Decementing options", false )
end
dlg.cmtSpacer3 = dialog.AddLabel( "" )
dlg.samingain = dialog.AddSlider( "MinGainForRuns", SA_MINGAIN, 0, 10*SA_MINGAIN, 1 )
dlg.maxCI = dialog.AddSlider( "MaxCI", CI_MAXSCALE, 0.0, 1.0, 2 )
dlg.rangeOfAction = dialog.AddTextbox( "Restrict to segs", "" )
dlg.ok = dialog.AddButton( "OK", 1 )
dlg.cancel = dialog.AddButton( "Cancel", 0 )
-- SHOW it to the user
if dialog.Show( dlg ) == 0 then return false end
if wantLunchPickers then SetLunchBuffetOptions( dlg ) end
-- LEARN what the user wanted
-- Basic params:
PRESERVE_USER_CUTS = dlg.preserveCuts.value
if PRESERVE_USER_CUTS then
IDEALIZE_USE_CUTS = false
PROB_FUSEWIGGLE_CUTFUSE = 0.00 -- don't use wigglers that put cuts
PROB_FUSEWIGGLE_LOCAL = 0.00 -- this one's too useless
PROB_FUSEWIGGLE_BLUEFUSE = 1.0
end
DebugPrint( "Preserve user cuts? ".. BoolStr( PRESERVE_USER_CUTS ) )
if InitialBandCount > 0 then
BANDS_PRESERVE_USER = dlg.preserveBands.value
if not BANDS_PRESERVE_USER then
InitialBandCount = 0
InitialBandStates = {}
DelBands( )
end
DebugPrint( "Preserve user bands? ".. BoolStr( PRESERVE_USER_BANDS ) )
end
if dlg.playCysteineGames ~= nil and dlg.playCysteineGames.value == true then
CYSTEINE_PERFORM_BANDING = true
local dlg2 = dialog.CreateDialog("Cysteine Pairings")
PutCysteineOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then
return false
end
if InitialBandCount > 0 then
print("Cannot honor user bands if cysteine bands are added")
InitialBandCount = 0
InitialBandStates = {}
DelBands( )
end
SetCysteineOptions( dlg2 )
PutCysteinePairBands( )
end
FORBID_ALL_QSTAB_FUSE = dlg.forbidQstab.value
FORBID_WIGGLE_POWER_CHANGE = dlg.forbidWPChange.value
DebugPrint( "Forbid qstab fuzing? "..BoolStr( FORBID_WIGGLE_POWER_CHANGE ))
DebugPrint( "Forbid wiggle power changes? "..BoolStr( FORBID_ALL_QSTAB_FUSE ))
if PuzzleHasContactMap then
CONTACTMAP_TAKEDROPS = dlg.cmForceContactBettering.value
if CONTACTMAP_TAKEDROPS then
DebugPrint( "Score drops of ".. CONTACTMAP_MAX_DROP .. " accepted if ContactMap improves" )
else
DebugPrint( "No score drops permitted" )
end
end
if PuzzleUsesFilters then
KILLING_FILTERS = dlg.cmKillFilters.value
end
if PuzzleAllowsMutate then
if dlg.whenToMutate.value == 0 then
MUTATE_NOT_SHAKE = false
DebugPrint("Never mutate")
elseif dlg.whenToMutate.value == 1 then
MUTATE_NOT_SHAKE = true
MUTATE_ONCE = true
DebugPrint("Mutate once per action")
else
MUTATE_NOT_SHAKE = true
MUTATE_ONCE = false
DebugPrint("Always mutate")
end
end
-- Advanced params
CI_MAXSCALE = dlg.maxCI.value
ExactSetCI( CI_MAXSCALE )
print( "Using MaxCI="..CI_MAXSCALE )
SA_MINGAIN = dlg.samingain.value
DebugPrint("Run counts as fail if gain < "..SA_MINGAIN)
if CI_MAXSCALE < 0.70 then USE_LOWCI_WIGGLES = true end
if dlg.wantRunParams.value then
-- this one gets its own dialog box, because it can get ugly
local dlg2 = dialog.CreateDialog( "Run Parameters" )
operationPutter( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then return false end
local r = operationSetter( dlg2 )
if r ~= nil and r == false then return false end
end
if dlg.rangeOfAction.value ~= nil and dlg.rangeOfAction.value ~= "" then
AllowedActionIndices = parseRangesStr( dlg.rangeOfAction.value )
print("AllowedActionIndices has "..(#AllowedActionIndices).." segs" )
if #AllowedActionIndices > 0 then
printVector( AllowedActionIndices, "ActOn", false )
else
print("Error Parsing: No ranges selected")
end
end
-- sub-dialogs based on Advanced Param choices
if PuzzleAllowsMutate and dlg.setMutate.value then
local dlg2 = dialog.CreateDialog( "Mutate Options" )
PutMutateOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then return false end
SetMutateOptions( dlg2 )
end
if dlg.IdRAdvancedPars.value then
local dlg2 = dialog.CreateDialog( "Idealize/Rebuild/Remix Options" )
PutIdealizeOptionsInBox( dlg2 )
PutlRebuildSubOptionsInBox( dlg2 )
PutRemixOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then return false end
SetIdealizeOptions( dlg2 )
SetRebuildSubOptions( dlg2 )
SetRemixOptions( dlg2 )
end
--if dlg.BanderPars.value then
-- local dlg2 = dialog.CreateDialog( "Bander Options" )
-- PutBanderOptionsInBox( dlg2 )
-- dlg2.ok = dialog.AddButton( "OK", 1 )
-- dlg2.cancel = dialog.AddButton( "Cancel", 0 )
-- if dialog.Show( dlg2 ) == 0 then return false end
-- SetBanderOptions( dlg2 )
--end
if wantFuse and dlg.WigglerPars.value then
local dlg2 = dialog.CreateDialog( "Fuser Options" )
USE_FUSEWIGGLE = true
PutSlowWiggleOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then return false end
SetSlowWiggleOptions( dlg2 )
end
if wantDecement and dlg.DecementPars.value then
local dlg2 = dialog.CreateDialog( "Decementing Options" )
PutDecementingOptionsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then return false end
SetDecementingOptions( dlg2 )
end
return true
end
function PutOtherSAOperationsInBox( dlg )
dlg.cmtSO = dialog.AddLabel( "-- Single Options" )
dlg.wantSALowCI = dialog.AddCheckbox( "LowCI", false )
dlg.wantSAStab1 = dialog.AddCheckbox( "Short Stabilizer", false )
dlg.wantSAStab2 = dialog.AddCheckbox( "Long Stabilizer", false )
dlg.wantSAEarlyMove = dialog.AddCheckbox( "Early Mover", false )
dlg.wantSAEarlyIdeal = dialog.AddCheckbox( "Early Ideal", false )
dlg.wantSARebuildBasic = dialog.AddCheckbox( "Basic Rebuild", false )
dlg.wantSARebuildDeep = dialog.AddCheckbox( "Deep Rebuild", false )
dlg.wantSAFuse = dialog.AddCheckbox( "Fuse", false )
if PuzzleHasContactMap then
dlg.wantSAContact = dialog.AddCheckbox( "ContactMap", false )
end
if DEBUGRUN then
dlg.cmtSO2 = dialog.AddLabel( "-- Test Option" )
dlg.wantTest = dialog.AddCheckbox( "Test", false )
end
end
function SetOtherSAOperationOptions( dlg )
if dlg.wantSALowCI.value then
return "SALowCI"
elseif dlg.wantSAStab1.value then
return "SAShortStab"
elseif dlg.wantSAStab2.value then
return "SALongStab"
elseif dlg.wantSAEarlyMove.value then
return "SAEarlyMove"
elseif dlg.wantSAEarlyIdeal.value then
return "SAEarlyIdeal"
elseif dlg.wantSARebuildBasic.value then
return "SARebuildBasic"
elseif dlg.wantSARebuildDeep.value then
return "SARebuildDeep"
elseif dlg.wantSAFuse.value then
return "SALate"
elseif PuzzleHasContactMap and dlg.wantSAContact.value then
return "SAContact"
elseif DEBUGRUN and dlg.wantTest.value then
return "SATest"
else
return nil -- something went wrong...
end
end
function LetUserChooseParams( )
-- any condition that should not carry between different visits to
-- dialog-box-land should be set to default values here.
SetSAParamDefaults()
DISABLE_ALL_USER_BANDS = false -- Do NOT put into SetSAParamDefaults
local gotResultYet = false
local operation
while not gotResultYet do
-- Welcome to the Netherworld!
local dlg = dialog.CreateDialog( ReVersion )
dlg.cmt1 = dialog.AddLabel( "Pick one of following (topmost checked will be run)" )
dlg.modLabel1 = dialog.AddLabel( "---------- Press button get candy" )
dlg.wantSASeq = dialog.AddCheckbox( "Standard Sequence", true )
dlg.cmtBlank1 = dialog.AddLabel( "" )
dlg.modLabel2 = dialog.AddLabel( "---------- Individual Options" )
dlg.wantSAStab = dialog.AddCheckbox( "Stabilizer", false )
dlg.wantSAEarly = dialog.AddCheckbox( "Early", false )
dlg.wantSaRebuilder = dialog.AddCheckbox( "Rebuild", false )
dlg.wantSAMid = dialog.AddCheckbox( "Midgame", false )
dlg.wantSAEnd = dialog.AddCheckbox( "HWP Endgame", false )
dlg.cmtBlank2 = dialog.AddLabel( "" )
dlg.modLabel3 = dialog.AddLabel( "---------- Experimenter's Option" )
dlg.wantLunchBuffet = dialog.AddCheckbox( "LunchBuffet", false )
dlg.cmtBlank3 = dialog.AddLabel( "" )
dlg.modLabel4 = dialog.AddLabel( "---------- Specialty Options" )
dlg.wantOtherSAType = dialog.AddCheckbox( "Other Operation", false )
dlg.ok = dialog.AddButton( "OK", 1 )
dlg.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg ) == 0 then return nil end
-- PICK the Operation
if dlg.wantSASeq.value then
operation = "SASequence"
elseif dlg.wantSAStab.value then
operation = "SAStab"
elseif dlg.wantSAEarly.value then
operation = "SAEarly"
elseif dlg.wantSaRebuilder.value then
operation = "SARebuild"
elseif dlg.wantSAMid.value then
operation = "SAMidgame"
elseif dlg.wantSAEnd.value then
operation = "SAEndgame"
elseif dlg.wantLunchBuffet.value then
operation = "SALunchBuffet"
elseif dlg.wantOtherSAType then
local dlg2 = dialog.CreateDialog( "Other SA Operations" )
PutOtherSAOperationsInBox( dlg2 )
dlg2.ok = dialog.AddButton( "OK", 1 )
dlg2.cancel = dialog.AddButton( "Cancel", 0 )
if dialog.Show( dlg2 ) == 0 then return nil end
operation = SetOtherSAOperationOptions( dlg2 )
if operation == nil then return nil end
else
return nil -- user didn't want anything!
end
-- ASK FOR MORE OPTIONS, offer as relevant to operation
if operation == "SASequence" then
gotResultYet = DoDialogParamChooser( "SASequence Options", PutSASequenceOptionsInBox, SetSASequenceOptions, true, true, false)
elseif operation == "SAStab" then
gotResultYet = DoDialogParamChooser( "Stabilizer SA Options", PutStabOptionsInBox, SetStabOptions, false, false, false)
elseif operation == "SAEarly" then
gotResultYet = DoDialogParamChooser( "Early SA Options", PutEarlyOptionsInBox, SetEarlyOptions, false, true, false)
elseif operation == "SARebuild" then
gotResultYet = DoDialogParamChooser( "Rebuild SA Options", PutRebuildOptionsInBox, SetRebuildOptions, false, false, false)
elseif operation == "SAMidgame" then
gotResultYet = DoDialogParamChooser( "Midgame SA Options", PutMidOptionsInBox, SetMidOptions, false, false, false)
elseif operation == "SALate" then
ALLOW_FUSE = true
gotResultYet = DoDialogParamChooser( "Fuser SA Options", PutLateOptionsInBox, SetLateOptions, true, false, false)
elseif operation == "SAEndgame" then
gotResultYet = DoDialogParamChooser( "Endgame SA Options", PutEndgameOptionsInBox, SetEndgameOptions, false, false, false)
elseif operation == "SALunchBuffet" then
gotResultYet = DoDialogParamChooser( "LunchBuffet Options", PutLunchBuffetRunOptionsInBox, SetLunchBuffetRunOptions, false, false, true)
elseif operation == "SAContact" then
gotResultYet = DoDialogParamChooser( "ContactMap SA Options", PutContactMapOptionsInBox, SetContactMapOptions, false, false, false)
elseif operation == "SALowCI" then
gotResultYet = DoDialogParamChooser( "LowCI SA Options", PutLowCIOptionsInBox, SetLowCIOptions, false, false, false)
elseif operation == "SAShortStab" then
gotResultYet = DoDialogParamChooser( "ShortStabilizer SA Options", PutStab1OptionsInBox, SetStab1Options, false, false, false)
elseif operation == "SALongStab" then
gotResultYet = DoDialogParamChooser( "LongStabilizer SA Options", PutStab2OptionsInBox, SetStab2Options, false, false, false)
elseif operation == "SAEarlyMove" then
gotResultYet = DoDialogParamChooser( "EarlyMover SA Options", PutEarly1OptionsInBox, SetEarly1Options, false, true, false)
elseif operation == "SAEarlyIdeal" then
gotResultYet = DoDialogParamChooser( "EarlyIdealizer SA Options", PutEarly2OptionsInBox, SetEarly2Options, false, true, false)
elseif operation == "SARebuildBasic" then
gotResultYet = DoDialogParamChooser( "BasicRebuild SA Options", PutRebuild1OptionsInBox, SetRebuild1Options, false, false, false)
elseif operation == "SARebuildDeep" then
gotResultYet = DoDialogParamChooser( "DeepRebuild SA Options", PutRebuild2OptionsInBox, SetRebuild2Options, false, false, false)
end
end
return operation
end
--------------------------------------------------------------------------
-- SETUP and CLEANUP
--------------------------------------------------------------------------
function CleanPuzzleState( )
ExactSetCI( InitialClashImportance )
selection.DeselectAll( )
ResetFrozenness( )
ResetCuts( )
DelBands( true )
ResetSecondaryStructures( 1, SegCt )
ResetUserBands( true )
behavior.SetWigglePower( InitialWigglePower )
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
if RESTORE_BEST_AT_END then LoadBest( ) end
if PERFORM_CLEANUP_AT_END then CleanPuzzleState( ) end
if KILLING_FILTERS then ResetFilterState( ) end
if SHOW_STATS_REPORT then
print("")
reportStats( )
print( "EndDate: "..os.date() )
print( "TotalShakeTime="..TotalShakeTime ) -- because I want to know.
print( "TotalMutateTime="..TotalMutateTime ) -- because I want to know.
end
PrintState( )
print( "" )
if errstr ~= nil then
local start, stop, line, msg = errstr:find ( ":(%d+):%s()" )
if msg ~= nil then
errstr = errstr:sub( msg, #errstr )
end
if errstr:find ( "Cancelled" ) ~= nil then
reason = "cancelled"
else
reason = "error"
end
if reason == "error" then
print ( "Unexpected error detected" )
print ( "Error line: " .. line )
print ( "Error: \"" .. errstr .. "\"" )
end
end
end
function InitializePuzzleState( )
-- some setup actions
seedRandom( )
save.Quicksave( QS_Start )
save.Quicksave( QS_CmBest )
save.Quicksave( QS_Best )
GenerateAllActionsList( )
StartTime = os.time( )
-- learn a few things about the user and puzzle description
Ident( ReVersion )
IdentPuzzleType( )
-- learn things the user did (StoreCuts would sure be nice to have)
InitialBandCount = band.GetCount()
StoreUserBands( )
StoreFrozenness( )
StoreSecondaryStructure( )
InitialClashImportance = behavior.GetClashImportance( )
CI_MAXSCALE = InitialClashImportance
-- learn things about the protein in the puzzle
InitialScore = getScore( )
GenerateNonLockedSegList( )
--StoreSecondaryStructure( )
FindAllMovableSegs( )
LocateHelices( )
LocateSheets( )
LocateLoops( )
LocateMissingHelices( ) -- places where a possible helix may be hiding
if #PossibleHelices > 0 then
print( "Treating some loops as helices: " )
for i=1, #PossibleHelices do
local bounds = PossibleHelices[i]
print(" "..i..". "..bounds.sIdx.."-"..bounds.eIdx )
end
end
setCysteineSegList( )
guessCysteinePairList( )
selection.DeselectAll( )
recentbest.Save( )
end
--------------------------------------------------------------------------
-- MAIN
--------------------------------------------------------------------------
function main( )
local operation = ""
InitializePuzzleState()
local didSomething = false
print( "Start is in qs="..QS_Start.."; Best is in "..QS_Best )
if PuzzleHasContactMap then
print( "CM-best is in "..QS_CmBest )
end
while true do
operation = LetUserChooseParams( )
if operation == nil then break end
if KILLING_FILTERS then TurnOffFilters( ) end
PerformOperation( operation )
didSomething = true
LoadBest( )
ResetUserBands( )
PrintState( )
if SHOW_STATS_REPORT then
reportStats()
end
resetStats()
end
if didSomething then
print( " Done!" )
End( )
else
print( "Come back again someday?" )
end
end
xpcall( main, End )