Lua Scripting Tutorial (Beginner 5) introduced Lua tables, which are used extensively in Foldit recipes. Tables are similar to arrays in other language, but Lua tables are much easier to use, and much more powerful.

The tutorial also introduced a function called Sort, lifted from Tvdl enhanced DRW 3.0.1 by Timo van der Laan. The function Sort changes the order of table. In the recipe, it's used to put the worst sections of the protein at the beginning of the table.

We'll take a more detailed look at how Sort works, then talk about some other things that Lua tables can do.

As before, the Lua 5.3 reference manual gives the technical details behind the Lua topics discussed here.

Most of the small chunks of Lua code below can be copied and pasted into the Foldit recipe editor for a quick test. Select "New (ScriptV2)" to get a blank recipe, paste in the code, and click "Run". You'll need to close the recipe editor to view the recipe output window. The Foldit recipe editor fine for this type of light tinkering.

Function SortEdit

Sorting a table doesn't take a lot of code:

function Sort ( tab, items ) --BACKWARD bubble sorting - lowest on top, only needed items
    for xx = 1, items do --items do
        for yy = xx + 1, #tab do
            if tab [ xx ] [ 1 ] > tab [ yy ] [ 1 ] then
                tab [ xx ], tab [ yy ] = tab [ yy ], tab [ xx ]
    return tab

The nice part about this sort is that it stops after sorting "items" table entries to the front. Most sorts would sort the entire table, which is fine, but sorting is hard work.

This small function demonstrates another unique feature to Lua, the ability to swap variables:

tab [ xx ], tab [ yy ] = tab [ yy ], tab [ xx ]

Here's an example that makes things clearer:

aa = 5
bb = 22
print ( "aa = " .. aa .. ", bb = " .. bb )
bb, aa = aa, bb
print ( "aa = " .. aa .. ", bb = " .. bb )

Try running those lines in a new Foldit recipe. Other languages can do the same thing, but make it more difficult, requiring an extra variable:

aa = 5
bb = 22
print ( "aa = " .. aa .. ", bb = " .. bb )
cc = bb
bb = aa
aa = cc
print ( "aa = " .. aa .. ", bb = " .. bb )

Once again, Lua is a very elegant language.

Another sort of sortEdit

Function Sort is useful, but it only works for a specific type of table. It sorts on the first column of a two-dimensional table. The column can contain numbers or characters, but it can't be another table. (For example, a three-dimensional table.)

Also, Sort only sorts in one direction.

Changing this line:

if tab [ xx ] [ 1 ] > tab [ yy ] [ 1 ] then

can change the behavior of Sort, for example:

if tab [ xx ] [ 2 ] < tab [ yy ] [ 2 ] then

would sort on column 2, in the opposite direction.

Lua has a built-in function, table.sort, which is more general-purpose. Unlike our Sort function, table.sort always sorts the entire table. Unlike Sort, table.sort can sort the table in different ways. You define a Lua function which compares two table entries, then pass it to table.sort, which calls the function

Lua lets you use an anonymous function, as an argument to table.sort. The following statement would sort the table of worst section in the same order as before:

table.sort ( worstTab, function ( a, b ) return a [ 1 ] < b [ 1 ] end  )

Unlike our custom Sort function, this statement sorts the entire table.

You can define a regular named function and pass it to table.sort:

function sortCol1 ( a, b )
    return a [ 1 ] < b [ 1 ] 
table.sort ( worstTab, sortCol1 )

This version produces the same results as the previous one.

More tablesEdit

In Foldit recipes, most tables are like the ones we've already seen, lists of entries indexed by numbers. Lua tables can take other forms as well. Here's a table of amino acid info that sometimes comes in handy in Foldit:

