Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- CONSTANTS
- DIRECTION = { NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3, UP = 4, DOWN = 5, first = 0, last = 5, num = 6,
- POS_X = 1, NEG_X = 3, POS_Y = 4, NEG_Y = 5, POS_Z = 2, NEG_Z = 0 }
- VALID_FUELS = { "minecraft:coal", "minecraft:charcoal", size = 2 }
- ACTION_STATE = { EXECUTING = 0, FINISHED = 1, FAILED = 2 }
- -- VARIABLES
- StuckScore = 0
- WasStuck = false
- -- HELPERS
- function Mod( a, b )
- return a - ( math.floor( a / b ) * b )
- end
- function Ternary( condition , onTrue , onFalse )
- if condition then return onTrue else return onFalse end
- end
- function DirectionVector( direction )
- if direction == DIRECTION.POS_X then
- return vector.new( 1, 0, 0 )
- elseif direction == DIRECTION.NEG_X then
- return vector.new( -1, 0, 0 )
- elseif direction == DIRECTION.POS_Y then
- return vector.new( 0, 1, 0 )
- elseif direction == DIRECTION.NEG_Y then
- return vector.new( 0, -1, 0 )
- elseif direction == DIRECTION.POS_Z then
- return vector.new( 0, 0, 1 )
- elseif direction == DIRECTION.NEG_Z then
- return vector.new( 0, 0, -1 )
- else
- assert( false, "Invalid direction" )
- end
- return vector.new( 0, 0, 0 )
- end
- function VecCompare( vecA, vecB )
- return vecA.x == vecB.x and vecA.y == vecB.y and vecA.z == vecB.z
- end
- function VecAssign( vecTo, vecFrom )
- vecTo.x = vecFrom.x
- vecTo.y = vecFrom.y
- vecTo.z = vecFrom.z
- end
- function VecAdd( vecA, vecB, result )
- result.x = vecA.x + vecB.x
- result.y = vecA.y + vecB.y
- result.z = vecA.z + vecB.z
- end
- -- DATA
- Position = vector.new( 0, 0, 0 )
- Direction = 0
- MoveConfirmation = { flag = 0, pos = vector.new( 0, 0, 0 ), fuel = 0 }
- CachedPosition = vector.new( 0, 0, 0 )
- QuarryFinished = false
- function WriteVector( handle, vector )
- handle.writeLine( vector.x )
- handle.writeLine( vector.y )
- handle.writeLine( vector.z )
- end
- function ReadVector( handle, vector )
- vector.x = tonumber( handle.readLine() )
- vector.y = tonumber( handle.readLine() )
- vector.z = tonumber( handle.readLine() )
- end
- function GetIntInput( queryText )
- local inputInt = nil
- term.clear()
- term.setCursorPos( 1, 1 )
- print( queryText )
- while true do
- inputInt = tonumber( read() )
- if type( inputInt ) == "number" and inputInt == math.floor( inputInt ) then
- return inputInt
- end
- term.clear()
- term.setCursorPos( 1, 1 )
- print( queryText )
- print( "Invalid entry" )
- end
- end
- function GetPositionInput( queryText, inputPos )
- inputPos.x = GetIntInput( queryText .. " xzy(_, z, y)" )
- inputPos.z = GetIntInput( queryText .. " xzy(" .. inputPos.x .. ", _, y)" )
- inputPos.y = GetIntInput( queryText .. " xzy(" .. inputPos.x .. ", " .. inputPos.z .. ", _)" )
- end
- function GetDirectionInput( queryText )
- local inputStr = nil
- term.clear()
- term.setCursorPos( 1, 1 )
- print( queryText .. " ((n)orth, (s)outh, (e)east, (w)est)" )
- while true do
- inputStr = string.lower( read() )
- if inputStr == "n" or inputStr == "north" then
- return DIRECTION.NORTH
- elseif inputStr == "e" or inputStr == "east" then
- return DIRECTION.EAST
- elseif inputStr == "s" or inputStr == "south" then
- return DIRECTION.SOUTH
- elseif inputStr == "w" or inputStr == "west" then
- return DIRECTION.WEST
- end
- term.clear()
- term.setCursorPos( 1, 1 )
- print( queryText .. " ((n)orth, (s)outh, (e)east, (w)est)" )
- print( "Invalid entry" )
- end
- end
- function LoadData()
- if not fs.exists( "data" ) then return false end
- local h = fs.open( "data", "r" )
- if h.readLine() ~= "VALID" then return false end
- ReadVector( h, Position )
- Direction = tonumber( h.readLine() )
- ReadVector( h, MoveConfirmation.pos )
- MoveConfirmation.fuel = tonumber( h.readLine() )
- MoveConfirmation.flag = tonumber( h.readLine() )
- ReadVector( h, CachedPosition )
- QuarryFinished = Ternary( h.readLine() == "T", true, false )
- local valid = h.readLine() == "END"
- h.close()
- return valid
- end
- function SaveData()
- local h = fs.open( "data", "w" )
- h.writeLine( "VALID" )
- WriteVector( h, Position )
- h.writeLine( Direction )
- WriteVector( h, MoveConfirmation.pos )
- h.writeLine( MoveConfirmation.fuel )
- h.writeLine( MoveConfirmation.flag )
- WriteVector( h, CachedPosition )
- h.writeLine( Ternary( QuarryFinished, "T", "F" ) )
- h.writeLine( "END" )
- h.close()
- end
- function ClearData()
- local h = fs.open( "data", "w" )
- h.writeLine( "INVALID" )
- h.close()
- end
- function InitData()
- term.clear()
- term.setCursorPos( 1, 1 )
- SaveData()
- end
- -- INSTRUCTIONS
- Instructions = {
- BlockIDs = { nil, nil },
- PosMin = vector.new( 0, 0, 0 ),
- PosMax = vector.new( 0, 0, 0 )
- }
- function LoadInstructions()
- if not fs.exists( "instructions" ) then return false end
- local h = fs.open( "instructions", "r" )
- Instructions.BlockIDs[1] = h.readLine()
- Instructions.BlockIDs[2] = h.readLine()
- ReadVector( h, Instructions.PosMin )
- ReadVector( h, Instructions.PosMax )
- local valid = h.readLine() == "END"
- h.close()
- return valid
- end
- function SaveInstructions()
- local h = fs.open( "instructions", "w" )
- h.writeLine( Instructions.BlockIDs[1] )
- h.writeLine( Instructions.BlockIDs[2] )
- WriteVector( h, Instructions.PosMin )
- WriteVector( h, Instructions.PosMax )
- h.writeLine( "END" )
- h.close()
- end
- function InitInstructions()
- local PosA = vector.new( 0, 0, 0 )
- local PosB = vector.new( 0, 0, 0 )
- local right = DirectionVector( Mod( Direction + 1, 4 ) )
- local width = GetIntInput( "Enter width" )
- PosB = PosB:add( right:mul( width - 1 ) )
- local forward = DirectionVector( Direction )
- local depth = GetIntInput( "Enter depth" )
- PosB = PosB:add( forward:mul( depth - 1 ) )
- local height = GetIntInput( "Enter height" )
- PosB.y = height - 1
- Instructions.PosMin.x = math.min( PosA.x, PosB.x )
- Instructions.PosMin.y = math.min( PosA.y, PosB.y )
- Instructions.PosMin.z = math.min( PosA.z, PosB.z )
- Instructions.PosMax.x = math.max( PosA.x, PosB.x )
- Instructions.PosMax.y = math.max( PosA.y, PosB.y )
- Instructions.PosMax.z = math.max( PosA.z, PosB.z )
- while true do
- term.clear()
- term.setCursorPos( 1, 1 )
- print( "Press enter when you have the materials in the first slots" )
- read()
- local item1 = turtle.getItemDetail( 1 )
- local item2 = turtle.getItemDetail( 2 )
- if item1 and item2 then
- Instructions.BlockIDs[1] = item1.name
- Instructions.BlockIDs[2] = item2.name
- break
- end
- end
- -- start position
- VecAssign( CachedPosition, Instructions.PosMin )
- CachedPosition.y = CachedPosition.y + 1
- term.clear()
- term.setCursorPos( 1, 1 )
- SaveData()
- SaveInstructions()
- end
- -- FUEL MANAGEMENT
- function FuelUpdate()
- if turtle.getFuelLimit() - turtle.getFuelLevel() < 80 then return true end
- for slot = 1, 16 do
- local itemDetail = turtle.getItemDetail( slot )
- if itemDetail then
- for validFuel = 1, VALID_FUELS.size do
- if itemDetail.name == VALID_FUELS[validFuel] then
- turtle.select( slot )
- return turtle.refuel( 1 )
- end
- end
- end
- end
- if turtle.getFuelLevel() == 0 then
- print( "Ran out of fuel" )
- return false
- end
- turtle.select( 1 )
- return true
- end
- -- INVENTORY
- function SelectMaterial( num )
- for slot = 1, 16 do
- local itemDetail = turtle.getItemDetail( slot )
- if itemDetail and itemDetail.name == Instructions.BlockIDs[ num ] then
- turtle.select( slot )
- return true
- end
- end
- return false
- end
- -- BASIC MOVEMENT
- function CreateMoveConfirmation( direction )
- VecAdd( Position, DirectionVector( direction ), MoveConfirmation.pos )
- MoveConfirmation.fuel = turtle.getFuelLevel()
- MoveConfirmation.flag = 1
- end
- function ConsumeMoveConfirmation()
- if MoveConfirmation.flag == 0 then return end
- if turtle.getFuelLevel() < MoveConfirmation.fuel then
- VecAssign( Position, MoveConfirmation.pos )
- StuckScore = 0
- end
- SaveData()
- ClearMoveConfirmation()
- end
- function ClearMoveConfirmation()
- MoveConfirmation.flag = 0
- MoveConfirmation.pos = vector.new( 0, 0, 0 )
- MoveConfirmation.fuel = 0
- end
- function Move( direction, mine )
- if direction == DIRECTION.NORTH or direction == DIRECTION.EAST or direction == DIRECTION.SOUTH or direction == DIRECTION.WEST then
- Face( Mod( direction + 2, 4 ) )
- CreateMoveConfirmation( direction )
- SaveData()
- if turtle.back() then
- ConsumeMoveConfirmation()
- return ACTION_STATE.FINISHED
- else
- ConsumeMoveConfirmation()
- StuckScore = StuckScore + 1
- if not mine then return ACTION_STATE.FAILED end
- Face( direction )
- if turtle.detect() and not turtle.dig() then return ACTION_STATE.FAILED end
- return Move( direction, false )
- end
- elseif direction == DIRECTION.UP then
- if turtle.detectUp() and not ( mine and turtle.digUp() ) then return ACTION_STATE.FAILED end
- CreateMoveConfirmation( direction )
- SaveData()
- if turtle.up() then
- ConsumeMoveConfirmation()
- return ACTION_STATE.FINISHED
- else
- ConsumeMoveConfirmation()
- StuckScore = StuckScore + 1
- return Ternary( mine, ACTION_STATE.EXECUTING, ACTION_STATE.FAILED )
- end
- elseif direction == DIRECTION.DOWN then
- if turtle.detectDown() and not ( mine and turtle.digDown() ) then return ACTION_STATE.FAILED end
- CreateMoveConfirmation( direction )
- SaveData()
- if turtle.down() then
- ConsumeMoveConfirmation()
- return ACTION_STATE.FINISHED
- else
- ConsumeMoveConfirmation()
- StuckScore = StuckScore + 1
- return Ternary( mine, ACTION_STATE.EXECUTING, ACTION_STATE.FAILED )
- end
- else
- assert( false, "Invalid direction" )
- return ACTION_STATE.FAILED
- end
- end
- function TurnRight()
- ClearData()
- local thread = coroutine.create( function()
- turtle.turnRight()
- end)
- coroutine.resume( thread )
- Direction = Mod( Direction + 1, 4 )
- SaveData()
- sleep(0.5)
- end
- function TurnLeft()
- ClearData()
- local thread = coroutine.create( function()
- turtle.turnLeft()
- end)
- coroutine.resume( thread )
- Direction = Mod( Direction - 1, 4 )
- SaveData()
- sleep(0.5)
- end
- function Face( direction )
- assert( direction < 4, "Unexpected direction" )
- local rotation = Mod( direction - Direction, 4 )
- if rotation == 1 then
- TurnRight()
- elseif rotation == 2 then
- TurnRight()
- TurnRight()
- elseif rotation == 3 then
- TurnLeft()
- end
- end
- -- ACTIONS
- function MoveToUpdate( pos, canMine )
- if VecCompare( Position, pos ) then return ACTION_STATE.FINISHED end
- local toPos = pos - Position
- local InitialDir = Direction
- for dirMod = DIRECTION.first, DIRECTION.last do
- local dir = Mod( InitialDir + dirMod, DIRECTION.num )
- if DirectionVector( dir ):dot( toPos ) > 0 and Move( dir, false ) ~= ACTION_STATE.FAILED then return ACTION_STATE.EXECUTING end
- end
- if canMine then
- InitialDir = Direction
- for dirMod = DIRECTION.first, DIRECTION.last do
- local dir = Mod( InitialDir + dirMod, DIRECTION.num )
- if DirectionVector( dir ):dot( toPos ) > 0 and Move( dir, true ) ~= ACTION_STATE.FAILED then return ACTION_STATE.EXECUTING end
- end
- end
- print( "Unable to move to (" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. ")" )
- return ACTION_STATE.FAILED
- end
- function IsInConstructionArea( pos )
- return pos.x <= Instructions.PosMax.x + 1 and pos.y <= Instructions.PosMax.y + 1 and pos.z <= Instructions.PosMax.z and
- pos.x >= Instructions.PosMin.x and pos.y >= Instructions.PosMin.y and pos.z >= Instructions.PosMin.z
- end
- function BuildDescription( localPos )
- -- Floor
- if Mod(localPos.y, 9) == 0 then
- return Ternary( Mod(localPos.x, 4) == 2 and Mod(localPos.z, 4) == 2, 2, 1)
- end
- -- Pillars
- if Mod(localPos.x, 4) == 0 and Mod(localPos.z, 4) == 0 then return 1 end
- -- Walls
- if Mod(localPos.y, 9) > 2 and ( Mod(localPos.x, 4) == 0 or Mod(localPos.z, 4) == 0 ) then return 1 end
- return 0
- end
- function ConstructBlockUpdate( direction )
- local buildPos = Position:add( DirectionVector( direction ) )
- if not IsInConstructionArea( buildPos ) then return ACTION_STATE.FINISHED end
- local material = BuildDescription( buildPos:sub( Instructions.PosMin ) )
- local occupied = nil
- local data = nil
- if direction == DIRECTION.UP then
- occupied, data = turtle.inspectUp()
- elseif direction == DIRECTION.DOWN then
- occupied, data = turtle.inspectDown()
- else
- occupied, data = turtle.inspect()
- end
- if occupied and ( material == 0 or data.name ~= Instructions.BlockIDs[material] ) then
- if direction == DIRECTION.UP then
- turtle.digUp()
- elseif direction == DIRECTION.DOWN then
- turtle.digDown()
- else
- turtle.dig()
- end
- end
- if material ~= 0 then
- if data.name == Instructions.BlockIDs[material] then return ACTION_STATE.FINISHED end
- if not SelectMaterial( material ) then
- print( "Ran out of " .. Instructions.BlockID )
- return ACTION_STATE.FAILED
- end
- local placed = false
- if direction == DIRECTION.UP then
- placed = turtle.placeUp()
- elseif direction == DIRECTION.DOWN then
- placed = turtle.placeDown()
- else
- placed = turtle.place()
- end
- if not placed then
- return ACTION_STATE.EXECUTING
- end
- end
- return ACTION_STATE.FINISHED
- end
- function ConstructionUpdate()
- if not IsInConstructionArea( Position ) then
- print( "Turtle is outside the construction area" )
- return ACTION_STATE.FAILED
- end
- if not VecCompare( Position, CachedPosition ) then
- if MoveToUpdate( CachedPosition, true ) == ACTION_STATE.FAILED then return ACTION_STATE.FAILED end
- return ACTION_STATE.EXECUTING
- end
- local constructBlockState = ConstructBlockUpdate( DIRECTION.DOWN )
- if constructBlockState ~= ACTION_STATE.FINISHED then return constructBlockState end
- constructBlockState = ConstructBlockUpdate( Direction )
- if constructBlockState ~= ACTION_STATE.FINISHED then return constructBlockState end
- constructBlockState = ConstructBlockUpdate( DIRECTION.UP )
- if constructBlockState ~= ACTION_STATE.FINISHED then return constructBlockState end
- local localPos = Position:sub( Instructions.PosMin )
- local xDest = Ternary( Mod( math.floor( ( localPos.y - 1 ) / 3 ) + localPos.z, 2 ) == 0, Instructions.PosMax.x, Instructions.PosMin.x )
- if Position.x ~= xDest then
- if Move( Ternary( xDest > Position.x, DIRECTION.POS_X, DIRECTION.NEG_X ), true ) == ACTION_STATE.FAILED then return ACTION_STATE.FAILED end
- VecAssign( CachedPosition, Position )
- return ACTION_STATE.EXECUTING
- end
- local zDest = Ternary( Mod( math.floor( ( localPos.y - 1 ) / 3 ), 2 ) == 0, Instructions.PosMax.z, Instructions.PosMin.z )
- if Position.z ~= zDest then
- if Move( Ternary( zDest > Position.z, DIRECTION.POS_Z, DIRECTION.NEG_Z ), true ) == ACTION_STATE.FAILED then return ACTION_STATE.FAILED end
- VecAssign( CachedPosition, Position )
- return ACTION_STATE.EXECUTING
- end
- -- Check if finished
- if Position.y > Instructions.PosMax.y then return ACTION_STATE.FINISHED end
- if Move( DIRECTION.POS_Y, true ) == ACTION_STATE.FAILED then return ACTION_STATE.FAILED end
- VecAssign( CachedPosition, Position )
- return ACTION_STATE.EXECUTING
- end
- function Update()
- if StuckScore > 128 then WasStuck = true end
- if StuckScore > 256 then return ACTION_STATE.FAILED end
- if not FuelUpdate() then return ACTION_STATE.FAILED end
- return ConstructionUpdate()
- end
- -- MAIN
- function Main()
- if not LoadData() then
- InitData()
- end
- if not LoadInstructions() then
- InitInstructions()
- end
- ConsumeMoveConfirmation()
- while true do
- local updateState = Update()
- if updateState ~= ACTION_STATE.EXECUTING then
- print( Ternary( updateState == ACTION_STATE.FINISHED, "Job finished!", "Job failed!" ) )
- break
- end
- end
- end
- Main()
Add Comment
Please, Sign In to add comment