Code
--ScriptV2 Basics v0.5
--lesson1 = 'done'
--[[ ==========================================================================
Lesson 1: Copy a recipe and modify it.
You cannot save a modified version of someone else's recipe without fooling
the system. You will find it helpful to keep the original recipe unmodified
and save a copy of the recipe under a different name. This recipe is designed
as a series of lessons with one or more tasks in each lesson. By the time you
complete all the lessons you should be able to read and modify other people's
recipes and create your own recipes.
After you complete this lesson you will know how to save a copy of a recipe.
To complete lesson 1:
1. Click on the "Edit Recipe" icon. (you've done that.)
2. Remove the two dashes from line two. (now it should look like:
lesson1 = 'done'
3. Click on the "Save As" icon.
4. Append your name to the end of the Recipe Title.
5. Click on the "OK" icon.
6. Click on the "Close" icon.
7. Run your new recipe.
]]
--[[ ==========================================================================
Lesson 2: Identify Comments and Code.
After you complete this lesson you will be able to recognize
comments and distinguish comments from code most of the time.
You will also recognize:
1. String literals.
2. A simple assignment statement.
3. One of the forms of the print statement.
Comments are ignored by the computer.
Code causes the computer to do something.
Computers do things by executing the code.
Programmers add comments in their programs to:
1. Document what the code does.
2. Disable code they don't want executed.
The text you are now reading is inside a level 0 long comment.
This comment started with the closest prior two dashes(-) followed by two open brackets([).
This comment is ended by the first two close brackets(]) appearing later in the program.
Short comments begin with two dashes not appearing inside a long comment
or a string literal and end at the end of the line.
A short comment is a very common way to disable a line of code.
lesson 2 uses print statements to print in the Recipe Output window.
Print statements and their parameters are part of the code.
When a print statement is followed by a string literal the string is the
print statement's parameter and the string will appear in the Recipe Output window.
String literals will be defined shortly.
There are several ways to open the Recipe Output window. Here is one:
On the left side of the cookbook window the third icon from the bottom
will display "Show recipe output" if you let the mouse pointer hover over it.
Click on the "Show recipe output" icon. Here is another: While the recipe
is running a window will appear. Click on the "Show Output" Icon.
If you click on the "Save" icon in the recipe editor your changes to the recipe
will still be here later even if you close the session or look at a different recipe.
If you do not click on the "Save" icon your changes will be lost when you close foldit
or open another recipe.
If the computer doesn't know what it is being told to do it will
print an error message in the Recipe Output window.
Using the error message to help you fix your code is called "debugging".
]]
-- Lesson 2, Task 1: Disable a print statement.
-- run your recipe before and after you make your change to it.
-- don't do multiple tasks at the same time because it makes debugging harder.
-- Disable the following print statement by turning it into a short comment.
print 'print a string literal.'
--[=[ Lesson 2, Task 2: Temporarily enable a block of code inside a long comment.
Several lines of code can be disabled by placing them inside a long comment.
To temporarily enable a disabled block of code you can turn the start of a
long comment into a short comment by placing one or more dashes in front of it
or separating the brackets from the dashes.
For instance by changing:
--[[ the start of a level 0 long comment
to one of these:
---[[ the start of a level 0 long comment
-- --[[ the start of a level 0 long comment
-- [[ the start of a level 0 long comment
the start of the long comment becomes a short comment that can easily
be restored to the original to once again disable the block of code.
by putting -- before the ]], the -- starts a short comment when not
embedded in a long comment. The end of a disabled block of code will
commonly look like this:
--]]
Now temporarily enable the following disabled block of code.
When you are done learning about short string literals again
disable the block of code so it doesn't clutter the Recipe Output window.
]=]
--[[ This is the start of a long comment as originally written.
print 'Dashes like this -- are part of the string literal when inside quotes.'
print "A short string literal begins and ends with either a single or double quote."
print "A short string ends with the next occurrence of the character that started it."
print "This means it's possible to include instances of the other character in a string."
- this is either a short comment or the end of a long comment ]]
--[[ Lesson 2, Task 3: fix a bug.
Lua scans the program from left to right, top to bottom.
It finishes what it's doing before moving on.
This means comments and string literals can become entangled.
That has happened here.
First enable to part of the program inside the level 2 long comment and run the program.
Then fix a bug by turning a level 0 long comment into a level 1 long comment.
Then enable the part of the program inside the new level 1 long comment
to print the string literal with the brackets inside it.
note: you may need to close the editor window to see the recipe output window
]]
--[==[ the start of a level 2 long comment
--[[ the start of an embedded level 0 long comment
print "a short string literal with ]] in it."
--]]
--]==]
-- Lesson 2, Task 4: work with long string literals
-- long strings follow the rules of long comments except without the leading dashes
-- Play around with the long string literal to prove to yourself you understand it.
--[==[
print [[
By tradition if the open string token is followed by a carriage return
then that blank line doesn't print.
Can you make two adjacent close brackets appear in the output of
this print statement while still using a long string? ]]
--]==]
-- Lesson 2 Task 5: enable this assignment to the variable lesson2 to
-- tell the program you've completed lesson2.
-- lesson2 = 'done'
--[[ ==========================================================================
Lesson 3: The Building Blocks of a Lua Program.
After you complete this lesson you will be able to understand
most of what a Lua program is doing. Some things may still seem strange.
Why the programmer wrote the program the way it is written may never be
clear. The important part is making the program do what you want it to do.
The smallest piece of Lua code is called a lexical unit or token.
Lua is a free form, case sensitive language. This means that except
to help identify one token from another spaces, tabs, and new lines
don't make a difference to the code. Other than some special character
tokens, tokens can be broadly categorized as names, keywords, and
literals. Here are the special character tokens other than the
ones used to denote the start and end of long strings and comments:
+ - * / % ^ #
== ~= <= >= < > =
( ) { } [ ] ::
; : , . .. ...
Here are the keywords:
and break do else elseif end
false for function goto if in
local nil not or repeat return
then true until while
Names start with an underscore(_) or letter. Subsequent
letters, digits, and underscores are part of the name.
Names identify variables, table fields, and labels.
Variables have values assigned to them. The default value is nil.
Variables starting with underscore and continuing upper case
letters are generally reserved for system variables.
String literals have, for the most part been defined earlier
as short strings and long strings. Numeric literals start
with either a digit (0 through 9) or with the negation sign(-).
Numeric literals have special form for scientific notation and
hexadecimal notation. I'll not go into the gory details.
If you care you can find them at:
http://www.lua.org/manual/5.1/manual.html#2.1
A Lua program is composed of one or more statements.
Statements include declarations, assignments, control
structures, and function calls.
A list of statements is called a block of code.
The list of statements execute sequentially.
While this even applies to control structures and
function calls their execution causes other statements
to be executed out of order or to be ignored.
You will be given less direction as you progress.
You are expected to remember to enable and disable code
to try the examples. You will learn more by taking the
opportunity to create your own variations of the examples.
]]
--[[ Lesson 3, Task 1: Identify arithmetic expressions and types of numeric literals.
An arithmetic expression is either a number or the result of
an evaluation of an arithmetic operator.
Numeric literals are either integers or real numbers.
Integers do not have decimal points where real numbers do.
Unless you encounter hexadecimal or scientific notation you
don't need to worry about them right now.
The normal arithmetic operators exist in Lua and have their
normal meanings. The lexical tokens for these operators are:
+ - * / % ^
Most people recognize the first 4 but % and ^ may be new.
% is the modulo operator and ^ is the exponentiation operator.
The order in which operators are evaluated can be controlled by
parentheses. Programmers often shorten that to parens.
]]
-- enable and modify this code to help you understand and verify your
-- understanding of arithmetic operators
--[[ integers and real numbers and operations involving them.
print ("3 + 2 is",3 + 2) -- this is the second form of a function call.
print ("3 / 2 is", 3 / 2)
print ("3.0 / -2 is", 3.0 / -2)
print ("1 + (1 * 2) is", 1 + (1*2))
print ("(1+1) * 2 is",(1+1)*2)
-- The order in which operations are evaluated is call precedence.
-- If in doubt use parentheses.
-- For more information see http://www.lua.org/manual/5.1/manual.html#2.5.6
--]]
--[[ the modulo operator
x = 0
repeat -- The start of a control structure
-- that ends with the expression after the keyword 'until'
x = x + 1
print (x," % 3 is",x % 3)
until x == 10 -- == is a relational operator.
--]]
--[[ the exponent operator
print("2 ^ 1 is",2^1) -- 2 raised to the 1st power
print("2 ^ 2 is",2^2) -- 2 raised to the 2nd power (2 squared)
print("2 ^ 3 is",2^3)
print("2 * 2 is",2*2)
print("2 * 2 * 2 is",2*2*2)
print("")
print("4 ^ 0.5 is",4 ^ 0.5) -- the square root of 4
--]]
--[[ Lesson 3, Task 2: Identify string expressions
There is only one operator for strings, the concatenation operator.
To concatenate strings means to combine them and form one string.
A string expression is either a string or the result of the concatenation operator.
Enable this code and modify it to learn and verify your understanding of the
concatenation operator
]]
--[[
x, y = 'combine two ', 'strings together' -- assign values to two strings in one statement.
print(x..y)
print("2+2 is "..tostring(2+2)) -- print with one argument, a string expression
print("2+2 is ",2+2) -- print with two arguments, a string literal and a numeric expression.
--]]
--[[ Lesson 3, Task 3: Identify boolean expressions
The keywords true and false are the two boolean literals.
The boolean negation operator is the keyword not.
The result of a relational operator is a boolean.
While the keywords and and or can be boolean operators, technically they are not.
Enable this code and modify it to learn and verify your understanding of boolean expressions.
]]
--[[ true and false are opposite boolean values.
print ('not true is',not true)
print ('not false is',not false)
print ('not (not false) is',not (not false))
-- nil is a type upon itself but not nil returns true
print('not nil is',not nil)
--]]
--[[ The relational operators == and ~=.
-- == means equals. To be equal the expressions on both sides of the equals
-- sign must be of the same type and value.
print ('6 is of type',type(6))
print ('"6" is of type',type("6"))
print ("6 == '6' is",6 == '6') -- type matters
print ("6 == 6 is",6 == 6)
print ("'this' == 'this' is",'this' == 'this')
print ("'this' == 'This' is",'this' == 'This') -- capitalization matters
print ("nil == false is",nil == false)
-- ~= means does not equal. ~= returns the opposite of ==
-- Modify the prior print statements to verify.
--]]
--[=[ The relational operators >, >=, <, and <=.
--[[
The expressions on both sides of these operators must be of the same type and be of types string or number.
> means greater than.
>= means greater than or equal to.
< means less than.
<= means less than or equal to.
]]
x,y,z = 1,2,2
print(x,'<',y,'is',x < y)
a,z,A,Z,zero,one,colon = 'a','z','A','Z','0','1',':'
print(a,'<',A,'is',a < A)
-- The way characters in a string compare is called the collating sequence
-- Different systems have different collating sequences.
print(a,'>',A,'is',a>A)
print(a,'>',Z,'is',a>Z)
print(z,'>',A,'is',z>A)
--]=]
--[[ Lesson 3, Task 4: Identify function definitions, function declarations, and function calls.
A function declaration is a statement.
A function definition is an expression.
A function call can be either a statement or an expression.
A function declaration has the form:
function functionname (paramlist) body end
A function definition has the form:
function (paramlist) body end
body is a chunk of code. This chunk of code doesn't execute until the function is called.
paramlist is a set of names to which values will be assigned before
executing the body of the function.
Most function calls have one of these forms:
functionname ( explist )
functionname string
When a function is done executing so is the function call
explist is a comma separated list of expressions.
Before the body of a function is executed the list of expressions are evaluated
and their values assigned to the names in the paramlist. Even if you use
the very same names for what you think is the very same thing in the paramlist
and outside the function the names in the paramlist reference different variables
than ones with the same name that might exist outside the function.
enable and modify this code to learn and verify your understanding of functions and calls to functions
]]
--[[ A function's parameters have a limited life. This is called the scope of a variable.
function func1 (x)
print (x)
x=10
end
x = 4
func1 (x)
print (x)
--]]
--[[ A function can return a list of values by executing a return statement
function func2 (x)
if type(x) == 'number' then
return x + 1,type(x)
else
return nil,type(x)
end
print "After executing the return no more statements in the function are executed"
end
a,b = func2(5)
print (a,b)
a,b = func2('test')
print(a,b)
--]]
--[[ The purpose of a function definition may not be clear right now.
-- Programmers have strange habits.
func3 = function () return "strange" end
print (func3())
print (type(func3))
print (type(func3()))
--]]
--[[ Lesson 3, Task 5: Identify the logical operators and control structures
Lua has 8 basic types of values. You've seen five of them: nil, boolean,
number, string, and function. Of the three remaining you will only see
the value type table in foldit. Tables will be explained in the next lesson.
I mention them here because the logical operators aren't all that logical
and a value of type table will be used in the for loop. For now you just
need to recognize a table definition, constructor, begins with a open
brace({) and ends with a close brace (}).
The three logical operators are:
and -- so called conjunction operator
-- returns the first value if nil or false
-- otherwise returns the second.
or -- so called disjunction operator
-- returns the first value if not nil or false
-- otherwise returns the second.
not -- so called logical negation operator
-- returns true if the value following it is nil or false
-- otherwise returns false.
There is one more operator not discussed in this lesson, the length operator #.
I will discuss it in the next lesson. I'll not discuss the order in which operators
are evaluated. If you care read http://www.lua.org/manual/5.1/manual.html#2.5.6
I prefer you use parentheses to indicate order where there is any question.
The control structures are:
if statement -- Conditionally execute a block of code.
for loop -- Execute a block of code a fixed number of times
-- or over a set of indexes into a table.
repeat loop -- Execute the same block of code until some condition is met.
while loop -- Execute the same block of code while some condition exists.
Enable the following code and modify it to learn and verify your understanding
]]
--[[ The and operator
print ('1 and 2 is',1 and 2)
print ("0 and 'a' is",0 and 'a') -- Zero is a number. it is neither false nor nil.
print ('0 and false is',0 and false)
print ('false and 5 is',false and 5)
]]
--[[ The or operator
print (type(x)) -- type is a predefined function
print ("x or 'x is not assigned a value' is",x or 'x is not assigned a value')
x = x or 'x is assigned a value'
print ("x or 'x is not assigned a value' is",x or 'x is not assigned a value')
x = x or "x is assigned a value if one wasn't already assigned"
print ("x or 'x is not assigned a value' is",x or 'x is not assigned a value')
print ("x or nil is",x or nil)
print (type(x))
--]]
--[[ the not operator has previously been defined. this is a review
print ("not aNamedVariable is",not aNamedVariable)
aNamedVariable = 'now it has a value assigned'
print ("not aNamedVariable is",not aNamedVariable)
--]]
--[[ the if statement
x = 5
if x then
-- type and tostring are predefined function
print('The value of x is the '..type(x)..': '..tostring(x))
end
if y then
print('The value of y is the '..type(y)..': '..tostring(y))
else
print("y has the default value "..type(y))
print("so assign y = '5'")
y = '5'
end
if x == y then
print('x and y are of the same type and have the same value')
elseif type(x) == type(y) then
print('x and y are both of type '..type(x)..'\nbut have different values')
else
print ('A '..type(x).." just isn't equal(==) to a "..type(y))
if (type(x)=='number') and (type(y)=='string') then -- an embedded if statement
if (tostring(x) == y) then
print("When x is converted to a string\nit has the same value, ('"..y.."') , as y")
end
-- you can include as many elseif clauses as you want
elseif (type(x)=='string') and (type(y)=='number') then
if (x == tostring(y)) then
print("When y is converted to a string\nit has the same value, ('"..x.."') , as x")
end
end
end
--]]
--[[ The for loop
There are two forms of for loops
for name = startvalue, endvalue, step do block end
-- step is optional it defaults to 1
for namelist in iterator do block end
-- iterator is a special type of function whose explanation is beyond the
-- scope of this lesson. The iterator ipairs will be used in example code.
]]
--[[ the variable named in the for statement is local to the for statement
y = 5
for x = y-1, y+1 do
print ('inside the for loop x is',x)
end
print ('outside the for loop x is',x)
--]]
--[[ when step is negative the loop stops when name is less than or equal to the endvalue
for a = 1, -10, -10 do
print (a)
b = a -- even though a has a local scope other variables needn't be local
end
print ('outside the loop b is ',b)
--]]
--[[ the second variety of for loop
aTable={'red','white','blue'}
for place,color in ipairs(aTable) do
print(color,'is in position',place)
end
--]]
--[[ the repeat loop
repeat
print "Press a button"
a = (a or 0) + 1
-- When a variable is declared local it's scope is the block of code in which it is declared.
-- A variable may be assigned a value when it is declared
local x = dialog.CreateDialog('Repeat loop?') -- in this case x is a special type of table.
x.l = dialog.AddLabel('You have been through the loop '..tostring(a)..' time(s).')
x.b1 = dialog.AddButton('Repeat',1) -- x.b1 is a named field within the table.
x.b2 = dialog.AddButton('Quit',0) -- dialog is also a special table called a library
y = dialog.Show(x) -- if you "x" out of the box it returns 0
print ("dialog.Show(x) returned",y)
until y == 0 -- quit when y is 0
print("outside the loop a is",a)
print("outside the loop y is",y)
print("outside the loop x is",x)
--]]
--[[ the while loop, the do statement, and the break statement
The while loop has this form:
while expression do block end
The block of code executes as long as the expression is not nil or false.
There is a statement called a do statement. It has the form:
do block end
The keyword do in the while statement is part of the while statement
and not the start of a do statement.
You can exit a for, repeat, or while loop early by using the break
statement. You cannot use the break to exit a do statement. The
do statement is used to limit the scope of a variable.
]]
--[[ this for and while loop produce the same results except for the scope of the variables
print 'The for loop example'
for x = 1, 3 do
print(x)
end
print ('The value of x is',x) -- the scope of x is the for loop
print 'The while loop example'
x = 1
while x <= 3 do
print(x)
x=x+1
end
print ('The value of x is',x)
print 'The while loop equivalent to the for loop'
print 'using a do statement and a local variable'
x = nil
do
local x = 1
while x <= 3 do
print(x)
x=x+1
end
end
print ('The value of x is',x)
--]]
--[[ the use of a break statement
do
local a, x
while true do
x = (x or 11) - 1
print (x)
if x == 1 then
print "abort!"
a = 'That was close.'
break -- this breaks out of the while loop
end
a = 'still counting'
end
print (a)
print ('We stopped counting at',x)
end
if a then -- a was defined as local to the do statement
print ("a has value",a)
end
--]]
-- Lesson 3, Task 6: Indicate Lesson 3 is done, Yipee!
--lesson3 = 'done'
--[[
There are a few more language constructs. You won't see them very often.
If you run into something you don't know and want to know find out what
it means you can look it up at http://www.lua.org/manual/5.1/manual.html
]]
--[[ ==========================================================================
Lesson 4: Working with Tables.
Tables are the primary way of grouping objects into a collection.
A table constructor is an expression so can appear on the right side
of a variable assignment. The Lua manual formally defines a table
constructor this way:
tableconstructor ::= { [fieldlist] }
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= [ exp ] = exp | Name = exp | exp
fieldsep ::= , | ;
Programmers learn this notation or variants of it called
Backus Normal Form or BackusNaur Form.
In this case items inside a pair of brackets are optional.
Items inside parentheses are optional and can be repeated.
Items inside quotes are required.
Items separated by pipes are alternatives one of which
must be selected. This will become clear as the lesson progresses.
]]
--[[ Lesson 4, Task 1: Identify a sequence and the length operator
A sequence is the portion of the table with sequential counting
number indexes without a gap. The normal way to describe a sequence
is by not assigning index values.
]]
--[[ a normal sequence table
x = {'Red','White','Blue'} -- assign the name x to a sequence table.
print 'Using the length operator'
for i=1,#x do -- use the length operator to find the length of the sequence.
print(x[i]..' is a color')
end
print 'Using the ipairs iterator'
for i,v in ipairs(x) do
print ('x['..tostring(i)..'] is',x[i])
end
--]]
--[[ a sequence table with nil values
x = {'Ball',3,'Blue',nil,4.2} -- assign the name x to a sequence table.
print 'Using the length operator on a sequence'
for i=1,#x do -- use the length operator to find the length of the sequence.
print('x['..tostring(i)..'] is',x[i])
end
-- ipairs stops at the first nil value in counting number indexes
print 'Using the ipairs iterator'
for i,v in ipairs(x) do
print ('x['..tostring(i)..'] is',x[i])
end
-- pairs ignores nil values
print 'Using the pairs iterator'
for i,v in pairs(x) do
print ('x['..tostring(i)..'] is',x[i])
end
--]]
--[[ an advanced topic related to the length operator and sequences
x = {'Ball',3.1,'Blue',nil,4.2}
print 'normal behavior'
for i=1,#x do -- use the length operator to find the length of the sequence.
print('x['..tostring(i)..'] is',x[i])
end
-- assigning nil to an index in the a sequence whose indexes haven't been modified
x[3]=nil
print 'normal assignment inside the sequence'
for i=1,#x do -- use the length operator to find the length of the sequence.
print('x['..tostring(i)..'] is',x[i])
end
-- attempting to modify the size of the sequence after declared cause strange behaviors
print 'extending a sequence containing a nil value'
table.insert(x,'insert at end') -- inserts at the end of the sequence
for i=1,#x do -- use the length operator to find the length of the sequence.
print('x['..tostring(i)..'] is',x[i])
end
for i=1,5 do -- the end of the sequence is #x+1 but what is #x
table.insert(x,'test'..tostring(i))
end
print 'after 5 inserts'
for i=1,#x do -- use the length operator to find the length of the sequence.
print('x['..tostring(i)..'] is',x[i])
end
-- attempting to assign nil to an index in the sequence after modifying its declared indexes
-- I cannot explain this behavior. If you can figure it out let me know.
print 'assigning nil after extending a sequence'
x[3]=nil -- inside the originally declared indexes
x[7]=nil -- outside the originally declared indexes
--x[8]=nil -- try running with this line disabled and with it enabled
for i=1,#x do -- use the length operator to find the length of the sequence.
print('x['..tostring(i)..'] is',x[i])
end
--]]
--[[ Lesson 4, Task 2: Work with tables other than sequences.
Tables are more generic than a sequence table. You can assign
a value to a name or other index. The contiguous set of counting
number indexes still work as though a sequence. During a table
declaration values not assigned to a specific index are assigned
sequentially to the counting numbers starting with 1. This happens
even when you have previously assigned a value to the counting number
index
Try various tests to make sure you understand tables, the length operator
when applied to tables, and how to index a multi-dimension table.
]]
--[[
x = {
[2]='Red',
[3]='White',
[1]='Yellow',
grey='Grey', -- this might help explain what the length operator is really doing.
[5]='Orange',
['members']=function() for i,v in pairs(x) do print('index',i,'has value',v) end end,
'Blue', -- this is the first value not assigned assigned to a specific index
list={4,3,nil,1}
}
print 'working with the "sequence"'
for i=1,#x do -- use the length operator to find the length of the sequence.
print(x[i]..' is a color')
end
-- When a string index conforms to the form of a name one can use "dot" notation
-- even though it was defined or assigned using an index notation.
x.members() -- notice the way the print statement handles functions and tables as values?
-- The sequence is still identified by the contiguous set of counting numbers
-- even though some where specifically identified
print ('The sequence has length '..tostring(#x))
x[4]='Yellow'
print ('Now the length is '..tostring(#x))
-- list is a table within a table. You can pass through it just like any other table.
for i = 1,#x.list do
print('x.list['..tostring(i)..'] is '..tostring(x.list[i]))
print('x.["list"]['..tostring(i)..'] is '..tostring(x["list"][i]))
end
--]]
--[[ an advanced topic, a formatted print of a two dimensional table
-- there shouldn't be much call for this in foldit.
x={ -- declare the table as a sequence of sequences
{'a', 'b', 'c', 2},
{'d', 'e', 'f', -3},
{'g', 'h', 'i', 14.5}
}
for i=1,#x do
local s = ' '
for j=1,#x[i] do
s=s..string.format('%-5s',x[i][j]) -- format a string as a left justified 5 character string
end
print (s)
end
print ' '
for i=1,#x do
-- unpack returns a list of the table values
print(string.format(' %-2s%-4s%5s%% : % 8.2f',unpack(x[i])))
end
-- formatting patterns, default is right justify.
-- %[flags][width][.precision]specifier
-- flags: - means left justify, + means always show sign, space means allow space for minus sign
-- specifiers: s means string, d means decimal, f means float. (There are more but seldom used.)
-- You must have as many additional parameters as you have formatting patterns in the first parameter.
-- %% inserts a % where it appears. other characters are copied to the output.
]]
--[[ Lesson 4, Task 3: Track down the standard libraries
Lua has several standard libraries defined at http://www.lua.org/manual/5.1/manual.html#5
The Foldit implementers have restricted access to some of them and to some
of the basic library. The basic library functions aren't inside a table.
If you see a function call and you don't find a definition for the function
then it is likely part of the basic library.
In addition to the basic library the following libraries are collected into
tables called packages:
table name -- Library
coroutine -- coroutine library
package -- package library
string -- string manipulation
table -- table manipulation
math -- mathematical functions
bit32 -- bitwise operations
io -- input and output
os -- operating system facilities
debug -- debug facilities
]]
--[=[
basic={ -- the basic library functions are not declared inside a table
_G=_G, -- the left side is the named index in the basic table
_VERSION=_VERSION, -- the right side is the value of the named object if it exists
assert=assert,
collectgarbage=collectgarbage,
dofile=dofile,
error=error,
getfenv=getfenv,
getmetatable=getmetatable,
ipairs=ipairs,
load=load,
loadfile=loadfile,
loadstring=loadstring,
next=next,
pairs=pairs,
pcall=pcall,
print=print,
rawequal=rawequal,
rawget=rawget,
rawset=rawset,
select=select,
setfenv=setenv,
setmetatable=setmetatable,
tonumber=tonumber,
tostring=tostring,
type=type,
unpack=unpack,
xpcall=xpcall
}
libraries={
coroutine=coroutine, -- to the left of the = sign is the named index
package=package, -- to the right is the name of a table uses as a library
string=string,
table=table,
math=math,
bit32=bit32,
io=io,
os=os,
debug=debug
}
print('Foldit implements lua version '.._VERSION..'.\n') -- \n means new line
for i, v in pairs(libraries) do
if v then print ('the library '..i..' is at least partially implemented.') end
end
print [[
The implemented functions or named values are:
]]
for i, v in pairs(libraries) do
if v then
for i2, v2 in pairs(v) do
print (' '..i..'.'..i2)
end
end
end
for i, v in pairs(basic) do
if v then
print (' '..i)
end
end
--]=]
--lesson4='done'
--[[ ==========================================================================
Lesson 5: The Foldit Libraries.
You can get more information by pressing the help button.
also http://foldit.wikia.com/wiki/Foldit_Lua_Functions
Some of the older recipes use the old foldit functions.
You will need to rely upon the wiki to figure them out.
Look at the code inside recipes you like. Copy the portions
you especially like into your own recipes.
You will find the easiest way to start writing a recipe
is to first outline it in comments then add the code to
cause the computer to do what you've outlined.
I've found many of my bright ideas for recipes didn't
pan out. Don't be discouraged. You learn from these
failures by analysing why they didn't work.
I will cover the foldit functions in more detail in another
recipe.
]]
-- help()
--lesson5='done'
--[[ ==========================================================================
Lesson 6: Parting Thoughts.
Let me know what you think and how I can make this more useful for you.
Let me know if you don't think it of value at all.
my username is GaryForbis. Send me a message.
This recipe is about 1,000 lines long.
Most of the time I used notepad++ to edit it.
It was much easier to find the errors that way as well.
You can get a copy at http://notepad-plus-plus.org/resources.html
You can copy the recipe by pressing alt-c.
You can cut the recipe by pressing alt-x.
You can paste into the recipe editor by pressing alt-v.
I set my notepad++ Language to lua.
I set my notepad++ Settings,preferences tab setting for lua to 2, replacing by space.
I set my notepad++ Edit, EOF Conversion to UNIX/OSX Format.
I save my recipe on disk with the lua extension.
I make major changes to my recipe I cut the recipe from the recipe editor.
I then copy my recipe from notepad++ and paste it into the recipe editor.
If I make minor changes, such as fixing syntax errors, I will make them
in the recipe editor then copy my recipe back into notepad++.
The line numbers in the recipe output window are easy to find in notepad++.
]]
lesson6='done'
--[[ ==========================================================================
The following is the part of the program that causes the dialogue boxes
to be displayed. You should be able to read and understand this code
once you complete all of the lessons. If you cannot you might want to
review the lessons.
]]
intro=intro or {} -- this says define intro as a table if it isn't already.
intro.Title = 'ScriptV2 Basics'
intro.Version = '0.5' -- 2014-10-25
intro.Author = 'Gary Forbis'
intro.lesson=intro.lesson or {}
intro.lesson[1]={
"Copy a recipe and modify it.", -- lesson title
lesson1, -- status
{
"Be brave "..user.GetPlayerName()..".",
"You can do the exercises.",
'',
'ScriptV2 recipes use the Lua programming language.',
"To the right of the recipe's name are the icons:",
' "Cut Recipe", "Edit Recipe", and "Run Recipe".',
'',
'To complete lesson 1:',
'1. Click on the "Edit Recipe" icon.',
'2. Remove the two dashes from line two.',
'3. Click on the "Save As" icon.',
'4. Append your name to the end of the Recipe Title.',
'5. Click the "OK" icon.',
'6. Click on the "Close" icon.',
'6. Run your new recipe.'
}
}
intro.lesson[2]={
'Identify Comments and Code.',
lesson2,
{
'The computer ignores comments and executes code.',
'Programmers add comments in their programs to:',
'1. Document what the code does.',
"2. Disable code they don't want executed.",
'',
'Lua has multle levels of comments.',
'Excluding some special rules covered later:',
'1. Everything to the right of -- is a comment',
' called a short comment.',
'2. Everything between --[[ and ]], including --',
' is a comment called a level 1 long comment',
'3. Everything between --[=[ and ]=], including',
' --, --[[, and ]] is a comment called a level 2',
' long comment.',
'Add additional = between opening and closing',
'brackets for deeper levels of long comments.',
'',
'Everything else is code.'
}
}
intro.lesson[3]={
'The Building Blocks of a Lua Program.',
lesson3,
{
'Lua scans the program text, ignoring comments,',
'and breaks it into tokens, lexical elements,',
'acording to s formal grammer.',
'',
'Except to separate one token from another spaces,',
'tabs, and new lines are ignored.',
'',
'Tokens are broadly categorized as names, keywords,',
'literals, and special character tokens.',
'',
'Tokens are combined to form statements.',
'Statements are broadly categorized as assignments,',
'declarations, function calls, and control structures.',
'',
'Statements are combined into lists called blocks',
'of code where the totality of all statements is',
'the program.',
'',
'These things will be explained in more detail',
'as you complete the Lesson 3 tasks.'
}
}
intro.lesson[4]={
'Working with Tables.',
lesson4,
{
'Tables are a set of indexed values.',
'They are useful for defining lists and other',
'collections such as library packages.',
'',
'A table constructor starts with { and ends with }',
'and may contain zero or more expressions along',
'with an optional index to which the expression is',
'assigned. Table fields appearing in the constructor',
'are separated by either a comma or a semicolon.',
"When the index isn't given sequential numeric indexes,",
'starting with 1, are assigned to field expressions.',
'',
'A table field is referenced by the value of an',
'expression appearing between [ and ]. If the',
'index is a string conforming to definition of a',
'name the field can referenced using the "dot"',
'notation. x.y and x["y"] reference the same field.',
'On the other hand, x[2] and x["2"] reference',
'different fields.'
}
}
intro.lesson[5]={
'The Foldit Libraries.',
lesson5,
{
'Prior to ScriptV2 the Foldit functions were jumbled',
"in with the basic Lua functions. That's not a good",
'idea. While those functions still exist there are',
'replacements grouped into library packages.',
'',
'You can see a cursory definition of the functions',
'by pressing the help button on the recipe editor.',
'',
'The tables for the various foldit packages are:',
'absolutebest, band, behavior, contactmap,',
'creditbest, current, dialog, freeze, puzzle,',
'recentbest, recipe, rotamer, save, scoreboard,',
'selection, structure, ui, undo, and user.'
}
}
intro.lesson[6]={
'Parting Thoughts.',
lesson6,
{
'Lessons 5 and 6 are stubs right now.',
"I'm hoping for some feedback to help me improve",
'this recipe or find out no one wants it.',
'',
'Send me your thoughts. My Foldit username is',
'GaryForbis'
}
}
-- showLesson displays the lesson outline for lessonNo
-- It returns a number telling doLessons what to do next.
function intro.showLesson(lessonNo)
-- convert lessonNo to a string once and use many times.
local lessonNoS = tostring(lessonNo)
-- The structure of entries in intro.lesson is
local Title = intro.lesson[lessonNo][1] -- a string
local Status = intro.lesson[lessonNo][2] -- a string
local Text = intro.lesson[lessonNo][3] -- a table of strings
-- now start building the dialogue box
local dlg=dialog.CreateDialog('Intro to Lua: Lesson '..lessonNoS)
dlg.lb1 = dialog.AddLabel("Lesson "..lessonNoS..": "..Title)
dlg.lb2 = dialog.AddLabel('')
--[[
I don't know why you have to assign labels to named indices in
the dialogue box's table. This does that for an arbitrary number
of lines in the table at intro.lesson[lessonNo][3]
]]
for i = 1, #Text, 1 do
dlg["l"..tostring(i)] = dialog.AddLabel(Text[i])
end
dlg.le1 = dialog.AddLabel('')
if Status ~= 'done' then
-- the following line isn't appropriate if you reviewing a prior lesson.
dlg.le2 = dialog.AddLabel('Quit the recipe and edit it to complete lesson '..lessonNoS..'.')
elseif lessonNo < #(intro.lesson) then
-- but if you are reviewing prior lessons then add the 'Next' button
dlg.next = dialog.AddButton('Next',lessonNo+1)
end
dlg.review = dialog.AddButton('Review',-1)
dlg.quit = dialog.AddButton('Quit',0)
return dialog.Show(dlg)
end
-- preface displays an outline of the process.
-- it returns a number telling doLessons what to do next
function intro.preface()
local Text = {
intro.Title,
'Version '..intro.Version..' By '..intro.Author,
'',
'This recipe is designed to teach you how to',
'read LUA code sufficiently well to copy and',
"modify someone else's Lua recipe and to start",
'building your own recipes.',
'',
'You learn by modifying a copy of this recipe.',
'The steps are divided into lessons. Each lesson',
'has one or more tasks for you to do.',
'',
'You will need to open the Recipe Output window',
'so you can see the effects of your lessons.',
'To open the Recipe Output window click on the',
'"Show Output" Icon.',
'',
'To get started press Lesson 1.',
'To see a list of the lessons press Review.'
}
local dlg=dialog.CreateDialog(intro.Title)
for i = 1, #Text, 1 do
dlg["l"..tostring(i)] = dialog.AddLabel(Text[i])
end
dlg.le1 = dialog.AddLabel('')
dlg.next = dialog.AddButton('Lesson 1',1)
dlg.review = dialog.AddButton('Review',-1)
dlg.quit = dialog.AddButton('Quit',0)
return dialog.Show(dlg)
end
-- display the review dialogue box.
function intro.review(priorLesson, maxReview)
local nextLesson = priorLesson + 1
if nextLesson > maxReview then
nextLesson = 1
end
local dlg = dialog.CreateDialog('Intro to Lua: Review')
for i, lesson in ipairs(intro.lesson) do
dlg['l'..tostring(i)] = dialog.AddLabel('Lesson '..tostring(i)..': '..lesson[1])
end
dlg.r0 = dialog.AddLabel('')
if maxReview > 1 then
dlg.r1 = dialog.AddLabel('Select the number of the lesson to review.')
dlg.r2 = dialog.AddSlider("Lesson:",nextLesson,1,maxReview,0)
dlg.bs = dialog.AddButton('Select',1)
dlg.bq = dialog.AddButton('Quit',0)
if dialog.Show(dlg) == 0 then
return 0
else
return dlg.r2.value
end
else
dlg.bs = dialog.AddButton('Lesson 1',1)
dlg.bq = dialog.AddButton('Quit',0)
return dialog.Show(dlg)
end
end
-- The outer loop that controls which dialogue box to display.
function intro.doLessons()
-- find the first lesson not marked done.
local currentLesson = 1
while (intro.lesson[currentLesson][2] == 'done') and (currentLesson < #intro.lesson) do
currentLesson = currentLesson+1
end
-- you can't review lessons beyond the one you are currently doing.
local maxReview = currentLesson
local priorLesson = currentLesson
if currentLesson == 1 then
currentLesson = intro.preface()
end
while currentLesson ~= 0 do
if currentLesson == -1 then
currentLesson = intro.review(priorLesson, maxReview)
else
priorLesson = currentLesson
currentLesson = intro.showLesson(currentLesson)
end
end
end
intro.doLessons() -- this is the code the dialogue boxes to be displayed.