View difference between Paste ID: ak2UXkuB and pdM1fQYK
SHOW: | | - or go back to the newest paste.
1
-- BeeAlverizer 1 fork of BeeAnalyzer 4
2
-- Original code by Direwolf20
3
-- Hotfix 1 by Mandydax
4
-- Hotfix 2 by Mikeyhun/MaaadMike
5
6
-- Major overhaul to make work without turtle by Damaged
7
8
-- JSON lib loaded to debug arrays
9
local JSON = (loadfile "JSON.lua")()
10
JSON.strictTypes = true
11
12
-- attribute scoring for same species tie-breaking -----------------------------
13
14
local allBeeData = {}
15
local princessSlot = 0
16
alveary = peripheral.wrap("back")
17-
   stackData = memoryChest.getStackInSlot(i)
17+
18-
   return stackData.qty
18+
19
20
function getCountInMemoryChest(i)
21
   local inventoryQuantity
22
   if not memoryChest.getStackInSlot(i) then
23
      inventoryQuantity = 0
24
   else
25
      invenotryQuantity = memoryChest.getStackInSlot(i)["qty"]
26
   end
27
   return invenotryQuantity
28
end
29
30
scoresFertility = {
31
   [1] = 0.1,
32
   [2] = 0.2,
33
   [3] = 0.3,
34
   [4] = 0.4
35
}
36
scoresSpeed = {
37
   ["0.3"] = 0.01, -- Slowest
38
   ["0.6"] = 0.02, -- Slower
39
   ["0.8"] = 0.03, -- Slow
40
   ["1"]   = 0.04, -- Normal
41
   ["1.2"] = 0.05, -- Fast
42
   ["1.4"] = 0.06, -- Faster
43
   ["1.7"] = 0.07  -- Fastest
44
}
45
scoresAttrib = {
46
   diurnal       = 0.004,
47
   nocturnal     = 0.003,
48
   tolerantFlyer = 0.002,
49
   caveDwelling  = 0.0001
50
}
51
scoresTolerance = {
52
   ["NONE"]   = 0.00000,
53
   ["UP 1"]   = 0.00001,
54
   ["UP 2"]   = 0.00002,
55
   ["UP 3"]   = 0.00003,
56
   ["UP 4"]   = 0.00004,
57
   ["UP 5"]   = 0.00005,
58
   ["DOWN 1"] = 0.00001,
59
   ["DOWN 2"] = 0.00002,
60
   ["DOWN 3"] = 0.00003,
61
   ["DOWN 4"] = 0.00004,
62
   ["DOWN 5"] = 0.00005,
63
   ["BOTH 1"] = 0.00002,
64
   ["BOTH 2"] = 0.00004,
65
   ["BOTH 3"] = 0.00006,
66
   ["BOTH 4"] = 0.00008,
67
   ["BOTH 5"] = 0.00010
68
}
69
70
-- the bee graph ---------------------------------------------------------------
71
72
bees = {}
73
74
function addParent(parent, offspring)
75
   if bees[parent] then
76
      bees[parent].mutateTo[offspring] = true
77
      else
78
      bees[parent] = {
79
         --name = parent,
80
         score = nil,
81
         mutateTo = {[offspring]=true},
82
         mutateFrom = {}
83
      }
84
   end
85
end
86
87
function addOffspring(offspring, parentss)
88
   if bees[offspring] then
89
      for i, parents in ipairs(parentss) do
90
         table.insert(bees[offspring].mutateFrom, parents)
91
      end
92
      else
93
      bees[offspring] = {
94
         score = nil,
95
         mutateTo = {},
96
         mutateFrom = parentss
97
      }
98
   end
99
   for i, parents in ipairs(parentss) do
100
      for i, parent in ipairs(parents) do
101
         addParent(parent, offspring)
102
      end
103
   end
104
end
105
106
-- score bees that have no parent combinations as 1
107
-- iteratively find the next bee up the line and increase the score
108
function scoreBees()
109
   -- find all bees with no mutateFrom data
110
   local beeCount = 0
111
   local beeScore = 1
112
   for name, beeData in pairs(bees) do
113
      if #beeData.mutateFrom == 0 then
114
         beeData.score = beeScore
115
         else
116
         beeCount = beeCount + 1
