Advertisement
Damaged

Bee Alverizer Breeding 1.1

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