minecraft-cc-tools/libs/robot.lua

231 lines
4.8 KiB
Lua

-- robot api
local api = {}
local ROBOT_DEFAULT_STATE_FILE = '/.robotstate'
local DEFAULT_CONFIG = {
autosave = false,
autoload = false,
stateFilePath = ROBOT_DEFAULT_STATE_FILE
}
local function identity(x)
return x
end
local function getConfig(givenConfig)
if givenConfig.onSave and not givenConfig.onLoad then
error('robot.getConfig: custom "onSave" passed in config but no "onLoad"')
end
if givenConfig.onLoad and not givenConfig.onSave then
error('robot.getConfig: custom "onLoad" passed in config but no "onSave"')
end
return {
autosave = givenConfig.autosave or DEFAULT_CONFIG.autosave,
autoload = givenConfig.autoload or DEFAULT_CONFIG.autoload,
stateFilePath = givenConfig.stateFilePath or DEFAULT_CONFIG.stateFilePath,
onSave = givenConfig.onSave or identity,
onLoad = givenConfig.onLoad or identity
}
end
local function createDefaultState()
return {
y = 0,
x = 0,
z = 0,
dir = 'FORWARD' -- FORWARD | BACKWARD | LEFT | RIGHT
}
end
local saveRobotState = function(stateFile, onSave, state)
state = state or createDefaultState()
local file = fs.open(stateFile, 'w')
if not file then
error('saveRobotState: cannot open ' .. stateFile .. ' file!')
end
local transformedState = onSave(state)
file.write(textutils.serializeJSON(transformedState))
file.close()
return transformedState
end
local loadRobotState = function(stateFile, onLoad, onSave)
local file = fs.open(stateFile, 'r')
if not file then
return robot.saveRobotState(stateFile, onSave)
end
local serializedRobotState = file.readAll()
file.close()
local parsedResult = textutils.unserializeJSON(serializedRobotState)
if not parsedResult then
return robot.saveRobotState(stateFile, onSave)
end
return parsedResult, onLoad(parsedResult)
end
local getAutoSave = function(config, state)
local autoSave = function() end
if config.autosave then
autoSave = function()
saveRobotState(config.stateFilePath, config.onSave, state)
end
end
return autoSave
end
api.create = function(state, givenConfig)
state = state or createDefaultState()
local config = getConfig(givenConfig)
if config.autoload then
local originalState = loadRobotState(config.stateFilePath, config.onLoad, config.onSave)
state = originalState
end
local autoSave = getAutoSave(config, state)
local mutateRobotPosition = function(isBackward)
local incValue = 1
if isBackward then incValue = -1 end
if state.dir == 'FORWARD' then
state.z = state.z + incValue
elseif state.dir == 'BACKWARD' then
state.z = state.z - incValue
elseif state.dir == 'LEFT' then
state.x = state.x - incValue
elseif state.dir == 'RIGHT' then
state.x = state.x + incValue
end
end
local robot = {}
robot.forward = function()
local ok, err = turtle.forward()
if ok then
mutateRobotPosition(false)
autoSave()
end
return ok, err
end
robot.back = function()
local ok, err = turtle.back()
if ok then
mutateRobotPosition(true)
autoSave()
end
return ok, err
end
robot.backward = robot.back
robot.up = function()
local ok, err = turtle.up()
if ok then
state.y = state.y + 1
autoSave()
end
return ok, err
end
robot.down = function()
local ok, err = turtle.down()
if ok then
state.y = state.y - 1
autoSave()
end
return ok, err
end
robot.turnLeft = function()
local ok, err = turtle.turnLeft()
if ok then
if state.dir == 'FORWARD' then
state.dir = 'LEFT'
elseif state.dir == 'LEFT' then
state.dir = 'BACKWARD'
elseif state.dir == 'RIGHT' then
state.dir = 'FORWARD'
elseif state.dir == 'BACKWARD' then
state.dir = 'RIGHT'
end
autoSave()
end
return ok, err
end
robot.turnRight = function()
local ok, err = turtle.turnRight()
if ok then
if state.dir == 'FORWARD' then
state.dir = 'RIGHT'
elseif state.dir == 'LEFT' then
state.dir = 'FORWARD'
elseif state.dir == 'RIGHT' then
state.dir = 'BACKWARD'
elseif state.dir == 'BACKWARD' then
state.dir = 'LEFT'
end
autoSave()
end
return ok, err
end
robot.turnBack = function()
local ok, errorMessage = robot.turnLeft()
if not ok then
error('turnBack: cannot turn left because ' .. tostring(errorMessage))
end
return robot.turnLeft()
end
robot.getState = function()
return state
end
robot.saveState = function()
return saveRobotState(config.stateFilePath, config.onSave, state)
end
robot.loadState = function()
local originalState, transformedState = loadRobotState(config.stateFilePath, config.onLoad, config.onSave)
state = originalState
return transformedState
end
return robot
end
return api