Initial commit
232
PriorityQueue.lua
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PriorityQueue - v1.0.1 - public domain Lua priority queue
|
||||||
|
implemented with indirect binary heap
|
||||||
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
|
based on binaryheap library (github.com/iskolbin/binaryheap)
|
||||||
|
|
||||||
|
author: Ilya Kolbin (iskolbin@gmail.com)
|
||||||
|
url: github.com/iskolbin/priorityqueue
|
||||||
|
|
||||||
|
See documentation in README file.
|
||||||
|
|
||||||
|
COMPATIBILITY
|
||||||
|
|
||||||
|
Lua 5.1, 5.2, 5.3, LuaJIT 1, 2
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
|
||||||
|
This software is dual-licensed to the public domain and under the following
|
||||||
|
license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
publish, and distribute this file as you see fit.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local floor, setmetatable = math.floor, setmetatable
|
||||||
|
|
||||||
|
local function siftup( self, from )
|
||||||
|
local items, priorities, indices, higherpriority = self, self._priorities, self._indices, self._higherpriority
|
||||||
|
local index = from
|
||||||
|
local parent = floor( index / 2 )
|
||||||
|
while index > 1 and higherpriority( priorities[index], priorities[parent] ) do
|
||||||
|
priorities[index], priorities[parent] = priorities[parent], priorities[index]
|
||||||
|
items[index], items[parent] = items[parent], items[index]
|
||||||
|
indices[items[index]], indices[items[parent]] = index, parent
|
||||||
|
index = parent
|
||||||
|
parent = floor( index / 2 )
|
||||||
|
end
|
||||||
|
return index
|
||||||
|
end
|
||||||
|
|
||||||
|
local function siftdown( self, limit )
|
||||||
|
local items, priorities, indices, higherpriority, size = self, self._priorities, self._indices, self._higherpriority, self._size
|
||||||
|
for index = limit, 1, -1 do
|
||||||
|
local left = index + index
|
||||||
|
local right = left + 1
|
||||||
|
while left <= size do
|
||||||
|
local smaller = left
|
||||||
|
if right <= size and higherpriority( priorities[right], priorities[left] ) then
|
||||||
|
smaller = right
|
||||||
|
end
|
||||||
|
if higherpriority( priorities[smaller], priorities[index] ) then
|
||||||
|
items[index], items[smaller] = items[smaller], items[index]
|
||||||
|
priorities[index], priorities[smaller] = priorities[smaller], priorities[index]
|
||||||
|
indices[items[index]], indices[items[smaller]] = index, smaller
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
index = smaller
|
||||||
|
left = index + index
|
||||||
|
right = left + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local PriorityQueueMt
|
||||||
|
|
||||||
|
local PriorityQueue = {}
|
||||||
|
|
||||||
|
local function minishigher( a, b )
|
||||||
|
return a < b
|
||||||
|
end
|
||||||
|
|
||||||
|
local function maxishigher( a, b )
|
||||||
|
return a > b
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue.new( priority_or_array )
|
||||||
|
local t = type( priority_or_array )
|
||||||
|
local higherpriority = minishigher
|
||||||
|
|
||||||
|
if t == 'table' then
|
||||||
|
higherpriority = priority_or_array.higherpriority or higherpriority
|
||||||
|
elseif t == 'function' or t == 'string' then
|
||||||
|
higherpriority = priority_or_array
|
||||||
|
elseif t ~= 'nil' then
|
||||||
|
local msg = 'Wrong argument type to PriorityQueue.new, it must be table or function or string, has: %q'
|
||||||
|
error( msg:format( t ))
|
||||||
|
end
|
||||||
|
|
||||||
|
if type( higherpriority ) == 'string' then
|
||||||
|
if higherpriority == 'min' then
|
||||||
|
higherpriority = minishigher
|
||||||
|
elseif higherpriority == 'max' then
|
||||||
|
higherpriority = maxishigher
|
||||||
|
else
|
||||||
|
local msg = 'Wrong string argument to PriorityQueue.new, it must be "min" or "max", has: %q'
|
||||||
|
error( msg:format( tostring( higherpriority )))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local self = setmetatable( {
|
||||||
|
_priorities = {},
|
||||||
|
_indices = {},
|
||||||
|
_size = 0,
|
||||||
|
_higherpriority = higherpriority or minishigher
|
||||||
|
}, PriorityQueueMt )
|
||||||
|
|
||||||
|
if t == 'table' then
|
||||||
|
self:batchenq( priority_or_array )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:enqueue( item, priority )
|
||||||
|
local items, priorities, indices = self, self._priorities, self._indices
|
||||||
|
if indices[item] ~= nil then
|
||||||
|
error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' )
|
||||||
|
end
|
||||||
|
local size = self._size + 1
|
||||||
|
self._size = size
|
||||||
|
items[size], priorities[size], indices[item] = item, priority, size
|
||||||
|
siftup( self, size )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:remove( item )
|
||||||
|
local index = self._indices[item]
|
||||||
|
if index ~= nil then
|
||||||
|
local size = self._size
|
||||||
|
local items, priorities, indices = self, self._priorities, self._indices
|
||||||
|
indices[item] = nil
|
||||||
|
if size == index then
|
||||||
|
items[size], priorities[size] = nil, nil
|
||||||
|
self._size = size - 1
|
||||||
|
else
|
||||||
|
local lastitem = items[size]
|
||||||
|
items[index], priorities[index] = items[size], priorities[size]
|
||||||
|
items[size], priorities[size] = nil, nil
|
||||||
|
indices[lastitem] = index
|
||||||
|
size = size - 1
|
||||||
|
self._size = size
|
||||||
|
if size > 1 then
|
||||||
|
siftdown( self, siftup( self, index ))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:contains( item )
|
||||||
|
return self._indices[item] ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:update( item, priority )
|
||||||
|
local ok = self:remove( item )
|
||||||
|
if ok then
|
||||||
|
self:enqueue( item, priority )
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:dequeue()
|
||||||
|
local size = self._size
|
||||||
|
|
||||||
|
assert( size > 0, 'Heap is empty' )
|
||||||
|
|
||||||
|
local items, priorities, indices = self, self._priorities, self._indices
|
||||||
|
local item, priority = items[1], priorities[1]
|
||||||
|
indices[item] = nil
|
||||||
|
|
||||||
|
if size > 1 then
|
||||||
|
local newitem = items[size]
|
||||||
|
items[1], priorities[1] = newitem, priorities[size]
|
||||||
|
items[size], priorities[size] = nil, nil
|
||||||
|
indices[newitem] = 1
|
||||||
|
size = size - 1
|
||||||
|
self._size = size
|
||||||
|
siftdown( self, 1 )
|
||||||
|
else
|
||||||
|
items[1], priorities[1] = nil, nil
|
||||||
|
self._size = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return item, priority
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:peek()
|
||||||
|
return self[1], self._priorities[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:len()
|
||||||
|
return self._size
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:empty()
|
||||||
|
return self._size <= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function PriorityQueue:batchenq( iparray )
|
||||||
|
local items, priorities, indices = self, self._priorities, self._indices
|
||||||
|
local size = self._size
|
||||||
|
for i = 1, #iparray, 2 do
|
||||||
|
local item, priority = iparray[i], iparray[i+1]
|
||||||
|
if indices[item] ~= nil then
|
||||||
|
error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' )
|
||||||
|
end
|
||||||
|
size = size + 1
|
||||||
|
items[size], priorities[size] = item, priority
|
||||||
|
indices[item] = size
|
||||||
|
end
|
||||||
|
self._size = size
|
||||||
|
if size > 1 then
|
||||||
|
siftdown( self, floor( size / 2 ))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
PriorityQueueMt = {
|
||||||
|
__index = PriorityQueue,
|
||||||
|
__len = PriorityQueue.len,
|
||||||
|
}
|
||||||
|
|
||||||
|
return setmetatable( PriorityQueue, {
|
||||||
|
__call = function( _, ... )
|
||||||
|
return PriorityQueue.new( ... )
|
||||||
|
end
|
||||||
|
} )
|
61
alarm.lua
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
local dfpwm = require("cc.audio.dfpwm")
|
||||||
|
|
||||||
|
local speaker = peripheral.find("speaker")
|
||||||
|
local monitor = peripheral.find("monitor")
|
||||||
|
local chat = peripheral.find("chatBox")
|
||||||
|
local detector = peripheral.find("playerDetector")
|
||||||
|
|
||||||
|
local distance = 20
|
||||||
|
local target = "OROURKEIRE"
|
||||||
|
--local target = "devplayer0"
|
||||||
|
|
||||||
|
function klaxon()
|
||||||
|
local decoder = dfpwm.make_decoder()
|
||||||
|
for chunk in io.lines("data/danger.dfpwm", 16 * 1024) do
|
||||||
|
local buffer = decoder(chunk)
|
||||||
|
|
||||||
|
while not speaker.playAudio(buffer) do
|
||||||
|
os.pullEvent("speaker_audio_empty")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function showWarning()
|
||||||
|
monitor.clear()
|
||||||
|
monitor.setTextScale(2)
|
||||||
|
--[[local w, h = monitor.getSize()
|
||||||
|
local tw = string.len("WARNING")
|
||||||
|
for i = 1, 3 do
|
||||||
|
monitor.setCursorPos(w/2 - tw/2, (h/3)*i)
|
||||||
|
monitor.write("WARNING")
|
||||||
|
end]]
|
||||||
|
monitor.setCursorPos(8, 3)
|
||||||
|
monitor.write("WARNING")
|
||||||
|
monitor.setCursorPos(8, 5)
|
||||||
|
monitor.write("WARNING")
|
||||||
|
monitor.setCursorPos(8, 8)
|
||||||
|
monitor.write("WARNING")
|
||||||
|
end
|
||||||
|
|
||||||
|
function broadcastWarning()
|
||||||
|
local msg = {
|
||||||
|
{text = "WARNING", color = "red"},
|
||||||
|
{text = ": Kevin is ", color = "white"},
|
||||||
|
{text = "IN THE BASE", color = "yellow"},
|
||||||
|
{text = "!"},
|
||||||
|
}
|
||||||
|
local msgJSON = textutils.serializeJSON(msg)
|
||||||
|
chat.sendFormattedMessage(msgJSON)
|
||||||
|
end
|
||||||
|
|
||||||
|
while true do
|
||||||
|
if detector.isPlayerInRange(25, target) then
|
||||||
|
showWarning()
|
||||||
|
broadcastWarning()
|
||||||
|
klaxon()
|
||||||
|
else
|
||||||
|
monitor.clear()
|
||||||
|
end
|
||||||
|
|
||||||
|
sleep(1)
|
||||||
|
end
|
BIN
danger.dfpwm
Normal file
1
datapack/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.zip
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"type": "computercraft:tool",
|
||||||
|
"item": "minecraft:diamond_pickaxe",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_pickaxe.adjective",
|
||||||
|
"allowEnchantments": true
|
||||||
|
}
|
6
datapack/pack.mcmeta
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"pack_format": 15,
|
||||||
|
"description": "Enchanted pickaxe for ComputerCraft"
|
||||||
|
}
|
||||||
|
}
|
BIN
icon/ore-coal.png
Normal file
After Width: | Height: | Size: 623 B |
BIN
icon/ore-copper.png
Normal file
After Width: | Height: | Size: 653 B |
BIN
icon/ore-diamond.png
Normal file
After Width: | Height: | Size: 625 B |
BIN
icon/ore-ds-coal.png
Normal file
After Width: | Height: | Size: 613 B |
BIN
icon/ore-ds-copper.png
Normal file
After Width: | Height: | Size: 636 B |
BIN
icon/ore-ds-diamond.png
Normal file
After Width: | Height: | Size: 641 B |
BIN
icon/ore-ds-emerald.png
Normal file
After Width: | Height: | Size: 636 B |
BIN
icon/ore-ds-gold.png
Normal file
After Width: | Height: | Size: 615 B |
BIN
icon/ore-ds-iron.png
Normal file
After Width: | Height: | Size: 624 B |
BIN
icon/ore-ds-lapis.png
Normal file
After Width: | Height: | Size: 661 B |
BIN
icon/ore-ds-redstone.png
Normal file
After Width: | Height: | Size: 715 B |
BIN
icon/ore-emerald.png
Normal file
After Width: | Height: | Size: 634 B |
BIN
icon/ore-generic.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
icon/ore-gold.png
Normal file
After Width: | Height: | Size: 633 B |
BIN
icon/ore-iron.png
Normal file
After Width: | Height: | Size: 615 B |
BIN
icon/ore-lapis.png
Normal file
After Width: | Height: | Size: 676 B |
BIN
icon/ore-redstone.png
Normal file
After Width: | Height: | Size: 644 B |
BIN
icon/turtle.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
727
mine.lua
Normal file
@ -0,0 +1,727 @@
|
|||||||
|
package.path = "/mod/?.lua;" .. package.path
|
||||||
|
local PriorityQueue = require "PriorityQueue"
|
||||||
|
|
||||||
|
function Set(list)
|
||||||
|
local set = {}
|
||||||
|
for _, l in ipairs(list) do set[l] = true end
|
||||||
|
return set
|
||||||
|
end
|
||||||
|
|
||||||
|
local yieldTime = 0
|
||||||
|
function yield()
|
||||||
|
if os.clock() - yieldTime > 2 then
|
||||||
|
sleep(0)
|
||||||
|
yieldTime = os.clock()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function arr(n, init)
|
||||||
|
local a = {}
|
||||||
|
for _ = 1, n do
|
||||||
|
table.insert(a, init)
|
||||||
|
end
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
function arr2(x, y, init)
|
||||||
|
local a = {}
|
||||||
|
for _ = 1, y do
|
||||||
|
table.insert(a, arr(x, init))
|
||||||
|
end
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
|
||||||
|
local dirMap = {
|
||||||
|
["0,-1"] = 0,
|
||||||
|
["0,1"] = 0.5,
|
||||||
|
["1,0"] = 0.25,
|
||||||
|
["-1,0"] = -0.25,
|
||||||
|
}
|
||||||
|
function direction(v)
|
||||||
|
local d = dirMap[v.x..","..v.z]
|
||||||
|
assert(d)
|
||||||
|
return d
|
||||||
|
end
|
||||||
|
|
||||||
|
function findDistances(points)
|
||||||
|
local dist = arr2(#points, #points, math.huge)
|
||||||
|
-- local prev = arr2(#points, #points)
|
||||||
|
|
||||||
|
for i = 1, #points do
|
||||||
|
for j = 1, #points do
|
||||||
|
if i ~= j then
|
||||||
|
dist[i][j] = (points[i] - points[j]):length()
|
||||||
|
-- prev[i][j] = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i = 1, #points do
|
||||||
|
dist[i][i] = 0
|
||||||
|
-- prev[i][i] = i
|
||||||
|
end
|
||||||
|
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
|
function groupOres(ores, dist, offset)
|
||||||
|
if not offset then
|
||||||
|
offset = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local groups = {}
|
||||||
|
for i, o in ipairs(ores) do
|
||||||
|
table.insert(groups, {
|
||||||
|
["type"] = o.name,
|
||||||
|
["blocks"] = {
|
||||||
|
[i] = vector.new(o.x, o.y, o.z),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local didJoin = true
|
||||||
|
while didJoin do
|
||||||
|
didJoin = false
|
||||||
|
for i, io in pairs(groups) do
|
||||||
|
for x, a in pairs(io.blocks) do
|
||||||
|
for j, jo in pairs(groups) do
|
||||||
|
if i ~= j and jo.type == io.type then
|
||||||
|
for y, b in pairs(jo.blocks) do
|
||||||
|
-- yield()
|
||||||
|
assert(a ~= b)
|
||||||
|
if dist[offset + x][offset + y] == 1 then
|
||||||
|
for z, p in pairs(jo.blocks) do
|
||||||
|
io.blocks[z] = p
|
||||||
|
end
|
||||||
|
groups[j] = nil
|
||||||
|
didJoin = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local retGroups = {}
|
||||||
|
for _, g in pairs(groups) do
|
||||||
|
local v = vector.new(0, 0, 0)
|
||||||
|
local retBlocks = {}
|
||||||
|
for _, p in pairs(g.blocks) do
|
||||||
|
v = v + p
|
||||||
|
table.insert(retBlocks, p)
|
||||||
|
end
|
||||||
|
g.blocks = retBlocks
|
||||||
|
g.center = v / #g.blocks
|
||||||
|
assert(g.center)
|
||||||
|
table.insert(retGroups, g)
|
||||||
|
end
|
||||||
|
|
||||||
|
return retGroups
|
||||||
|
end
|
||||||
|
|
||||||
|
function pathThrough(points, dist, s, e)
|
||||||
|
-- local n = #points
|
||||||
|
|
||||||
|
-- dist[s][n] = 0
|
||||||
|
-- dist[n][s] = 0
|
||||||
|
-- dist[e][n] = 0
|
||||||
|
-- dist[n][e] = 0
|
||||||
|
|
||||||
|
-- for k = 1, #points do
|
||||||
|
-- for i = 1, #points do
|
||||||
|
-- for j = 1, #points do
|
||||||
|
-- if dist[i][j] > dist[i][k] + dist[k][j] then
|
||||||
|
-- dist[i][j] = dist[i][k] + dist[k][j]
|
||||||
|
-- prev[i][j] = prev[k][j]
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- yield()
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- local path = {e}
|
||||||
|
-- while s ~= e do
|
||||||
|
-- e = prev[s][e]
|
||||||
|
-- table.insert(path, 1, e)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- return path
|
||||||
|
|
||||||
|
-- nearest neighbour
|
||||||
|
local unvisited = {}
|
||||||
|
local ui = nil
|
||||||
|
for i = 1, #points do
|
||||||
|
if not e or i ~= e then
|
||||||
|
table.insert(unvisited, i)
|
||||||
|
end
|
||||||
|
if i == s then
|
||||||
|
ui = #unvisited
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(ui)
|
||||||
|
|
||||||
|
local visited = {}
|
||||||
|
local route = {}
|
||||||
|
while #unvisited ~= 1 do
|
||||||
|
local u = unvisited[ui]
|
||||||
|
table.remove(unvisited, ui)
|
||||||
|
|
||||||
|
local cDist = math.huge
|
||||||
|
local closest = nil
|
||||||
|
for ii = 1, #unvisited do
|
||||||
|
local i = unvisited[ii]
|
||||||
|
assert(i ~= u)
|
||||||
|
if dist[u][i] < cDist then
|
||||||
|
cDist = dist[u][i]
|
||||||
|
closest = ii
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(closest)
|
||||||
|
table.insert(route, unvisited[closest])
|
||||||
|
ui = closest
|
||||||
|
end
|
||||||
|
if e then
|
||||||
|
table.insert(route, e)
|
||||||
|
end
|
||||||
|
|
||||||
|
return route
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A*
|
||||||
|
function findPath(s, e)
|
||||||
|
local points = {}
|
||||||
|
function addPoint(p)
|
||||||
|
local k = p:tostring()
|
||||||
|
if not points[k] then
|
||||||
|
points[k] = p
|
||||||
|
end
|
||||||
|
return k
|
||||||
|
end
|
||||||
|
s = addPoint(s)
|
||||||
|
e = addPoint(e)
|
||||||
|
|
||||||
|
function h(i)
|
||||||
|
return (points[e] - points[i]):length()
|
||||||
|
end
|
||||||
|
|
||||||
|
function neighbors(k)
|
||||||
|
local p = points[k]
|
||||||
|
local ns = {
|
||||||
|
p + vector.new( 1, 0, 0),
|
||||||
|
p + vector.new( 0, 1, 0),
|
||||||
|
p + vector.new( 0, 0, 1),
|
||||||
|
p + vector.new(-1, 0, 0),
|
||||||
|
p + vector.new( 0, -1, 0),
|
||||||
|
p + vector.new( 0, 0, -1),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, n in ipairs(ns) do
|
||||||
|
ns[i] = addPoint(n)
|
||||||
|
end
|
||||||
|
return ns
|
||||||
|
end
|
||||||
|
|
||||||
|
local gScoreT = {}
|
||||||
|
gScoreT[s] = 0
|
||||||
|
function gScore(i)
|
||||||
|
if gScoreT[i] then
|
||||||
|
return gScoreT[i]
|
||||||
|
else
|
||||||
|
return math.huge
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local fScoreT = {}
|
||||||
|
fScoreT[s] = h(s)
|
||||||
|
function fScore(i)
|
||||||
|
if fScoreT[i] then
|
||||||
|
return fScoreT[i]
|
||||||
|
else
|
||||||
|
return math.huge
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local openSet = PriorityQueue(function(a, b)
|
||||||
|
return fScore(a) < fScore(b)
|
||||||
|
end)
|
||||||
|
openSet:enqueue(s, s)
|
||||||
|
|
||||||
|
local prev = {}
|
||||||
|
local found = false
|
||||||
|
while not openSet:empty() do
|
||||||
|
local current = openSet:dequeue()
|
||||||
|
if current == e then
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local ns = neighbors(current)
|
||||||
|
for _, n in ipairs(ns) do
|
||||||
|
tentativeG = gScore(current) + 1
|
||||||
|
if tentativeG < gScore(n) then
|
||||||
|
prev[n] = current
|
||||||
|
gScoreT[n] = tentativeG
|
||||||
|
fScoreT[n] = tentativeG + h(n)
|
||||||
|
if not openSet:contains(n) then
|
||||||
|
openSet:enqueue(n, n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(found)
|
||||||
|
|
||||||
|
local path = {points[e]}
|
||||||
|
local current = e
|
||||||
|
while prev[current] do
|
||||||
|
current = prev[current]
|
||||||
|
table.insert(path, 1, points[current])
|
||||||
|
end
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
local ORES = Set{
|
||||||
|
"minecraft:coal_ore",
|
||||||
|
"minecraft:deepslate_coal_ore",
|
||||||
|
"minecraft:iron_ore",
|
||||||
|
"minecraft:deepslate_iron_ore",
|
||||||
|
"minecraft:copper_ore",
|
||||||
|
"minecraft:deepslate_copper_ore",
|
||||||
|
"minecraft:gold_ore",
|
||||||
|
"minecraft:deepslate_gold_ore",
|
||||||
|
"minecraft:redstone_ore",
|
||||||
|
"minecraft:deepslate_redstone_ore",
|
||||||
|
"minecraft:emerald_ore",
|
||||||
|
"minecraft:deepslate_emerald_ore",
|
||||||
|
"minecraft:lapis_ore",
|
||||||
|
"minecraft:deepslate_lapis_ore",
|
||||||
|
"minecraft:diamond_ore",
|
||||||
|
"minecraft:deepslate_diamond_ore",
|
||||||
|
|
||||||
|
"create:ochrum",
|
||||||
|
"create:zinc_ore",
|
||||||
|
"create:deepslate_zinc_ore",
|
||||||
|
"create_new_age:thorium_ore",
|
||||||
|
|
||||||
|
"powah:deepslate_uraninite_ore_poor",
|
||||||
|
"powah:deepslate_uraninite_ore",
|
||||||
|
"powah:deepslate_uraninite_ore_dense",
|
||||||
|
"powah:uraninite_ore_poor",
|
||||||
|
"powah:uraninite_ore",
|
||||||
|
"powah:uraninite_ore_dense",
|
||||||
|
|
||||||
|
-- "minecraft:diamond_ore",
|
||||||
|
-- "minecraft:netherrack",
|
||||||
|
}
|
||||||
|
local BLACKLIST = Set{
|
||||||
|
"minecraft:diamond_pickaxe",
|
||||||
|
"computercraft:wireless_modem_advanced",
|
||||||
|
"advancedperipherals:geo_scanner",
|
||||||
|
"enderchests:ender_chest",
|
||||||
|
"functionalstorage:ender_drawer",
|
||||||
|
"advancedperipherals:chunk_controller",
|
||||||
|
}
|
||||||
|
local FUEL = "minecraft:coal"
|
||||||
|
local CHANNEL = 1337
|
||||||
|
|
||||||
|
settings.define("mine.name", {
|
||||||
|
description = "Miner name",
|
||||||
|
default = "DiggyBoi",
|
||||||
|
type = "string",
|
||||||
|
})
|
||||||
|
|
||||||
|
function selectItem(item, nbt)
|
||||||
|
for i = 1, 16 do
|
||||||
|
info = turtle.getItemDetail(i)
|
||||||
|
if (not item and not info) or (info and info.name == item and (not nbt or item.nbt == nbt)) then
|
||||||
|
turtle.select(i)
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Miner = {}
|
||||||
|
function Miner.new()
|
||||||
|
local self = setmetatable({}, { __index = Miner })
|
||||||
|
self.name = settings.get("mine.name")
|
||||||
|
self.equipped = {
|
||||||
|
["left"] = {
|
||||||
|
["last"] = "NONE",
|
||||||
|
["lastNbt"] = nil,
|
||||||
|
["fun"] = turtle.equipLeft,
|
||||||
|
},
|
||||||
|
["right"] = {
|
||||||
|
["last"] = "NONE",
|
||||||
|
["lastNbt"] = nil,
|
||||||
|
["fun"] = turtle.equipRight,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Get upgrades to a known state by "equipping" nothing
|
||||||
|
self:equip(nil, "left")
|
||||||
|
self:equip(nil, "right")
|
||||||
|
|
||||||
|
self:equip("advancedperipherals:geo_scanner", "right")
|
||||||
|
self.scanner = peripheral.wrap("right")
|
||||||
|
|
||||||
|
self:equip("computercraft:wireless_modem_advanced", "right")
|
||||||
|
self.modem = peripheral.wrap("right")
|
||||||
|
self.modem.open(CHANNEL)
|
||||||
|
|
||||||
|
self.pos = vector.new(0, 0, 0)
|
||||||
|
self:doGPS(true)
|
||||||
|
|
||||||
|
self:equip("advancedperipherals:chunk_controller", "left")
|
||||||
|
|
||||||
|
self.i = 1
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:equip(item, side, nbt)
|
||||||
|
local e = self.equipped[side]
|
||||||
|
if item == e.last and nbt == e.lastNbt then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(selectItem(item, nbt))
|
||||||
|
e.fun()
|
||||||
|
e.last = item
|
||||||
|
e.lastNbt = nbt
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:sendMessage(type, msg)
|
||||||
|
self:equip("computercraft:wireless_modem_advanced", "right")
|
||||||
|
msg["type"] = type
|
||||||
|
msg["name"] = self.name
|
||||||
|
msg["pos"] = self.absolutePos
|
||||||
|
self.modem.transmit(CHANNEL, CHANNEL, msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:dig(dir)
|
||||||
|
self:equip("minecraft:diamond_pickaxe", "right")
|
||||||
|
if dir == "up" then
|
||||||
|
assert(turtle.digUp())
|
||||||
|
elseif dir == "forward" then
|
||||||
|
assert(turtle.dig())
|
||||||
|
elseif dir == "down" then
|
||||||
|
assert(turtle.digDown())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:xchgItems()
|
||||||
|
local slots = {}
|
||||||
|
local emptySlots = 0
|
||||||
|
for i = 1, 16 do
|
||||||
|
local info = turtle.getItemDetail(i)
|
||||||
|
if info then
|
||||||
|
assert(info.name)
|
||||||
|
if not BLACKLIST[info.name] then
|
||||||
|
slots[i] = info
|
||||||
|
end
|
||||||
|
else
|
||||||
|
emptySlots = emptySlots + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if emptySlots >= 2 and turtle.getFuelLevel() >= 1000 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if turtle.detectDown() then
|
||||||
|
self:dig("down")
|
||||||
|
end
|
||||||
|
|
||||||
|
if emptySlots < 2 then
|
||||||
|
selectItem("enderchests:ender_chest")
|
||||||
|
assert(turtle.placeDown())
|
||||||
|
|
||||||
|
for i, info in pairs(slots) do
|
||||||
|
assert(turtle.select(i))
|
||||||
|
assert(turtle.dropDown())
|
||||||
|
end
|
||||||
|
self:dig("down")
|
||||||
|
end
|
||||||
|
|
||||||
|
if turtle.getFuelLevel() < 1000 then
|
||||||
|
selectItem("functionalstorage:ender_drawer")
|
||||||
|
assert(turtle.placeDown())
|
||||||
|
assert(turtle.suckDown())
|
||||||
|
assert(turtle.refuel())
|
||||||
|
self:dig("down")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:safeMove(dir)
|
||||||
|
if dir == "up" then
|
||||||
|
while turtle.detectUp() do
|
||||||
|
self:dig("up")
|
||||||
|
end
|
||||||
|
assert(turtle.up())
|
||||||
|
elseif dir == "forward" then
|
||||||
|
while turtle.detect() do
|
||||||
|
self:dig("forward")
|
||||||
|
end
|
||||||
|
assert(turtle.forward())
|
||||||
|
else
|
||||||
|
if turtle.detectDown() then
|
||||||
|
self:dig("down")
|
||||||
|
end
|
||||||
|
assert(turtle.down())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:doGPS(orientation)
|
||||||
|
local x, y, z = gps.locate()
|
||||||
|
assert(x)
|
||||||
|
self.absolutePos = vector.new(x, y, z)
|
||||||
|
|
||||||
|
if orientation then
|
||||||
|
assert(turtle.forward())
|
||||||
|
x, y, z = gps.locate()
|
||||||
|
assert(x)
|
||||||
|
self.dir = vector.new(x, y, z) - self.absolutePos
|
||||||
|
assert(turtle.back())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:findOres(radius)
|
||||||
|
self:equip("advancedperipherals:geo_scanner", "right")
|
||||||
|
local info, err = self.scanner.scan(radius)
|
||||||
|
assert(info, err)
|
||||||
|
|
||||||
|
local found = {}
|
||||||
|
for _, b in ipairs(info) do
|
||||||
|
-- only ores and avoid bedrock
|
||||||
|
if ORES[b.name] and self.absolutePos.y + b.y >= -58 then
|
||||||
|
table.insert(found, b)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return found
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:faceDir(newDir)
|
||||||
|
local deltaDir = direction(newDir) - direction(self.dir)
|
||||||
|
if deltaDir == 0.25 or deltaDir == -0.75 then
|
||||||
|
assert(turtle.turnRight())
|
||||||
|
self.dir = newDir
|
||||||
|
elseif deltaDir == -0.25 or deltaDir == 0.75 then
|
||||||
|
assert(turtle.turnLeft())
|
||||||
|
self.dir = newDir
|
||||||
|
elseif deltaDir == 0.5 or deltaDir == -0.5 then
|
||||||
|
assert(turtle.turnRight())
|
||||||
|
assert(turtle.turnRight())
|
||||||
|
self.dir = newDir
|
||||||
|
elseif deltaDir == 0 then
|
||||||
|
-- nothing to do :)
|
||||||
|
else
|
||||||
|
assert(false, "invalid delta dir "..deltaDir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:navigateThrough(path)
|
||||||
|
for _, p in ipairs(path) do
|
||||||
|
-- print("move from to", self.pos, p)
|
||||||
|
local delta = p - self.pos
|
||||||
|
assert(delta:length() ~= 0)
|
||||||
|
-- print("doing", delta)
|
||||||
|
if delta:length() ~= 1 then
|
||||||
|
-- print("path finding between points")
|
||||||
|
local path = findPath(self.pos, p)
|
||||||
|
table.remove(path, 1)
|
||||||
|
table.remove(path, #path)
|
||||||
|
assert(#path ~= 0)
|
||||||
|
|
||||||
|
self:navigateThrough(path)
|
||||||
|
delta = p - self.pos
|
||||||
|
end
|
||||||
|
assert(delta:length() == 1)
|
||||||
|
|
||||||
|
local moveDir = nil
|
||||||
|
if delta.y == 1 then
|
||||||
|
moveDir = "up"
|
||||||
|
elseif delta.y == -1 then
|
||||||
|
moveDir = "down"
|
||||||
|
else
|
||||||
|
self:faceDir(delta)
|
||||||
|
moveDir = "forward"
|
||||||
|
end
|
||||||
|
|
||||||
|
self:safeMove(moveDir)
|
||||||
|
self.pos = p
|
||||||
|
self.absolutePos = self.absolutePos + delta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Miner:mineOres(radius)
|
||||||
|
local startingDir = self.dir
|
||||||
|
self.pos = vector.new(0, 0, 0)
|
||||||
|
|
||||||
|
local ores = self:findOres(radius)
|
||||||
|
local orePoints = {}
|
||||||
|
for _, b in ipairs(ores) do
|
||||||
|
table.insert(orePoints, vector.new(b.x, b.y, b.z))
|
||||||
|
end
|
||||||
|
local veins = groupOres(ores, findDistances(orePoints))
|
||||||
|
print("Found "..#ores.." ores ("..#veins.." veins)")
|
||||||
|
|
||||||
|
local veinsPoints = {
|
||||||
|
self.pos,
|
||||||
|
self.dir * radius * 2,
|
||||||
|
}
|
||||||
|
for _, v in ipairs(veins) do
|
||||||
|
table.insert(veinsPoints, v.center)
|
||||||
|
end
|
||||||
|
|
||||||
|
local veinsPath = pathThrough(veinsPoints, findDistances(veinsPoints), 1, 2)
|
||||||
|
-- strip out end point
|
||||||
|
table.remove(veinsPath, #veinsPath)
|
||||||
|
|
||||||
|
local veinsSummary = {}
|
||||||
|
for _, i in ipairs(veinsPath) do
|
||||||
|
local v = veins[i - 2]
|
||||||
|
table.insert(veinsSummary, {
|
||||||
|
pos = self.absolutePos + v.center,
|
||||||
|
type = v.type,
|
||||||
|
count = #v.blocks,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
self:sendMessage("iterationStart", {
|
||||||
|
i = self.i,
|
||||||
|
oreCount = #ores,
|
||||||
|
veins = veinsSummary,
|
||||||
|
})
|
||||||
|
|
||||||
|
for pi, i in ipairs(veinsPath) do
|
||||||
|
self:xchgItems()
|
||||||
|
|
||||||
|
local vein = veins[i - 2]
|
||||||
|
local closest = nil
|
||||||
|
local cDist = math.huge
|
||||||
|
for _, b in ipairs(vein.blocks) do
|
||||||
|
local d = (b - self.pos):length()
|
||||||
|
if d < cDist then
|
||||||
|
closest = b
|
||||||
|
cDist = d
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(closest)
|
||||||
|
|
||||||
|
local pathToStart = findPath(self.pos, closest)
|
||||||
|
table.remove(pathToStart, 1)
|
||||||
|
table.remove(pathToStart, #pathToStart)
|
||||||
|
|
||||||
|
print("Moving to vein of " .. #vein.blocks .. " " .. vein.type .. " " .. cDist .. " blocks away starting at", closest)
|
||||||
|
self:navigateThrough(pathToStart)
|
||||||
|
|
||||||
|
local veinPoints = {self.pos}
|
||||||
|
for _, b in ipairs(vein.blocks) do
|
||||||
|
table.insert(veinPoints, b)
|
||||||
|
end
|
||||||
|
|
||||||
|
local veinPathI = pathThrough(veinPoints, findDistances(veinPoints), 1)
|
||||||
|
local veinPath = {}
|
||||||
|
for _, i in ipairs(veinPathI) do
|
||||||
|
table.insert(veinPath, veinPoints[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Digging through vein (" .. #vein.blocks .. " blocks)")
|
||||||
|
self:sendMessage("veinStart", {
|
||||||
|
i = pi,
|
||||||
|
total = #veins,
|
||||||
|
oreType = vein.type,
|
||||||
|
oreCount = #vein.blocks,
|
||||||
|
})
|
||||||
|
self:navigateThrough(veinPath)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:navigateThrough({veinsPoints[2]})
|
||||||
|
self:faceDir(startingDir)
|
||||||
|
self.i = self.i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local miner = Miner.new()
|
||||||
|
while true do
|
||||||
|
miner:mineOres(16)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- test code, please ignore
|
||||||
|
assert(false)
|
||||||
|
|
||||||
|
-- local f, err = fs.open("points.csv", "w")
|
||||||
|
-- assert(f, err)
|
||||||
|
|
||||||
|
local points = {
|
||||||
|
vector.new(0, 0, 0),
|
||||||
|
vector.new(0, 0, -16),
|
||||||
|
}
|
||||||
|
for _, b in ipairs(ores) do
|
||||||
|
-- print("found " .. b.name .. " at " .. b.x .. ", " .. b.y .. ", " .. b.z)
|
||||||
|
table.insert(points, vector.new(b.x, b.y, b.z))
|
||||||
|
end
|
||||||
|
print("found "..#ores.." ores")
|
||||||
|
|
||||||
|
local dist = findDistances(points)
|
||||||
|
local groups = groupOres(ores, dist, 2)
|
||||||
|
|
||||||
|
for _, g in ipairs(groups) do
|
||||||
|
print("group of "..#g.blocks.." "..g.type.." at", g.center)
|
||||||
|
end
|
||||||
|
print(#groups, "groups of ore found")
|
||||||
|
|
||||||
|
local gPoints = {
|
||||||
|
vector.new(0, 0, 0),
|
||||||
|
vector.new(0, 0, -16),
|
||||||
|
}
|
||||||
|
for _, g in ipairs(groups) do
|
||||||
|
table.insert(gPoints, g.center)
|
||||||
|
end
|
||||||
|
|
||||||
|
local gDist = findDistances(gPoints)
|
||||||
|
local gPath = pathThrough(gPoints, gDist, 1, 2)
|
||||||
|
for _, i in ipairs(gPath) do
|
||||||
|
local p = gPoints[i]
|
||||||
|
f.write(p.x..","..p.y..","..p.z.."\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
f.write("MARK\n")
|
||||||
|
|
||||||
|
-- print(points[1], gPoints[gPath[1]])
|
||||||
|
-- local pathTo = findPath(points[1], gPoints[gPath[1]])
|
||||||
|
-- for _, p in ipairs(pathTo) do
|
||||||
|
-- -- local p = pathTo[i]
|
||||||
|
-- -- print(p)
|
||||||
|
-- f.write(p.x..","..p.y..","..p.z.."\n")
|
||||||
|
-- end
|
||||||
|
|
||||||
|
miner:mineOres(groups)
|
||||||
|
|
||||||
|
-- table.remove(pathTo, 1)
|
||||||
|
-- table.remove(pathTo, #pathTo)
|
||||||
|
-- miner:navigateThrough(pathTo)
|
||||||
|
|
||||||
|
-- f.write("MARK\n")
|
||||||
|
|
||||||
|
-- local allPath = pathThrough(points, dist, 1, 2)
|
||||||
|
-- for _, i in ipairs(allPath) do
|
||||||
|
-- local p = points[i]
|
||||||
|
-- -- print(points[i])
|
||||||
|
-- f.write(p.x..","..p.y..","..p.z.."\n")
|
||||||
|
-- end
|
||||||
|
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
-- local f = vector.new(1, 0, 0)
|
||||||
|
-- local p = vector.new(0, -1, 7)
|
||||||
|
-- local t = vector.new(-1, -1, 7)
|
||||||
|
|
||||||
|
-- print(direction(t - p) - direction(f))
|
185
mineMonitor.lua
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
local CHANNEL = 1337
|
||||||
|
local TARGET = "devplayer0"
|
||||||
|
local ICON_BASE = "https://p.nul.ie/cc/icon/"
|
||||||
|
local ORE_ICONS = {
|
||||||
|
["minecraft:coal_ore"] = "coal",
|
||||||
|
["minecraft:deepslate_coal_ore"] = "ds-coal",
|
||||||
|
["minecraft:iron_ore"] = "iron",
|
||||||
|
["minecraft:deepslate_iron_ore"] = "ds-iron",
|
||||||
|
["minecraft:copper_ore"] = "copper",
|
||||||
|
["minecraft:deepslate_copper_ore"] = "ds-copper",
|
||||||
|
["minecraft:gold_ore"] = "gold",
|
||||||
|
["minecraft:deepslate_gold_ore"] = "ds-gold",
|
||||||
|
["minecraft:redstone_ore"] = "redstone",
|
||||||
|
["minecraft:deepslate_redstone_ore"] = "ds-redstone",
|
||||||
|
["minecraft:emerald_ore"] = "emerald",
|
||||||
|
["minecraft:deepslate_emerald_ore"] = "ds-emerald",
|
||||||
|
["minecraft:lapis_ore"] = "lapis",
|
||||||
|
["minecraft:deepslate_lapis_ore"] = "ds-lapis",
|
||||||
|
["minecraft:diamond_ore"] = "diamond",
|
||||||
|
["minecraft:deepslate_diamond_ore"] = "ds-diamond",
|
||||||
|
|
||||||
|
-- ["create:ochrum"] =,
|
||||||
|
-- ["create:zinc_ore"] =,
|
||||||
|
-- ["create:deepslate_zinc_ore"] =,
|
||||||
|
-- ["create_new_age:thorium_ore"] =,
|
||||||
|
|
||||||
|
-- ["powah:deepslate_uraninite_ore_poor"] =,
|
||||||
|
-- ["powah:deepslate_uraninite_ore"] =,
|
||||||
|
-- ["powah:deepslate_uraninite_ore_dense"] =,
|
||||||
|
-- ["powah:uraninite_ore_poor"] =,
|
||||||
|
-- ["powah:uraninite_ore"] =,
|
||||||
|
-- ["powah:uraninite_ore_dense"] =,
|
||||||
|
}
|
||||||
|
|
||||||
|
function oreIcon(t)
|
||||||
|
local i = "generic"
|
||||||
|
if ORE_ICONS[t] then
|
||||||
|
i = ORE_ICONS[t]
|
||||||
|
end
|
||||||
|
|
||||||
|
return ICON_BASE .. "ore-" .. i .. ".png"
|
||||||
|
end
|
||||||
|
|
||||||
|
local modem = peripheral.find("modem")
|
||||||
|
-- local monitor = peripheral.find("monitor")
|
||||||
|
local chat = peripheral.find("chatBox")
|
||||||
|
local cartographer = peripheral.find("cartographer")
|
||||||
|
|
||||||
|
function vecToStr(v)
|
||||||
|
return v.x .. "," .. v.y .. "," .. v.z
|
||||||
|
end
|
||||||
|
|
||||||
|
function markerSet(msg)
|
||||||
|
return "autominer_" .. msg.name
|
||||||
|
end
|
||||||
|
|
||||||
|
function setPosMarker(msg)
|
||||||
|
local id = markerSet(msg)
|
||||||
|
local mId = id .. "_pos"
|
||||||
|
cartographer.removeMarker(id, mId)
|
||||||
|
cartographer.addPOIMarker(
|
||||||
|
id, mId, msg.name, msg.name .. "'s position",
|
||||||
|
msg.pos.x, msg.pos.y, msg.pos.z,
|
||||||
|
ICON_BASE .. "turtle.png")
|
||||||
|
end
|
||||||
|
|
||||||
|
function handleStart(msg)
|
||||||
|
local cMsg = {
|
||||||
|
{text = msg.name, color = "green"},
|
||||||
|
{text = " @ ", color = "white"},
|
||||||
|
{text = vecToStr(msg.pos), color = "aqua"},
|
||||||
|
{text = " found ", color = "white"},
|
||||||
|
{text = tostring(msg.oreCount), color = "red"},
|
||||||
|
{text = " ores (", color = "white"},
|
||||||
|
{text = tostring(#msg.veins), color = "red"},
|
||||||
|
{text = " veins) on iteration ", color = "white"},
|
||||||
|
{text = tostring(msg.i), color = "green"},
|
||||||
|
{text = "!", color = "white"},
|
||||||
|
}
|
||||||
|
local msgJSON = textutils.serializeJSON(cMsg)
|
||||||
|
chat.sendFormattedMessage(msgJSON, "AutoMine")
|
||||||
|
|
||||||
|
local id = markerSet(msg)
|
||||||
|
cartographer.addMarkerSet(id, "AutoMiner " .. msg.name)
|
||||||
|
cartographer.clearMarkerSet(id)
|
||||||
|
|
||||||
|
setPosMarker(msg)
|
||||||
|
|
||||||
|
local orePoints = {}
|
||||||
|
for i, v in ipairs(msg.veins) do
|
||||||
|
table.insert(orePoints, v.pos)
|
||||||
|
cartographer.addPOIMarker(
|
||||||
|
id, id .. "_vein_" .. i, v.count .. " " .. v.type, "Vein of " .. v.count .. " " .. v.type,
|
||||||
|
v.pos.x, v.pos.y, v.pos.z,
|
||||||
|
oreIcon(v.type))
|
||||||
|
end
|
||||||
|
|
||||||
|
cartographer.addLineMarker(
|
||||||
|
id, id .. "_vein_path", "Mining path #" .. msg.i, "Current mining path",
|
||||||
|
"#FF00FF", 0.7, 3,
|
||||||
|
orePoints)
|
||||||
|
end
|
||||||
|
|
||||||
|
function handleVein(msg)
|
||||||
|
local cMsg = {
|
||||||
|
{text = msg.name, color = "green"},
|
||||||
|
{text = " @ ", color = "white"},
|
||||||
|
{text = vecToStr(msg.pos), color = "aqua"},
|
||||||
|
{text = " is mining ", color = "white"},
|
||||||
|
{text = tostring(msg.oreCount), color = "red"},
|
||||||
|
{text = " ", color = "white"},
|
||||||
|
{text = msg.oreType, color = "dark_purple"},
|
||||||
|
{text = " (vein ", color = "white"},
|
||||||
|
{text = tostring(msg.i), color = "red"},
|
||||||
|
{text = " / ", color = "white"},
|
||||||
|
{text = tostring(msg.total), color = "red"},
|
||||||
|
{text = ")!", color = "white"},
|
||||||
|
}
|
||||||
|
local msgJSON = textutils.serializeJSON(cMsg)
|
||||||
|
chat.sendFormattedMessageToPlayer(msgJSON, TARGET, "AutoMine")
|
||||||
|
|
||||||
|
local id = markerSet(msg)
|
||||||
|
setPosMarker(msg)
|
||||||
|
if msg.i ~= 1 then
|
||||||
|
cartographer.removeMarker(id, id .. "_vein_" .. (msg.i - 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cartographer.refreshIntegrations()
|
||||||
|
|
||||||
|
modem.open(CHANNEL)
|
||||||
|
|
||||||
|
-- handleStart({
|
||||||
|
-- i = 69,
|
||||||
|
-- oreCount = 1337,
|
||||||
|
-- veins = {
|
||||||
|
-- {
|
||||||
|
-- pos = {x = 297, y = 124, z = 1935},
|
||||||
|
-- type = "minecraft:coal_ore",
|
||||||
|
-- count = 12,
|
||||||
|
-- },
|
||||||
|
-- {
|
||||||
|
-- pos = {x = 297, y = 134, z = 1935},
|
||||||
|
-- type = "minecraft:iron_ore",
|
||||||
|
-- count = 7,
|
||||||
|
-- },
|
||||||
|
-- {
|
||||||
|
-- pos = {x = 400, y = 134, z = 1935},
|
||||||
|
-- type = "minecraft:diamond_ore",
|
||||||
|
-- count = 2,
|
||||||
|
-- },
|
||||||
|
-- {
|
||||||
|
-- pos = {x = 400, y = 134, z = 1975},
|
||||||
|
-- type = "minecraft:sussy_ore",
|
||||||
|
-- count = 7,
|
||||||
|
-- }
|
||||||
|
-- },
|
||||||
|
-- name = "test",
|
||||||
|
-- pos = {x = 297, y = 154, z = 1935},
|
||||||
|
-- })
|
||||||
|
-- handleVein({
|
||||||
|
-- i = 2,
|
||||||
|
-- total = 69,
|
||||||
|
-- oreCount = 1337,
|
||||||
|
-- oreType = "minecraft:yeet",
|
||||||
|
-- name = "test",
|
||||||
|
-- pos = {x = 1, y = 2, z = 3},
|
||||||
|
-- })
|
||||||
|
-- assert(false)
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local event, side, channel, replyChannel, msg, distance = os.pullEvent("modem_message")
|
||||||
|
if channel == CHANNEL then
|
||||||
|
if msg.type == "iterationStart" then
|
||||||
|
handleStart(msg)
|
||||||
|
-- sendChat(msg.name.." found "..msg.oreCount.." ores ("..msg.veinCount.." veins)")
|
||||||
|
-- for _, v in ipairs(msg.path) do
|
||||||
|
-- print("vein path "..v.x..", "..v.y..", "..v.z)
|
||||||
|
-- end
|
||||||
|
elseif msg.type == "veinStart" then
|
||||||
|
handleVein(msg)
|
||||||
|
-- sendChat(msg.name.." is mining "..msg.count.." "..msg.oreType.." (vein "..msg.i..") @ "..msg.pos.x..", "..msg.pos.y..", "..msg.pos.z)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
134
tree.lua
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
local dirt = "minecraft:dirt"
|
||||||
|
local sapling = "minecraft:oak_sapling"
|
||||||
|
local meal = "minecraft:bone_meal"
|
||||||
|
local log = "minecraft:oak_log"
|
||||||
|
local apple = "minecraft:apple"
|
||||||
|
local stick = "minecraft:stick"
|
||||||
|
local items = {
|
||||||
|
sapling, meal, log, apple, stick
|
||||||
|
}
|
||||||
|
|
||||||
|
local mealCount = 16
|
||||||
|
|
||||||
|
function selectItem(item)
|
||||||
|
for i = 1, 16 do
|
||||||
|
info = turtle.getItemDetail(i)
|
||||||
|
if info and info.name == item then
|
||||||
|
turtle.select(i)
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Farmer = {}
|
||||||
|
function Farmer:new(invName)
|
||||||
|
local t = setmetatable({}, { __index = Farmer })
|
||||||
|
t.invName = invName
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
function Farmer:connectInv()
|
||||||
|
local m = peripheral.find("modem")
|
||||||
|
self.mName= m.getNameLocal()
|
||||||
|
self.inv = peripheral.wrap(self.invName)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Farmer:unload(item)
|
||||||
|
for i = 1, 16 do
|
||||||
|
info = turtle.getItemDetail(i)
|
||||||
|
if info and info.name == item then
|
||||||
|
-- print(item, self.mName, i)
|
||||||
|
self.inv.pullItems(self.mName, i)
|
||||||
|
sleep(0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Farmer:yoink(item, count)
|
||||||
|
for i, info in pairs(self.inv.list()) do
|
||||||
|
if info.name == item then
|
||||||
|
if info.count >= count then
|
||||||
|
self.inv.pushItems(self.mName, i, count)
|
||||||
|
sleep(0.5)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Farmer:farmTree(noMeal)
|
||||||
|
assert(turtle.turnRight())
|
||||||
|
assert(turtle.turnRight())
|
||||||
|
assert(turtle.forward())
|
||||||
|
assert(turtle.forward())
|
||||||
|
assert(turtle.down())
|
||||||
|
|
||||||
|
assert(selectItem(dirt))
|
||||||
|
assert(turtle.place())
|
||||||
|
assert(turtle.up())
|
||||||
|
assert(selectItem(sapling))
|
||||||
|
assert(turtle.place())
|
||||||
|
|
||||||
|
if noMeal then
|
||||||
|
while true do
|
||||||
|
local present, info = turtle.inspect()
|
||||||
|
assert(present)
|
||||||
|
if info.name == log then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
sleep(20)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
assert(selectItem(meal))
|
||||||
|
local grown = false
|
||||||
|
for i = 1, mealCount do
|
||||||
|
turtle.place()
|
||||||
|
sleep(1)
|
||||||
|
local present, info = turtle.inspect()
|
||||||
|
assert(present)
|
||||||
|
if info.name == log then
|
||||||
|
grown = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not grown then
|
||||||
|
assert(false, "failed to grow tree")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
turtle.select(1)
|
||||||
|
assert(turtle.dig())
|
||||||
|
assert(turtle.down())
|
||||||
|
assert(turtle.dig())
|
||||||
|
assert(turtle.up())
|
||||||
|
sleep(5)
|
||||||
|
assert(turtle.down())
|
||||||
|
for i = 1, 8 do
|
||||||
|
sleep(0.5)
|
||||||
|
turtle.suck()
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(turtle.up())
|
||||||
|
assert(turtle.turnRight())
|
||||||
|
assert(turtle.turnRight())
|
||||||
|
assert(turtle.forward())
|
||||||
|
assert(turtle.forward())
|
||||||
|
sleep(0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Farmer:xchgItems()
|
||||||
|
self:connectInv()
|
||||||
|
for _, i in pairs(items) do
|
||||||
|
self:unload(i)
|
||||||
|
end
|
||||||
|
assert(self:yoink(sapling, 1))
|
||||||
|
return self:yoink(meal, mealCount)
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = Farmer:new("ae2:interface_0")
|
||||||
|
while true do
|
||||||
|
local noMeal = not f:xchgItems()
|
||||||
|
f:farmTree(noMeal)
|
||||||
|
end
|