View difference between Paste ID: 8k0aNbVG and v5zbwNqg
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)