This tutorial is a continuation of Lua Scripting Tutorial (Beginner 4), which introduced the programming concept of looping.

The recipe used in this tutorial is Beginner Rebuild SCRIPT 5.01.

This tutorial continues to extend the same basic recipe used in the other beginner tutorials.

New featuresEdit

In this tutorial, Lua tables are introduced as a way to keep track of how well parts of a protein are scoring.

This tutorial introduces a new Foldit function, current.GetSegmentEnergyScore, which counts the segments in the protein.

A new and useful function called Sort is added as well. This function, taken from Tvdl enhanced DRW 3.0.1 by Timo van der Laan, sorts a table. The trick of this "Sort" is that it only sorts as many items as you want sorted.

As in the other tutorials, start Foldit with beginner or a revisiting puzzle. Reset the puzzle if you've already played it for the other tutorials. It's probably best to shake and wiggle before using the recipe, but it's not required.

Download Beginner Rebuild SCRIPT 5.01 and open it in the Foldit recipe editor. As before, it's best to export the recipe and then use an external editor like Notepad++, but the Foldit editor will do. One more advantage of an external editor is that it's easier to compare this version of the recipe to the previous versions.


In Lua, tables are similar to arrays in other programming languages, but much more powerful. This tutorial only begins to introduce the features of tables.

Creating a new table is simple. The statement

scoreTab = {}

in this tutorial's recipe creates a new table with nothing in it.

The most common way to use tables in Lua is have a numeric index that corresponds to a row in the table. In Lua (unlike some other languages), the assumption is that you'll start with index 1. This is perfect for working with Foldit proteins, which start with segment 1.

The first new step in the recipe is to create a table containing the score for each segment. That's just three lines of Lua:

for ii = 1, segCnt do
    scoreTab [ #scoreTab + 1 ] = current.GetSegmentEnergyScore ( ii ) 

As before, "ii" is a local variable that can be used only in the for loop, and "segCnt" is the number of segments in the protein, determined in an earlier step.

On the right-hand side of one statement inside the loop, the function current.GetSegmentEnergyScore gets the score of the corresponding segment.

The left-hand side is what requires some explaining:

scoreTab [ #scoreTab + 1 ]

Used in front of a table name, the "#" gives the number of numeric indexes in a table. The first time through the loop, #scoreTab gives a value of 0 (zero). So #scoreTab + 1 = 1, giving the first entry.

The square braces "[" and "]" are how you specify the index of a table. So, the first time through the loop, the statement ends up being:

scoreTab [ 1 ] = current.GetSegmentEnergyScore ( ii )

You could also write:

scoreTab [ ii ] = current.GetSegmentEnergyScore ( ii )

but in general, using the "#" operator is more flexible.

Tablulating, stage 2Edit

Having a table of segment scores is not too useful in itself, but it's a good first step.

The next step is to use the information in the segment scores table to help make some decisions about the protein.

The previous version of the recipe rebuilt the protein in sections of three, so segments 1 to 3, 4 to 6, 7 to 9, and so on.

That approach is great, but rebuilding takes time. Being a little more selective won't hurt.

In this version of the recipe, the goal is to pick the worst-scoring groups of three segments, then rebuild only a certain number of those.

The key to realizing this goal is to use the scoreTab create another table.

The code should look a little familiar already:

worstTab = {}           
for ii = 1, segCnt - buildLen + 1, buildLen do
    local partScore = 0
    for jj = ii, ii + buildLen - 1 do
        partScore = partScore + scoreTab [ jj ]
    worstTab [ #worstTab + 1 ] = { partScore, ii, ii + buildLen - 1 }

Here "worstTab" is the new table, and "buildLen" is the number of segments to rebuild at a time. As before, "buildLen" is set to 3, but you can also change this value.

There are actually two "nested" for loops in this example. Again "ii" is used to index the outer for loop, while "jj" is used for the inner. T

There's a variable "partScore", which is used to total up the "buildLen" segments.

The tricky part is the statement which adds a new table entry:

worstTab [ #worstTab + 1 ] = { partScore, ii, ii + buildLen - 1 }

Here the left-hand side of the equal sign is basically the same as what was used for the first table. The right-hand side is a little more confusing:

{ partScore, ii, ii + buildLen - 1 }

The curly braces "{" and "}" say that this is a table, but one with values, unlike the two empty tables we already created.

Each index in worstTab is going to be a table, so worstTab is really a table of tables. (A lot of Lua tables work this way.) Each index in worstTab will contain a table of three values:

  • segment score total for buildLen segments
  • first segment index
  • last segment index

These values make up the columns in worstTab.

The end result is that worstTab will look something like this:

worstTab = {
    { 3.72, 1, 3, },
    { 12.55, 2, 4, },
    { -7.8 3, 5, },
    ...and so on...

You can use statements like these to define a two-dimensional table like worstTab, but that makes sense only when you know all the values in advance.

Sorting it outEdit

The latest version of the recipe includes a new function Sort, which starts like this:

function Sort ( tab, items )

This line tells that Sort takes two arguments. One is "tab", the table to be sorted, and the other is "items", the number of items that will be used.

As before, the function statement and the lines that follow "function sort" (up until "end") don't do anything until you actually call the function.

We won't get into the details of how Sort works, but its really just two nested for loops, somewhat similar to the loops that produced worstTab.

The unique feature of this sort is that it partially sorts the table, stopping when after "items" table entries have been sorted to the beginning of the table. The table entries are sorted based on the first column, the segment score total, lowest values first.

To use Sort, we just call it with worstTab, and a variable "buildWorst", which specifies how many sections to rebuild:

buildWorst = 5
worstTab = Sort ( worstTab, buildWorst )

The sorted version of worstTab replaces the unsorted version.

See Lua Scripting Tutorial (Beginner 5 Tech Supplement) for more on function Sort.

Running it throughEdit

The final phase is to use the sorted table to rebuild a limited number of sections. As in the previous versions of the recipe, this happens in a for loop. In this version of the recipe, there are just a couple of changes to the for loop.

The first change is to use the variable "buildWorst" to control the loop, which actually makes things a bit easier:

for ii = 1, buildWorst do

The second change is to how the segments are selected. This version uses the second and third clumns of worstTab:

selection.SelectRange ( worstTab [ ii ] [ 2 ], worstTab [ ii ] [ 3 ] )

The rest of the for loop is much the same as before. The only other change doesn't affect what happens, but it does tell you what's going on:

print ( "rebuild "
            .. ii ..
            .. buildWorst .. 
        ", segments " 
            .. worstTab [ ii ] [ 2 ] .. 
        " - "
            .. worstTab [ ii ] [ 3 ] .. 
        ", score = "
            .. round ( worstTab [ ii ] [ 1 ] )

It's not necessary to format the print statement this way -- everything could appear on just one line. But lining things up this way makes it easier to see what's what.

Wrapping upEdit

There are two key variables which control this recipe:

buildLen = 3    -- number of segments to rebuild at a time
buildWorst = 5  -- number of groups of buildLen segments to rebuild

Try changing these values to see the effect on the results.

See Lua Scripting Tutorial (Beginner 5 Tech Supplement) for more on tables and the function Sort.

Back to Lua Scripting Tutorial (Beginner 4) Continue with Lua Scripting Tutorial (Intermediate)
Community content is available under CC-BY-SA unless otherwise noted.