How to shuffle a table

Shuffling Tables Using the Fisher-Yates Algorithm

Introduction

Lua does not provide a built-in method for shuffling tables, so I wanted to share an efficient and fair way to shuffle tables using the Fisher-Yates algorithm.

Why Use Fisher-Yates?

:white_check_mark: Efficient – Runs in O(n) time, making it fast even for large tables.
:white_check_mark: Fair – Ensures every possible permutation has an equal chance.
:white_check_mark: No Duplicates – Cards are properly shuffled without repetition.

Now, let’s see how we can apply this algorithm in a game that uses playing cards.


Step 1: Creating a Deck of Cards

We first define the suits and ranks for our deck:

local suits = {"Hearts", "Diamonds", "Clubs", "Spades"} -- Create the table of available suits
local ranks = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"} -- Create the table of available ranks

Now, let’s create an empty table to store the deck:

local deck = {} -- Create an empty table to store the deck

We populate the deck by combining each rank with each suit:

for _, suit in ipairs(suits) do -- Loop through each suit
    for _, rank in ipairs(ranks) do -- Loop through each rank
        table.insert(deck, rank .. " of " .. suit) -- Insert the card into the deck
    end
end

Step 2: Shuffling the Deck Using Fisher-Yates Algorithm

We use the Fisher-Yates shuffle to randomize the deck:

for i = #deck, 2, -1 do -- Start from the last card down to the second card
    local j = math.random(1, i)  -- Select a random index between 1 and i
    deck[i], deck[j] = deck[j], deck[i]  -- Swap the randomly selected card with the current card
end

To verify the shuffle, we print the deck:

for i, v in ipairs(deck) do
    print(v) -- Print each shuffled card
end

:small_blue_diamond: Note: The output will differ each time you run it since the shuffle is random.


Step 3: Distributing Cards to Players

Now that we have a shuffled deck, let’s distribute cards to players.

First, define our players:

local players = {"Player1", "Player2", "Player3", "Player4"} -- List of players
local hands = {}  -- Table to store each player's hand

Initialize empty hands for each player:

for _, player in ipairs(players) do
    hands[player] = {} -- Create an empty table for each player's hand
end

Dealing 4 Cards per Player

local cardsPerPlayer = 4  -- Number of cards each player gets
for i = 1, cardsPerPlayer do -- Loop to distribute the set number of cards per player
    for _, player in ipairs(players) do -- Loop through each player
        if #deck > 0 then  -- Ensure there are still cards left in the deck
            local card = table.remove(deck, 1)  -- Remove the top card from the deck
            table.insert(hands[player], card)  -- Assign the removed card to the player
        end
    end
end

Printing Each Player’s Hand

for player, hand in pairs(hands) do
    print(player .. "'s hand:") -- Print player's name
    for _, card in ipairs(hand) do
        print("  - " .. card) -- Print each card in the player's hand
    end
end

:small_blue_diamond: Note: The card distribution will vary each time due to randomness.


Example Output:

Player1’s hand:

  • 4 of Hearts
  • 6 of Spades
  • 7 of Clubs
  • 6 of Clubs
    Player2’s hand:
  • 8 of Spades
  • A of Diamonds
  • 4 of Diamonds
  • 5 of Spades
    Player4’s hand:
  • 2 of Diamonds
  • A of Spades
  • 9 of Spades
  • 10 of Diamonds
    Player3’s hand:
  • 10 of Clubs
  • Q of Hearts
  • 4 of Clubs
  • 8 of Clubs

Conclusion

With this method, we’ve successfully:
:white_check_mark: Shuffled a deck of cards using Fisher-Yates.
:white_check_mark: Ensured randomness for fair gameplay.
:white_check_mark: Distributed cards evenly among players.

I hope this tutorial was helpful! Let me know if you have any questions. :flower_playing_cards::game_die:

7 Likes

Hello!
In Roblox’s global environment you could also use Random.new():Shuffle(table) :derp:

10 Likes

Oh wow I didn’t notice, Thanks

1 Like

Great algorithm, however most developers would just stick with Random.new():Shuffle(table) as mentioned above.

1 Like

I’ve never understood why the fisher-yates algo is done in reverse. Do you know?

Save on math operations?

Well I don’t really know but maybe because this approach would ensure that every position in the array has an equal probability of ending up with any given value? I am not really sure but hey, it works!