洗牌表项

本教程探讨了基本洗牌以及如何在 Corona/Lua 中实现它。例如,考虑一个基本的纸牌游戏,其中,玩家抽一张随机的牌。最初的考虑可能是简单使用 math.random() 选择一张随机的牌,但是不同于重复出现多个数字的掷骰子,一张特定的牌在游戏过程中只应出现一次。

基本而言,每次需要从一个较大的集合中抽取一个项目并确保它从不重复时都可应用洗牌逻辑,例如

基本洗牌

我们进一步探讨“牌组”场景,在该场景中,在每场游戏开始之前,牌组都会洗牌。在 Lua 中,可以通过对一个值表进行随机排序来实现这一点。下面基于标准扑克牌来看一个基本示例

local cardDeck = { "AS", "AH", "2S", "3S", "KH", "QD", "QS", "KD", "4D", "10H" }

显然,对于一个实际的纸牌游戏,你需要用全部 52 张扑克牌来填充该表,但为了本教程,我们将保持简单。

凭借这个数字索引表(数组),我们可以调用以下函数来随机化项目

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 )

更详细地检查此代码,我们执行以下任务

  1. 在第一行,我们设置伪随机数字生成器——这是一个重要的代码行,但只需要执行一次,因此可以简单地将其包含在 main.lua 顶部附近的位置。

  2. 在函数内部,我们首先确认一个 Lua 表作为唯一的参数传递进来。如果不是,该函数将发出警告并返回 false

  3. 接下来,我们反向循环该表 (t)。此处,循环索引 (i) 是尚未洗牌的项目的计数。在循环内部,我们在 1i 之间生成一个随机数,然后交换这两个表项目。此处理将重复进行,直至倒数第二个项目,这是因为,此时,最后一个项目将已洗牌。

  4. 最后一行调用该函数并有效地洗牌组,并将结果设置回表示牌组的 cardDeck 变量。

抽牌

在对该表进行洗牌后,我们可以使用以下代码来从该组中选牌。由于该表本身已经按随机顺序排列,因此我们不必担心生成随机数,只须在列表中获取下一个数字即可。我们也不必“从牌组中移除已抽的牌”——相反,我们使用一个简单的变量 currentIndex 来表示牌组顶部是什么牌。此变量在游戏开始时从 1 开始,在抽牌时,它以相同的值递增

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 )

让我们更详细地看看此代码

  1. 如上所述,我们最初设置一个变量 currentIndex1 来表示牌组顶部。

  2. drawCards() 函数内的第一行,我们创建一个本地空表 (cardsDrawn) 以存储要抽取的卡牌。

  3. 在随后的循环中,我们简单地从 currentIndex 循环 num 次并将卡牌存储在 cardsDrawn 表中。

  4. 在函数的结尾,我们将 currentIndex 增加 num,有效地表明从牌组抽取了 num 张卡牌。

  5. 要抽取卡牌,只需用一定数量的卡牌(5)和要从中抽取卡牌的牌组(上一部分代码中的 cardDeck)调用 drawCards() 函数。

当牌组耗尽和/或您想开始新游戏时,您可以只洗牌、将 currentIndex 重置为 1 并重新开始。由于未从主卡牌表(cardDeck)中“移除”卡牌,因此不需要重新插入卡牌或任何其他复杂操作,只需重新洗牌并重置起始卡牌,即可开始!

结论

您可看到,创建一个不重复的随机数序列很简单。从纸牌游戏到益智游戏等等,只需几个基本功能便可轻松实现洗牌!