Advertisement
Damaged

Bee Alverizer Breeding

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