117
      end
118
   end
119
   while beeCount > 0 do
120
      beeScore = beeScore * 2
121
      -- find all bees where all parent combos are scored
122
      for name, beeData in pairs(bees) do
123
         if not beeData.score then
124
            local scoreBee = true
125
            for i, beeParents in ipairs(beeData.mutateFrom) do
126
               local parent1 = bees[beeParents[1]]
127
               local parent2 = bees[beeParents[2]]
128
               
129
               if not parent1.score
130
                  or parent1.score == beeScore
131
                  or not parent2.score
132
                  or parent2.score == beeScore then
133
                  scoreBee = false
134
                  break
135
               end
136
            end
137
            if scoreBee then
138
               beeData.score = beeScore
139
               beeCount = beeCount - 1
140
            end
141
         end
142
      end
143
   end
144
end
145
146
-- produce combinations from 1 or 2 lists
147
function choose(list, list2)
148
   local newList = {}
149
   if list2 then
150
      for i = 1, #list2 do
151
         for j = 1, #list do
152
            if list[j] ~= list[i] then
153
               table.insert(newList, {list[j], list2[i]})
154
            end
155
         end
156
      end
157
      else
158
      for i = 1, #list do
159
         for j = i, #list do
160
            if list[i] ~= list[j] then
161
               table.insert(newList, {list[i], list[j]})
162
            end
163
         end
164
      end
165
   end
166
   return newList
167
end
168
169
-- Fix for some versions returning bees.species.*
170
function fixName(name)
171
   return name:gsub("bees%.species%.",""):gsub("^.", string.upper)
172
end
173
174
for key, value in pairs (alveary.getBeeBreedingData()) do
175
   addOffspring( fixName(value.result), {{ fixName(value.allele1), fixName(value.allele2) }} )
176
end
177
scoreBees()
178
179
-- logging ---------------------------------------------------------------------
180
181
local logFile = fs.open("bee.log", "w")
182
function log(msg)
183
   msg = msg or ""
184
   logFile.write(tostring(msg))
185
   logFile.flush()
186
   io.write(msg)
187
end
188
function logLine(msg)
189
   msg = msg or ""
190
   logFile.write(msg.."\n")
191
   logFile.flush()
192
   io.write(msg.."\n")
193
end
194
195
function logTable(table)
196
   for key, value in pairs (table) do
197
      logLine(key .. " = " .. tostring(value))
198
   end
199
end
200
201
202
-- analyzing functions ---------------------------------------------------------
203
204
function clearSystem()
205
   -- clear out alveary
206
   for i = 1,9 do
207
      memoryChest.pullItem("north",i)
208
   end
209
   -- clear out analyzer
210
   for i = 1, 12 do
211
      analyzer.pushItem("up",i)
212
   end
213
end
214-
   for i, 3,9 do 
214+
215
function getBees()
216
   -- get bees from apiary
217
   log("waiting for bees.")
218
   while not not alveary.getStackInSlot(1) do
219
      sleep(10)
220
      log(".")
221
   end
222
   log("*")
223
   for i = 3,9 do 
224-
function breedBees(droneSlot)
224+
225-
   memoryChest.pushItemToSlot("north",princessSlot,1,1)
225+
226-
   memoryChest.pushItemToSlot("north",droneSlot,1,2)
226+
227
   end
228-
      
228+
229
end
230
231
function analyzeBees()
232
   princessSlot = 0
233
   logLine("analyzing bees...")
234-
      if data.rawName == "item.beeprincess" then
234+
   memoryChest.condenseItems()
235-
         princessSlot = i
235+
236
   for i,data in pairs(memoryChest.getAllStacks()) do
237
      if not ( data.rawName == "item.beeprincessge" or data.rawName == "item.beequeenge" or data.rawName == "item.beedronege" ) then
238
         memoryChest.pushItem("east",i)
239
         print("P")
240
      else
241
         print("B")
242-
         if not data.beeInfo.isAnalyzed then
242+
         --print(JSON:encode(data["beeInfo"]))
243-
            analyzer.pullItem("up",i)
243+
         --print(data["beeInfo"]["isAnalyzed"]) 
244-
            while not analyzer.pushItem("up",9,data.qty,i) do sleep(1) end
