· 4 years ago · Mar 21, 2021, 05:08 PM
1
2-- Mysplit borrowed kindly from the interwebs
3
4function mysplit (inputstr, sep)
5 if sep == nil then
6 sep = "%s"
7 end
8 local t={}
9 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
10 table.insert(t, str)
11 end
12 return t
13end
14
15
16-- Remove trailing and prefixing whitespaces
17function tail(string)
18 return string.sub(2)
19end
20
21function head(string)
22 return string.sub(1, -1)
23end
24
25function removeTW(string)
26 if string.sub(1, 1) == " " then
27 return removeTW(tail(string))
28 elseif string.sub(-1, -1) == " " then
29 return removeTW(head(string))
30 else
31 return string
32 end
33end
34
35-- Should return a dictionary:
36-- Origin co-ordinates
37-- Chest co-ordinates
38
39
40function ParseConfiguration()
41 local tableT = {}
42
43
44 local fileHandler = io.open("./Configuration.config", 'r')
45
46 local data = fileHandler:read("*all")
47
48 local data_array = mysplit(data, "\n")
49
50 for i,item in ipairs(data_array) do
51 if item.sub(1, 2) ~= "//" then
52 local seperation = mysplit(item, ":")
53
54 seperation[1] = removeTW(seperation[1])
55 seperation[2] = removeTW(seperation[2])
56
57 local coordinates = mysplit(seperation[2], ',')
58 coordinates[1] = tonumber(removeTW(coordinates[1]))
59 coordinates[2] = tonumber(removeTW(coordinates[2]))
60 coordinates[3] = tonumber(removeTW(coordinates[3]))
61
62 tableT[seperation[1]] = coordinates
63 end
64 end
65
66 return tableT
67end
68
69
70function taxicabDistance(vecA, vecB)
71 return math.abs((vecB[1] - vecA[1]) + (vecB[2] - vecA[2]) + (vecB[3] - vecA[3]))
72end
73
74-- -------------------------- Meta Class for Turtle ------------------------- --
75-- I can get away with defining it as 'Turtle' due to the fact that the turtle
76-- API is lowercase
77-- -------------------------------------------------------------------------- --
78
79Turtle = {
80 origin = {0, 0, 0}, -- To be constant
81 savedPositionBuffer = {}, -- To be a dictionary. Key = Tag, Value = Position Coords
82 state = {},
83 selectedSlot = 1
84}
85
86-- --------------------------- Turtle Constructor --------------------------- --
87-- Some key ideas:
88-- In this quarry system, there should exist a chest where items are to be dropped
89-- once the turtle is full. We need the co-ordinates of this chest before we begin.
90--
91-- We also need our own co-ordinates.
92--
93-- We also need the co-ordinates of our desired rest position.
94-- -------------------------------------------------------------------------- --
95
96function Turtle:new()
97 o = {}
98
99 setmetatable(o, self)
100 self.__index = self
101 self.savedPositionBuffer = ParseConfiguration()
102
103 self.state["Orientation"] = 0
104 self.state["Stuck"] = false
105 self.state["Current Position"] = self.savedPositionBuffer["Start Position"]
106 self.state["Blocks to move"] = turtle.getFuelLevel()
107 self.savedPositionBuffer["oldPos"] = {}
108 return o
109end
110
111
112-- ----------- Some data on directions and alterations to position ---------- --
113
114directionalLookupTable = {
115 [0] = {0, 1},
116 [1] = {-1, 0},
117 [2] = {0, -1},
118 [3] = {1, 0},
119}
120
121
122
123-- -------------------------------- Movement! ------------------------------- --
124
125function Turtle:attemptPathFix(direction)
126 local actions = {}
127 actions["forward"] = {turtle.attack, turtle.dig, turtle.forward}
128 actions["up"] = {turtle.attackUp, turtle.digUp, turtle.up}
129 actions["down"] = {turtle.attackDown, turtle.digDown, turtle.down}
130 actions["back"] = {turtle.attackBack, turtle.digBack, turtle.back}
131
132
133
134 local incidentCounter = 0
135
136 while incidentCounter < 50 do
137 local result = false
138
139 for i,action in ipairs(actions) do
140 result = action[direction]()
141 end
142
143 if not result then
144 incidentCounter = incidentCounter + 1
145 else
146 return
147 end
148 end
149
150 self:Goto(self.savedPositionBuffer["Start Position"])
151 self:Halt("Error 1: Persistent impediment detected in quarry. Returned to home and awaiting instructions.", true)
152end
153
154function Turtle:forward()
155 local result = turtle.forward()
156 if not result then
157 self:attemptPathFix("forward")
158 turtle.forward()
159 end
160
161
162 -- Alter current position dependent on direction
163 self.state["Current Position"][1] = self.state["Current Position"][1] + directionalLookupTable[self.state["Orientation"]][1]
164 self.state["Current Position"][2] = self.state["Current Position"][2] + directionalLookupTable[self.state["Orientation"]][2]
165
166 self.state["Blocks to move"] = self.state["Blocks to move"] - 1
167end
168
169function Turtle:backward()
170 local result = turtle.back()
171
172 if not result then
173 self:attemptPathFix("back")
174 end
175
176 self.state["Current Position"][1] = self.state["Current Position"][1] - directionalLookupTable[self.state["Orientation"]][1]
177 self.state["Current Position"][2] = self.state["Current Position"][2] - directionalLookupTable[self.state["Orientation"]][2]
178
179 self.state["Blocks to move"] = self.state["Blocks to move"] - 1
180
181end
182
183function Turtle:left()
184 local result = turtle.turnLeft()
185 self.state["Orientation"] = (self.state["Orientation"] + 1) % 4
186end
187
188function Turtle:right()
189 local result = turtle.turnRight()
190
191 self.state["Orientation"] = (self.state["Orientation"] - 1) % 4
192end
193
194function Turtle:up()
195 local result = turtle.up()
196 if not result then
197 self:attemptPathFix("up")
198 end
199
200 self.state["Current Position"][3] = self.state["Currnet Position"][3] + 1
201 self.state["Blocks to move"] = self.state["Blocks to move"] - 1
202
203end
204
205function Turtle:down()
206 local result = turtle.down()
207
208 if not result then
209 self:attemptPathFix("down")
210 end
211
212 self.state["Current Position"][3] = self.state["Current Position"][3] - 1
213 self.state["Blocks to move"] = self.state["Blocks to move"] - 1
214end
215
216function Turtle:dig()
217 turtle.dig()
218end
219
220function Turtle:Orient(direction)
221 while (self.state["Orientation"] ~= direction) do
222 self:left()
223 end
224end
225
226function Turtle:Goto(position, order)
227 order = order or {1, 2, 3}
228 if position[1] == self.state["Current Position"][1] and position[2] == self.state["Current Position"][2] and position[3] == self.state["Current Position"][3] then
229 return
230 end
231
232 for i, item in ipairs(order) do
233 if item == 1 or item == 2 then
234 if self.state["Current Position"][item] < position[item] then
235 self:Orient(item - 1)
236 print("Oriented: "..item-1)
237 for i = 1, position[item] - self.state["Current Position"][item] do
238 self:forward()
239 end
240 else
241 self:Orient(item + 1)
242
243 for i = 1, self.state["Current Position"][item] - position[item] do
244 self:forward()
245 end
246 end
247
248
249 else
250 if self.state["Current Position"][item] < position[item] then
251 for i = 1, position[item] - self.state["Current Position"][item] do
252 self:up()
253 end
254 else
255 for i = 1, self.state["Current Position"][item] - position[item] do
256 self:down()
257 end
258 end
259 end
260 end
261end
262
263function Turtle:CheckNeedToReturn()
264 local d = self.state["Orientation"]
265
266 turtle.refuel()
267
268 self.state["Blocks to move"] = turtle.getFuelLevel()
269 if taxicabDistance(self.state["Current Position"], self.savedPositionBuffer["Refuel Chest Position"]) >= self.state["Blocks to move"] then
270 self.state["Save"] = self.state["Current Position"]
271 self:Goto(self.savedPositionBuffer["Refuel Chest Position"], {3, 1, 2})
272
273 turtle.select(1)
274 turtle.suck()
275 turtle.refuel()
276
277 if turtle.getFuelLevel() < 500 then
278 self:Halt("Error 2: Fuel levels are low (<500) even after local and global refuel attempt. Please add fuel into slot 1 and continue.", true)
279
280 end
281
282 self:Goto(self.savedPositionBuffer["Save"], {1, 2, 3})
283 self:Orient(d)
284
285 end
286
287end
288
289function Turtle:CheckNeedToDeposit()
290 local d = self.state["Orientation"]
291
292 local counter = 0
293
294 while turtle.getItemCount(self.selectedSlot) > 0 do
295 self.selectedSlot = (self.selectedSlot%16)+1
296
297
298 counter = counter + 1
299
300 if (counter == 16) then
301 self.state["Save"] = self.state["Current Position"]
302 print("we here?")
303 self:Goto(self.savedPositionBuffer["Item Chest Position"], {3, 2, 1})
304
305
306 counter = 0
307 while turtle.getItemCount(self.selectedSlot) > 0 do
308 self.selectedSlot = (self.selectedSlot%16)+1
309
310 if self.selectedSlot ~= 1 then
311 turtle.drop(self.selectedSlot)
312 end
313
314 counter = counter + 1
315
316 if (counter == 16) then
317 return
318 end
319 end
320
321 self:Goto(self.savedPositionBuffer["Save"], {1, 2, 3})
322 self:Orient(d)
323 return
324
325 end
326 end
327
328
329end
330
331function Turtle:chunk()
332
333 local x = 3
334 local y = 3
335
336
337 for z = 1, self.savedPositionBuffer["Start Position"][3] - 2 do
338 self:CheckNeedToReturn()
339 turtle.digDown()
340 self:down()
341 self:Orient(0)
342 self.savedPositionBuffer["oldPos"][1] = self.state["Current Position"][1]
343 self.savedPositionBuffer["oldPos"][2] = self.state["Current Position"][2]
344 self.savedPositionBuffer["oldPos"][3] = self.state["Current Position"][3]
345
346 for i = 1, x do
347 for j = 2, y do
348 self:CheckNeedToReturn()
349 self:CheckNeedToDeposit()
350
351
352
353 self:dig()
354 self:forward()
355 end
356
357 if self.state["Orientation"] == 0 then
358
359 self:right()
360 self:dig()
361
362 self:CheckNeedToReturn()
363 self:CheckNeedToDeposit()
364
365
366
367 self:forward()
368
369
370 self:right()
371 else
372 self:left()
373 self:dig()
374
375 self:CheckNeedToReturn()
376 self:CheckNeedToDeposit()
377
378
379 self:forward()
380
381
382 self:left()
383 end
384
385 end
386 print(self.savedPositionBuffer["oldPos"][1])
387 print(self.state["Current Position"][1])
388 self:Goto(self.savedPositionBuffer["oldPos"], {1, 2, 3})
389
390
391 end
392
393 self:Goto(self.savedPositionBuffer["Item Chest Position"], {3, 2, 1})
394 self:Halt("[Log] The turtle has finished operations.")
395end
396
397function Turtle:Halt(message, isError)
398 print("Halted. Given message: "..message)
399
400 if isError then
401 print("You are advised to correct the current error")
402 print("or refer to Mila if you are unsure on what to do.")
403 print("Once you have corrected the error, please press enter.")
404 else
405 print("The system determines that this is not an error. Instead, it is")
406 print("likely a log that requires your attention. Please act on the message")
407 print("or refer to Mila if you are unsure on what to do.")
408
409 end
410 io.read()
411end
412
413t = Turtle:new()
414t:chunk()