Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --By xXxMoNkEyMaNxXx
- local type,next=type,next
- local tonumber,tostring=tonumber,tostring
- local concat=table.concat
- local remove=table.remove
- local abs=math.abs
- local floor=math.floor
- local rand=math.random
- local tick=os.clock
- math.randomseed(os.time())
- math.random()
- local arg={...}
- if peripheral then
- for _,side in next,{"left","right","front","back","bottom","top"} do
- if peripheral.getType(side)=="modem" then
- rednet.open(side)
- end
- end
- end
- local nans={tostring(1/0),tostring(-1/0),tostring(-(0/0)),tostring(0/0)}
- local function isnan(x)
- local s=tostring(x)
- for i,v in next,nans do
- if s==v then
- return i
- end
- end
- end
- local function nonenan(t)
- for i=1,#t do
- if isnan(t[i]) then
- return false,i
- end
- end
- return true
- end
- local function GPS(e0,e1,e2,e3,e4)
- local x0,y0,z0,t0=e0[1],e0[2],e0[3],e0[4]
- local x1,y1,z1,t1=e1[1],e1[2],e1[3],e1[4]
- local x2,y2,z2,t2=e2[1],e2[2],e2[3],e2[4]
- local x3,y3,z3,t3=e3[1],e3[2],e3[3],e3[4]
- local x4,y4,z4,t4=e4[1],e4[2],e4[3],e4[4]
- --I left brackets in some because it's easier to see the grouping
- local s1=x1-x0
- local s3=y1-y0
- local s7=z1-z0
- local s10=t1-t0
- local s2=(x2-x0)/s1
- local s5=(x3-x0)/s1
- local s9=(x4-x0)/s1
- local s6=(y2-y0)-s2*s3
- local s13=(z2-z0)-s2*s7
- local s16=(t2-t0)-s2*s10
- local s11=((y3-y0)-s5*s3)/s6
- local s17=((z3-z0)-s5*s7)-s11*s13
- local s21=((t3-t0)-s5*s10)-s11*s16
- local s15=((y4-y0)-s9*s3)/s6
- local s20=(((z4-z0)-s9*s7)-s15*s13)/s17
- local s4=x0^2+y0^2+z0^2-t0^2
- local s12=((x1^2+y1^2+z1^2-t1^2)-s4)/2
- local s14=((x2^2+y2^2+z2^2-t2^2)-s4)/2-s2*s12
- local s19=((x3^2+y3^2+z3^2-t3^2)-s4)/2-s5*s12-s11*s14
- --Calculators weren't good enough for this! I solved it by hand ;D
- local t=-(((x4^2+y4^2+z4^2-t4^2)-s4)/2-s9*s12-s15*s14-s20*s19)/((((t4-t0)-s9*s10)-s15*s16)-s20*s21)
- local z=(s21*t+s19)/s17
- local y=(s16*t-s13*z+s14)/s6
- local x=(s10*t-s3*y-s7*z+s12)/s1
- return {floor(x+0.5),floor(y+0.5),floor(z+0.5),t}
- end
- local rec=rednet.receive
- local broadcast=rednet.broadcast
- local unserialize=textutils.unserialize
- local function receive(timeout)
- local id,msg,d=rec(timeout)
- local ret=msg and unserialize(msg) or {}
- ret.senderId=id
- ret.message=msg
- ret.distance=d
- return ret
- end
- local function locate(timeout,period)
- timeout=timeout or 10
- period=period or 1
- local t0=tick()
- broadcast("PING")
- local p={}
- local sat={}
- repeat
- local data=receive(period)
- if #data==4 then
- local e={}
- for i=1,4 do
- local v=data[i]
- if type(v)=="number" then
- e[i]=v
- else
- break
- end
- end
- if #e==4 then
- sat[#sat+1]=e
- end
- elseif #data==3 and type(data.distance)=="number" then
- local e={}
- for i=1,3 do
- local v=data[i]
- if type(v)=="number" then
- e[i]=v
- else
- break
- end
- end
- if #e==3 then
- e[4]=-data.distance
- sat[#sat+1]=e
- end
- else
- local jesus=true
- while #sat>=5 do
- local chosen={}
- for i=1,5 do
- chosen[i]=remove(sat,rand(#sat))
- end
- p=GPS(unpack(chosen))
- if #p==4 and nonenan(p) and abs(p[4])<0.001 then
- jesus=false
- break
- end
- end
- if jesus then
- print'Not enough hosts, needs more.'
- broadcast'PING'
- end
- end
- until #p==4 and nonenan(p) and abs(p[4])<0.001 or tick()-t0>timeout
- return p
- end
- local p
- if #arg==3 then
- local x,y,z=unpack(arg)
- if tonumber(x) and tonumber(y) and tonumber(z) then
- p={tonumber(x),tonumber(y),tonumber(z)}
- else
- error'Invalid coordinates'
- end
- elseif #arg==1 and type(arg[1])=="string" and arg[1]~="here" then
- local x,y,z=arg[1]:match'(.+),(.+),(.+)'
- if tonumber(x) and tonumber(y) and tonumber(z) then
- p={tonumber(x),tonumber(y),tonumber(z)}
- end
- else
- p=locate(1000,5)
- end
- local send=rednet.send
- local receive=rednet.receive
- local serialize=textutils.serialize
- if p and #p>=3 and nonenan(p) then
- print(concat(p,","))
- local n=0
- while true do
- local id,msg,d=receive()
- if msg=="PING" then
- send(id,serialize{p[1],p[2],p[3],-d})
- n=n+1
- if n>1 then
- local x,y=term.getCursorPos()
- term.setCursorPos(1,y-1)
- end
- print(n.." GPS request"..(n==1 and "" or "s").." served.")
- end
- end
- else
- error'Invalid/missing/indeterminate position.'
- end
Advertisement
Add Comment
Please, Sign In to add comment