244+
         if data["beeInfo"]["isAnalyzed"] == false then
245
            print("Analyzing: ".. i)
246
            analyzer.pullItemIntoSlot("up",i,64,3)
247
            while analyzer.pushItem("up",9,61,i) == 0 do sleep(1) end
248
            data = memoryChest.getStackInSlot(i)
249
         end
250
         -- Check if it's a drone or princess
251
         allBeeData[i] = {}
252
         if string.find(data.rawName, "princess") then
253
            allBeeData[i]["type"] = "princess"
254
         else
255
            allBeeData[i]["type"] = "drone"
256
         end               
257
         -- Active values
258
         for key, value in pairs (data.beeInfo.active) do
259
            if key == "species" then
260
               allBeeData[i]["speciesPrimary"] = value
261
            else
262
               allBeeData[i][key] = value
263-
         
263+
264-
         
264+
265
         -- Inactive values
266
         allBeeData[i]["speciesSecondary"] = data.beeInfo.inactive.species
267
         allBeeData[i]["speciesPrimary"] = fixName(allBeeData[i]["speciesPrimary"])
268
         allBeeData[i]["speciesSecondary"] = fixName(allBeeData[i]["speciesSecondary"])
269-
               memoryChest.swap(i,1)
269+
270
            if i ~= 1 then
271
               memoryChest.swapStacks(i,1)
272
            end
273
            princessSlot = 1
274
         end
275
      end
276
      -- check for untargeted species
277
      if allBeeData[i] and (not bees[allBeeData[i]["speciesPrimary"]].targeted or not bees[allBeeData[i]["speciesSecondary"]].targeted) then
278
         memoryChest.pushItem("east",i)
279
         allBeeData[i] = nil
280
      end
281
   end
282
   
283
   if princessSlot > 0 then
284
      logLine("compacting drones...")
285
      for i = 2, memoryChest.getInventorySize() do
286-
         if getCountInMemoryChest(i) > 0 and allBeeData[i] then
286+
         if not allBeeData[i] then
287
            for j = i + 1, memoryChest.getInventorySize() do
288
               if allBeeData[j] then
289-
               if getCountInMemoryChest(j) > 0 and allBeeData[j] then
289+
                  memoryChest.swapStacks(i, j)
290
                  allBeeData[i], allBeeData[j] = allBeeData[j], allBeeData[i]
291
                  break
292
               end
293
            end
294
         end
295
      end
296
      -- selection sort drones
297
      logLine("sorting drones...")
298
      for i = 2, memoryChest.getInventorySize() do
299
         highestScore = i
300-
               memoryChest.swap(i, highestScore)
300+
301
            allBeeData[i].score = scoreBee(allBeeData[princessSlot], allBeeData[i])
302
            for j = i + 1, memoryChest.getInventorySize() do
303
               if allBeeData[j] then
304
                  if not allBeeData[j].score then
305
                     allBeeData[j].score = scoreBee(allBeeData[princessSlot], allBeeData[j])
306
                  end
307
                  if allBeeData[j].score > allBeeData[highestScore].score then
308
                     highestScore = j
309
                  end
310
               end
311
            end
312
            -- swap bees
313
            if highestScore ~= i then
314
               memoryChest.swapStacks(i, highestScore)
315
               allBeeData[i], allBeeData[highestScore] = allBeeData[highestScore], allBeeData[i]
316
            end
317
         end
318
      end
319
      printHeader()
320
      allBeeData[princessSlot].slot = 1
321
      printBee(allBeeData[princessSlot])
322
      for i = 2, memoryChest.getInventorySize() do
323
         if allBeeData[i] then
324
            allBeeData[i].slot = i
325
            printBee(allBeeData[i])
326
         end
327
      end
328
   end
329
   logLine()
330
end
331
332
function scoreBee(princessData, droneData)
333
   local droneSpecies = {droneData["speciesPrimary"], droneData["speciesSecondary"]}
334
   -- check for untargeted species
335
   if not bees[droneSpecies[1]].targeted or not bees[droneSpecies[2]].targeted then
336
      return 0
337
   end
338
   local princessSpecies = {princessData["speciesPrimary"], princessData["speciesSecondary"]}
339
   local score
340
   local maxScore = 0
