Как поместить данные в таблицу из существующего файла - PullRequest
0 голосов
/ 25 января 2019

У меня есть программа для черепахи в ComputerCraft, которая предназначена для хранения. Я ввожу элемент, и он должен прочитать файл, чтобы найти, куда поместить элемент. Если есть новый элемент, он добавляет информацию в файл. Когда я делаю

blockTypes = {}

local file = fs.open(blockTable","r")
line = file.readAll()
table.insert(blockTypes,line)
file.close()

Информация помещается в виде строки. Это означает, что я не могу сделать

print(blockTypes[1][1])

И получите значение, которое обычно будет в этой позиции.

Вот мой код:

blockAmount = 3
highestVal = {2,0,5}
blockTypes = {}
function addBlock()
    local file = fs.open("blockTable", "a")
    file.write(name)
    file.write(" = {")
    file.write(highestVal[1])
    file.write(",")
    file.write(highestVal[2])
    file.write(",")
    file.write(highestVal[3])
    file.writeLine("};")
    file.close()
end
function getBlock()
    local file = fs.open("blockTable","r")
    line = file.readAll()
    table.insert(blockTypes,line)
    file.close()
end
--This was used to test before implementing the new file system that I am trying to get to work
blockTypesOld = {
    log = {2.0,0,1};
    dirt = {2,0,2};
    cobblestone = {2,0,3};
    iron_ingot = {2,0,4};
    planks = {2,0,5};
}
pos = {0,0,0}
looking = 0
function fuel()
    if turtle.getFuelLevel() < 20 then
        turtle.select(16)
        turtle.refuel(1)
    end
end
function left()
    turtle.turnLeft()
    looking = looking - 1
    if looking < 0 then
        looking = 3
    end
end
function right()
    turtle.turnRight()
    looking = looking + 1
    if looking > 3 then
        looking = 0
    end
end
function forward()
    fuel()
        if turtle.forward() then
            if looking == 0 then
                pos[1] = pos[1] - 1
            elseif looking == 1 then
                pos[3] = pos[3] - 1 
            elseif looking == 2 then
                pos[1] = pos[1] + 1
            elseif looking == 3 then
                pos[3] = pos[3] + 1
            else
            end
        end

end
function up()
    fuel()
    turtle.up()
    pos[2] = pos[2] + 1
end
function down()
    fuel()
    turtle.down()
    pos[2] = pos[2] - 1
end
function goHome()
    while pos[3] > 0 do
        while  looking > 1 do
            left()
        end
        forward()
    end
    while  pos[2] > 0 do
        down()
    end
    while  pos[1] > 0 do
        while  looking > 0 do
            left()
        end
        forward()
    end
end
function goTo(a,b,c)
    goHome()
    while looking < 2 or looking > 2 do
        right()
    end
    for i = pos[1],a do
        forward()
    end
    while looking > 3 or looking < 3 do
        right()
    end
    for i = pos[3],c do
        forward()
    end
    for i = pos[2],b do
        up()
    end
    while looking < 2 or looking > 2 do
        left()
    end
end
while true do
    turtle.select(15)
    while not turtle.suck() do
        sleep(1)
    end
    itemDetails = turtle.getItemDetail()
    --Finding what mod item is from and removing corresponding labels--
    --EX: "minecraft:log" becomes "log"
    if itemDetails.name:match("^ae2stuff:(.+)$") then
        name = itemDetails.name:match("^ae2stuff:(.+)$")
    elseif itemDetails.name:match("^minecraft:(.+)$") then
        name = itemDetails.name:match("^minecraft:(.+)$")
    elseif itemDetails.name:match("^appliedenergistics2:(.+)$") then
        name = itemDetails.name:match("^appliedenergistics2:(.+)$")
    elseif itemDetails.name:match("^buildcraftbuilders:(.+)$") then
        name = itemDetails.name:match("^buildcraftbuilders:(.+)$")
    elseif itemDetails.name:match("^forge:(.+)$") then
        name = itemDetails.name:match("^forge:(.+)$")
    elseif itemDetails.name:match("^buildcraftenergy:(.+)$") then
        name = itemDetails.name:match("^buildcraftenergy:(.+)$")
    elseif itemDetails.name:match("^buildcraftfactory:(.+)$") then
        name = itemDetails.name:match("^buildcraftfactory:(.+)$")
    elseif itemDetails.name:match("^buildcraftsilicon:(.+)$") then
        name = itemDetails.name:match("^buildcraftsilicon:(.+)$")
    elseif itemDetails.name:match("^buildcrafttransport:(.+)$") then
        name = itemDetails.name:match("^buildcrafttransport:(.+)$")
    elseif itemDetails.name:match("^buildcraftcore:(.+)$") then
        name = itemDetails.name:match("^buildcraftcore:(.+)$")
    elseif itemDetails.name:match("^buildcraftlib:(.+)$") then
        name = itemDetails.name:match("^buildcraftlib:(.+)$")
    elseif itemDetails.name:match("^computercraft:(.+)$") then
        name = itemDetails.name:match("^computercraft:(.+)$")
    elseif itemDetails.name:match("^enderstorage:(.+)$") then
        name = itemDetails.name:match("^enderstorage:(.+)$")
    elseif itemDetails.name:match("^extracells:(.+)$") then
        name = itemDetails.name:match("^extracells:(.+)$")
    elseif itemDetails.name:match("^thermaldynamics:(.+)$") then
        name = itemDetails.name:match("^thermaldynamics:(.+)$")
    elseif itemDetails.name:match("^thermalexpansion:(.+)$") then
            name = itemDetails.name:match("^thermalexpansion:(.+)$")
    elseif itemDetails.name:match("^thermalfoundation:(.+)$") then
        name = itemDetails.name:match("^thermalfoundation:(.+)$")
    elseif itemDetails.name:match("^tconstruct:(.+)$") then
        name = itemDetails.name:match("^tconstruct:(.+)$")
    elseif itemDetails.name:match("^webdisplays:(.+)$") then
        name = itemDetails.name:match("^webdisplays:(.+)$")
    elseif itemDetails.name:match("^ironchest:(.+)$") then
        name = itemDetails.name:match("^ironchest:(.+)$")
    else
        print("ERROR MOD NOT FOUND")
    end
    getBlock()
    local elem = blockTypes[name]
    --Gets fuel from fuel chest
    right()
    turtle.select(16)
    turtle.suck(5)
    turtle.select(15)
    if elem then
    --If the item does exist, the turtle goes to it's chest and places it in the chest
        goTo(elem[1]-1, elem[2]-1, elem[3]-1)
        turtle.select(15)
        turtle.drop()
        goHome()
        right()
        turtle.select(16)
        turtle.drop()
        turtle.select(15)
        left()
    else
        --Creates information for new item--
        addBlock()
        blockAmount = blockAmount + 1
        highestVal[3] = highestVal[3] + 1
        if highestVal[3] > 5 then
            highestVal[3] = 1
            highestVal[2] = highestVal[2] + 1
        end
        if highestVal[2] > 4 then
            highestVal[2] = 0
            highestVal[1] = highestVal[1] + 2
        end
        blockTypes[blockAmount] = name
        blockTypes[name] = {highestVal[1],highestVal[2],highestVal[3]}
        local elem = blockTypes[name]
        left()
        turtle.select(15)
        turtle.drop()
        right()
        turtle.select(16)
        turtle.suck(2)
        fuel()
        turtle.drop()

        goTo(1,-1,4)
        --Crafts an Iron Chest for the New Item
        for i = 1,3 do
            turtle.select(i)
            turtle.suck(1)
        end
        turtle.select(5)
        turtle.suck(1)
        turtle.select(7)
        turtle.suck(1)
        for i = 9,11 do
            turtle.select(i)
            turtle.suck(1)
        end
        turtle.select(6)
        turtle.craft()
        goTo(1,-1,3)
        for i = 1,3 do
            turtle.select(i)
            turtle.suck(1)
        end
        turtle.select(5)
        turtle.suck(1)
        turtle.select(7)
        turtle.suck(1)
        for i = 9,11 do
            turtle.select(i)
            turtle.suck(1)
        end
        turtle.select(1)
        turtle.craft()
        goHome()
        right()
        turtle.select(16)
        turtle.suck(5)
        goTo(elem[1]-1, elem[2]-1, elem[3]-1)
        turtle.select(1)
        turtle.place()
        goHome()
    end
end

Файл, содержащий координаты для элементов, называется blockTable и состоит из этого:

--blockName = {xCoord,yCoord,zCoord};--
oak_stairs = {2.0,0.0,5.0};
iron_ingot = {2.0,0.0,4.0};
turtle = {2.0,0.0,5.0};

Когда я кладу новый предмет, он регистрирует предмет, делает сундук и вставляет его. Когда я кладу тот же предмет, он направляется прямо к сундуку, не создавая новый. Однако, когда я перезагружаю черепаху и вставляю тот же предмет, он создает новый сундук и пытается разместить его для нового предмета. Я хочу, чтобы он мог хранить информацию даже после перезагрузки. Я боролся с этой программой некоторое время, любая помощь будет оценена. Спасибо!

Ответы [ 2 ]

0 голосов
/ 25 января 2019

Хотя не рекомендуется читать файл каждый раз, когда вы добавляете в новый блок, как указано в DarkWiiPlayer.

Чтобы ответить на ваш вопрос, вы можете прочитать таблицу и выполнить код из строки, используя loadstring.

Чтобы сделать это, используя существующие строки в предоставленном вами файле, требуется дополнительная работа. Эта дополнительная работа может быть удалена путем корректировки строки в файле.

blockTypes = {}

line = "oak_stairs = {2.0,0.0,5.0};"
table_name = line:match("[%a_]+%s")
do_line = assert(loadstring('local ' .. line .. ' return ' .. table_name))
table = do_line();
table.insert(blockTypes,table)

Здесь мы получаем имя загружаемой таблицы, используя match. Создайте строку для loadstring, которая создает и возвращает таблицу. Выполните загруженную строку и вставьте ее в blockTypes.


В качестве альтернативы вы можете настроить сохраняемый файл так, чтобы он действовал как модуль.

local blocktypes = {
    oak_stairs = {2.0,0.0,5.0},
    iron_ingot = {2.0,0.0,4.0},
    turtle = {2.0,0.0,5.0},
}
return blockTypes

Тогда вы бы это загрузили данные:

blockTypes = require("blockTable")
0 голосов
/ 25 января 2019

Чтение / запись всего файла каждый раз, когда вы добавляете новый блок, выглядит немного грязно, особенно если учесть, что вы можете перезапустить черепашку в процессе записи нового файла и в итоге половина ваших данных будет потеряна.

У вас есть файловая система, так почему бы не использовать ее вместо этого?Создайте каталог и напишите новый файл для каждого имени блока, затем сохраните в нем координаты.Это также позволяет вам хранить более одного сундука для каждого типа блока, в случае, если вы получите грязное богатство, которое произойдет раньше, чем вы ожидаете, используя черепах для раскопок огромных кусков карты.

Я только что понял, чтоНа самом деле я не ответил на вопрос, так что вот что:

Когда у вас есть файл file, вы можете легко прочитать одну строку с помощью file.readLine().Это возвращает либо строку, которую она прочитала как строку, либо nil, если вы находитесь в конце файла.Предполагая, что вы просто пишете три координаты, разделенные пробелами после имени блока, вы можете затем разобрать их в таблицу следующим образом:

local file = fs.open('chests')
local chests = {}
while true do
  local line = file.readLine()
  if line then
    local name, x, y, z = line:match("(%a+) ([%d.+-]+) ([%d.+-]+) ([%d.+-]+)")
    chests[name] = {
      tonumber(x),
      tonumber(y),
      tonumber(z)
    }
  else
    break
  end
end

Оберните все это в функцию для дополнительной аккуратности.

Примечание:

Компьютерное дело несколько неудобно для работы с файлами.В обычном Lua я бы сделал это:

local function map(f, elem, ...)
    if elem then return f(elem), map(f, ...) end
end

local function readchests(file)
    local res = {}
    for line in io.open(file):lines() do
        local name, x, y, z = line:match("(%a+)"..(" [%d.-+]+"):rep(3))
        res[name]={map(tonumber, x, y, z)}
    end
    return res
end

Если вы хотите сохранить формат хранения данных в качестве действительного кода Lua, вы можете прочитать весь файл с помощью file.readAll(), добавив "return {" вначать и "}" в конце, а затем просто загрузить и выполнить эту строку.В общем, я не рекомендую это все же.Не было бы лучше, если бы весь файл был просто верным кодом Lua, который вы можете прочитать и запустить.

...