Code
--[[
MicroIdealize 4.1.1
Adapted from Microidealize 4.0 by spvincent, 2016/04/30
Microidealize 4.0 test - LociOiling 2017/12/18
* Track effect of idealizing locked or unlocked segments
for aflatoxin and similar puzzles
MicroIdealize 4.1 - 2019/12/02 - 2020/01/06
* add quasi-introspective trace for crashy puzzles
* add adjustable lengths by popular demand
* switch to modularized version of Timo code (SLT)
* use named values in worklist and ideality tables
* rework filter logic a little
* added wiggle factor plus display/change wiggle power
* seed the random number generator
* improve score reporting a little
MicroIdealize 4.1.1 - LociOiling - 2020/01/08
* ifx t7po WPout s.b. WPOut
* fix handling of cancel in main dialog
]]--
Recipe = "Microidealize"
Version = "4.1.1"
ReVersion = Recipe .. " " .. Version
kOriginalStructureOrNewBest = 1 -- the starting structure, or any subsequent improvement, will be stored in this quicksave slot
best_score = 0
orig_score = 0
min_idealize_length = 1
max_idealize_length = 3
min_residue = 1
max_residue = 999
worst_first = true
original_slow_filters_setting = 0
kDefaultWiggle = 3
WF = 1
WigglePower = ""
WPOut = ""
PowerNames = { l = "low", m = "medium", h = "high", a = "auto", }
WFDefaults = { l = 2, m = 4, h = 4, a = 3, }
WPPrompt = ""
HighPowerOK = false
kSphereRadius = 10
segCnt = 0
segCnt2 = 0
dolocked = false -- if locked sections present, work on locked sections only
locksphr = false -- if locked sections present, include locked sections in wiggle sphere
ulcksphr = true -- if locked sections present, include unlocked sections in wiggle sphere
lockedL = {} -- list of locked segments
lockedS = {} -- set of locked segments
unlockedS = {} -- set of unlocked segments
idealz = {} -- table of ideality by segment
HASFILTER = false -- puzzle has filters
FILTEROFF = false -- disable filters if true
VERBOSE = false -- massive debug if true
TRACKED = false -- tracked ideality changes by segment
function r3 ( i )
return i - i % 0.001
end
function FX ( tag, funcX, ... )
if VERBOSE then
print ( tag, unpack ( arg ) )
end
local ret = funcX ( unpack ( arg ) )
return ret
end
function pv ( ... )
if VERBOSE then
print ( ... )
end
end
SLT = { -- SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--
--[[
SLT - Segment set, list, and type module v0.5
Includes the segment set and list module and the segment type module
developed by Timo van der Laan.
The following Foldit recipes contain the original code for these modules:
* Tvdl enhanced DRW 3.1.1 - https://fold.it/portal/recipe/102840
* TvdL DRemixW 3.1.2 - https://fold.it/portal/recipe/102398
The "set and list" module performs logical operations and
transformations on tables containing ranges of segment.
The segment type module find lists and sets of segments with various
properties, such as selected or frozen.
A "list" is one-dimensional table containing segment numbers.
A "set" is a two-dimensional table containing segment number ranges.
For example, given a list of segments:
list = { 1, 2, 3, 7, 8, 11, 13, 14, 15 }
the corresponding set is:
set = { { 1, 3 }, { 7, 8 }, { 11, 11 }, {13, 15 } }
Most functions assume that the sets are well-formed,
meaning they are ordered and have no overlaps.
As an example, the method FindUnlocked returns a set of
all the unlocked segments in a puzzle. The method can be
called as follows:
funlocked = SLT:FindUnlocked ()
The return value funlocked is a two-dimensional table
containing ranges of unlocked segments.
In source format, the table might look like this:
funlocked = {
{ 27, 35, },
{ 47, 62, },
{ 78, 89, },
}
The code to use this table would look like:
--
-- for each range of segments
--
for ii = 1, #funlocked do
--
-- for each segment in the range, so something
--
for jj = funlocked [ ii ] [ 1 ], funlocked [ ii ] [ 2 ] do
... something ...
end
end
This psuedo-module is a table containing a mix of
data fields and methods. This wiki article explains
the packaging technique:
https://foldit.fandom.com/wiki/Lua_packaging_for_Foldit
Authorship
----------
Original by Timo van der Laan:
02-05-2012 TvdL Free to use for non commercial purposes
French comments by Bruno Kestemont and perhaps others.
v0.1 - LociOiling
+ extract and reformat code
v0.2 - LociOiling - 2017/11/03
+ add primary FindUnlocked function
v0.3 - LociOiling
+ add FindRotamers function
v0.4 - LociOiling - 2019/10/29
+ package as table
+ remove dependencies on segCnt and segCnt2
v0.5 - LociOiling - 2019/12/17
+ convert functions to methods, update internal references
]]--
--
-- variables
--
segCnt = nil, -- segment count, not adjusted for ligands
segCnt2 = nil, -- segment count, not including terminal ligands
--
-- initializer - can be called externally, but invoked inline if segCnt or segCnt2 are nil
--
Init = function ( self )
self.segCnt = structure.GetCount ()
self.segCnt2 = self.segCnt
while structure.GetSecondaryStructure ( self.segCnt2 ) == "M" do
self.segCnt2 = self.segCnt2 - 1
end
end,
--
-- segment set and list functions
--
SegmentListToSet = function ( self, list ) -- retirer doublons
local result = {}
local ff = 0
local ll = -1
table.sort ( list )
for ii = 1, #list do
if list [ ii ] ~= ll + 1 and list [ ii ] ~= ll then
-- note: duplicates are removed
if ll > 0 then
result [ #result + 1 ] = { ff, ll }
end
ff = list [ ii ]
end
ll = list [ ii ]
end
if ll > 0 then
result [ #result + 1 ] = { ff, ll }
end
return result
end,
SegmentSetToList = function ( self, set ) -- faire une liste a partir d'une zone
local result = {}
for ii = 1, #set do
for kk = set [ ii ] [ 1 ], set [ ii ] [ 2 ] do
result [ #result + 1 ] = kk
end
end
return result
end,
SegmentCleanSet = function ( self, set )
-- Makes it well formed
return self:SegmentListToSet ( self:SegmentSetToList ( set ) )
end,
SegmentInvertSet = function ( self, set, maxseg )
--
-- Gives back all segments not in the set
-- maxseg is added for ligand
--
local result={}
if maxseg == nil then
maxseg = structure.GetCount ()
end
if #set == 0 then
return { { 1, maxseg } }
end
if set [ 1 ] [ 1 ] ~= 1 then
result [ 1 ] = { 1, set [ 1 ] [ 1 ] - 1 }
end
for ii = 2, #set do
result [ #result + 1 ] = { set [ ii - 1 ] [ 2 ] + 1, set [ ii ] [ 1 ] - 1, }
end
if set [ #set ] [ 2 ] ~= maxseg then
result [ #result + 1 ] = { set [ #set ] [ 2 ] + 1, maxseg }
end
return result
end,
SegmentInvertList = function ( self, list )
if self.segCnt2 == nil then
self:Init ()
end
table.sort ( list )
local result = {}
for ii = 1, #list - 1 do
for jj = list [ ii ] + 1, list [ ii + 1 ] - 1 do
result [ #result + 1 ] = jj
end
end
for jj = list [ #list ] + 1, self.segCnt2 do
result [ #result + 1 ] = jj
end
return result
end,
SegmentInList = function ( self, seg, list ) -- verifier si segment est dans la liste
table.sort ( list )
for ii = 1, #list do
if list [ ii ] == seg then
return true
elseif list [ ii ] > seg then
return false
end
end
return false
end,
SegmentInSet = function ( self, set, seg ) --verifie si segment est dans la zone
for ii = 1, #set do
if seg >= set [ ii ] [ 1 ] and seg <= set [ ii ] [ 2 ] then
return true
elseif seg < set [ ii ] [ 1 ] then
return false
end
end
return false
end,
SegmentJoinList = function ( self, list1, list2 ) -- fusionner 2 listes de segments
local result = list1
if result == nil then
return list2
end
for ii = 1, #list2 do
result [ #result + 1 ] = list2 [ ii ]
end
table.sort ( result )
return result
end,
SegmentJoinSet = function ( self, set1, set2 ) --fusionner (ajouter) 2 zones
return self:SegmentListToSet ( self:SegmentJoinList ( self:SegmentSetToList ( set1 ), self:SegmentSetToList ( set2 ) ) )
end,
SegmentCommList = function ( self, list1, list2 ) -- chercher intersection de 2 listes
local result = {}
table.sort ( list1 )
table.sort ( list2 )
if #list2 == 0 then
return result
end
local jj = 1
for ii = 1, #list1 do
while list2 [ jj ] < list1 [ ii ] do
jj = jj + 1
if jj > #list2 then
return result
end
end
if list1 [ ii ] == list2 [ jj ] then
result [ #result + 1 ] = list1 [ ii ]
end
end
return result
end,
SegmentCommSet = function ( self, set1, set2 ) -- intersection de 2 zones
return self:SegmentListToSet ( self:SegmentCommList ( self:SegmentSetToList ( set1 ), self:SegmentSetToList ( set2 ) ) )
end,
SegmentSetMinus = function ( self, set1, set2 )
return self:SegmentCommSet ( set1, self:SegmentInvertSet ( set2 ) )
end,
SegmentPrintSet = function ( self, set )
print ( self:SegmentSetToString ( set ) )
end,
SegmentSetToString = function ( self, set ) -- pour pouvoir imprimer
local line = ""
for ii = 1, #set do
if ii ~= 1 then
line = line .. ", "
end
line = line .. set [ ii ] [ 1 ] .. "-" .. set [ ii ] [ 2 ]
end
return line
end,
SegmentSetInSet = function ( self, set, sub )
if sub == nil then
return true
end
--
-- Checks if sub is a proper subset of set
--
for ii = 1, #sub do
if not self:SegmentRangeInSet ( set, sub [ ii ] ) then
return false
end
end
return true
end,
SegmentRangeInSet = function ( self, set, range ) -- verifier si zone est dans suite
if range == nil or #range == 0 then
return true
end
local bb = range [ 1 ]
local ee = range [ 2 ]
for ii = 1, #set do
if bb >= set [ ii ] [ 1 ] and bb <= set [ ii ] [ 2 ] then
return ( ee <= set [ ii ] [ 2 ] )
elseif ee <= set [ ii ] [ 1 ] then
return false
end
end
return false
end,
SegmentSetToBool = function ( self, set ) --vrai ou faux pour chaque segment utilisable ou non
local result = {}
for ii = 1, structure.GetCount () do
result [ ii ] = self:SegmentInSet ( set, ii )
end
return result
end,
--
-- End of Segment Set module
--
--
-- Module Find Segment Types
--
FindMutablesList = function ( self )
if self.segCnt2 == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt2 do
if structure.IsMutable ( ii ) then
result [ #result + 1 ] = ii
end
end
return result
end,
FindMutables = function ( self )
return self:SegmentListToSet ( self:FindMutablesList () )
end,
FindFrozenList = function ( self )
if self.segCnt2 == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt2 do
if freeze.IsFrozen ( ii ) then
result [ #result + 1 ] = ii
end
end
return result
end,
FindFrozen = function ( self )
return self:SegmentListToSet ( self:FindFrozenList () )
end,
FindLockedList = function ( self )
if self.segCnt2 == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt2 do
if structure.IsLocked ( ii ) then
result [ #result + 1 ] = ii
end
end
return result
end,
FindLocked = function ( self )
return self:SegmentListToSet ( self:FindLockedList () )
end,
FindUnlockedList = function ( self )
if self.segCnt2 == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt2 do
if not structure.IsLocked ( ii ) then
result [ #result + 1 ] = ii
end
end
return result
end,
FindUnlocked = function ( self )
return self:SegmentListToSet ( self:FindUnlockedList () )
end,
FindZeroScoreList = function ( self )
if self.segCnt == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt do
local sub = 0
for jj = 1, #SubScores do
sub = sub + current.GetSegmentEnergySubscore ( ii, SubScores [ jj ] [ 1 ] )
end
if sub == 0 then
result [ #result + 1 ] = ii
end
end
return result
end,
FindZeroScore = function ( self )
return self:SegmentListToSet ( self:FindZeroScoreList () )
end,
FindRotamersList = function ( self )
if self.segCnt == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt do
local rots = rotamer.GetCount ( ii )
if rots > 1 then
result [ #result + 1 ] = ii
end
end
return result
end,
FindRotamers = function ( self )
return self:SegmentListToSet ( self:FindRotamersList () )
end,
FindSelectedList = function ( self )
if self.segCnt == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt do
if selection.IsSelected ( ii ) then
result [ #result + 1 ] = ii
end
end
return result
end,
FindSelected = function ( self )
return self:SegmentListToSet ( self:FindSelectedList () )
end,
FindAAtypeList = function ( self, aa )
if self.segCnt2 == nil then
self:Init ()
end
local result = {}
for ii = 1, self.segCnt2 do
if structure.GetSecondaryStructure ( ii ) == aa then
result [ #result + 1 ] = ii
end
end
return result
end,
FindAAtype = function ( self, aa )
return self:SegmentListToSet ( self:FindAAtypeList ( aa ) )
end,
FindAminotype = function ( self, at ) --NOTE: only this one gives a list not a set
if self.segCnt2 == nil then
self:Init ()
end
local result={}
for ii = 1, self.segCnt2 do
if structure.GetAminoAcid ( ii ) == at then
result [ #result + 1 ] = ii
end
end
return result
end,
}-- SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--
-- Thanks too Rav4pl
function ShuffleTable(tab) --randomize order of elements
local cnt=#tab
for i=1,cnt do
local r=math.random(cnt)
tab[i],tab[r]=tab[r],tab[i]
end
return tab
end
function GetScore ()
pv ( "GetScore: enter" )
if not FILTEROFF then
score = current.GetEnergyScore ()
else
behavior.SetFiltersDisabled ( false )
score = current.GetEnergyScore ()
behavior.SetFiltersDisabled ( true )
end
pv ( "GetScore: end, score = " .. score )
return score
end
function DoesPuzzleHaveFilters ()
local names = filter.GetNames ()
if names ~= nil and #names > 0 then
return true
else
return false
end
end
function SphereSelect ( start_idx, end_idx )
selection.DeselectAll ()
for ii = 1, segCnt2 do
for jj = start_idx, end_idx do
if lockedL [ ii ] then
if locksphr then
if structure.GetDistance ( ii , jj ) < kSphereRadius then
selection.Select ( ii )
end
end
else
if ulcksphr then
if structure.GetDistance ( ii , jj ) < kSphereRadius then
selection.Select ( ii )
end
end
end
end
end
end
--
-- GetWorklist
--
-- return set of segments to work on
--
-- sSet - segment set
-- lenX - length
-- gMinR - minimum residue
-- gMaxR - maximum residue
--
function GetWorklist ( sSet, lenX, gMinR, gMaxR )
local lsx = {}
for uu = 1, #sSet do
local minR = sSet [ uu ] [ 1 ]
local maxR = sSet [ uu ] [ 2 ]
if ( #sSet == 1 and minR >= gMinR and maxR <= gMaxR )
or ( #sSet > 1 and minR > gMinR and maxR <= gMaxR )
then
for ii = minR, maxR - lenX + 1 do
lsx [ #lsx + 1 ] = { seg1 = ii, seg2 = ii + lenX - 1, ideal = nil, after = nil, }
end
end
end
return lsx
end
function GoSegment ( start_idx, end_idx, startideal )
pv ( "GoSegment: " .. start_idx .. "-" .. end_idx )
if start_idx > 1 then
FX ( "structure.InsertCut", structure.InsertCut, start_idx )
end
if end_idx < segCnt2 then
FX ( "structure.InsertCut", structure.InsertCut, end_idx )
end
FX ( "selection.DeselectAll", selection.DeselectAll )
FX ( "selection.SelectRange ", selection.SelectRange, start_idx , end_idx )
FX ( "structure.IdealizeSelected", structure.IdealizeSelected )
if start_idx > 1 then
FX ( "structure.DeleteCut", structure.DeleteCut, start_idx )
end
if end_idx < segCnt2 then
FX ( "structure.DeleteCut", structure.DeleteCut, end_idx )
end
SphereSelect ( start_idx, end_idx )
pv ( "GoSegment: before wiggle" )
FX ( "structure.WiggleSelected", structure.WiggleSelected, kDefaultWiggle * WF )
pv ( "GoSegment: after wiggle" )
pv ( "GoSegment: before GetScore" )
local score = GetScore ()
pv ( "GoSegment: after GetScore" )
if score > best_score then
local newideal = ScoreIdealitySection ( start_idx, end_idx )
best_score = score
print ( "Improvement to ".. r3 ( best_score ) .. ", ideality change " .. r3 ( newideal - startideal ) )
save.Quicksave ( kOriginalStructureOrNewBest )
end
save.Quickload ( kOriginalStructureOrNewBest )
pv ( "GoSegment: end" )
end
function ScoreIdealitySection ( seg1, seg2 )
local ideal = 0
for ii = seg1, seg2 do
ideal = ideal + current.GetSegmentEnergySubscore ( ii, "ideality" )
end
return ideal
end
function ScoreIdeality ( wlist )
local tideal = 0
for ii = 1, #wlist do
wlist [ ii ].ideal = ScoreIdealitySection ( wlist [ ii ].seg1, wlist [ ii ].seg2 )
tideal = tideal + wlist [ ii ].ideal
end
return wlist, tideal
end
function SortIdealAsc ( xyzzy )
table.sort ( xyzzy, function ( a, b ) return a.ideal < b.ideal end)
return xyzzy
end
function Idealize ( idealize_length )
local start_score = GetScore ()
print ( "----------------------------------------" )
print ( "Idealizing length " .. idealize_length .. ", start score = " .. r3 ( start_score ) )
local inc
local worklist = {}
if dolocked then
worklist = GetWorklist ( lockedS, idealize_length, min_residue, max_residue )
else
worklist = GetWorklist ( unlockedS, idealize_length, min_residue, max_residue )
end
local tideal = 0
worklist, tideal = ScoreIdeality ( worklist )
local meanideal = tideal / #worklist
print ( "Mean ideality = " .. r3 ( meanideal ) .. " for " .. #worklist .. " sections" )
if worst_first then
worklist = SortIdealAsc ( worklist )
else
worklist = ShuffleTable ( worklist )
end
for ii = 1, #worklist do
print ( "Idealizing "
.. worklist [ ii ].seg1 ..
"-"
.. worklist [ ii ].seg2 ..
" ("
.. ii ..
"/"
.. #worklist ..
"), ideality = "
.. r3 ( worklist [ ii ].ideal )
)
GoSegment ( worklist [ ii ].seg1, worklist [ ii ].seg2, worklist [ ii ].ideal )
worklist [ ii ].after = ScoreIdealitySection ( worklist [ ii ].seg1, worklist [ ii ].seg2 )
end
local stop_score = GetScore ()
local len_gain = stop_score - start_score
print ( "End length " .. idealize_length .. ", score = " .. r3 ( stop_score ) .. ", gain = " .. r3 ( len_gain ) )
end
function GetParameters ()
local changed = false
local uerror = ""
local rc
repeat
local dlog = dialog.CreateDialog ( ReVersion )
dlog.WigglePower = dialog.AddTextbox ( "Wiggle Power", WPOut )
dlog.WPkey = dialog.AddLabel ( WPPrompt )
dlog.WF = dialog.AddSlider ( "Wiggle Factor", WF, 1, 5, 0 )
dlog.min_idealize_length = dialog.AddSlider ( "Min idealize len" , min_idealize_length , 1 , 20 , 0 )
dlog.max_idealize_length = dialog.AddSlider ( "Max idealize len" , max_idealize_length , 1 , 20 , 0 )
dlog.min_residue = dialog.AddSlider ( "Min residue" , 1 , 1 , segCnt2 , 0 )
dlog.max_residue = dialog.AddSlider ( "Max residue" , segCnt2 , 1 , segCnt2 , 0 )
dlog.worst_first = dialog.AddCheckbox ( "Worst first?" , worst_first )
if #lockedS > 0 then
dlog.dolocked = dialog.AddCheckbox ( "Do locked segments only?" , dolocked )
dlog.locksphr = dialog.AddCheckbox ( "Include locked in wiggle?" , locksphr )
dlog.ulcksphr = dialog.AddCheckbox ( "Include unlocked in wiggle?" , ulcksphr )
end
dlog.FILTEROFF = dialog.AddCheckbox ( "Disable filters" , FILTEROFF )
dlog.VERBOSE = dialog.AddCheckbox ( "Verbose output" , VERBOSE )
dlog.TRACKED = dialog.AddCheckbox ( "Report ideality" , TRACKED )
dlog.ok = dialog.AddButton ( "OK" , 1 )
dlog.cancel = dialog.AddButton ( "Cancel" , -1 )
rc = dialog.Show ( dlog )
uerror = ""
if rc > 0 then
local WPtest = dlog.WigglePower.value:lower()
WPtest = WPtest:sub ( 1, 1 )
local WPtnam = PowerNames [ WPtest ]
if WPtnam ~= nil then
if WPtest ~= "h" or HighPowerOK then
print ( "new wiggle power = " .. WPtnam )
WPOut = WPtnam
behavior.SetWigglePower ( WPtest )
else
uerror = "high wiggle power not allowed on this puzzle"
print ( "ERROR: " .. uerror )
end
else
uerror = "invalid wiggle power entered: \"" .. dlog.WigglePower.value .. "\""
print ( "ERROR: " .. uerror )
end
WF = dlog.WF.value
min_idealize_length = dlog.min_idealize_length.value
max_idealize_length = dlog.max_idealize_length.value
min_residue = dlog.min_residue.value
max_residue = dlog.max_residue.value
worst_first = dlog.worst_first.value
if #lockedS > 0 then
dolocked = dlog.dolocked.value
locksphr = dlog.locksphr.value
ulcksphr = dlog.ulcksphr.value
end
FILTEROFF = dlog.FILTEROFF.value
VERBOSE = dlog.VERBOSE.value
TRACKED = dlog.TRACKED.value
end
until rc < 0 or ( not changed and uerror:len () == 0 )
return rc > 0
end
--
-- Ident - print identifying information at beginning and end of recipe
--
-- slugline - first line to print - normally recipe name and version
--
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 () )
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
end
--
-- seedRandom -- original by KarenCH
--
-- looks for a seed > 10,000,000 and < 2 ^ 32
--
-- v2 - LociOiling - 20191103
-- * added 2 ^ 32 overflow check
--
function seedRandom()
local seed = os.time () / math.abs ( current.GetEnergyScore () )
seed = seed % 0.001
seed = 1 / seed
while seed < 10000000 do
seed = seed * 1000
end
while seed > 2 ^ 32 do
seed = seed / 10
end
seed = seed - seed % 1
print ( "Random number seed = " .. seed )
math.randomseed( seed )
-- throw away a couple of randoms
math.random ()
math.random ()
end
function Initialize ()
seedRandom ()
segCnt = structure.GetCount()
segCnt2 = segCnt
while structure.GetSecondaryStructure ( segCnt2 ) == "M" do
segCnt2 = segCnt2 - 1
end
print ( "initial segment count: " .. segCnt )
if segCnt ~= segCnt2 then
print ( "ligand found, adjusted segment count: " .. segCnt2 )
end
for ii = 1, segCnt2 do
lockedL [ #lockedL + 1 ] = structure.IsLocked ( ii )
end
lockedS = SLT:FindLocked ()
print ( #lockedS .. " locked sections found" )
unlockedS = SLT:FindUnlocked ()
print ( #unlockedS .. " unlocked sections found" )
local names = filter.GetNames ()
if names ~= nil and #names > 0 then
HASFILTER = true
FILTEROFF = true
end
--
-- wiggle power/wiggle factor
--
WigglePower = behavior.GetWigglePower ()
WPOut = PowerNames [ WigglePower ]
WF = WFDefaults [ WigglePower ]
HighPowerOK = behavior.HighPowerAllowed ()
if HighPowerOK then
WPPrompt = "wiggle power: l = low, m = medium, h = high, a = auto"
else
WPPrompt = "wiggle power: l = low, m = medium, a = auto"
end
end
function main ()
Ident ( ReVersion )
save.Quicksave ( kOriginalStructureOrNewBest )
best_score = GetScore ()
orig_score = best_score
print ( "Start score " .. r3 ( best_score ) )
Initialize ()
original_slow_filters_setting = behavior.GetFiltersDisabled ()
if GetParameters () then
if FILTEROFF then
behavior.SetFiltersDisabled ( true )
end
print ( "--" )
print ( "Options: " )
print ( "Wiggle power: " .. WPOut )
print ( "Wiggle factor: " .. WF )
print ( "Min idealize length: " .. min_idealize_length )
print ( "Max idealize length: " .. max_idealize_length )
if #lockedS > 0 then
print ( "Idealize locked: " .. tostring ( dolocked ) )
print ( "Include locked in sphere: " .. tostring ( locksphr ) )
print ( "Include unlocked in sphere: " .. tostring ( ulcksphr ) )
end
print ( "Worst first: " .. tostring ( worst_first ) )
print ( "Disable filters: " .. tostring ( FILTEROFF ) )
print ( "Verbose output: " .. tostring ( VERBOSE ) )
print ( "Track ideality: " .. tostring ( TRACKED ) )
--
-- record locked status and initial ideality of each segment
--
if TRACKED then
for ii = 1, segCnt2 do
local ideal = current.GetSegmentEnergySubscore ( ii, "ideality" )
idealz [ #idealz + 1 ] = { seg = ii, locked = lockedL [ ii ], ideal = ideal, after = 0, }
end
end
local inc = 1
if min_idealize_length > max_idealize_length then
inc = -1
end
for len = min_idealize_length, max_idealize_length, inc do
Idealize ( len )
end
end
cleanup ()
end
function cleanup ( errmsg )
if CLEANUPENTRY ~= nil then
return
end
CLEANUPENTRY = true
print ( "---" )
local reason
local start, stop, line, msg
if errmsg == nil then
reason = "complete"
else
--
-- civilized error reporting, thanks to Bruno K. and Jean-Bob
--
start, stop, line, msg = errmsg:find ( ":(%d+):%s()" )
if msg ~= nil then
errmsg = errmsg:sub ( msg, #errmsg )
end
if errmsg:find ( "Cancelled" ) ~= nil then
reason = "cancelled"
else
reason = "error"
end
end
--
-- print recipe name, puzzle, track, time, score, and gain
--
Ident ( ReVersion .. " " .. reason )
if reason == "error" then
print ( "Unexpected error detected" )
print ( "Error line: " .. line )
print ( "Error: \"" .. errmsg .. "\"" )
end
--
-- reset clash importance, clear selections, restore structures, etc.
--
save.Quickload ( kOriginalStructureOrNewBest )
local final_score = GetScore ()
local gain = final_score - orig_score
print ( "start score = " .. r3 ( orig_score ) )
print ( "end score = " .. r3 ( final_score ) )
print ( "gain = " .. r3 ( gain ) )
behavior.SetClashImportance ( 1.0 )
behavior.SetFiltersDisabled ( original_slow_filters_setting )
if TRACKED and idealz ~= nil and #idealz > 0 then
--
-- record final ideality
--
for ii = 1, segCnt2 do
idealz [ ii ].after = current.GetSegmentEnergySubscore ( ii, "ideality" )
end
print ( "--spreadsheet output--" )
print ( "segment\tlocked\tbefore\tafter\tdiff" )
for ii = 1, #idealz do
local locked
if idealz [ ii ].locked then
locked = "L"
else
locked = "U"
end
local before = r3 ( idealz [ ii ].ideal )
local after = r3 ( idealz [ ii ].after )
local diff = r3 ( after - before )
print ( idealz [ ii ].seg .. "\t" .. locked .. "\t" .. before .. "\t" .. after .. "\t" .. diff )
end
end
if errmsg == nil then
end
end
xpcall ( main, cleanup )