341
   for _, combo in ipairs({{princessSpecies[1], droneSpecies[1]}
342
      ,{princessSpecies[1], droneSpecies[2]}
343
      ,{princessSpecies[2], droneSpecies[1]}
344
   ,{princessSpecies[2], droneSpecies[2]}}) do
345
   -- find maximum score for each combo
346
   score = (bees[combo[1]].score + bees[combo[2]].score) / 2
347
   for name, beeData in pairs(bees) do
348
      if beeData.targeted then
349
         for i, parents in ipairs(beeData.mutateFrom) do
350
            if combo[1] == parents[1] and combo[2] == parents[2]
351
               or combo[2] == parents[1] and combo[1] == parents[2] then
352
               score = (score + beeData.score) / 2
353
            end
354
         end
355
      end
356
   end
357
   maxScore = maxScore + score
358
   end
359
   -- add one for each combination that results in the maximum score
360
   score = maxScore
361
   -- score attributes
362
   score = score + math.max(scoresFertility[droneData["fertility"]], scoresFertility[princessData["fertility"]])
363
   score = score + math.min(scoresSpeed[tostring(droneData["speed"])], scoresSpeed[tostring(princessData["speed"])])
364
   if droneData["nocturnal"] or princessData["nocturnal"] then score = score + scoresAttrib["nocturnal"] end
365
   if droneData["tolerantFlyer"] or princessData["tolerantFlyer"] then score = score + scoresAttrib["tolerantFlyer"] end
366
   if droneData["caveDwelling"] or princessData["caveDwelling"] then score = score + scoresAttrib["caveDwelling"] end
367
   score = score + math.max(scoresTolerance[string.upper(droneData["temperatureTolerance"])], scoresTolerance[string.upper(princessData["temperatureTolerance"])])
368
   score = score + math.max(scoresTolerance[string.upper(droneData["humidityTolerance"])], scoresTolerance[string.upper(princessData["humidityTolerance"])])
369
   return score
370
end
371
372
function printHeader()
373
   logLine()
374
   logLine("sl t species f spd n f c tmp hmd score ")
375
   logLine("--|-|-------|-|---|-|-|-|---|---|------")
376
end
377
378
-- string constants for console output
379
toleranceString = {
380
   ["NONE"] = "  - ",
381
   ["UP 1"] = " +1 ",
382
   ["UP 2"] = " +2 ",
383
   ["UP 3"] = " +3 ",
384
   ["UP 4"] = " +4 ",
385
   ["UP 5"] = " +5 ",
386
   ["DOWN 1"] = " -1 ",
387
   ["DOWN 2"] = " -2 ",
388
   ["DOWN 3"] = " -3 ",
389
   ["DOWN 4"] = " -4 ",
390
   ["DOWN 5"] = " -5 ",
391
   ["BOTH 1"] = "+-1 ",
392
   ["BOTH 2"] = "+-2 ",
393
   ["BOTH 3"] = "+-3 ",
394
   ["BOTH 4"] = "+-4 ",
395
   ["BOTH 5"] = "+-5 "
396
}
397
398
speedString = {
399
   ["0.3"] = "0.3", -- Slowest
400
   ["0.6"] = "0.6", -- Slower
401
   ["0.8"] = "0.8", -- Slow
402
   ["1"]   = "1.0", -- Normal
403
   ["1.2"] = "1.2", -- Fast
404
   ["1.4"] = "1.4", -- Faster
405
   ["1.7"] = "1.7"  -- Fastest
406
}
407
408
function printBee(beeData)
409
   log(beeData["slot"] < 10 and " "..beeData["slot"].." " or beeData["slot"].." ")
410
   -- type
411
   log(beeData["type"] == "princess" and "P " or "D ")
412
   -- species
413
   log(beeData["speciesPrimary"]:gsub("bees%.species%.",""):sub(1,3)..":"..beeData["speciesSecondary"]:gsub("bees%.species%.",""):sub(1,3).." ")
414
   -- fertility
415
   log(tostring(beeData["fertility"]).." ")
416
   -- speed
417
   log(speedString[tostring(beeData["speed"])].." ")
418
   -- nocturnal
419
   log(beeData["nocturnal"] and "X " or "- ")
420
   -- flyer
421-
   for i = 3, memoryChest.getInventorySize() do
