Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- IC2 Rubber Farm v0.4
- local component = require "component"
- local computer = require "computer"
- local robot = require "erobot"
- local shell = require "shell"
- local sides = require "sides"
- local event = require "event"
- require "table_io"
- local pathfinder = require "pathfinder"
- local inv
- -- local geolyzer
- -- farmMap metatable
- -- Use farmMapArr() as constructor, v(x,y,z) as acces and v:setTree(x, z, h) as set value
- if not farmMapArr then farmMapArr = function() return setmetatable({
- treeData = { },
- setTree = function(t, x, z, h)
- t.treeData[z] = t.treeData[z] or {}
- t.treeData[z][x] = h
- end,
- }, { __call = function(t, x, y, z)
- if y == 0 then
- return (x ~= 0) or (z ~= 0)
- end
- if not t.treeData[z] or not t.treeData[z][x] then return nil end
- return y <= t.treeData[z][x]
- end
- })end end
- local farmMap
- local farmPoints
- local maxTry = 20
- local SLEEP_TIME = 60 * 5
- local RUB_WOOD = "IC2:blockRubWood"
- local RUB_SAPLING = "IC2:blockRubSapling"
- local ETREETAP_USE_COST = 50
- local ETREETAP_CAP = 10000
- local MIN_ENERGY = 500
- local START_ENERGY = 19000
- function sleep(timeout)
- checkArg(1, timeout, "number", "nil")
- local deadline = computer.uptime() + (timeout or 0)
- repeat
- local ev = event.pull(deadline - computer.uptime(), "interrupt")
- if ev ~= nil then
- robot.rotateTo(robot.getStartOrientation())
- os.exit(1)
- end
- until computer.uptime() >= deadline
- end
- function checkSide(side)
- return side and side >= 2 and side <= 5
- end
- function swingmove(direction)
- for try = 1, maxTry do
- if checkEnergy() then
- return false, "service"
- end
- if component.robot.detect(direction) then
- local ok, substance = component.robot.swing(direction) --air, block, entity
- if not ok and (substance ~= "air") then
- return false, "fatal barrier ("..tostring(substance)..")"
- end
- else
- local ok, err = component.robot.move(direction)
- if ok then
- return true
- elseif err == "impossible move" then
- return false, err
- end
- end
- end
- return false, "movement limit"
- end
- function moveTo(x, y, z, noabort)
- local rX, rY, rZ = robot.toRealCoord(x, y, z)
- while 1 do
- local ok, err = robot.moveTo(rX, rY, rZ, swingmove)
- if ok then
- return
- end
- if noabort then
- print(err)
- sleep(5)
- else
- if err == "service" then
- service()
- else
- emergency(err)
- end
- end
- end
- end
- function moveToF(x, y, z, noabort)
- local pos = { }
- pos.x, pos.y, pos.z = robot.toVirtCoord(robot.getPos())
- local crumb = pathfinder.findPath(farmMap, pos, { x = x, y = y, z = z })
- if crumb == nil then
- emergency('Path not found: '..'['.. pos.x..","..pos.y..","..pos.z.."]->"..'['.. p.x..","..p.y..","..p.z.."]")
- else
- while crumb.next ~= nil do
- crumb = crumb.next
- moveTo(crumb.pos.x, crumb.pos.y, crumb.pos.z, noabort)
- end
- end
- end
- function go_home()
- moveToF(0, 0, 0, true)
- robot.rotateTo(robot.getStartOrientation())
- end
- function checkEnergy(l)
- l = l or MIN_ENERGY
- return computer.energy() < l
- end
- function service()
- local x, y, z = robot.toVirtCoord(robot.getPos())
- local d = robot.getOrientation()
- go_home()
- while checkEnergy(START_ENERGY) do
- sleep(10)
- end
- moveToF(x, y, z)
- robot.rotateTo(d)
- end
- function emergency(err)
- error("emergency: "..err)
- end
- function clear_inventory()
- for slot = 1, robot.inventorySize() do
- robot.select(slot)
- robot.dropDown()
- end
- robot.select(1)
- end
- function check_tool(energy)
- return robot.durability() * ETREETAP_CAP < energy
- end
- function charge_tool(energy)
- while check_tool(energy) do
- robot.turnRight()
- inv.equip()
- inv.dropIntoSlot(sides.front, 1)
- sleep(10)
- inv.suckFromSlot(sides.front, 1)
- inv.equip()
- robot.turnLeft()
- end
- end
- local nedded_check_use_cost = false
- function treetap_use()
- if not nedded_check_use_cost then
- robot.use()
- return
- end
- local e1 = robot.durability() * ETREETAP_CAP
- robot.use()
- local e2 = robot.durability() * ETREETAP_CAP
- local e = e2 - e1
- if e < ETREETAP_USE_COST then
- ETREETAP_USE_COST = e
- end
- nedded_check_use_cost = false
- end
- -- 3, 9 - south
- -- 2, 8 - north
- -- 5, 11 - east
- -- 4, 10 - west
- -- z
- -- (-)
- -- north
- -- x (-) west east (+) x
- -- south
- -- (+)
- -- z
- local rubberPoint = {
- [2] = function(x, y, z) return sides.south, x, y, z - 1 end, -- north
- [3] = function(x, y, z) return sides.north, x, y, z + 1 end, -- south
- [4] = function(x, y, z) return sides.east, x - 1, y, z end, -- west
- [5] = function(x, y, z) return sides.west, x + 1, y, z end, -- east,
- }
- rubberPoint[8] = rubberPoint[2]
- rubberPoint[9] = rubberPoint[3]
- rubberPoint[10] = rubberPoint[4]
- rubberPoint[11] = rubberPoint[5]
- function wood_analyze()
- -- local d = geolyzer.analyze(sides.left)
- -- if d.name == RUB_WOOD then
- -- if d.metadata >= 2 then
- -- local p = { }
- -- p.x, p.y, p.z = robot.getPos()
- -- p.x, p.y, p.z = robot.toVirtCoord(p.x, p.y, p.z)
- -- p.x = p.x + 1
- -- p.side, p.x, p.y, p.z = rubberPoint[d.metadata](robot.toRealCoord(p.x, p.y, p.z))
- -- p.x, p.y, p.z = robot.toVirtCoord(p.x, p.y, p.z)
- -- table.insert(farmPoints, p)
- -- end
- -- return true
- -- end
- -- return false
- end
- function tree_analyze()
- local h = 0
- while 1 do
- local wood = wood_analyze()
- if not wood then
- if h == 0 then
- return 10
- end
- break
- end
- h = h + 1
- local ok, err = swingmove(sides.up)
- if not ok then
- if err == "service" then
- service()
- else
- emergency(err)
- end
- end
- end
- for i = 1, h do
- local ok, err = swingmove(sides.down)
- if not ok then
- if err == "service" then
- service()
- else
- emergency(err)
- end
- end
- end
- return h
- end
- function treeCoord(ix, iz)
- return (ix - 1) * 2 + 1, (iz - 1) * 2 + 1
- end
- function farm_analyze(l, w)
- print("Анализ фермы")
- farmPoints = { }
- local move = function(side)
- local ok, err = swingmove(side)
- if not ok then
- if err == "service" then
- service()
- else
- emergency(err)
- end
- end
- end
- move(sides.up)
- for ix = 1, l do
- robot.turnRight()
- for iz = 1, w do
- move(sides.forward)
- local x, z = treeCoord(ix, iz)
- farmMap:setTree(x, z, tree_analyze())
- move(sides.forward)
- end
- robot.turnAround()
- for iz = 1, w do
- move(sides.forward)
- move(sides.forward)
- end
- robot.turnRight()
- move(sides.forward)
- move(sides.forward)
- end
- robot.turnAround()
- for ix = 1, l do
- move(sides.forward)
- move(sides.forward)
- end
- move(sides.down)
- robot.turnAround()
- local n = #farmPoints
- print("Найдено "..n.. " точек сбора")
- -- for _,p in ipairs(farmPoints) do
- -- print('['..p.x..","..p.y..","..p.z.."]")
- -- end
- if n > 0 then
- print("Оптимизация пути")
- farmPoints = opt_points(farmPoints)
- end
- print("Анализ завершён.")
- -- for _,p in ipairs(farmPoints) do
- -- print('['..p.x..","..p.y..","..p.z.."]")
- -- end
- end
- function distance(blockA, blockB)
- pathfinder.findPath(farmMap, blockA, blockB)
- local crumb = pathfinder.findPath(farmMap, blockA, blockB)
- local n = 0
- if crumb == nil then
- error('Path not found: '..'['.. blockA.x..","..blockA.y..","..blockA.z.."]->"..'['.. blockB.x..",".. blockB.y..",".. blockB.z.."]")
- else
- while crumb.next ~= nil do
- crumb = crumb.next
- n = n + 1
- end
- end
- return n
- end
- function closest_point(point, points)
- local cl_num = 1
- local length = distance(point, points[1])
- for i=1, #points do
- local l = distance(point, points[i])
- if l < length then
- cl_num = i
- length = l
- end
- end
- return cl_num
- end
- function opt_points(holes_table, last)
- local way_table = {}
- local count = #holes_table
- table.insert(way_table, {x=0, z=0, y=0})
- while count ~= #way_table - 1 do
- local j = closest_point(way_table[#way_table], holes_table)
- table.insert(way_table, holes_table[j])
- table.remove(holes_table, j)
- end
- return way_table, last
- end
- function farm_collect()
- local pos = { }
- pos.x, pos.y, pos.z = robot.toVirtCoord(robot.getPos())
- for i,p in ipairs(farmPoints) do
- moveToF(p.x, p.y, p.z)
- if p.side then
- robot.rotateTo(p.side)
- -- local d = geolyzer.analyze(sides.front)
- -- if d.name ~= RUB_WOOD or d.metadata <= 1 then
- -- print("В точке ".."["..p.x..","..p.y..","..p.z.."]".." нет подтёка!")
- -- end
- -- if d.metadata < 8 then
- treetap_use()
- -- end
- end
- end
- go_home()
- end
- function workGuard(func, ...)
- local ok, err = pcall(func, ...)
- if not ok then
- if type(err) ~= "table" then
- print(err)
- end
- print('Ошибка/препятствие. Возврат робота.')
- go_home()
- return false
- end
- return true
- end
- local farmDataFileName = "/home/rubber-farm.cfg"
- function farm(w, l, analyze, side)
- farmMap = farmMapArr()
- if analyze then
- robot.navInit(side)
- for ix = 1, l do
- for iy = 1, w do
- local x, z = treeCoord(ix, iy)
- farmMap:setTree(x, z, 10)
- end
- end
- workGuard(farm_analyze, w, l)
- local farmCfg= { }
- farmCfg.points = farmPoints
- farmCfg.treeData = farmMap.treeData
- farmCfg.side = side
- local err = table.save(farmCfg, farmDataFileName)
- if err then
- print("Не могу сохранить конфигурацию фермы: "..err)
- os.exit(1)
- end
- else
- local farmCfg, err = table.load(farmDataFileName)
- if err then
- print("Не могу загрузить конфигурацию фермы: "..err)
- os.exit(1)
- end
- if not (farmCfg.points and farmCfg.treeData and checkSide(farmCfg.side)) then
- print("Неверный формат файла конфигурации фермы.")
- os.exit(1)
- end
- farmPoints = farmCfg.points or { }
- farmMap.treeData = farmCfg.treeData
- robot.navInit(farmCfg.side)
- local n = #farmPoints
- if n > 0 then
- local neddedEnergy = n * ETREETAP_USE_COST
- while 1 do
- if check_tool(neddedEnergy) then
- charge_tool(neddedEnergy)
- end
- nedded_check_use_cost = true
- workGuard(farm_collect)
- go_home()
- clear_inventory()
- sleep(SLEEP_TIME)
- end
- else
- print("На ферме нет подтёков!")
- os.exit(1)
- end
- end
- end
- function farm_check_components()
- if not component.isAvailable("inventory_controller") then
- print("Контроллер инвентаря не обнаружен. Принудительная остановка программы.")
- os.exit(1)
- end
- inv = component.inventory_controller
- -- if not component.isAvailable("geolyzer") then
- -- print("Геосканер не обнаружен. Принудительная остановка программы.")
- -- os.exit(1)
- -- end
- -- geolyzer = component.geolyzer
- if robot.durability() == nil then
- print("Инструмент не обнаружен. Принудительная остановка программы.")
- os.exit(1)
- end
- end
- function main(args, options)
- local function argNumber(x)
- local v = tonumber(x)
- if type(v) ~= 'number' then
- io.write("Аргументы должны быть заданы в виде чисел.\n")
- os.exit(1)
- end
- return v
- end
- local function getNumberOption(name)
- local v = options[name]
- if v then
- v = argNumber(v)
- end
- return v
- end
- if options.help then
- io.write("ссылка\n")
- return
- end
- farm_check_components()
- if options.analyze and #args == 3 then
- local l = argNumber(args[1])
- local w = argNumber(args[2])
- local side = sides[args[3]]
- if not side then
- local tr = {
- ["юг"] = sides.south,
- ["север"] = sides.north,
- ["запад"] = sides.west,
- ["восток"] = sides.east,
- ["ю"] = sides.south,
- ["с"] = sides.north,
- ["з"] = sides.west,
- ["в"] = sides.east,
- ["s"] = sides.south,
- ["n"] = sides.north,
- ["w"] = sides.west,
- ["e"] = sides.east,
- }
- side = tr[args[3]]
- if not side then
- print("Неверная сторона")
- os.exit(1)
- end
- end
- farm(l, w, options["analyze"], side)
- elseif options.run then
- farm()
- else
- io.write("Запуск:\nrubber-farm --analyze ряды_вперёд ряды_справа сторона_света\n")
- io.write("Запуск:\nrubber-farm\n")
- io.write("Опции:\n")
- io.write("--help — информация о программе\n")
- end
- end
- main(shell.parse(...))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement