LUA: поиск конкретной таблицы по ее переменной

В настоящее время я начинаю работу над текстовой приключенческой игрой на Lua — никаких дополнений, только чистый Lua для моего первого проекта. По сути, вот моя проблема; Я пытаюсь выяснить, как выполнить "обратный просмотр" таблицы, используя одну из ее переменных. Вот пример того, что я пытался сделать:

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) каждой комнаты. У кого-нибудь есть идеи, как сделать более гибкую систему, которая могла бы найти таблицу, если игрок введет одну из ее переменных? Заранее спасибо!

-блокчейнпортер


person blockchainporter    schedule 10.12.2019    source источник


Ответы (2)


Это не дает прямого ответа на ваш вопрос, как вы его задали, но я думаю, что это послужит цели того, что вы пытаетесь сделать. Я создаю таблицу под названием «добыча», которая может содержать множество предметов, и игрок может поместить любой из них в свою «сумку», набрав имя.

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

Чтобы получить бонусные очки, вы можете проверить «сумку», чтобы узнать, есть ли у игрока что-то из этого предмета, а затем просто обновить количество...

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

Опять же, это не решение «обратного поиска», как вы просили... но я думаю, что оно ближе к тому, что вы пытаетесь сделать, позволяя пользователю выбирать что-то.

Мой отказ от ответственности заключается в том, что я не использую функции ввода-вывода в своем собственном использовании lua, поэтому я должен предположить, что ваш x = io.read("*l") верен.


PS. Если вы хотите, чтобы объекты имели только имя и количество, а не какие-либо другие свойства (например, условие, чары или что-то еще), вы также можете упростить мое решение, используя пары ключ/значение:

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
person Dahk    schedule 11.12.2019
comment
Я бы рекомендовал объявлять ваши переменные как local в функциях, телах циклов и т. д. - person Personage; 11.12.2019
comment
@Personage Полностью согласен с локальной областью действия; Я оставил это только для отражения синтаксиса, используемого в вопросе. - person Dahk; 11.12.2019

У меня есть несколько заметок, чтобы начать, прежде чем я конкретно отвечу на ваш вопрос. (Я просто хочу сделать это, прежде чем я забуду, поэтому, пожалуйста, потерпите меня!)

Я рекомендую печатать на терминал, используя stderr вместо stdout — функция Lua print использует последнее. Когда я пишу Lua-скрипт, я часто создаю функцию в стиле C с именем eprintf для вывода форматированного вывода в 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. Так, например, если игрок нашел сундук с сокровищами с золотом, мечом и зельем и хотел взять это золото, он набрал Gold в stdin, и оно было помещено в его инвентарь.

Основываясь на том, что у вас есть, похоже, что вы используете таблицы Lua для создания этих элементов: каждая таблица имеет индекс name, а другая называется ap; и, если текст, введенный игроком, совпадает с названием предмета, игрок берет этот предмет.

Я бы порекомендовал создать класс Item, который вы могли бы красиво абстрагировать, поместив его в собственный скрипт, а затем загружая его по мере необходимости с помощью require. Это очень простой модуль класса Item, который я написал:

----------------
-- 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

Надеюсь, это поможет!

person Personage    schedule 11.12.2019