421+
422-
      if getCountInMemoryChest(i) > 0 then
422+
423-
         -- drop drones over ( max inv - 9 ) to clear space for newly bred bees and product
423+
424-
         if i > ( memoryChest.getInventorySize() - 9 ) then
424+
425-
            memoryChest.pushItem("east",i)
425+
426-
            allBeeData[i] = nil
426+
427
   log(toleranceString[string.upper(beeData["humidityTolerance"])])
428
   -- score
429
   log(beeData.score and string.format("%5.1d", beeData.score).." " or "      ")
430
   logLine()
431
end
432
433
function dropExcess()
434
   logLine("dropping excess...")
435
   for i = ( memoryChest.getInventorySize() - 9 ), memoryChest.getInventorySize() do
436
      -- drop drones over ( max inv - 9 ) to clear space for newly bred bees and product
437
      memoryChest.pushItem("east",i)
438
      allBeeData[i] = nil
439
   end 
440
end
441
442
function isPurebred(princessData, droneData)
443
   -- check if princess and drone are exactly the same and no chance for mutation
444
   if princessData["speciesPrimary"] ~= princessData["speciesSecondary"] then
445
      return false
446
   end
447
   for key, value in pairs(princessData) do
448
      if value ~= droneData[key] and key ~= "territory" and key ~= "type" and key ~= "slot" then
449
         return false
450
      end
451
   end
452
   return true
453
end
454
455
function getUnknown(princessData, droneData)
456
   -- lists species that are not in the bee graph
457
   local unknownSpecies = {}
458
   if not bees[princessData["speciesPrimary"]] then
459
      table.insert(unknownSpecies, princessData["speciesPrimary"])
460
   end
461
   if not bees[princessData["speciesSecondary"]] then
462
      table.insert(unknownSpecies, princessData["speciesSecondary"])
463
   end
464
   for _, beeData in pairs(droneData) do
465
      if not bees[beeData["speciesPrimary"]] then
466
         table.insert(unknownSpecies, beeData["speciesPrimary"])
467
      end
468
      if not bees[beeData["speciesSecondary"]] then
469
         table.insert(unknownSpecies, beeData["speciesSecondary"])
470
      end
471
   end
472
   return unknownSpecies
473
end
474
475
-- targeting -------------------------------------------------------------------
476
477
-- set species and all parents to targeted
478
function targetBee(name)
479
   local bee = bees[name]
480
   if bee and not bee.targeted then
481
      bee.targeted = true
482
      for i, parents in ipairs(bee.mutateFrom) do
483
         for j, parent in ipairs(parents) do
484
            targetBee(parent)
485
         end
486
      end
487
   end
488
end
489
490
-- set bee graph entry to targeted if species was specified on the command line
491
-- otherwise set all entries to targeted
492
tArgs = { ... }
493
if #tArgs > 0 then
494
   logLine("targeting bee species:")
495
   for i, target in ipairs(tArgs) do
496
      targetBee(target)
497
      for name, data in pairs(bees) do
498
         if data.targeted and data.score > 1 then
499
            logLine(name .. string.rep(" ", 20-#name), data.score)
500
         end
501
      end
502
   end
503
   else
504
   for _, beeData in pairs(bees) do
505
      beeData.targeted = true
506
   end
507-
      if isPurebred(princessData, allBeeData[2]) then
507+
508
509
-- breeding loop ---------------------------------------------------------------
510
511
logLine("Clearing system...")
512-
      breedBees(1, 2)
512+
513
redstone.setOutput("bottom", true)
514-
      allBeeData[2] = nil
514+
515
   analyzeBees()
516
   if allBeeData[princessSlot] then
517
      if isPurebred(allBeeData[princessSlot], allBeeData[2]) then
518
         logLine("Bees are purebred")
519
         redstone.setOutput("bottom", false)
520
         break
521
      end
522
if true then break end
523
      memoryChest.pushItemIntoSlot("north",1,1,1)
524
      memoryChest.pushItemIntoSlot("north",2,1,2)
525
      allBeeData[1] = nil
526
      if not memoryChest.getAllStacks()[2] then
527
         allBeeData[2] = nil
528
      end
529
      dropExcess()
530
   end
531
   getBees()
532
end
533
logFile.close()