Tutorial Lua Part 2: Operators, Tables, Loops and Statements

Discussion in 'Starbound Modding' started by The | Suit, Jan 20, 2015.

  1. The | Suit

    The | Suit Agent S. Forum Moderator

    [​IMG]



    This multipart guide was made in collaboration with @severedskullz and @AstralGhost

    INDEX


    TABLE OF CONTENTS
    REFERENCE PAGES

    If you have not read part 1. I suggest taking a look at it. If you have, than welcome to Part 2. In part 2 we will be focusing on tables, operators, statements and loops. Or the meat and potatoes of lua. So lets get started

    Also remember to use http://repl.it to follow along. So you can test the code your self and first hand witness each lesson in action.

    .


    CHAPTER 5: OPERATORS


    LUA has different type of operators; Arithmetic and Relational, Logical

    Arithmetic Operators
    Code:
    `+´ (addition), `-´ (subtraction), `*´ (multiplication), `/´ (division), and the unary `-´ (negation)
    With partial support for `^´ (exponentiation)
    Relational Operators
    Code:
    <  >  <=  >=  ==  ~=
    Relational operators always result in a value of TRUE or FALSE

    • < : Less Than - True if the value before the operator is less than the second value.
    • > : Greater Than - True if the value before the operator is greater than the second value.
    • <= : Less Than or Equal To - Same as the Less Than operator, but also True if both values are equal.
    • >= : Greater Than or Equal To - Same as the Greater Than operator, but also True if both values are equal.
    • == : Equal To - True only if both values are equal to each other.
    • ~= : Not Equal To - False if both values are equal to each other, otherwise True.

    When comparing values with different types, you must be careful: Remember that "0"==0 is false. Moreover, 2<15 is obviously true, but "2"<"15" is false (alphabetical order!). To avoid inconsistent results, Lua raises an error when you mix strings and numbers in an order comparison, such as 2<"15".

    Logical Operators

    Logical operators help create conditional statements in functions, to understand what that means first lets get a basic idea of each of the logical operators.
    The 3 logical operators are;
    Code:
    and, or, not
    • and - requires all conditions to be true to result in a true result
    • or - requires only a single condition to be true
    • not - inverses the value. So if the statement is true, it will result in a false value.

    Now to get a better idea lets look at a code example
    Do not worry about the if else statement in the following piece of code. We will get more into that later.
    First lets look at "and"

    Code:
    a = 1
    b = 2
    c = 3
    d = 4
    
    if a > b and c < d then
        print("true")
    else
        print("false")
    end
    Now if you notice in the code 1 > 2 and 3 < 4.
    Obviously 1 is not greater than 2 - hence the statement is false.
    Using "And" allows us to create a condition which requires both conditions to be met to result in a true value.

    Lets look at "or" now.
    Code:
    a = 1
    b = 2
    c = 3
    d = 4
    
    if a > b or c < d then
        print("true")
    else
        print("false")
    end
    Here you will notice that the 2nd statement is true. Hence the final result of the logical operator will be true. Using the "Or" operator requires only a single statement to be true before it returns a true value.

    Now for sake of completion lets make them both false values
    Code:
    a = 1
    b = 2
    c = 3
    d = 4
    
    if a > b or c > d then
        print("true")
    else
        print("false")
    end
    As you will notice in this case both statements are false, hence it produces a false value.

    not - function simply causes the result to be opposite. For example lets look at a true statement and add "not"
    Code:
    a = 1
    b = 2
    c = 3
    d = 4
    
    if not (a < b and c < d) then
        print("true")
    else
        print("false")
    end
    Now as you can see 1 is less than 2, and 3 is less than 4. But because of not the result again ends up being false.
    If you have keen eyes you will also notice the statement is now in brackets - in order to properly perform the order of operations.

    .


    CHAPTER 6: TABLES



    TERMINOLOGY
    Tables - are objects which holds information generally on basic rows and columns based system. In LUA there is no limit to the amount of data added to a table, nor the type of information. You can house variables, functions, strings, and even other arrays. Tables in LUA use associative arrays. But before we get into that lets look at the tables.

    Classic Table
    Baseball Team Wins
    Code:
    Teams        Wins
    Red Sox        2
    Astros         3
    Mets           9  
    LUA TABLE - Array
    Code:
    Baseball[1] = 2
    Baseball[2] = 3
    Baseball[3] = 9
    LUA TABLE - Associative Array
    Code:
    Baseball["Red Sox"] = 2
    Baseball["Astros"] = 3
    Baseball["Mets"] = 9
    As you can see the classic table you grew up with is not exactly the same as the Table we see when we look at LUA. No column names, row names, just pure unadulterated data. In the case of an array you can see each value is held by a numerical key [starting by default from 1 - though it can start with any number if defined so], and with an associative array a string. Though don't be fooled an associative array need not be a string key, it can be a numerical value or a variable also.

    PARTS OF A TABLE

    Before we go into making a table, lets look at the parts of one.

    Code:
    a[b] = c
    a = the current table identifier.
    Tables are anonymous and are not permanently attached to the identifier. They can be switched to any identifier at any time. But once no identifier is attached to the table, the table deletes it self.

    b = the key
    Notice it is enclosed by square brackets. The information inside the square bracket is the key value associated with the data. The key value can it self be any identifier, even a string. Note if a key is not assigned as in writing into a table directly - the table automatically assigns a numerical key which we will see a bit later.

    c = the data
    The data can be anything from a variable, string, function, or even another table, etc.

    CREATING AND SETTING UP TABLES

    Now that we know the parts of a table and the basic terminology involved. Lets first look at creating a table. For sake of time lets divide it into two main methods; simple and complex.

    Simple method
    Code:
    a = {} -- You first create the table.
    a[key] = data -- afterwards you assign keys and data accordingly
    In the simple method we first create a table and assign values to it.

    Complex method
    Code:
    complexTable = {"Auto Index 1" , "Index 2", "Index 3", [10] = "manual index 10", secretKey = "Mine is 'secretKey' "}
    print(complexTable[1])
    In the complex method we not only create the table but assign values to it in one fell swoop. Yet a keen eye will notice that is not all we did. We also used different methods of assigning keys to that data. So lets take another look at keys.

    • Data without an assigned key will automatically be assigned a key by lua in numerical order starting from one.
    • ["bob"] = "dole" - Will assign the key bob to the value dole. You are free to use any number also even negatives.

    NESTED TABLES
    Now to finish off tables lets look at nested tables. As we started earlier nested tables are tables within tables. Lets look at a few examples.

    Code:
    someTable = {anotherTable = { yetAnotherTable = { } } } -- We now have 3 tables!
    Access them the same way you would normally. I used a keyed value so I would type this:
    Code:
    someTable.anotherTable.yetAnotherTable -- Would give me the third table.
    someTable["anotherTable"]["yetAnotherTable"] -- Same thing but with Array-like access.
    Assigning still works the same, but at a different level
    Code:
    someTable.anotherTable.aNewTable = {} -- We just created a new table inside anotherTable. 
    "anotherTable" now has 2 tables: aNewTable and yetAnotherTable

    STRINGED KEYS AND NAMED FIELDS AND ACCESSING DATA

    Now that we know about how to create a table and what are nested tables. Let us look at accessing the data from the tables. As you may remember the simple method for placing data is essentially the same way to access the data. So if I wanted to access data for example from the table.

    Code:
    a = {}
    a["bob"] = 10
    print[a["bob"]) -- Would result in 10
    Even in the case of nested tables I would do same thing.
    Code:
    a = { b = { c = { "ten" } } }
    print(a["b"]["c"][1])
    Now this part is where variable names and string names becomes very important. A variable and a string are 2 different things. If you remember from the previous part a ≠ "a" even though they can. They are not by default equal. One is a variable the other is a string. So lets take a look at an example

    Code:
    a = "bob"
    table = {}
    table[a] = 99
    print(table[a]) -- You will get 99
    print(table["a"]) -- You will get Nil
    This is because the interpreter will automatically exchange the variable a with its value bob. To pull the data. Or in other words it is actually "bob" which is assigned the data. The variable "a" points to the value "bob" which is passed in to the table index lookup which finally returns our value of 99 stored there.

    Now a stringed key is simply a "string" which is a key. But there are 2 methods to set-up a stringed key. one method is without quotes, the other is with quotes and square brackets. If you use quotes without square brackets, you created a string. A string it self cannot hold data, it is not a variable.
    So

    Code:
    a["This is valid"] -- Works
    a.This is valid -- Does not work.
    a.This_is_valid -- Works, but the key is set to "This_is_valid"
    Another thing to point is when using the simple method to define a string key, you cannot use spaces. If you want spaces for a string key you need to use quotes and brackets. You can access data more quickly by setting up a field name with dots. For example

    Code:
    a = { b = { c = {"hello"}}}
    print(a.b.c[1]) -- prints hello
    print(a["b"]["c"][1]) -- prints hello
    Code:
    a = { ["bob is cool"] = { c = { "hello"}}}
    print(a.bob is cool.c[1]) -- would not work because of the space.
    The correct method would be
    Code:
    print(a["bob is cool"].c[1])
    SIZE OF ARRAY
    In some cases you may want to find the size of an array. Lua provides 2 functions
    • table.getn()
    • #table_name
    Examples
    Code:
    numb = { "one", "two", "three", "four" }
    print(table.getn(numb))
    or
    Code:
    numb = { "one", "two", "three", "four" }
    print(#numb)
    These functions though simple only provide the table size of numerically indexed data and ignores stringed keys.
    For example
    Code:
    a = {"one", "two", "three", "four"}
    a["five"] = ten
    a["eleven"] = twelve
    print(#a) --> will result only in 4
    The other main issue is it does not ignore nil values so it does not give an accurate representation in how much data is held with in the table. For example
    Code:
    a = {"one", "two", "three", "four"}
    a[8] = "Hello"
    print(#a) --> will result in 8
    In this example it will show 8 values are in the array, even though there are only 5.
    To get an accurate representation in the amount of numerically indexed data in an array we use a for loop.
    Code:
    a = {"one", "two", "three", "four"}
    a[8] = "Hello"
    count = 0
    for _ in pairs(a) do count = count + 1 end
    print(count) 
    .


    BREAK TIME


    Now is a good time to take a break. You now have a fundamental knowledge of arrays and tables in LUA. Take some time to ponder what you learned and get ready for a quiz. Fair warning, some topics from the previous part are included to help you concrete the basics.

    Question 1: Since spaces do not work for the simple method of creating string keys, is there another character you can use besides space to make the simple string key method to work?

    Question 2: Using string.gsub() change the word "problem" to "answer". Assign a new value through a function.
    Code:
    a = {"Test problem 2"}
    print(a[1])
    Question 3: Find the Mistake if any.
    Code:
    a.B.c = {"bob"}
    print(a.b.c[1])
    Question 4: Find the mistake if any.
    Code:
    a = { b = c = {"bob"}}}
    print(a[c][1])
    Question 5:
    Create a multi layered nested table. Where
    The first table contains 2 nested tables. And each nested within the tables contains 2 nested tables each. The last 4 nested tables should hold the values one, two , three, four respectively. Print the final nests and its values as proof.

    ANSWERS

    Answer 1: Underscore is one option. for example a["bob_is_cool"]

    Answer 2: Since we want to modify a[1] - we first need to assign a "new value" with a[1] than use a function to manipulate that value.
    Code:
    a = {"Test problem 2"}
    a[1] = string.gsub(a[1], "problem", "answer")
    print(a[1])

    Answer 3: There are 2 mistakes in the code.
    Code:
    a = { b = { c = { } } }
    a.b.c = {"bob"}
    print(a.b.c[1])
    The first mistake was the table was not initially defined. Hence did not even exist.
    The 2nd mistake is capitalization. b and B are not the same.

    Answer 4: in the print function the b and c are variables with no values. They are not the identifier of the key.
    Code:
    print(a["b"]["c"][1])
    Answer 5:
    The identifiers do not matter - but the concept is easy once you understand how nested tables work. It becomes even more legible if you break each component into a separate line.
    Code:
    z = { a = { c = {"one"}, d = {"two"} }, b = { e = {"three"}, f ={"four"} } }
    print(z.a.c[1], z.a.d[1], z.b.e[1], z.b.f[1])

    .


    CHAPTER 7: LOOPS AND STATEMENTS



    A statement is a set of instructions which occurs when a specific condition is met. Also each statement requires you to add an "end" to it. Which is very important, as it is a common cause of errors when you forget to do so.

    IF ELSE THEN (and ELSEIF)
    Essentially what this statement does is, first, it checks if the statement is true. If it is, then it does the first set of instructions. If the statement is false, it performs the 2nd set. One thing to keep in mind: each IF statement requires an end, and each function requires an end. If you use elseif - then it requires only 1 end ( not including the function's end ) - now all that just sounds complicated, so better just look at the example.

    Our first example would be what it would be like without else
    Code:
    a = 1
    b = 2
    c = 3
    d = 4
    
    if a > b then
      print("1 is less than 2")
    end
    if b > a then
      print(b.." is greater then "..a)
    end
    Since the statement is not true the first statement gives no result after which the next statement gets processed.
    If both statements were true, both statements get printed.

    What we need to learn is end essentially defines the end of that block of code. So what if we wanted a single result?
    Which is where "else" comes in. It will give one result or the other in sequential order.
    Code:
    a = 1
    b = 2
    c = 3
    d = 4
    
    if a > b then
      print("1 is less than 2")
    else
      print(b.." is greater then "..a)
    end
    Because the first statement was false - the 2nd result comes, but only one result will appear.
    What if we wanted to test multiple problems? We have elseif
    Code:
    a = 1
    b = 2
    c = 3
    d = 4
    
    if a > b then
      print("1 is less than 2")
    elseif
      b > c then
        print(b.." is greater than "..c)
    elseif
      c < d then
        print(c.." is less then "..d)
    end
    Since the first statement is false, it goes to the 2nd statement and since that is false it goes the the 3rd. Since the third is true it prints the result accordingly.

    WHILE \ DO LOOPS

    A while loop keeps continuing until a certain condition has been met. These are great ways to process arrays.
    The syntax of a while loop is

    Code:
    while condition do
    Let us take a look at an example
    Code:
    example = {"one", "two", "three", "four"}
    x=1
    while x <= #example do
        print(example[x])
            x = x + 1
            end
    FOR \ DO LOOPS
    "FOR" loops give us a different type of control when it comes to loops. Especially as it focuses more on numbers. The syntax of a for loop is
    Code:
    for variable = beginning, finish, step do
    Code:
    for x = 1, 10, 1 do
      print(x)
    end
    Now lets break it down
    The starting number of the variable is 1, it must end at 10, and it increments the numbers by 1.
    Now what purpose might this serve? It allows a statement inside the FOR block to keep repeating for a specific number of times. For example say you wanted poison damage to be applied

    PUTTING IT TOGETHER
    Now lets make a simple function to look for "Bob" and perform an action when it is found
    Code:
    entityID = {entity1, entity2, entity3, entity4}
    entity1 = "Phil"
    entity2 = "Katrina"
    entity3 = "Jessica"
    entity4 = "Bob"
    
    for x = 1, #entityID, 1 do
      if entityID[x] == "Bob" then
      print("found")
      break
      end
    end
    Now in this block of code it will keep increasing one till the total number of values in the array entityID is met.
    Now we have another block statement using "IF" which will wait till the value equals bob.
    We use break to end that particular piece of the loop to allow the main block to continue. The loop then add one value to "x" and continue until it reaches the end of the array.

    Question: What can we quickly add if we also wanted to know the position of "Bob" in the array?
    Code:
    print("found in position "..x)


    .


    BREAK TIME



    Question 1: Find and print the size of the following table
    Code:
    a = {"one", "two", "three", "hundred", "dog", "cow"}
    Question 2: Print all the odd numbers upto 10

    Question 3: Find the mistake in the code
    Code:
    if 1 > 2
    print["true"] else
    print("false")
    Question 4: What kind of keys does using the # or table.getn() only return? and what keys do they not return?

    ANSWERS

    Answer 1:
    Code:
    a = {"one", "two", "three", "hundred", "dog", "cow"}
    print (#a)
    Answer 2:
    Code:
    for x = 1, 10, 2 do
      print(x)
    end
    Answer 3:
    Code:
    if 1 > 2 then
      print("true") else
      print("false")
    end
    • "then" is missing after the condition
    • the first print uses square brackets instead of round brackets
    • end is missing
    Answer 4: Numerical, they do not return stringed keys.



    If you spot any errors just leave a message so we can get that fixed up.

     
    Last edited: Feb 5, 2015
  2. poweredbygamespy

    poweredbygamespy Phantasmal Quasar

    nice lua tutorial man ;) will this guide become more starbound related later? cos now its just lua basics...
     
  3. AstralGhost

    AstralGhost Pangalactic Porcupine

    Yep! The next tutorial will include some Starbound specific content. We're working on it. :)
     
  4. poweredbygamespy

    poweredbygamespy Phantasmal Quasar

    nice to hear :) thank you very much
     
  5. The | Suit

    The | Suit Agent S. Forum Moderator

    While you wait - these two tutorials should be ample to get you started.
    By referencing vanilla code and going to the lua docs page you should be able to make some basic Lua items already.
     
  6. InflamedSebi

    InflamedSebi Void-Bound Voyager

    awesome :)
    Might wanna add the second form of for loops? You used it in the tutorial but never explained it :p

    I dunno if it is usefull for starbound, but it is essential for normal coding.
     
    poweredbygamespy and The | Suit like this.
  7. AstralGhost

    AstralGhost Pangalactic Porcupine

    Wait, we didn't add that? We talked about it quite a bit. I thought we added it.... Hmm. My proofreading skills suck. :p

    Also, I found this in the loop section:
    The 'function' being referred to there actually does stop when it finds "Bob" because there is a "break" in the if-statement when found. So you can remove this line.

    That was one of those things I found before the guide was posted then forgot about later and missed on my last proof-read. :facepalm:
     
  8. poweredbygamespy

    poweredbygamespy Phantasmal Quasar

    guys actually lua is pretty similar to visual basic am i right? i dont use it much, i prefer c# for obvious reasons but i think vb is many similarities at the syntax
     
    Last edited: Feb 5, 2015
  9. InflamedSebi

    InflamedSebi Void-Bound Voyager

    You are mixing things up here, Sir.

    lua actually is a scripting language and Visual basic is not. VB is a Programming language (not to be confused with VBScript).
    Scripting languages aren't meant to write programms in but can extend an existing programm to easyly add features or maintain stuff.
    C# is a programming language like java or python, which are used to design whole programms.
    Programming languages are way more powerfull but also more strict in syntax and less forgiving with variables & types.
    So switching from script to programming is much harder than the other way round.

    But yes, if you can code a single language, you basically just need to learn a new syntax and will be able to code in a new language ... they all work pretty much the same way.
     
  10. poweredbygamespy

    poweredbygamespy Phantasmal Quasar

    i know man i am a c# programmer myself but there really can be similarities between script and programming languages. They work the same way but scriptiong languages are not compiled and can be interpreted by other programs differently (due to bugs or so - just like internet explorer is interpreting javascript not as firefox does). The syntax of scripting and programming languages may have similarities although the purpose is completely different. The syntax of lua reminds me of vb for example although there is no real connection between them cos lua is scripting and vb is programming.
     
  11. The | Suit

    The | Suit Agent S. Forum Moderator

    I will look into adding this when I can break it down into simpler examples - but thanks for catching that.
     
  12. Dont EVER use ipairs(). Just save yourself the headache. Unless you consistently make sure that youre table indexes are always consecutive whole numbers with no breaks then you are going to have what is called "Undefined Behaviour".
     
    The | Suit likes this.

Share This Page