This tutorial explores basic shuffling and how to implement it in Corona/Lua. For example, consider a basic card game where the player draws a random card. The initial consideration may be to simply select a random card using math.random()
, but unlike rolling dice where a number can appear multiple times, a specific card should only appear once during a game.
Basically, shuffling logic applies any time you need to pull an item from a larger collection and ensure that it’s never repeated, for instance:
Let’s further explore the “deck of cards” scenario where, before each game begins, the deck is shuffled. In Lua, this can be accomplished by randomly sorting a table of values. Consider a basic example based on standard playing cards:
local cardDeck = { "AS", "AH", "2S", "3S", "KH", "QD", "QS", "KD", "4D", "10H" }
Obviously, for an actual card game, you’d need to populate the table with all 52 cards, but we’ll keep it simple for this tutorial.
With this
math.randomseed( os.time() ) -- Seed the pseudo-random number generator local function shuffleTable( t ) if ( type(t) ~= "table" ) then print( "WARNING: shuffleTable() function expects a table" ) return false end local j for i = #t, 2, -1 do j = math.random( i ) t[i], t[j] = t[j], t[i] end return t end cardDeck = shuffleTable( cardDeck )
Inspecting this code in more detail, we perform these tasks:
On the first line, we seed the main.lua
.
Inside the function, we first confirm that a Lua table was passed in as the sole parameter. If not, the function issues a warning and returns false
.
Next, we loop through the table (t
) in reverse. Here, the loop index (i
) is the count of items which have not yet been shuffled. Inside, we generate a random number between 1
and i
and then swap the two table items. This process is repeated until the
The final line calls the function and effectively shuffles the deck, setting the result back to the cardDeck
variable which represents the deck.
With the table shuffled, we can use the following code to pick cards from the deck. Since the table itself is already in random order, we don’t have to worry about generating random numbers, just simply get the next number in the list. We also don’t need to “remove drawn cards from currentIndex
which represents which card is on top of the deck. This variable begins at 1
when the game starts and, when cards are drawn, it increments by the same value:
local currentIndex = 1 -- Deck starts at top card (1) local function drawCards( num, deck ) local cardsDrawn = {} -- Empty table to begin for i = currentIndex, num do cardsDrawn[#cardsDrawn+1] = deck[i] end currentIndex = currentIndex + num return cardsDrawn end -- Deal 5 cards to a player local playerHand = drawCards( 5, cardDeck )
Let’s look further in detail at this code:
As stated above, we initially set a variable currentIndex
to 1
to represent the top of the deck.
On the first line inside the drawCards()
function, we create a local empty table (cardsDrawn
) to store the cards that will be drawn.
In the loop following, we simply loop from currentIndex
for num
iterations and store that card in the cardsDrawn
table.
At the end of the function, we increase currentIndex
by num
, effectively indicating that num
amount of cards were drawn from the deck.
To draw cards, we simply call the drawCards()
function with a number of cards (5
) and the deck to draw from (cardDeck
from the code in the previous section).
When the deck is exhausted and/or when you want to start a new game, you can just shuffle the deck, reset currentIndex
to 1
, and start fresh. Because no cards were “removed” from the master card table (cardDeck
), there’s no need to
As you can see, creating a