Code
--[[
bandfun
Example of adding spacebands (lots of spacebands) with precise geometry
using band.Add.
Also demonstrates using pcall to trap errors returned by one of the
Foldit Lua functions. Without pcall, invalid parameters to a function
like band.Add cause the recipe to terminate.
]]--
Recipe = "bandfun"
Version = "1.0"
ReVersion = Recipe .. " v." .. Version
--
-- safe functions v 1.0
--
-- safe functions use pcall to invoke functions which
-- may unexpectedly terminate the script
--
-- safe functions are added to the exist foldit psuedo-classes
--
--
-- ParseError -- common routine used by safe functions
--
function ParseError ( errmsg )
local reason
local start, stop, line, msg
start, stop, line, msg = errmsg:find ( ":(%d+):%s()" )
if msg ~= nil then
errmsg = errmsg:sub ( msg, #errmsg )
end
return errmsg
end
--
-- band.SafeAdd uses pcall
-- to call band.Add, returning
-- a numeric return code.
--
-- If the return code is zero, the band index
-- is the second returned value.
--
-- The return codes are:
--
-- 0 - successful, second returned
-- value is band index
-- -1 - bad segment number
-- -2 - reserved
-- -3 - reserved
-- -4 - bad rho
-- -5 - bad theta
-- -6 - bad phi
-- -999 - other error
--
band.SafeAdd = function ( ... )
--
-- error messages
--
local BADSEG = "segment index out of bounds"
local BADRHO = "rho must be"
local BADTHETA = "theta must be"
local BADPHI = "phi must be"
--
local good, errmsg = pcall ( band.Add, unpack ( arg ) )
if good then
return 0, errmsg
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
local errp = err2:find ( BADRHO )
if errp ~= nil then
return -4, err2
end
local errp = err2:find ( BADTHETA )
if errp ~= nil then
return -5, err2
end
local errp = err2:find ( BADPHI )
if errp ~= nil then
return -6, err2
end
return -999, err2
end
end
--
-- band.SafeAddBetweenSegments uses pcall
-- to call band.AddBetweenSegments, returning
-- a numeric return code.
--
-- If the return code is zero, the band index
-- is the second returned value.
--
-- The return codes are:
--
-- 0 - successful, second returned
-- value is band index
-- -1 - bad segment number
-- -2 - bad atom number
-- -999 - other error
--
band.SafeAddBetweenSegments = function ( ... )
--
-- error messages
--
local BADSEG = "segment index out of bounds"
local BADATOM = "atom number out of bounds"
--
local good, errmsg = pcall ( band.AddBetweenSegments, unpack ( arg ) )
if good then
return 0, errmsg
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
local errp = err2:find ( BADATOM )
if errp ~= nil then
return -2, err2
end
return -999, err2
end
end
--
-- band.SafeAddToBandEndpoint uses pcall
-- to call band.ToBandEndpoint, returning
-- a numeric return code.
--
-- If the return code is zero, the band index
-- is the second returned value.
--
-- The return codes are:
--
-- 0 - successful, second returned
-- value is band index
-- -1 - bad segment number
-- -2 - bad atom number
-- -3 - bad band number
-- -999 - other error
--
band.SafeAddToBandEndpoint = function ( ... )
--
-- error messages
--
local BADSEG = "segment index out of bounds"
local BADATOM = "atom number out of bounds"
local BADBAND = "band index out of bounds"
--
local good, errmsg = pcall ( band.AddToBandEndpoint, unpack ( arg ) )
if good then
return 0, errmsg
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
local errp = err2:find ( BADATOM )
if errp ~= nil then
return -2, err2
end
local errp = err2:find ( BADBAND )
if errp ~= nil then
return -3, err2
end
return -999, err2
end
end
--
-- behavior.SafeSetClashImportance uses pcall
-- to call behavior.SetClashImportance, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -1 - bad CI
-- -999 - other error
--
behavior.SafeSetClashImportance = function ( ... )
--
-- error message
--
local BADCLASH = "clashing importance value outside valid range"
--
local good, errmsg = pcall ( behavior.SetClashImportance, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADCLASH )
if errp ~= nil then
return -1, err2
end
return -999, err2
end
end
--
-- selection.SafeSelect uses pcall
-- to call selection.Select, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -1 - bad segment index
-- -999 - other error
--
selection.SafeSelect = function ( ... )
--
-- error message
--
local BADSEG = "segment index out of bounds"
--
local good, errmsg = pcall ( selection.Select, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
return -999, err2
end
end
--
-- selection.SafeSelectRange uses pcall
-- to call selection.SelectRange, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -1 - bad segment index
-- -999 - other error
--
selection.SafeSelectRange = function ( ... )
--
-- error message
--
local BADSEG = "segment index out of bounds"
--
local good, errmsg = pcall ( selection.SelectRange, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
return -999, err2
end
end
--
-- rotamer.SafeSetRotamer uses pcall
-- to call rotamer.SetRotamer, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -1 - bad segment index
-- -2 - bad rotamer index
-- -999 - other error
--
rotamer.SafeSetRotamer = function ( ... )
--
-- error messages
--
local BADSEG = "segment index out of bounds"
local BADSNAP = "snap index out of bounds"
--
local good, errmsg = pcall ( rotamer.SetRotamer, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
local errp = err2:find ( BADSNAP )
if errp ~= nil then
return -2, err2
end
return -999, err2
end
end
--
-- structure.SafeSetAminoAcid uses pcall
-- to call structure.SetAminoAcid, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -1 - bad segment index
-- -2 - bad amino acid code
-- -999 - other error
--
structure.SafeSetAminoAcid = function ( ... )
--
-- error messages
--
local BADSEG = "(segment index out of bounds)"
local BADACID = "invalid argument, unknown aa code"
--
local good, errmsg = pcall ( structure.SetAminoAcid, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
local errp = err2:find ( BADACID )
if errp ~= nil then
return -2, err2
end
return -999, err2
end
end
--
-- structure.SafeSetAminoAcidSelected uses pcall
-- to call structure.SetAminoAcidSelected, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -2 - bad amino acid code
-- -999 - other error
--
structure.SafeSetAminoAcidSelected = function ( ... )
--
-- error message
--
local BADACID = "invalid argument, unknown aa code"
--
local good, errmsg = pcall ( structure.SetAminoAcidSelected, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADACID )
if errp ~= nil then
return -2, err2
end
return -999, err2
end
end
--
-- structure.SafeSetSecondaryStructure uses pcall
-- to call structure.SetSecondaryStructure, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -1 - bad segment index
-- -2 - bad secondary structure code
-- -999 - other error
--
structure.SafeSetSecondaryStructure = function ( ... )
--
-- error messages
--
local BADSEG = "segment index out of bounds"
local BADCODE = "invalid argument"
local good, errmsg = pcall ( structure.SetSecondaryStructure, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADSEG )
if errp ~= nil then
return -1, err2
end
local errp = err2:find ( BADCODE )
if errp ~= nil then
return -2, err2
end
return -999, err2
end
end
--
-- structure.SafeSetSecondaryStructureSelected uses pcall
-- to call structure.SetSecondaryStructureSelected, returning
-- a numeric return code and an error message.
--
-- The return codes are:
--
-- 0 - successful, error message is nil
-- -2 - bad secondary structure code
-- -999 - other error
--
structure.SafeSetSecondaryStructureSelected = function ( ... )
--
-- error message for an invalid secondary structure code
--
local BADCODE = "invalid argument"
local good, errmsg = pcall ( structure.SetSecondaryStructureSelected, unpack ( arg ) )
if good then
return 0, nil
else
local err2 = ParseError ( errmsg )
local errp = err2:find ( BADCODE )
if errp ~= nil then
return -2, err2
end
return -999, err2
end
end
--
-- end of safe functions v 1.0
--
function main ()
print ( ReVersion )
print ( "Puzzle: " .. puzzle.GetName () )
print ( "Track: " .. ui.GetTrackName () )
save.Quicksave ( 3 )
save.SaveSecondaryStructure ()
local segCnt = structure.GetCount ()
print ( "Segment count = " .. segCnt )
--
-- many functions use segment indexes,
-- define some useful ones
--
local SEGOUT = segCnt + 1
local SEGFOO1 = -1
local SEGFOO2 = -999
local SEGFOO3 = 999
local SEGMID = math.floor ( segCnt / 2 )
print ( "Middle segment = " .. SEGMID )
--
-- assorted other bad values
--
local HIATOM = 99 -- atom number
local HIROTA = 999 -- rotamer number
local HIRHO = 11000 -- you take the high rho
local LORHO = -39 -- and I'll take the low rho
local OKRHO = 20 -- and this one is just right
local HITHETA = 4.0
local LOTHETA = -1.0
local OKTHETA = 3.14 / 2
local HIPHI = 3.14 * 3
local LOPHI = -1.0
local OKPHI = 3.14
local rc, errmsg
for theta = 0, 3.14, 3.14 / 4 do
for phi = 0, 2 * 3.14, 3.14 / 4 do
rc, errmsg = band.SafeAdd ( SEGMID, 1, segCnt , OKRHO * 2, theta, phi )
if rc == 0 then
band.SetStrength ( errmsg, 10 )
else
print ( "rc = " .. rc )
if errmsg ~= nil then
print ( "errmsg = " .. errmsg )
end
end
end
end
for theta = 0, 3.14, 3.14 / 16 do
for phi = 0, 2 * 3.14, 3.14 / 16 do
rc, errmsg = band.SafeAdd ( SEGMID, 1, segCnt, OKRHO, theta, phi )
if rc ~= 0 then
print ( "rc = " .. rc )
if errmsg ~= nil then
print ( "errmsg = " .. errmsg )
end
end
end
end
--
cleanup ()
end
function cleanup ( error )
print ( "---" )
--
-- model 100 - print recipe name, puzzle, track, time, score, and gain
--
local reason
local start, stop, line, msg
if error == nil then
reason = "complete"
else
--
-- model 120 - civilized error reporting,
-- thanks to Bruno K. and Jean-Bob
--
start, stop, line, msg = error:find ( ":(%d+):%s()" )
if msg ~= nil then
error = error:sub ( msg, #error )
end
if error:find ( "Cancelled" ) ~= nil then
reason = "cancelled"
else
reason = "error"
end
end
print ( ReVersion .. " " .. reason )
print ( "Puzzle: " .. puzzle.GetName () )
print ( "Track: " .. ui.GetTrackName () )
if reason == "error" then
print ( "Unexpected error detected" )
if line ~= nil then
print ( "Error line: " .. line )
end
print ( "Error: \"" .. error .. "\"" )
end
--
-- model 130 - reset clash importance, clear selections, restore structures, etc.
--
end
-- main call
xpcall ( main, cleanup )
--end of script