【问题标题】:How to Put Data Into a Table From an Existing File如何将现有文件中的数据放入表中
【发布时间】:2019-01-26 04:46:24
【问题描述】:

我在 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};

当我放入新物品时,它会注册该物品,制作箱子并放入。当我放入相同物品时,它会直接进入箱子而不制作新物品。但是,当我重新启动乌龟并放入相同的物品时,它会创建另一个新箱子并尝试将其放置在新物品中。我希望它即使在重新启动后也能够保留其信息。我已经在这个程序上苦苦挣扎了一段时间,任何帮助将不胜感激。谢谢!

【问题讨论】:

    标签: lua computercraft


    【解决方案1】:

    每次添加新块时读取/写入整个文件似乎有点混乱,特别是如果您考虑在写入新文件的过程中可能会重新启动 turtle 并最终导致一半数据丢失。

    您确实有一个文件系统,那么为什么不使用它呢?创建一个目录并为每个块名称写入一个新文件,然后将坐标保存在其中。这还允许您为每种方块类型存储多个箱子,以防您在使用海龟挖掘大块地图时比您预期的更快发财。

    我刚刚意识到我并没有真正回答这个问题,所以这里是这样的:

    当您有一个文件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 代码,那就再好不过了。

    【讨论】:

    • @WatsonBoi 很高兴听到这个消息:)
    【解决方案2】:

    虽然如 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")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-15
      • 2015-11-13
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 2020-07-14
      相关资源
      最近更新 更多