SHOW:
|
|
- or go back to the newest paste.
1 | - | --[[ com.ape42.turtle.Farm |
1 | + | --[[ com.ape42.turtle.Farm 0.7.1 |
2 | For computercraft 1.63 | |
3 | Farms X rows, trying to alternate | |
4 | crops according to the reference | |
5 | - | slots, The first contiguous slots |
5 | + | slots, which are the first |
6 | - | that have seeds. If it doesn't |
6 | + | contiguous slots that have seeds. |
7 | - | have enough seed to alternate it |
7 | + | If it doesn't have enough seed to |
8 | - | will leave a gap. Sleeps, repeats. |
8 | + | alternate, it will leave a gap. |
9 | - | Note, the x.x.0 releases are |
9 | + | There are two globals constants - |
10 | - | untested and almost always defective. |
10 | + | to sleep GROW_WAIT minutes, and |
11 | repeat MAX_REPEATS or until out | |
12 | of fuel. | |
13 | - | Changes by version: |
13 | + | |
14 | ||
15 | Feature Changes by version: | |
16 | 0.1.0: Reaps one row. | |
17 | - | 0.2.1: Seed selection defect is |
17 | + | |
18 | - | corrected, so that you now get |
18 | + | |
19 | - | a whole row of a given plantable, |
19 | + | 0.2.1: You now get a whole row of |
20 | - | if there are enough seeds. |
20 | + | a given plantable,if there are |
21 | enough seeds. | |
22 | 0.2.2: Better stoppage for out-of | |
23 | - | 0.3.0: Sleeps and runs twice more |
23 | + | |
24 | - | 0.3.1: Fixes a return-stop bug |
24 | + | 0.3.1: Sleeps and runs twice more |
25 | - | 0.4.0: Tries to plant each row, |
25 | + | 0.4.1: Tries to plant each row, |
26 | alternating crops if possible | |
27 | - | 0.4.1: alternation algorithm is |
27 | + | |
28 | - | repaired. |
28 | + | |
29 | If there isn't enough for the | |
30 | next one it stops. | |
31 | 0.5.1: if it has to stop, it | |
32 | shouldn't bother to sleep, so now | |
33 | - | 0.5.1: if it has to stop, it |
33 | + | it doesn't. |
34 | - | shouldn't bother to sleep. |
34 | + | 0.6.1: No functional changes, but |
35 | - | 0.6.0: No functional changes, but |
35 | + | |
36 | 0.7.1: Improved fuel-use. Now at | |
37 | - | 0.6.1: Corrected the one-off errors. |
37 | + | the end of each row it sees if |
38 | there's enough fuel to do another | |
39 | row and make it back to base. If | |
40 | - | - Ensure that there's enough fuel to |
40 | + | not it goes back to the start |
41 | - | return from a given point, and use |
41 | + | right away. |
42 | - | it when needed. |
42 | + | Added auto-refueling: Slot 9. |
43 | - | - Given fuel and field size, estimate |
43 | + | |
44 | - | the number of harvests. |
44 | + | |
45 | - | - Allow use of blocks instead of row |
45 | + | - Estimate max field size plantable |
46 | for two harvests, given the fuel. | |
47 | - After run - Estimate how many more | |
48 | runs & rows it'll be able to do | |
49 | with current fuel level. | |
50 | - Change param meaning so that the | |
51 | result is N rows, N blocks long | |
52 | - Add melon/pumpkin slots, handling. | |
53 | - | - Estimate max field size plantable |
53 | + | - Give more explicit usage instructions |
54 | - Allow use of blockers instead of row | |
55 | parameter. | |
56 | - Allow the turtle to start at right | |
57 | corner, depending which way is | |
58 | open. | |
59 | - Create a routine for automated field | |
60 | creation, given flat grassy area, | |
61 | a bucket and a source of water. | |
62 | ||
63 | This work is licensed under the | |
64 | Creative Commons Attribution 4.0 | |
65 | International License. To view a copy | |
66 | - | -- The wait time between beginning of each harvest, in minutes. |
66 | + | |
67 | http://creativecommons.org/licenses/by/4.0/ | |
68 | or send a letter to Creative Commons, | |
69 | 444 Castro Street, Suite 900, Mountain | |
70 | View, California, 94041, USA. | |
71 | ]] | |
72 | ||
73 | -- The wait time between beginning of | |
74 | -- each harvest, in minutes. | |
75 | GROW_WAIT = 40 | |
76 | ||
77 | -- The number of times to farm the | |
78 | -- field, baring other constraints | |
79 | MAX_REPEATS = 3 | |
80 | ||
81 | -- Initial slots indicate what items | |
82 | -- the user deems plantable. | |
83 | local plntblCnt = 1 | |
84 | ||
85 | -- Initializes the Plantable Count. | |
86 | -- Called before any work is done, this | |
87 | -- finds the last populated inventory | |
88 | -- slot. That and the ones below | |
89 | -- will be used as reference. | |
90 | -- @return plntblCnt | |
91 | local function initPlntblCnt() | |
92 | local indx = 0 | |
93 | local isPlntbl = true | |
94 | while isPlntbl and indx < 16 do | |
95 | indx = indx + 1 | |
96 | turtle.select(indx) | |
97 | isPlntbl= turtle.getItemCount()> 0 | |
98 | end | |
99 | plntblCnt = indx - 1 | |
100 | return plntblCnt | |
101 | end | |
102 | ||
103 | -- For the non - reference slots, | |
104 | -- find one that matches the | |
105 | -- currently selected and match that. | |
106 | -- Or return false. | |
107 | local function selectNonRefSlot() | |
108 | ||
109 | local s = plntblCnt + 1 | |
110 | local seedy = false | |
111 | while s < 16 and seedy == false do | |
112 | seedy = turtle.compareTo( s ) | |
113 | if seedy then | |
114 | turtle.select(s) | |
115 | end | |
116 | - | local function sow( rowIndex, block, prevRow ) |
116 | + | |
117 | end --while | |
118 | return seedy | |
119 | end | |
120 | ||
121 | -- Decides what to plant based the | |
122 | -- reference slots (plntblCnt) | |
123 | -- @param rowIndex the current row | |
124 | -- @block block # within the row, | |
125 | -- starting with 1. | |
126 | -- @param prevRow an array of crop | |
127 | -- types for previous row | |
128 | local function sow( rowIndex, block, | |
129 | prevRow ) | |
130 | local seedy = false | |
131 | ||
132 | -- Alternate among the plantables: | |
133 | -- loop through reference slots. | |
134 | local i = 0 | |
135 | local refSlt = 0 | |
136 | while i < plntblCnt and seedy == false do | |
137 | --use what was for a given reference slot | |
138 | refSlt = ( (rowIndex + i )% plntblCnt) + 1 | |
139 | ||
140 | turtle.select(refSlt) | |
141 | if turtle.getItemCount(refSlt) > 1 then | |
142 | seedy = true | |
143 | else | |
144 | seedy = selectNonRefSlot() | |
145 | end | |
146 | i = i + 1 | |
147 | end | |
148 | ||
149 | if seedy then | |
150 | if prevRow[block]== refSlt then | |
151 | prevRow[block] = 0 | |
152 | else | |
153 | prevRow[block] = refSlt | |
154 | turtle.place() | |
155 | end -- if matches | |
156 | end -- if seedy | |
157 | ||
158 | return seedy | |
159 | end | |
160 | ||
161 | -- Harvests a row: Digs (hoes) and | |
162 | -- moves forward the length or until | |
163 | -- the way is blocked | |
164 | -- @param lth the expected length of | |
165 | -- the row or 0 if not yet determined | |
166 | -- @return how long the row was, or | |
167 | -- 0 if there was an unexpected stop | |
168 | -- due to fuel outage after first row. | |
169 | local function reapRow( lth ) | |
170 | print( "Reaping a row ") | |
171 | ||
172 | -- Loop until length is reached or | |
173 | -- the way is blocked | |
174 | local keepGoing = true | |
175 | local placeR = 1 | |
176 | ||
177 | -- lth 0 just means that really | |
178 | -- the length is not yet determined | |
179 | local firstRow = lth == 0 | |
180 | if firstRow then | |
181 | local fuel = turtle.getFuelLevel() | |
182 | lth = fuel/2 - 1 | |
183 | print(string.format("First row. " | |
184 | .."fuel %d, max length %d", | |
185 | fuel, lth)) | |
186 | end | |
187 | while keepGoing do | |
188 | ||
189 | turtle.dig() -- reaps | |
190 | keepGoing = turtle.forward() | |
191 | ||
192 | -- sees if it can keepGoing | |
193 | if keepGoing then | |
194 | placeR = placeR + 1 | |
195 | if placeR >= lth and lth > 0 then | |
196 | keepGoing = false | |
197 | end | |
198 | -- prevents infinite loop | |
199 | if placeR > 1023 then | |
200 | keepGoing = false | |
201 | end | |
202 | else | |
203 | if firstRow == false then | |
204 | print("Stopped unexpectedly") | |
205 | placeR = 0 | |
206 | print("placeR="..placeR) | |
207 | end | |
208 | end | |
209 | ||
210 | end -- while loop | |
211 | ||
212 | lth = placeR | |
213 | return lth | |
214 | end | |
215 | ||
216 | -- Backs up, tilling & planting | |
217 | -- @param lnth row length | |
218 | - | -- Harvests and plants every other row |
218 | + | |
219 | -- @param prevRow array of crop plantings | |
220 | - | -- @return found row length. If stopped |
220 | + | |
221 | - | -- unexpectedly this will be 0. |
221 | + | -- @return true if successful. False |
222 | -- means seeds or fuel ran out, or | |
223 | -- there was a blockage. | |
224 | local function sowRow(lnth, indx, prevRow) | |
225 | print( "Sowing a row." ) | |
226 | local block = 1 | |
227 | local seedy = true | |
228 | ||
229 | -- while it has length & seeds | |
230 | while block < lnth and seedy do | |
231 | ||
232 | seedy = turtle.back() | |
233 | turtle.dig() | |
234 | ||
235 | -- if there are still seeds | |
236 | if seedy then | |
237 | seedy = sow(indx, block, prevRow) | |
238 | - | while (rowIndex< rows) and isSeedy do |
238 | + | |
239 | print("sowRow(): seedy== false" ) | |
240 | end | |
241 | block = block + 1 | |
242 | end | |
243 | ||
244 | -- return if there's seeds still. | |
245 | return seedy | |
246 | - | -- Stop loop |
246 | + | |
247 | end | |
248 | ||
249 | - | -- After the first row |
249 | + | -- Determines whether there's enough |
250 | - | if isFirst == false then |
250 | + | -- fuel to: move to another row, |
251 | - | -- Move to the next row |
251 | + | -- reap it, sow it, and return to |
252 | - | turtle.turnRight() |
252 | + | -- base |
253 | - | turtle.forward() |
253 | + | -- @param rowIndex, rowLength |
254 | - | turtle.turnLeft() |
254 | + | local function isFuelOKForNextRow( |
255 | rowIndex, rowLength) | |
256 | - | rowLength = reapRow( rowLength ) |
256 | + | |
257 | - | if isFirst then |
257 | + | local fuelNeed = 1 + rowIndex |
258 | - | -- initializes previous array |
258 | + | + ( rowLength * 2 ) |
259 | - | for i = 1, rowLength do |
259 | + | |
260 | - | prevRow[i] = 0 |
260 | + | local fuelLevel = turtle.getFuelLevel() |
261 | - | end |
261 | + | |
262 | local isEnough= fuelLevel >= fuelNeed | |
263 | - | if rowLength > 0 then |
263 | + | if isEnough ~= true then |
264 | - | isSeedy=sowRow(rowLength, rowIndex, prevRow) |
264 | + | print("Not enough fuel for next " |
265 | - | -- if stopped, zero-out. |
265 | + | .."row and return trip.") |
266 | - | rowLength= isSeedy and rowLength or 0 |
266 | + | print( string.format( |
267 | "fuelNeed %d, rowIndex %d, " | |
268 | - | end --else |
268 | + | .."rowLength %d", fuelNeed, |
269 | rowIndex, rowLength ) ) | |
270 | ||
271 | - | end -- while |
271 | + | print( string.format( "fuelLevel %d", |
272 | - | return rowLength |
272 | + | fuelLevel ) ) |
273 | ||
274 | end | |
275 | ||
276 | return isEnough | |
277 | ||
278 | end | |
279 | ||
280 | -- Checks fuel, and if good, moves to | |
281 | - | for i= 1, forwards do |
281 | + | -- next row, reaps and sows. |
282 | -- @param rowLength, isFirst, prevRow, | |
283 | -- rowIndex. | |
284 | -- prevRow is array of ints, each | |
285 | -- a reference item slot, from, you | |
286 | -- guessed it: the previous row. | |
287 | -- @return isFuelOK, rowLength, isSeedy | |
288 | local function moveOnAndDoOne( rowLength, | |
289 | isFirst, prevRow, rowIndex ) | |
290 | ||
291 | local isFuelOK = true | |
292 | ||
293 | -- After the first row | |
294 | if isFirst == false then | |
295 | ||
296 | isFuelOK = isFuelOKForNextRow(rowIndex, | |
297 | rowLength) | |
298 | ||
299 | if isFuelOK then | |
300 | -- Move to the next row | |
301 | turtle.turnRight() | |
302 | turtle.forward() | |
303 | turtle.turnLeft() | |
304 | end | |
305 | ||
306 | end -- if after first | |
307 | ||
308 | local isSeedy = true | |
309 | if isFuelOK then | |
310 | rowLength= reapRow( rowLength ) | |
311 | if isFirst then | |
312 | -- initializes previous array | |
313 | for i = 1, rowLength do | |
314 | prevRow[i] = 0 | |
315 | end | |
316 | end | |
317 | ||
318 | if rowLength > 0 then | |
319 | isSeedy=sowRow( rowLength, rowIndex, prevRow) | |
320 | -- if stopped, zeroes-out. | |
321 | rowLength= isSeedy and rowLength or 0 | |
322 | end -- if rowLength | |
323 | ||
324 | end -- if fuel OK | |
325 | ||
326 | return isFuelOK, rowLength, isSeedy | |
327 | ||
328 | end | |
329 | ||
330 | -- Harvests and plants the rows | |
331 | -- @param rows number of plantable rows | |
332 | -- @return number of rows planted. | |
333 | -- If stopped unexpectedly this will | |
334 | -- be 0. | |
335 | local function reapAndSow( rows ) | |
336 | - | local fuelStart = turtle.getFuelLevel() |
336 | + | |
337 | - | while n<=3 and okSoFar do |
337 | + | |
338 | -- reference. | |
339 | - | local zeroStopped = reapAndSow( rowCntFromUsr ) |
339 | + | |
340 | - | if zeroStopped > 0 then |
340 | + | |
341 | - | okSoFar = returnAndStore(rowCntFromUsr) |
341 | + | |
342 | " slots \nare deemed plantable") | |
343 | ||
344 | local prevRow = {} | |
345 | - | print("after harvest: "..(n).." of 3") |
345 | + | |
346 | local rowLength = 0 | |
347 | - | local fuelPerTurn = (fuelStart-fuelLevel)/n |
347 | + | |
348 | local isSeedy = true | |
349 | - | if fuelLevel< fuelPerTurn and n < 3 then |
349 | + | local isFuelOK = true |
350 | - | print("not enough for another go") |
350 | + | |
351 | - | okSoFar = false |
351 | + | |
352 | while (rowIndex< rows) and isSeedy | |
353 | and isFuelOK do | |
354 | print( "rowIndex ".. rowIndex ) | |
355 | ||
356 | -- If there was an unexpected | |
357 | - | if (n < 3) and okSoFar then |
357 | + | |
358 | -- rowLength will be its initial | |
359 | -- value, 0 | |
360 | if rowLength<= 0 and isFirst== false then | |
361 | -- Stops loop | |
362 | isSeedy = false | |
363 | else | |
364 | ||
365 | - | end -- of three times loop |
365 | + | isFuelOK, rowLength, isSeedy = |
366 | moveOnAndDoOne(rowLength, | |
367 | isFirst, prevRow, | |
368 | - | print("Unplanned stop.") |
368 | + | rowIndex ) |
369 | ||
370 | print( string.format( | |
371 | "in farm(), after " | |
372 | .."moveOnAndDoOne( rowLength %d, " | |
373 | .."isFirst %s, rowIndex %d)", | |
374 | rowLength, tostring(isFirst), | |
375 | rowIndex ) ) | |
376 | ||
377 | print( string.format( | |
378 | "Which returned isFuelOK %s, " | |
379 | .."rowLength %d, isSeedy %s", | |
380 | tostring( isFuelOK ), rowLength, | |
381 | tostring(isSeedy) ) ) | |
382 | ||
383 | end -- if rowLength > 0 & not first | |
384 | ||
385 | isFirst = false | |
386 | rowIndex = rowIndex + 1 | |
387 | ||
388 | end -- while rows & isSeedy | |
389 | ||
390 | -- The number of rows traversed | |
391 | -- or 0 if unexpected problem | |
392 | local rtrnVal = 0 | |
393 | if rowLength > 0 then | |
394 | -- If fuel was too low, it did not | |
395 | -- move to next row, so therefore | |
396 | -- its row is one less than otherwise | |
397 | rtrnVal = isFuelOK and rowIndex or rowIndex - 1 | |
398 | else | |
399 | rtrnVal = 0 | |
400 | end | |
401 | ||
402 | return rtrnVal | |
403 | ||
404 | end | |
405 | ||
406 | -- Returns to the start and drops all | |
407 | -- inventory except one of each | |
408 | -- reference item. (It's assumed there | |
409 | -- are hoppers & a chest.) | |
410 | -- @param rows how many rows are | |
411 | -- planted. | |
412 | -- @return true if successful. False | |
413 | -- means there was blockage or fuel | |
414 | -- outage. | |
415 | local function returnAndStore(rows) | |
416 | print( "Returning to the start.") | |
417 | ||
418 | turtle.turnLeft() | |
419 | local canGo = true | |
420 | local forwards = (rows - 1) | |
421 | local stp = 1 | |
422 | while (stp <= forwards) and canGo do | |
423 | canGo = turtle.forward() | |
424 | stp = stp + 1 | |
425 | end | |
426 | ||
427 | turtle.turnLeft() | |
428 | ||
429 | if canGo then | |
430 | for i = 16, 1, -1 do | |
431 | turtle.select(i) | |
432 | if i > plntblCnt then | |
433 | turtle.drop() | |
434 | else | |
435 | turtle.drop( | |
436 | turtle.getItemCount(i)- 1) | |
437 | end | |
438 | end | |
439 | else | |
440 | print( string.format( | |
441 | "returnAndStore(rows) " | |
442 | .."couldn't store. rows %d, " | |
443 | .."forwards %d", rows, forwards )) | |
444 | end --canGo | |
445 | turtle.turnLeft() | |
446 | turtle.turnLeft() | |
447 | return canGo | |
448 | end | |
449 | ||
450 | -- Farms the field repeatedly up to | |
451 | -- MAX_REPEATS, or the fuel runs out, | |
452 | -- or there's some unexpected stop. | |
453 | -- @param rowCntFromUsr is the number | |
454 | -- of rows to farm, according to user | |
455 | local function farm( rowCntFromUsr ) | |
456 | ||
457 | --[[ Start ]] | |
458 | -- three times, if enough fuel | |
459 | local n = 1 | |
460 | local okSoFar = true | |
461 | while n<= MAX_REPEATS and okSoFar do | |
462 | local startTime = os.clock(); | |
463 | turtle.select(9) | |
464 | turtle.refuel() | |
465 | local fuelStart = turtle.getFuelLevel() | |
466 | print("fuelStart = ".. fuelStart) | |
467 | local rowsDone = reapAndSow( rowCntFromUsr ) | |
468 | okSoFar = returnAndStore(rowsDone) | |
469 | if rowsDone == rowCntFromUsr then | |
470 | if okSoFar then | |
471 | ||
472 | local fuelLevel = turtle.getFuelLevel() | |
473 | ||
474 | print("after harvest: "..(n) | |
475 | .." of ".. MAX_REPEATS) | |
476 | ||
477 | print("fuelLevel ".. fuelLevel) | |
478 | local fuelPerTurn = (fuelStart-fuelLevel) | |
479 | print( "fuelPerTurn ".. fuelPerTurn ) | |
480 | if fuelLevel< fuelPerTurn and n < MAX_REPEATS then | |
481 | print("Next harvest will be partial,") | |
482 | print("unless enough more fuel is added.") | |
483 | print("Use slot 9 (first slot of 3rd row).") | |
484 | end | |
485 | local endTime = os.clock() | |
486 | local duration = endTime - startTime | |
487 | local waitTime = ( GROW_WAIT*60)-duration | |
488 | local nextTime = endTime+ waitTime | |
489 | if (n < MAX_REPEATS) and okSoFar then | |
490 | os.sleep(waitTime) | |
491 | end | |
492 | end --okSofar | |
493 | else | |
494 | okSoFar = false | |
495 | end | |
496 | n = n + 1 | |
497 | end -- of MAX_REPEATS loop | |
498 | ||
499 | if okSoFar == false then | |
500 | print("Stopped.") | |
501 | end | |
502 | ||
503 | end | |
504 | ||
505 | local function main( tArgs ) | |
506 | local rowCntFromUsr = 0 | |
507 | ||
508 | --[[ If user supplies a good number, | |
509 | this uses it as row count. If user | |
510 | supplied a bad argument, it indicates. | |
511 | ]] | |
512 | local argCount = table.getn(tArgs) | |
513 | local badArg = false | |
514 | local badArgMsg = "Argument OK" | |
515 | if argCount > 0 then | |
516 | rowCntFromUsr = tArgs[1] | |
517 | if tonumber(rowCntFromUsr)==nil then | |
518 | badArg = true | |
519 | badArgMsg = "Argument not a number" | |
520 | else | |
521 | rowCntFromUsr = tonumber(rowCntFromUsr) | |
522 | end | |
523 | ||
524 | else | |
525 | badArg = true | |
526 | badArgMsg = "Supply how many rows" | |
527 | end | |
528 | ||
529 | if badArg then | |
530 | print( badArgMsg ) | |
531 | print("Put at least 1 of something" ) | |
532 | print(" plantable in first few slots.") | |
533 | else | |
534 | farm( rowCntFromUsr ) | |
535 | end | |
536 | ||
537 | end | |
538 | ||
539 | local tArgs = {...} | |
540 | main(tArgs) |