learning lua

23 October 2007

dealhand.lua

For our second program, let us create a deck of playing cards, shuffle the deck, and then deal ourselves a bridge hand (13 cards out of the pack of 52). We'll expand upon our card dealing program in coming installments, but for now it'll be used as a centerpiece for a beginning discussion on Lua types and values.
#!/usr/local/bin/lua

-- constant declarations

HANDLEN = 13
FACES = { 'A', 'K', 'Q', 'J', '0', '9', '8', '7', '6', '5', '4', '3', '2' }
SUITS = { 'S', 'H', 'D', 'C' }

-- function definitions

function shuffle (list)
  local n = #list
  while n > 1 do
    k = math.random(n)
    if k ~= n then
      list[n], list[k] = list[k], list[n]
    end
    n = n - 1
  end
end

function slice (list, b, l)
  local sl = {}
  local l = l or (#list - b + 1)
  local e = b + l - 1
  for i = b, e do
    sl[#sl+1] = list[i]
  end
  return sl
end

-- main

math.randomseed (os.time())

deckofcards = {}
for _, f in ipairs(FACES) do
  for _, s in ipairs(SUITS) do
    deckofcards[#deckofcards+1] = { ["f"] = f, ["s"] = s }
  end
end

shuffle (deckofcards)

hand = slice(deckofcards, 1, HANDLEN)
for _, card in ipairs(hand) do
  io.write(card.f .. card.s .. ' ')
end

print('')

A sample run:

$ ./dealhand.lua 
0S 2S 7S QC 9C 6S QD 8S AS 3D JH 4D JC

In subsequent posts, we'll enhance our first stab at a bridge playing bot, but let's dive into Lua types and values. The definitive textbook on the matter, Programming in Lua, offers this breakdown:

nil
The non-value, indicates a variable that has not been initialized yet, or one that has been deleted.
booleans
true or false. Truth in Lua is unlike other modern programming languages — only nil or false compute to being false. Take note, fellow coders, as the empty string ('') and the number 0 evaluate as true in Lua.
numbers
Lua makes no distinction between integers and floating point.
strings
Strings in Lua work similar to the Java programming language — they are immutable, and to modify a string means you create a new string.
tables
In Unix parlance, everything is a file. Likewise, in Lua, everything is a table. At first glance, the notion of table is confusing — in essence, a table is akin to how arrays in Javascript and PHP. Tables can represent simple integer indexed arrays or associative arrays with string (or other Lua object type) keys. And tables can be nested within other tables. A new table is thrust into existence with the {} constructor.
functions
Functions are "first class objects" in Lua. That's a fancy way of saying that they can serve as normal variables, be passed to functions, returned as function results, etc.… In another words, Lua offers support for functional programming.
threads
Will save study and discussion of threads for eventual, advanced topic set.

OK, those are the values that are bopped about. Before we can dive deep into script comprehension efforts, some basic Lua idiom grounding is necessary.

Lua Idioms

{} is the table constructor
Tables consisting of nil to complex structures with vast nesting are possible. Dynamically defined, and capable of storing any Lua type. Can also mix integer arrays and associative arrays. Can access individual elements with [] notation. Example: mytable[3] or groovy_table[x] or anothertable["rating"] (the latter could also be referenced via anothertable.rating)
# is the length operator
# can be applied to strings and "non"-associative arrays.
.. is the string concatenation operator
Used to join strings together.
-- denotes a comment
All following text until end of line is ignored by interpreter.
list[#list + 1] = newitem
Adding entries to an array. Could also be performed with this instruction — table.insert(list, newitem)
local declares a "local" variable, with scope confined to that code block
By default, all variables are global.
~= means "not equal"
Don't get it confused with the =~ regular expression match operator in Perl and Ruby. All of the other logical operators are fairly obvious — == for "equals", <=, >=, >, < should be self explanatory.
list assignment
Functions can return multiple values. Or several assignments in series, can be made, such as a, b = b, a
_ often serves as a "dummy" variable
Valid identifiers are strings of alphanumeric (letters and digits) characters and underscores that cannot begin with a digit. Avoid names with a prefix followed by uppercase characters — as those are used as Lua internal globals.
table indexing is one-based
Unlike just about any other modern programming language. A throwback to the days of COBOL and FORTRAN. Which is why list[#list + 1] can be an idiom! Also might lend to a slightly different algorithmic attack approach. Consider the slice function in the program listing. Function code would be much more concise if it had an argument signature of function slice(list, b, e) where e denoted the inclusive ending index. Then, the "1" juggling would be unneeded.

No comments: