LUA:通过其变量查找特定的 table

LUA: Looking for a specific table by its variable

我目前正在 Lua 开始开发一款文字冒险游戏 -- 没有插件,只是 Lua 我的第一个项目。本质上,这是我的问题; 我正在尝试找出如何使用其中一个变量对 table 执行 "reverse lookup"。 这是我尝试过的示例做:

print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
     table.insert(bag,gold)
     print("You took the " .. gold.name .. ".")
end

显然,像这样对游戏中的每个对象都写一行会非常……令人筋疲力尽——尤其是因为我认为我不仅可以使用这个解决方案来获取物品,还可以从房间中移动使用每个房间的 (x,y) 坐标进行反向查找来查找房间。任何人都对如何制作一个更灵活的系统有任何想法,该系统可以通过玩家输入其中一个变量来找到 table 吗?提前致谢!

-区块链搬运工

这并没有直接回答您提出的问题,但我认为它可以满足您的目的。我创建了一个名为 'loot' 的 table,它可以容纳许多对象,玩家可以通过输入名称将其中任何一个放入 'bag' 中。

bag = {}
loot = {
    {name="Gold", qty=3},
    {name="Axe", qty=1},
}

print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
    if (x == loot[i].name) then
        table.insert(bag, table.remove(loot,i))
    else
        i = i + 1
    end
end

对于奖励积分,您可以检查 'bag' 以查看玩家是否已经拥有该物品,然后只需更新数量...

while loot[i] do
    if (x == loot[i].name) then
        j, found = 1, nil
        while bag[j] do
            if (x == bag[j].name) then
                found = true
                bag[j].qty = bag[j].qty + loot[i].qty
                table.remove(loot,i)
            end
            j = j + 1
        end
        if (not found) then
            table.insert(bag, table.remove(loot,i))
        end
    else
        i = i + 1
    end
end

同样,这不是您要求的 'reverse lookup' 解决方案...但我认为它更接近于让用户选择掠夺某些东西来尝试做的事情。

我的免责声明是我在自己的 lua 用法中没有使用 IO 函数,因此我必须假设您的 x = io.read("*l") 是正确的。


PS。如果您只希望对象具有名称和数量,而不需要任何其他属性(如条件、附魔或其他),那么您还可以使用 key/val 对来简化我的解决方案:

bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }

print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
    if x == name then
        bag.name = (bag.name or 0) + qty
        loot.name = nil
    end
end

在我专门回答你的问题之前,我有一些笔记要开始。 (我只是想在忘记之前做这个,所以请多多包涵!)

我建议使用 stderr 而不是 stdout 打印到终端——Lua 函数 print 使用后者。当我编写 Lua 脚本时,我经常创建一个名为 eprintf 的 C 风格函数来将格式化输出打印到 stderr。我是这样实现的:

local function eprintf(fmt, ...)
    io.stderr:write(string.format(fmt, ...))
    return
end

请注意,与 print 不同,此函数不会自动将换行符附加到输出字符串;为此,请记住将 \n 放在 fmt 字符串的末尾。

接下来,定义调用 io.read("*l") 以获取整行输入的辅助函数可能会很有用。在编写一些示例代码来帮助回答您的问题时,我调用了我的函数 getline——就像具有类似行为的 C++ 函数一样——并像这样定义它:

local function getline()
    local read = tostring(io.read("*l"))
    return read
end

如果我正确地理解了你正在尝试做什么,玩家将有一个库存——你称之为 bag——他可以通过在 stdin。因此,例如,如果玩家发现一个装有金子、一把剑和一瓶药水的宝箱,并且他想拿走金子,他会在 stdin 中输入 Gold 然后它会被放置在他的库存中。

根据您目前的情况,您似乎正在使用 Lua table 来创建这些项目:每个 table 都有一个 name 索引,并且另一个叫 ap;并且,如果玩家的文本输入与物品的名称匹配,则玩家会拾取该物品。

我建议创建一个 Item class,您可以通过将它放在自己的脚本中然后根据需要使用 require 加载它来很好地抽象它。这是一个非常基础的 Item class 模块 我写的:

----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item

-- __newindex metamethod.
function Item.__newindex(self, k, v)
    local err = string.format(
        "type `Item` does not have member `%s`",
        tostring(k)
    )
    return error(err, 2)
end

-- Item constructor
function Item.new(name_in, ap_in)
    assert((name_in ~= nil) and (ap_in ~= nil))
    local self = {
        name = name_in,
        ap = ap_in
    }
    return setmetatable(self, Item)
end

return Item

从那里开始,我编写了一个主要驱动程序来封装您在问题中描述的一些行为。 (是的,我知道我的 Lua 代码看起来更像 C。)

#!/usr/bin/lua

-------------
-- Modules --
-------------
local Item = assert(require("Item"))

local function eprintf(fmt, ...)
    io.stderr:write(string.format(fmt, ...))
    return
end

local function printf(fmt, ...)
    io.stdout:write(string.format(fmt, ...))
    return
end

local function getline()
    local read = tostring(io.read("*l"))
    return read
end

local function main(argc, argv)
    local gold = Item.new("Gold", 3)
    printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
    return 0
end
main(#arg, arg)

现在,对于您描述的反向搜索,此时您所要做的就是根据 Item 的名称检查用户的输入。这是在主要功能中:

local function main(argc, argv)
    local gold = Item.new("Gold", 3)
    local bag = {}
    eprintf("What are you trying to take? ")
    local input = getline()
    if (input == gold.name) then
        table.insert(bag, gold)
        eprintf("You took the %s.\n", gold.name)
    else
        eprintf("Unrecognized item `%s`.\n", input)
    end
    return 0
end

希望对您有所帮助!