Code
-----------------------------------------------------------------------
-- Ripple Wiggle v1.0 by KarenCH
--
-- A walker that wiggles those segments that were changed by the
-- last previous wiggle iteration. Alternates LocalWiggle with Wiggle.
-----------------------------------------------------------------------
segCt = structure.GetCount()
USENORMALSCORE = true
BASE_ITERS = 8
GAINWANTED = 0.001
function getScore( wantRB )
if wantRB == nil then wantRB = false end
local s=0.0
if not USENORMALSCORE then
if wantRB then s = recentbest.GetEnergyScore()
else s=current.GetEnergyScore()
end
else
if wantRB then s = recentbest.GetScore()
else s=current.GetScore()
end
end
return s
end
function isMovableSeg( seg1 )
local BB, SC = freeze.IsFrozen( seg1 )
local sl = structure.IsLocked( seg1 )
return not (BB or SC or sl)
end
function RippleWiggle( time, idxListStart, idxListVisited, threshold, doLocalWiggle )
local scListStart = {}
local scListNext= {}
local currIdxList = idxListStart
local nextIdxList = {}
local notDoneYet = true
idxListVisited = idxListStart
for i=1, segCt do
scListStart[ i ] = current.GetSegmentEnergyScore( i )
end
while notDoneYet do
printstr = ""
scListNext = {}
nextIdxList = {}
selection.DeselectAll()
for i = 1, #currIdxList do
selection.Select( currIdxList[ i ] )
if printstr ~= "" then printstr = printstr.."," end
printstr = printstr..currIdxList[i]
end
if doLocalWiggle then print("LWig: " ..printstr )
else print( "Wigg: " ..printstr )
end
recentbest.Save()
if doLocalWiggle then
structure.LocalWiggleSelected( time )
else
structure.WiggleSelected( time )
end
recentbest.Restore() -- just in case we have one of those scoring cliffs that we don't want to fall off of
-- which ones changed? make a nextIdxList
for i=1, segCt do
scListNext[ i ] = current.GetSegmentEnergyScore( i )
end
for i=1, segCt do
local changed = math.abs( scListNext[i] - scListStart[i] ) > threshold
if i > 1 then changed = changed or math.abs( scListNext[i-1] - scListStart[i-1] ) > threshold end
if i < segCt then changed = changed or math.abs( scListNext[i+1] - scListStart[i+1] ) > threshold end
if changed then
nextIdxList[#nextIdxList + 1] = i
idxListVisited[i] = true
end
end
-- set up for next iteration
currIdxList = nextIdxList
scListStart = scListNext
if #nextIdxList == 0 then notDoneYet = false end
end -- WHILE (notDoneYet)
selection.DeselectAll()
end
function RippleWiggleFromOneSeg( time, idx, threshold, doLocalWiggle, idxListVisited )
if idxListVisited == nil then idxListVisited = {} end
local idxListStart = { idx }
RippleWiggle( time, idxListStart, idxListVisited, threshold, doLocalWiggle )
end
function RippleWiggleFromRange( time, startIdx, endIdx, threshold, doLocalWiggle, idxListVisited )
if idxListVisited == nil then idxListVisited = {} end
local idxListStart = { }
for i=startIdx, endIdx do idxListStart[ #idxListStart + 1] = i end
RippleWiggle( time, idxListStart, idxListVisited, threshold, doLocalWiggle )
end
function RippleWiggleAll( time, threshold )
local doLocalWiggle = true -- we'll alternate; 1st time true, next time false, ...
local gain = 0.0
local ctVisitAlls = 0
repeat
gain = 0.0
local startScore = getScore()
print("start score="..startScore)
for i=1, segCt do
if isMovableSeg( i ) then
RippleWiggleFromOneSeg( time, i, threshold, doLocalWiggle )
end
end
doLocalWiggle = not doLocalWiggle
local nextScore = getScore()
gain = nextScore - startScore
print("new score="..nextScore.." for gain of "..gain)
if nextScore > startScore then
save.Quicksave(3)
startScore = nextScore
end
ctVisitAlls = ctVisitAlls + 1
until gain < threshold and ctVisitAlls % 2 == 0 -- insist on even number of passes!
end
function GetUserParams()
dlg = dialog.CreateDialog( "Ripple Wiggle" )
dlg.iters = dialog.AddSlider("Iters", BASE_ITERS, 1, 20, 0)
dlg.comment = dialog.AddLabel( "WiggleGain is decimal places: 1, 0.1, .., 0.0001")
dlg.mingain = dialog.AddSlider( "Wiggle Gain", 3, 0, 4, 0 ) -- there is no good constant to use here!
dlg.ok = dialog.AddButton("OK", 1)
dlg.cancel = dialog.AddButton("Cancel", 0)
if dialog.Show(dlg) == 0 then return false end
BASE_ITERS = dlg.iters.value
if dlg.mingain.value == 0 then
GAINWANTED = 1.0
elseif dlg.mingain.value == 1 then
GAINWANTED = 0.1
elseif dlg.mingain.value == 2 then
GAINWANTED = 0.01
elseif dlg.mingain.value == 3 then
GAINWANTED = 0.001
else -- if dlg.mingain.value == 4 then
GAINWANTED = 0.0001
end
print("iters="..BASE_ITERS.." gain="..GAINWANTED)
return true
end
function cleanup()
save.Quickload(3)
end
function main( )
save.Quicksave(2) --starting position
save.Quicksave(3) --high score
if GetUserParams() then
RippleWiggleAll( BASE_ITERS, GAINWANTED)
end
end
xpcall( main, cleanup )