AminoAcids = {
       a = { "Ala", "Alanine",        "nonpolar", "neutral",   1.8 },
    -- b = { "Asx", "Asparagine or Aspartic acid" }, 
       c = { "Cys", "Cysteine",       "nonpolar", "neutral",   2.5 },
       d = { "Asp", "Aspartate",      "polar",    "negative", -3.5 },
       e = { "Glu", "Glutamate",      "polar",    "negative", -3.5 },
       f = { "Phe", "Phenylalanine",  "nonpolar", "neutral",   2.8 },
       g = { "Gly", "Glycine",        "nonpolar", "neutral",  -0.4 },
       h = { "His", "Histidine",       "polar",   "neutral",  -3.2 },
       i = { "Ile", "Isoleucine",     "nonpolar", "neutral",   4.5 },
    -- j = { "Xle", "Leucine or Isoleucine" },  
       k = { "Lys", "Lysine",          "polar",   "positive", -3.9 },
       l = { "Leu", "Leucine",        "nonpolar", "neutral",   3.8 },
       m = { "Met", "Methionine ",    "nonpolar", "neutral",   1.9 },
       n = { "Asn", "Asparagine",     "polar",    "neutral",  -3.5 },
    -- o = { "Pyl", "Pyrrolysine" }, 
       p = { "Pro", "Proline",        "nonpolar", "neutral",  -1.6 },
       q = { "Gln", "Glutamine",      "polar",    "neutral",  -3.5 },
       r = { "Arg", "Arginine",       "polar",    "positive", -4.5 },
       s = { "Ser", "Serine",         "polar",    "neutral",  -0.8 },
       t = { "Thr", "Threonine",      "polar",    "neutral",  -0.7 },
    -- u = { "Sec", "Selenocysteine" },
       v = { "Val", "Valine",         "nonpolar", "neutral",   4.2 },
       w = { "Trp", "Tryptophan",     "nonpolar", "neutral",  -0.9 },
       x = { "Xaa", "Unspecified/unknown", "", "", 0 }, 
       y = { "Tyr", "Tyrosine",       "polar",    "neutral",  -1.3 },
    -- z = { "Glx", "Glutamine or glutamic acid" } ,

This table is indexed by the one-character amino acid code used in Foldit and elsewhere. The function structure.GetAminoAcid returns these codes.

Usually there are only 20 codes, but some Foldit puzzles have used the code "x" for a segment which represents a ligand. The list also includes some commented-out entries like "u" for Selenocystine, which are known to biochemists but not used in Foldit.

Defining a table this way lets you perform lookups based on a character value. For example, this code could be used to validate the amino acid codes found in a protein:

for ii = 1, structure.GetCount () do
       local aac = structure.GetAminoAcid ( ii )
       if AminoAcids [ aac ] == nil then 
           print ( "WARNING: unknown amino acid \'" 
                       .. aac .. 
                   "\' at segment " 
                       .. ii

This type of validation could allow a recipe to avoid any segments with unknown amino codes.

In other languages, a lookup like this would require looping through the table to find a matching entry.

The Foldit recipe print protein 2.4 uses the AminoAcids table to prepare a detailed report on the protein.

In ConclusionEdit

These "beginner" tutorials started out relatively easy, but quickly moved to more advanced topics.

The main focus has been on some of the unique features of Lua, and how they are used in Lua recipes. The tutorials have also discussed some of the import functions in the Foldit Lua Interface.

The sample recipe started as a simple series of commands like the ones in a GUI recipe. The recipe grew in complexity, eventually becoming one which selectively rebuilt only the worst segments in the protein.

The basic technique in this recipe is very similar the one used in the "DRW" -- "deep rebuild worst" -- family of recipes. The latest version of DRW is Tvdl enhanced DRW 3.0.1.

Unlike our sample recipe, DRW 3.0.1 is several thousand lines of Lua code. As the "deep" part of the name suggests, it tries to rebuild each section of the protein more than once. It also has more advanced techniques for stabilizing the protein after a rebuild, versus the simple shake and wiggle used in the example.

Although DRW 3.0.1 is big, there's nothing in it that should be totally mysterious at this point. There are lots of functions which do various things, and lots of tables which look at different aspects of the protein. All these functions and tables work just like the ones we've already looked at.

The first step toward writing you own recipes is generally to start with a good example. DRW 3.0.1 is a big recipe, but it contains lots of useful ideas.

Regardless of the size of recipe, you'll want to use an external editor. As suggested previously, Notepad++ is a good free editor for Windows, and if you name your files with the ".lua" extension, it will automatically highlight Lua keywords.

This series of tutorial has been completely revised as of April 2017. The older Lua Scripting Tutorial (Intermediate) and Lua Scripting Tutorial (Advanced) will be revised in the near future.

Community content is available under CC-BY-SA unless otherwise noted.