Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local robot = require("robot")
- local computer = require("computer")
- local serialization = require("serialization")
- local filesystem = require("filesystem")
- local component = require("component")
- local sides = require("sides")
- local WORK_FILE = "/home/work.dat"
- local POS_FILE = "/home/pos.dat"
- local SECONDS_PER_BLOCK = 1.75
- local last_check_time = computer.uptime()
- local last_power_amount = computer.energy()
- local pos = {}
- local work = {}
- local average_rf_per_second, average_time_remaining
- local smoothing_strength = 0.75
- function load_state()
- local resuming_work = false
- if filesystem.exists(POS_FILE) then
- local state_file = io.open(POS_FILE, "r")
- pos = serialization.unserialize(state_file:read("*a"))
- state_file:close()
- else
- pos = {x=0, y=0, z=0, rot=0, docking=false}
- save_pos()
- end
- if filesystem.exists(WORK_FILE) then
- local work_file = io.open(WORK_FILE, "r")
- work = serialization.unserialize(work_file:read("*a"))
- work_file:close()
- resuming_work = true
- else
- work = {}
- save_work()
- end
- return resuming_work
- end
- function power_percentage()
- return computer.energy() / computer.maxEnergy()
- end
- function check_power_usage()
- local current_power = computer.energy()
- local current_check_time = computer.uptime()
- local power_change = current_power - last_power_amount
- local time_change = current_check_time - last_check_time
- if time_change == 0 then
- time_change = 1
- end
- local rf_per_second = power_change/time_change
- last_check_time = current_check_time
- last_power_amount = current_power
- if average_rf_per_second == nil then
- average_rf_per_second = rf_per_second
- else
- average_rf_per_second = average_rf_per_second * smoothing_strength + rf_per_second * (1-smoothing_strength)
- end
- local time_left = math.max(1/-average_rf_per_second * computer.energy(), 0)
- if rf_per_second > 0 then
- return average_rf_per_second, 1e309
- end
- if average_time_left == nil then
- average_time_left = time_left
- else
- average_time_left = average_time_left * smoothing_strength + time_left * (1 - smoothing_strength)
- end
- return average_rf_per_second, average_time_left
- end
- function save_pos()
- local state_file = io.open(POS_FILE,"w")
- state_file:write(serialization.serialize(pos))
- state_file:flush()
- state_file:close()
- end
- function save_work()
- local work_file = io.open(WORK_FILE, "w")
- work_file:write(serialization.serialize(work, 1e309))
- work_file:flush()
- work_file:close()
- end
- function move_forward()
- local detection, type = robot.detect()
- while detection and not (should_return() and not pos["docking"]) do
- robot.swing()
- robot.suck()
- detection, type = robot.detect()
- end
- if robot.forward() then
- local inc_axis = nil
- local dec_axis = nil
- if pos["rot"] == 0 then
- inc_axis = "x"
- dec_axis = nil
- elseif pos["rot"] == 1 then
- inc_axis = "z"
- dec_axis = nil
- elseif pos["rot"] == 2 then
- inc_axis = nil
- dec_axis = "x"
- elseif pos["rot"] == 3 then
- inc_axis = nil
- dec_axis = "z"
- else
- error("Invalid rotation value")
- end
- if inc_axis ~= nil then
- pos[inc_axis] = pos[inc_axis] + 1
- elseif dec_axis ~= nil then
- pos[dec_axis] = pos[dec_axis] - 1
- else
- error("Invalid inc/dec axis")
- end
- end
- save_pos()
- end
- function turn_left()
- robot.turnLeft()
- pos["rot"] = (pos["rot"] + 3) % 4
- save_pos()
- end
- function turn_right()
- robot.turnRight()
- pos["rot"] = (pos["rot"] + 1) % 4
- save_pos()
- end
- function face_direction(direction)
- local direction_delta = (pos["rot"] - direction + 4) % 4
- if direction_delta == 1 then
- turn_left()
- elseif direction_delta == 3 then
- turn_right()
- elseif direction_delta == 2 then
- turn_right()
- turn_right()
- end
- end
- function move_up()
- local detection, type = robot.detectUp()
- while detection and not (should_return() and not pos["docking"]) do
- robot.swingUp()
- robot.suckUp()
- detection, type = robot.detectUp()
- end
- if robot.up() then
- pos["y"] = pos["y"] + 1
- end
- save_pos()
- end
- function move_down()
- local detection, type = robot.detectDown()
- while detection and not (should_return() and not pos["docking"]) do
- robot.swingDown()
- robot.suckDown()
- detection, type = robot.detectDown()
- end
- if robot.down() then
- pos["y"] = pos["y"] - 1
- end
- save_pos()
- end
- function move_relative(x, y, z)
- if x < 0 then
- face_direction(2)
- elseif x > 0 then
- face_direction(0)
- end
- while x ~= 0 and not (should_return() and not pos["docking"])do
- move_forward()
- x = x - (x/math.abs(x))
- end
- if z < 0 then
- face_direction(3)
- elseif z > 0 then
- face_direction(1)
- end
- while z ~= 0 and not (should_return() and not pos["docking"])do
- move_forward()
- z = z - (z/math.abs(z))
- end
- while y ~= 0 and not (should_return() and not pos["docking"])do
- if y < 0 then
- move_down()
- elseif y > 0 then
- move_up()
- end
- y = y - (y/math.abs(y))
- end
- end
- function dock()
- pos["docking"] = true
- move_to(0, 0, 0)
- face_direction(1)
- deposit_items()
- face_direction(0)
- while power_percentage() < 0.99 do
- os.sleep(1)
- io.write(".")
- end
- print("")
- pos["docking"] = false
- end
- function deposit_items()
- if pos["x"] == 0 and pos["y"] == 0 and pos["z"] == 0 then
- local other_index = 1
- for i = 1, robot.inventorySize() do
- robot.select(i)
- if component.inventory_controller.getStackInInternalSlot(i) ~= nil then
- while component.inventory_controller.getStackInSlot(sides.front, other_index) ~= nil do
- other_index = other_index + 1
- end
- component.inventory_controller.dropIntoSlot(sides.front, other_index)
- end
- end
- end
- end
- function dist_from_dock()
- return math.abs(pos["x"]) + math.abs(pos["y"]) + math.abs(pos["z"])
- end
- function should_return()
- local power_usage, time_remaining = check_power_usage()
- local time_to_return = dist_from_dock() * SECONDS_PER_BLOCK
- print(string.format("PU: %8.4f ATR: %8.2f TTR: %6.2f", power_usage, time_remaining, time_to_return))
- if time_remaining < time_to_return + 20 then
- print("Low power")
- return true
- end
- local open_spaces = 0
- for i = 1, robot.inventorySize() do
- if robot.count(i) == 0 then
- open_spaces = open_spaces + 1
- end
- end
- if open_spaces == 0 then
- return true
- end
- return false
- end
- function push_work(obj)
- table.insert(work, obj)
- save_work()
- end
- function pop_work()
- local val = table.remove(work, #work)
- save_work()
- return val
- end
- function peek_work()
- return work[#work]
- end
- function move_to(x, y, z)
- local dX = x - pos["x"]
- local dY = y - pos["y"]
- local dZ = z - pos["z"]
- move_relative(dX, dY, dZ)
- end
- function rectangle(x, y, z, x2, z2)
- local dX = x2 - x
- local dZ = z2 - z
- local sX, sZ, eX, eZ
- if dX < 0 then
- sX = x2
- eX = x
- else
- sX = x
- eX = x2
- end
- if dZ < 0 then
- sZ = z2
- eZ = z
- else
- sZ = z
- eZ = z2
- end
- assert(sX < eX)
- assert(sZ < eZ)
- local on_left = true
- for iX = sX, eX do
- if on_left then
- for iZ = sZ, eZ do
- push_work({["x"] = iX, ["y"] = y, ["z"] = iZ, ["type"] = 0 })
- end
- else
- for iZ = sZ, eZ do
- push_work({["x"] = iX, ["y"] = y, ["z"] = sZ + eZ - iZ, ["type"] = 0})
- end
- end
- on_left = not on_left
- end
- end
- function quarry(x, y, z, x2, y2, z2)
- local dY = y2 - y
- local sY, eY
- if dY > 0 then
- sY = y
- eY = y2
- else
- sY = y2
- eY = y
- end
- if math.abs(dY) > 0 then
- push_work({["x"]=x, ["y"] = eY-1, ["z"]=z, ["x2"]=x2, ["y2"]=sY, ["z2"]=z2, ["type"]="quarry"})
- end
- push_work({["x"]=x, ["y"]=eY, ["z"]=z, ["x2"]=x2, ["z2"]=z2, ["type"]="rect"})
- end
- function execute_work()
- local next_step = peek_work()
- if should_return() then
- print("docking")
- dock()
- elseif next_step["type"] == 0 then
- move_to(next_step["x"], next_step["y"], next_step["z"])
- pop_work()
- elseif next_step["type"] == "rect" then
- pop_work()
- rectangle(next_step["x"], next_step["y"], next_step["z"], next_step["x2"], next_step["z2"])
- elseif next_step["type"] == "quarry" then
- pop_work()
- quarry(next_step["x"], next_step["y"], next_step["z"], next_step["x2"], next_step["y2"], next_step["z2"])
- else
- error("Invalid work")
- end
- end
- if not load_state() then
- dock()
- quarry(27, -36, -10, 31, -66, 10)
- end
- while #work > 0 do
- execute_work()
- end
- dock()
Add Comment
Please, Sign In to add comment