Code
--[[
AA Edit
Get and set primary structure
The primary structure of a protein is the sequence of the
amino acids that make up the protein.
AA Edit displays the current primary structure as a sequence
of single-character amino acid codes.
The displayed value can be selected and cut or copied.
If there are any "mutable" segments, the "Change" button
is displayed, and a a new value can be pasted in. If there are
no mutable segments, any input to the "AAseq" box is ignored.
When the "Change" button is clicked, the currently displayed
primary structure is applied to the protein. The input amino
acid codes are converted to lower case.
The recipe checks each amino acid code against the list of 20
amino acids used in Foldit. Any input not found in the list is
ignored, and the corresponding segment is left unchanged.
Some puzzles have a mix of mutable and non-mutable segments.
The recipe does not attempt to change any non-mutable segments.
If the structure list is longer than the protein, AA Edit
discards the extra entries at the end of the list.
If the structure list is shorter than the protein, AA Edit
applies the list to the first *n* segments of the protein,
where *n* is the length of the list. Any remaining segments
are unchanged.
Some puzzles have a terminal ligand represented by a segment
which returns "unk" for its amino acid type. This code and
anything else not found in the normal list of 20 amino acids
is changed to "x" for the purposes of this recipe. Segments
with an "x" for their amino acid code in the replacment string
are not changed.
All changes are written to the scriptlog.
See "AA Copy Paste Compare v 1.1.1 -- Brow42" for
a full-function recipe that works with primary and
primary structures.
version 1.2 -- 2016/12/23 -- LociOiling
* clone of PS Edit v1.2
* enable 1-step undo with undo.SetUndo ( false )
]]--
--
-- Globals
--
Recipe = "AA Edit"
Version = "1.2"
ReVersion = Recipe .. " v." .. Version
mutable = false -- true if any mutable segments found
--
-- amino acid names and abbeviations
--
AANames = {
w = { "tryptophan", 'TRP', },
g = { "glycine", 'GLY', },
a = { "alanine", 'ALA', },
c = { "cysteine", 'CYS', },
v = { "valine", 'VAL', },
l = { "leucine", 'LEU', },
i = { "isoleucine", 'ILE', },
m = { "methionine", 'MET', },
p = { "proline", 'PRO', },
f = { "phenylalanine", 'PHE', },
y = { "tyrosine", 'TYR', },
r = { "arginine", 'ARG', },
s = { "serine", 'SER', },
t = { "threonine", 'THR', },
n = { "asparagine", 'ASN', },
d = { "aspartate", 'ASP', },
q = { "glutamine", 'GLN', },
e = { "glutamate", 'GLU', },
h = { "histidine", 'HIS', },
k = { "lysine", 'LYS', },
}
--
-- end of globals section
--
function report_time(start_clock,start_time,clock_msg,time_msg)
local seconds,minutes,hours,days
if clock_msg==nil then clock_msg="CPU time" end
if time_msg==nil then time_msg="Elasped time" end
print(string.format("%s",os.date()))
days,remainder=math.modf((os.clock()-start_clock)/(24*60*60))
hours,remainder=math.modf(remainder*24)
minutes,remainder=math.modf(remainder*60)
seconds,remainder=math.modf(remainder*60)
print(string.format("%s(%02id:%02ih:%02im:%02is)",clock_msg,days,hours,minutes,seconds))
days,remainder=math.modf(os.difftime(os.time(),start_time)/(24*60*60))
hours,remainder=math.modf(remainder*24)
minutes,remainder=math.modf(remainder*60)
seconds,remainder=math.modf(remainder*60)
print(string.format("%s(%02id:%02ih:%02im:%02is)",time_msg,days,hours,minutes,seconds))
end
function getPS ( )
psList = ""
for ii = 1, structure.GetCount () do
local ps = structure.GetAminoAcid ( ii )
local sName = AANames [ ps ]
if sName == nil then
ps = "x"
end
psList = psList .. ps
end
return psList
end
function setPS ( oldtab, tab )
local changes = 0
for ii = 1, math.min ( tab:len (), structure.GetCount () ) do
local sType = tab:sub ( ii, ii )
local oType = oldtab:sub ( ii, ii )
if sType ~= oType then
local sName = AANames [ sType ]
if sName ~= nil then
if structure.IsMutable ( ii ) then
structure.SetAminoAcid ( ii, sType )
changes = changes + 1
else
print ( "segment "
.. ii ..
" is not mutable, skipping change to type \""
.. sType .. "\"" )
end
else
print ( "segment " .. ii .. ", skipping invalid type \"" .. sType .. "\"" )
end
end
end
return changes
end
function GetParameters ( tab )
local dlog = dialog.CreateDialog ( ReVersion )
dlog.tab0 = dialog.AddLabel ( "Primary structure" )
dlog.tab = dialog.AddTextbox ( "AASeq", tab )
dlog.u0 = dialog.AddLabel ( "" )
if mutable then
dlog.u1 = dialog.AddLabel ( "Usage: use select all and copy, cut, or paste" )
dlog.u2 = dialog.AddLabel ( "to save or change primary structure" )
else
dlog.u1 = dialog.AddLabel ( "Usage: use select all and copy" )
dlog.u2 = dialog.AddLabel ( "to save primary structure" )
end
dlog.w0 = dialog.AddLabel ( "" )
if mutable then
dlog.w1 = dialog.AddLabel ( "Windows: ctrl + a = select all" )
dlog.w2 = dialog.AddLabel ( "Windows: ctrl + x = cut" )
dlog.w3 = dialog.AddLabel ( "Windows: ctrl + c = copy" )
dlog.w4 = dialog.AddLabel ( "Windows: ctrl + v = paste" )
else
dlog.w1 = dialog.AddLabel ( "Windows: ctrl + a = select all" )
dlog.w3 = dialog.AddLabel ( "Windows: ctrl + c = copy" )
end
dlog.z0 = dialog.AddLabel ( "" )
if mutable then
dlog.ok = dialog.AddButton ( "Change" , 1 )
end
dlog.exit = dialog.AddButton ( "Exit" , 0 )
if ( dialog.Show ( dlog ) > 0 ) then
tab = dlog.tab.value
return tab:lower ()
else
return ""
end
end
function main ()
print ( ReVersion )
print ( "Puzzle: " .. puzzle.GetName () )
print ( "Track: " .. ui.GetTrackName () )
undo.SetUndo ( false )
for ii = 1, structure.GetCount () do
if structure.IsMutable ( ii ) == true then
mutable = true
break
end
end
local changeNum = 0
local psList = ""
repeat
psList = getPS ()
print ( "primary structure, change # " .. changeNum )
print ( psList )
local psList2 = GetParameters ( psList )
if psList2:len() > 0 then
changeNum = changeNum + 1
local start_clock = os.clock ()
local start_time = os.time ()
local filter = behavior.GetFiltersDisabled ()
behavior.SetFiltersDisabled ( true )
print ( "-------- " .. "start of change " .. changeNum .. " --------" )
local sChg = setPS ( psList, psList2 )
behavior.SetFiltersDisabled ( filter )
report_time ( start_clock, start_time )
print ( sChg .. " segments changed" )
print ( "-------- " .. "end of change " .. changeNum .. " --------" )
end
until psList2:len() == 0
cleanup ()
end
function cleanup ( errmsg )
--
-- optionally, do not loop if cleanup causes an error
-- (any loop here is automatically terminated after a few iterations, however)
--
if CLEANUPENTRY ~= nil then
return
end
CLEANUPENTRY = true
print ( "---" )
--
-- model 100 - print recipe name, puzzle, track, time, score, and gain
--
local reason
local start, stop, line, msg
if errmsg == nil then
reason = "complete"
else
--
-- model 120 - civilized errmsg 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 ( ReVersion .. " " .. reason )
print ( "Puzzle: " .. puzzle.GetName () )
print ( "Track: " .. ui.GetTrackName () )
if reason == "error" then
print ( "Unexpected error detected" )
print ( "Error line: " .. line )
print ( "Error: \"" .. errmsg .. "\"" )
end
end
xpcall ( main, cleanup )