About filters, one thing I do on recipes is disable them with structure functions (wiggle, shake...) and enable them for getting score.
I have written a code for overload the lua classes, so we can set/unset filters for all the functions in a class, and easily modify the old recipes.
The idea is:
MutClass(structure, false): set filters disabled on all the functions in 'structure'
MutClass(band, false): set filters disabled for band functions
MutClass(current, true): set filters enabled on all the functions in 'current' (for example GetEnergyScore
On that way if you are cutting, wiggling, and so on, you change filters only one time, avoiding disable_filters/cut/enable/disable/cut/enable/disable... For example, a sequence of actions:
getScore: filter on
Wiggle: filters off
Shake: nothing
Wiggle: nothing
Shake: nothing
getScore: filters on
For this, the functions:
-- function to copy class/table
function CopyTable(orig)
local copy = {}
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
return copy
end
-- functions for filters
function FiltersOn()
if behavior.GetSlowFiltersDisabled() then
behavior.SetSlowFiltersDisabled(false)
end
end
function FiltersOff()
if behavior.GetSlowFiltersDisabled()==false then
behavior.SetSlowFiltersDisabled(true)
end
end
-- function to overload a funtion
function mutFunction(func)
local currentfunc = func
local function mutate(func, newfunc)
local lastfunc = currentfunc
currentfunc = function(...) return newfunc(lastfunc, ...) end
end
local wrapper = function(...) return currentfunc(...) end
return wrapper, mutate
end
-- function to overload a class
-- to do: set the name of function
classes_copied = 0
myclcp = {}
function MutClass(cl, filters)
classes_copied = classes_copied+1
myclcp[classes_copied] = CopyTable(cl)
local mycl =myclcp[classes_copied]
for orig_key, orig_value in pairs(cl) do
myfunc, mutate = mutFunction(mycl[orig_key])
if filters==true then
mutate(myfunc, function(...)
print("Mutated function called: filter on")
FiltersOn()
if table.getn(arg)>1 then
-- first arg is self (function pointer), we pack from second argument
local arguments = {}
for i=2,table.getn(arg) do
arguments[i-1]=arg[i]
end
return mycl[orig_key](unpack(arguments))
else
--print("No arguments")
return mycl[orig_key]()
end
end)
cl[orig_key] = myfunc
else
mutate(myfunc, function(...)
print("mutated funcion called: filter off")
FiltersOff()
if table.getn(arg)>1 then
local arguments = {}
for i=2, table.getn(arg) do
arguments[i-1]=arg[i]
end
return mycl[orig_key](unpack(arguments))
else
return mycl[orig_key]()
end
end)
cl[orig_key] = myfunc
end
end
end
-- how to use:
MutClass(structure, false)
MutClass(band, false)
MutClass(current, true)
On this way class structure and class band will be with no filters, and class current will use filters. Write this code at the start of your recipe.
print("Mutated function called: filter on")
print("mutated funcion called: filter off")
Not sure it will affect the functions but if not it would be easier to follow drw progress without these lines
you can remove prints, thanks for testings :)
I really like this idea of automatically redoing classes.
There may be simpler way to accomplish this in some recipes. Many recipes already have a separate function Score() for collecting the overall score. It's easy to add filter toggling in this case. Some recipes may also get segment scores or subscores. It's easy to add a wrapper function for these as well.
Once the scoring functions toggle filters, all that's needed to disable the filter at the beginning of the recipe.
This approach avoid the issue of having "?" for the function name in the recipe status window. (I suspect the foldit client may construct a table of functions at startup. The question mark may appear when the client can't find one of the modified functions in the table. )
One additional tip is that it's helpful to reenable filters at the end. I suggest using a cleanup routine in all recipes, and resetting the filters there.
Here's sample code for filter-toggling score, segment score, and segment subscore functions:
function Score ()
local foff = behavior.GetSlowFiltersDisabled()
if foff then
behavior.SetSlowFiltersDisabled ( false )
end
local cscor = current.GetEnergyScore ()
if foff then
behavior.SetSlowFiltersDisabled ( true )
end
return cscor
end
function SegScore ( ii )
local foff = behavior.GetSlowFiltersDisabled()
if foff then
behavior.SetSlowFiltersDisabled ( false )
end
local cscor = current.GetSegmentEnergyScore ( ii )
if foff then
behavior.SetSlowFiltersDisabled ( true )
end
return cscor
end
function SegSubScore ( ii, subs )
local foff = behavior.GetSlowFiltersDisabled()
if foff then
behavior.SetSlowFiltersDisabled ( false )
end
local cscor = current.GetSegmentEnergySubscore ( ii, subs )
if foff then
behavior.SetSlowFiltersDisabled ( true )
end
return cscor
end
Thanks for this generic solution !
It works well on heavy puzzles. An order of magnitude more speed (see recipes by porkythepundit).
I still wonder if it's better to disable filter when wiggling or not. See http://fold.it/portal/node/2000171
I noticed that wiggling with filters enabled takes much more time ... but finds more points.
Disabling filters during most operations with your generic script makes much more attempts (loops) in a given time. After a certain time, the yield is better than running less loops with filters enabled.
I suppose that there should be a kind of "best compromise", like running with filters off on start design (trying to rise filter bonus), and running with filter off (unless current actions) at the end, when maximum filter bonus is achieved?
and only enable filters when scoring :P
My 1st script that do this: https://fold.it/portal/recipe/100580
Will try to update rest of my main scripts to do same thing.
Those filters are REALLY slow.
To do: set the names of functions. When you run a recipe with classes mutated it shows "?" instead the function name (wiggleselested, shakeAll...) when you run it. I have had investigating (a lot :D) but I have been unable. If anybody find the way please tell me.