Advertisement
Stabbysolid

Untitled

Feb 19th, 2018
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Note: This is basically finished. I may tweak it here or there, which is why I reccomend using my program
  2. -- That I wrote to automatically update this. (See the bottom of this verbose description)
  3. -- This is an algorithm to automatically breed seeds in Minecraft's Agricraft Modpack,
  4. -- which have 3 integer values (x, y, z) as a tuple.
  5. -- I want to write a turtle AI to be "efficient enough" in breeding my Agricraft seeds so I can give it a 1/1/1 seed,
  6. -- and come back later and eventually, have 1 or more 10/10/10 seeds of that type.
  7. -- It will NOT actually breed new seed types; that's up to the players to create and provide for the turtle bot, but
  8. -- Eventually, once it's complete, this turtlebot AI should eventually be able to, given 2 seeds of any value,
  9. -- Breed them into a 10/10/10 seed.
  10. -- I started this algorithm on November 15, 2016, and pretty much finished it by November 20th, with a few tweaks since then.
  11. -- 04.28.2017 - Now saves settings into a file MatthewC/Agricraft/Data/SeedBreederSettings; you can now override the default settings by changing values within this file. This way, if emerald or lapis are too expensive, you can replace with cheaper (but unique!) materials.
  12. -- This algorithm was downloaded from: http://pastebin.com/V1MQRVQv
  13. -- A more visual example of the setup expected for the turtle is located: http://imgur.com/gallery/gPpK4
  14. -- The program to automatically download and run this file is located: http://pastebin.com/Vuxsn2mX
  15. -- A youtube video explaining this and demonstrating it in action is located: https://www.youtube.com/watch?v=-dN5wSv5SsY
  16. --
  17. --
  18. --
  19. --  Note: THANKS to AndyWilliams757 (Minecraft tag), I was able to test a few cases for the turtle, and improbe it a bit.
  20. --      Now, the turtle will query the player to give it fuel if it starts running without any fuel.
  21. --      Additionally, seeds can now be retrieved case - insensitive, so if a seed is called "Seed" instead of "seed",
  22. --      or "SeEd", or other mixed-cases, the turtle will handle that crap.
  23. --
  24. -- ********************************WARNING*******************************************
  25. -- PLANTS WHICH PRODUCE ITEMS WITH THE NAME "SEED" IN THEM CAN BREAK THE TURTLE. I PLAN ON EVENTUALLY CORRECTING THIS,
  26. -- BUT HAVEN'T GOTTEN AROUND TO IT YET>
  27. -- ITEMS KNOWN TO CAUSE PROBLEMS: "Mustard Seed",
  28.  
  29. --------------------------------------------------------------------------------------------------
  30. -- Settings
  31. --------------------------------------------------------------------------------------------------
  32. local numberOfPerfectSeedsToBreed = 30 -- Stores the total number of perfect seeds to breed.
  33. local blockNameBorderRight = "minecraft:iron_block" -- The name of the block on the right side of the setup.
  34. local blockNameBorderLeft = "minecraft:gold_block" -- The name of the block on the left side of the setup.
  35. local blockNameBorderFront = "minecraft:netherrack" -- The name of the block on the forward side of the setup.
  36. local blockNameBorderBack = "minecraft:nether_brick" -- the name of the block on the back side of the setup.
  37. local blockNameSeedAnalyzer = "AgriCraft:peripheral" -- The name of the Seed Analyzer
  38. local itemNameCropSticks = "AgriCraft:cropsItem" -- The name of the crop sticks
  39. local itemNameFuel = "minecraft:coal" -- The name of the fuel the turtle will be using (Can only accept 1 type of fuel.)
  40. local itemNameBoneMeal = "minecraft:dye" -- The name of bonemeal. (really, the fertilizer, if the turtle can use it... I'm just only familiar with bonemeal...) Note: This is odd, because the turtle detect's the name as "minecraft:dye:"...
  41. local itemMetaDataBoneMeal = 15 -- This is the metadata value associated with bonemeal. This is necessary because bone meal registers as dye, so I use metadata to differentiate between bonemeal and other dyes.
  42. local frontCompassDirection = "NORTH" -- The direction of the front of the workspace. Valid Values are: "SOUTH", "NORTH", "EAST", "WEST".
  43. local useBoneMealOnCenter = false -- Whether to use bone meal on center cross crop.
  44.  
  45. --------------------------------------------------------------------------------------------------
  46. -- Variables
  47. --------------------------------------------------------------------------------------------------
  48. local seed1 = {X = 1, Y = 1, Z = 1, Fitness = nil} -- Stores the Left seed or "parent"
  49. local seed2 = {X = 1, Y = 1, Z = 1, Fitness = nil} -- Stores the Right seed or "parent"
  50. local generation = 1 -- Stores the number of generations it took to get to our current set of parents.
  51. local leftSeedName = "" -- Stores the name of the seed type we are currently breeding.
  52. local rightSeedName = "" -- Stores the name of the right seed type we are currently breeding.
  53. local childSeedName = "" -- Stores the name of the child seed type we are currently breeding.
  54. local perfectFitnessValue = nil -- Stores perfect Fitness value that is attainable. calulated in post-initialization.
  55. local currentNumberOfPerfectSeedsBred = 0 -- Stores the number of seeds we have bred so far in our current work.
  56. local xPosition = 1 -- 1 = far left, 2 = 2 in, 3 = 3 middle, 4 = 4 in, 5 = far right
  57. local zPosition = 1 -- 1 = far back, 2 = 2 in, 3 = 2 in, 4 = far front
  58. local cropStickPosition = nil -- Stores the position of crop sticks in the inventory. If nil, we need to scan for them.
  59. local boneMealPosition = nil -- Stores the position of bonemeal in inventory. If nil, we need to scan for them.
  60. local loadedData = false -- True if we have loaded data and are resuming our old state, false if not.
  61. local hasFailedOnRetrievingBoneMealLastTime = false -- If this is true, we won't bother trying to go stock up on boneMeal unless we're forced to.
  62.  
  63. --------------------------------------------------------------------------------------------------
  64. -- Function Definitions
  65. --------------------------------------------------------------------------------------------------
  66.  
  67. -- Provided a number array, returns the minimum value in the array.
  68. --      Inputs:
  69. --          int[] numArray : The number array / table to retrieve the minimum value of.
  70. --      Outputs:
  71. --          int minVal     : The value of the minimum value within the provided array.
  72. local GetMinValueFromNumberArray = nil
  73.  
  74. -- Calculates the fitness of a provided seed.
  75. -- Note: I tested this fitness value with an algorithm that predicts a potential offspring of the parent-seeds,
  76. -- And determined it to be the best of 5 other algorithms, with an average Total Generation count of 72.29.
  77. -- This calculation was based on a breeding algorithm which averages the X,Y, and Z scores of two parent seeds to produce
  78. --   An offspring, with a 40% chance to increment each individual stat of the seed.
  79. --   (10/10/10 + 1/1/1 = 5/5/5 with a 40% chance of Any individual stat being a 6 instead.)
  80. --      Inputs:
  81. --          Table { int X, int Y, int Z, int Fitness } : The table representing a singular seed.
  82. --      Outputs:
  83. --          int fitness : The fitness for the seed; 4 is the worst possible, 40 is the best possible.
  84. local GetSeedFitness = nil
  85.  
  86. -- Returns the index of the item in the inventory by the name provided. Returns nil if it can't be found.
  87. -- Note: If you are searching for a nil name, will return the first nil position.
  88. --      Inputs:
  89. --          string name : The name of the seed to search for. Performs a string.match, so partial names are counted.
  90. --          bool caseInsensitive : Whether to perform the search with a case-sensitive or case-insensitive search.
  91. --      Outputs:
  92. --          int inventoryLocation : The inventory location of the item, or nil if it doesn't exist in the inventory.
  93. local ScanForItemInInventoryByName = nil
  94.  
  95. -- Purges the inventory of items deemed unecessary (seeds and such)
  96. --      Inputs:
  97. --          N/A
  98. --      Outputs:
  99. --          N/A
  100. local PurgeInventoryOfExtraneousItems = nil
  101.  
  102. -- Tries to reset the Turtle Bot to the center (top level, middle horizontally) position.
  103. -- Attempts this based off of various Blocks (bottom / top blocks)
  104. --      Inputs:
  105. --          N/A
  106. --      Outputs:
  107. --          N/A
  108. local ResetLocationToCenter = nil
  109.  
  110. -- Send the turtle to the specified location.
  111. --      xPos : 1 = far left, 2 = 1 in, 3 = middle, 4 = 3 in, 5 = far right
  112. --      zPos : 1 = far back, 2 = 1 forward, 3 = 2 forward, 4 = far front
  113. --      Inputs:
  114. --          int xPos : The X-position to travel to.
  115. --          int yPos : The Y-position to travel to.
  116. --      Outputs:
  117. --          N/A
  118. local TravelToPosition = nil
  119.  
  120. -- Throws an item away at the index provided (1 - 16 inclusive)
  121. --      Inputs:
  122. --          int index : The index of the stack to throw away.
  123. --      Outputs:
  124. --          N/A
  125. local ThrowStackAway = nil
  126.  
  127. -- Equips Crop Sticks in the inventory.
  128. -- If we are out, we will pick them up from the crop stick input station, and then return to our original location.
  129. --      Inputs:
  130. --          N/A
  131. --      Outputs:
  132. --          N/A
  133. local EquipCropSticks = nil
  134.  
  135. -- Equips bonemeal
  136. --      Inputs:
  137. --          bool allowRefill : True if you want to allow the turtle to refill if it's out, false if you don't.
  138. --      Outputs:
  139. --          N/A
  140. local EquipBoneMeal = nil
  141.  
  142. -- If the turtle is below 10% fuel, it needs to go to the chest to refuel.
  143. --      Inputs:
  144. --          N/A
  145. --      Outputs:
  146. --          N/A
  147. local HandleFuel = nil
  148.  
  149. -- Stores the item in the noted index at the storage location.
  150. --      Inputs:
  151. --          int index : The index of the stack to save.
  152. --      Outputs:
  153. --          N/A
  154. local SaveStack = nil
  155.  
  156. -- Create a redstone impulse at .9 seconds on the bottom of the turtle.
  157. --      Inputs:
  158. --          N/A
  159. --      Outputs:
  160. --          N/A
  161. local redstoneImpulseOnBottom = nil
  162.  
  163. -- Sucks up a new seed.
  164. --      Inputs:
  165. --          int numOfSeedsToSuckUp : The number of seeds to suck up.
  166. --      Outputs:
  167. --          boolean true if it sucked up 2 seeds, 1 if it sucked up 1 seed.
  168. local SuckUpNewSeed = nil
  169.  
  170. -- Plant seed on the left side.
  171. --      Inputs:
  172. --          N/A
  173. --      Outputs:
  174. --          N/A
  175. local PlantSeedOnLeft = nil
  176.  
  177. -- Plant seed on right side.
  178. --      Inputs:
  179. --          N/A
  180. --      Outputs:
  181. --          N/A
  182. local PlantSeedOnRight = nil
  183.  
  184. -- Employs the Computer Controlled Seed Analyzer at the current location to
  185. -- Analyze the current seed, and return a table for the seed's properties.
  186. --      Inputs:
  187. --          N/A
  188. --      Outputs:
  189. --          Table { int X, int Y, int Z, int Fitness }
  190. local AnalyzeSeedAtCurrentLocation = nil
  191.  
  192. -- If it is determined that the state of the board no longer matches what we expect,
  193. -- let's reset our save data.
  194. --      Inputs:
  195. --          N/A
  196. --      Outputs:
  197. --          N/A
  198. local ResetSaveData = nil
  199.  
  200. -- Prepares for planting, if this station isn't already prepared.
  201. --      Inputs:
  202. --          N/A
  203. --      Outputs:
  204. --          N/A
  205. local PrepareForPlanting = nil
  206.  
  207. -- Has the turtle wait until it can detect that an offspring has been produced.
  208. --      Inputs:
  209. --          N/A
  210. --      Outputs:
  211. --          N/A
  212. local WaitForOffspring = nil
  213.  
  214. -- Function to eliminate parent 1, and replace with the current offspring.
  215. --      Inputs:
  216. --          Table offspring { int X, int Y, int Z, int Fitness }
  217. --      Outputs:
  218. --          N/A
  219. local PlantOffSpringOnSeed1 = nil
  220.  
  221. -- Function to eliminate parent 2, and replace with the current offspring.
  222. --      Inputs:
  223. --          Table offspring { int X, int Y, int Z, int Fitness }
  224. --      Outputs:
  225. --          N/A
  226. local PlantOffSpringOnSeed2 = nil
  227.  
  228. -- Function to reject our current offspring (Probably throw it away in a trash can or something...)
  229. --      Inputs:
  230. --          N/A
  231. --      Outputs:
  232. --          N/A
  233. local RejectOffspring = nil
  234.  
  235. -- Function to save our offspring (Probably put into a chest or something...)
  236. -- Call this if the offspring, as well as both parents, are 10/10/10 seeds.
  237. --      Inputs:
  238. --          N/A
  239. --      Outputs:
  240. --          N/A
  241. local SaveOffspring = nil
  242.  
  243. -- Function to analyze the offspring seed, and determine if it should replace either parent or be rejected.
  244. -- At this point, the seed has already been harvested/analyzed,
  245. -- and we just need to determine whether we reject it, or replace one of our parents with it.
  246. --      Inputs:
  247. --          Table offspring { int X, int Y, int Z, int Fitness }
  248. --      Outputs:
  249. --          N/A
  250. local HarvestedOffspring = nil
  251.  
  252. -- Function to harvest the current offspring.
  253. --      Inputs:
  254. --          N/A
  255. --      Outputs:
  256. --          N/A
  257. local HarvestOffspring = nil
  258.  
  259. -- Function to clean up after the turtle has finished.
  260. -- (Basically just reinitializes the data.)
  261. --      Inputs:
  262. --          N/A
  263. --      Outputs:
  264. --          N/A
  265. local CleanUp = nil
  266.  
  267. -- Loads pertinent Data.
  268. --      Inputs:
  269. --          N/A
  270. --      Outputs:
  271. --          N/A
  272. local Load = nil
  273.  
  274. -- Saves the pertinent Data.
  275. --      Inputs:
  276. --          N/A
  277. --      Outputs:
  278. --          N/A
  279. local Save = nil
  280.  
  281. -- Main program entry point.
  282. --      Inputs:
  283. --          N/A
  284. --      Outputs:
  285. --          N/A
  286. local MainExecutionLoop = nil
  287.  
  288. --------------------------------------------------------------------------------------------------
  289. -- Functions
  290. --------------------------------------------------------------------------------------------------
  291.  
  292. -- Provided a number array, returns the minimum value in the array.
  293. --      Inputs:
  294. --          int[] numArray : The number array / table to retrieve the minimum value of.
  295. --      Outputs:
  296. --          int minVal     : The value of the minimum value within the provided array.
  297. GetMinValueFromNumberArray =
  298. function(array)
  299.     local min = 999999
  300.  
  301.     for i = 1, #array, 1 do
  302.         if array[i] < min then
  303.             min = array[i]
  304.         end
  305.     end
  306.  
  307.     return min
  308. end
  309.  
  310. -- Calculates the fitness of a provided seed.
  311. -- Note: I tested this fitness value with an algorithm that predicts a potential offspring of the parent-seeds,
  312. -- And determined it to be the best of 5 other algorithms, with an average Total Generation count of 72.29.
  313. -- This calculation was based on a breeding algorithm which averages the X,Y, and Z scores of two parent seeds to produce
  314. --   An offspring, with a 40% chance to increment each individual stat of the seed.
  315. --   (10/10/10 + 1/1/1 = 5/5/5 with a 40% chance of Any individual stat being a 6 instead.)
  316. --      Inputs:
  317. --          Table{ int X, int Y, int Z, int Fitness } : The table representing a singular seed.
  318. --      Outputs:
  319. --          int fitness : The fitness for the seed; 4 is the worst possible, 40 is the best possible.
  320. GetSeedFitness =
  321. function(inputSeed)
  322.     local fitness = inputSeed["X"] + inputSeed["Y"] + inputSeed["Z"]
  323.         + GetMinValueFromNumberArray({inputSeed["X"], inputSeed["Y"], inputSeed["Z"]})
  324.  
  325.     inputSeed["Fitness"] = fitness
  326.     return fitness
  327. end
  328.  
  329. -- Returns the index of the item in the inventory by the name provided. Returns nil if it can't be found.
  330. -- Note: If you are searching for a nil name, will return the first nil position.
  331. --      Inputs:
  332. --          string name : The name of the seed to search for. Performs a string.match, so partial names are counted.
  333. --          bool caseInsensitive : Whether to perform the search with a case-sensitive or case-insensitive search.
  334. --      Outputs:
  335. --          int inventoryLocation : The inventory location of the item, or nil if it doesn't exist in the inventory.
  336. ScanForItemInInventoryByName =
  337. function(name, caseInsensitive)
  338.     for i = 1, 16, 1 do
  339.         local item = turtle.getItemDetail(i)
  340.        
  341.         if item then
  342.             local itemName = item.name
  343.            
  344.             if caseInsensitive then
  345.                 itemName = string.lower(itemName)
  346.                 name = string.lower(name)
  347.             end
  348.            
  349.             if name and string.match(itemName, name) and (name ~= itemNameBoneMeal or (name == itemNameBoneMeal and item.damage == itemMetaDataBoneMeal)) then
  350.                 return i
  351.             end
  352.         end
  353.        
  354.         if item == nil and name == nil then
  355.             return i
  356.         end
  357.     end
  358.  
  359.     return nil
  360. end
  361.  
  362. -- Purges the inventory of items deemed unecessary (seeds and such)
  363. --      Inputs:
  364. --          N/A
  365. --      Outputs:
  366. --          N/A
  367. PurgeInventoryOfExtraneousItems =
  368. function()
  369.     local archivedXPos = xPosition
  370.     local archivedZPos = zPosition
  371.    
  372.     for i = 1, 16 do
  373.         local item = turtle.getItemDetail(i)
  374.        
  375.         if item then
  376.             if item.name == itemNameCropSticks then
  377.             elseif item.name == itemNameBoneMeal and item.damage == itemMetaDataBoneMeal then
  378.             else
  379.                 TravelToPosition(5, 2)
  380.                 ThrowStackAway(i)
  381.             end
  382.         end
  383.     end
  384.    
  385.     TravelToPosition(archivedXPos, archivedZPos)
  386. end
  387.  
  388. -- Tries to reset the Turtle Bot to the center (top level, middle horizontally) position.
  389. -- Attempts this based off of various Blocks (bottom / top blocks)
  390. --      Inputs:
  391. --          N/A
  392. --      Outputs:
  393. --          N/A
  394. ResetLocationToCenter =
  395. function()
  396.     print("Resetting Location To Center")
  397.    
  398.     -- Move forward 4 times to guarantee we are facing a wall of the border.
  399.     turtle.forward()
  400.     turtle.forward()
  401.     turtle.forward()
  402.     turtle.forward()
  403.    
  404.     local success, item = turtle.inspect()
  405.     if item.name == blockNameBorderRight then -- We are on the far right side facing the border.
  406.         -- Turn right, head all the way to the back, and then turn right, recenter, turn right.
  407.         turtle.turnRight()
  408.         turtle.forward()
  409.         turtle.forward()
  410.         turtle.forward()
  411.         turtle.turnRight()
  412.         turtle.forward()
  413.         turtle.forward()
  414.         turtle.turnRight()
  415.         xPosition = 3
  416.         zPosition = 1
  417.     elseif item.name == blockNameBorderFront then -- We are at far front side facing the border
  418.         -- Turn right, head all the way to the right, and then go back, back, left, back, back, back, back
  419.         turtle.turnRight()
  420.         turtle.forward()
  421.         turtle.forward()
  422.         turtle.forward()
  423.         turtle.forward()
  424.         turtle.back()
  425.         turtle.back()
  426.         turtle.turnLeft()
  427.         turtle.back()
  428.         turtle.back()
  429.         turtle.back()
  430.         xPosition = 3
  431.         yPosition = 1
  432.     elseif item.name == blockNameBorderLeft then -- We are at far left side facing the border
  433.         -- Turn Left, go all the way forward (towards the back), turn right, go back 2
  434.         turtle.turnLeft()
  435.         turtle.forward()
  436.         turtle.forward()
  437.         turtle.forward()
  438.         turtle.turnRight()
  439.         turtle.back()
  440.         turtle.back()
  441.         turtle.turnRight()
  442.         xPosition = 3
  443.         yPosition = 1
  444.     elseif item.name == blockNameBorderBack then -- We are that the far back facing the border
  445.         -- Turn Left, goo all the way to the end, go back twice, turn right
  446.         turtle.turnRight()
  447.         turtle.forward()
  448.         turtle.forward()
  449.         turtle.forward()
  450.         turtle.forward()
  451.         turtle.back()
  452.         turtle.back()
  453.         turtle.turnRight()
  454.         xPosition = 3
  455.         yPosition = 1
  456.     else
  457.         print("\r\n\r\nUnable to find position based off of block in front by name of: "..item.name.."\r\n\r\n")
  458.     end
  459. end
  460.  
  461. -- Send the turtle to the specified location.
  462. --      xPos : 1 = far left, 2 = 1 in, 3 = middle, 4 = 3 in, 5 = far right
  463. --      zPos : 1 = far back, 2 = 1 forward, 3 = 2 forward, 4 = far front
  464. --      Inputs:
  465. --          int xPos : The X-position to travel to.
  466. --          int yPos : The Y-position to travel to.
  467. --      Outputs:
  468. --          N/A
  469. TravelToPosition =
  470. function(xPos, zPos)
  471.     -- Manipulate xPos and zPos to guarantee we end up somewhere in the field (even if not where expected)
  472.     if xPos < 0 then xPos = -xPos end
  473.     if zPos < 0 then zPos = -zPos end
  474.     xPos = xPos % 6
  475.     zPos = zPos % 5
  476.    
  477.     if xPos ~= xPosition then
  478.         if xPos < xPosition then -- We need to move to the left.
  479.             local difference = xPosition - xPos
  480.             turtle.turnLeft()
  481.            
  482.             for i = 1, difference, 1 do
  483.                 turtle.forward()
  484.             end
  485.            
  486.             turtle.turnRight()
  487.         else -- We need to move to the right
  488.             local difference = xPos - xPosition
  489.             turtle.turnRight()
  490.            
  491.             for i = 1, difference, 1 do
  492.                 turtle.forward()
  493.             end
  494.            
  495.             turtle.turnLeft()
  496.         end
  497.        
  498.         xPosition = xPos
  499.     end
  500.  
  501.     if zPos ~= zPosition then
  502.         if zPos < zPosition then -- We need to move backward
  503.             local difference = zPosition - zPos
  504.            
  505.             for i = 1, difference, 1 do
  506.                 turtle.back()
  507.             end
  508.         else
  509.             local difference = zPos - zPosition
  510.            
  511.             for i = 1, difference, 1 do
  512.                 turtle.forward()
  513.             end
  514.         end
  515.        
  516.         zPosition = zPos
  517.     end
  518. end
  519.  
  520. -- Throws an item away at the index provided (1 - 16 inclusive)
  521. --      Inputs:
  522. --          int index : The index of the stack to throw away.
  523. --      Outputs:
  524. --          N/A
  525. ThrowStackAway =
  526. function(index)
  527.     if index ~= nil and turtle.getItemDetail(index) ~= nil then
  528.         local archivedX = xPosition
  529.         local archivedZ = zPosition
  530.         TravelToPosition(5, 2)
  531.         turtle.select(index)
  532.         turtle.dropDown()
  533.         TravelToPosition(archivedX, archivedZ)
  534.     end
  535. end
  536.  
  537. -- Equips Crop Sticks in the inventory.
  538. -- If we are out, we will pick them up from the crop stick input station, and then return to our original location.
  539. --      Inputs:
  540. --          N/A
  541. --      Outputs:
  542. --          N/A
  543. EquipCropSticks =
  544. function()
  545.     if cropStickPosition == nil then
  546.         cropStickPosition = ScanForItemInInventoryByName(itemNameCropSticks)
  547.     end
  548.    
  549.     local cropSticks
  550.  
  551.     if cropStickPosition ~= nil then
  552.         cropSticks = turtle.getItemDetail(cropStickPosition)
  553.         turtle.select(cropStickPosition)
  554.     end
  555.  
  556.     if cropSticks == nil then
  557.         -- We need to refill on cropSticks. Archive our current location.
  558.         local archivedX = xPosition
  559.         local archivedZ = zPosition
  560.        
  561.         TravelToPosition(2, 1) -- Travel to position in order to pick up crop sticks.
  562.         turtle.suckDown()
  563.         TravelToPosition(archivedX, archivedZ)
  564.         cropStickPosition = ScanForItemInInventoryByName(itemNameCropSticks)
  565.        
  566.         if cropStickPosition ~= nil then
  567.             turtle.select(cropStickPosition)
  568.         end
  569.     end
  570. end
  571.  
  572. -- Equips bonemeal
  573. --      Inputs:
  574. --          bool allowRefill : True if you want to allow the turtle to refill if it's out, false if you don't.
  575. --      Outputs:
  576. --          N/A
  577. EquipBoneMeal =
  578. function(allowRefill)
  579.     if allowRefill == nil then allowRefill = false end
  580.    
  581.      if boneMealPosition == nil then
  582.         boneMealPosition = ScanForItemInInventoryByName(itemNameBoneMeal)
  583.     end
  584.    
  585.     local boneMeal
  586.  
  587.     if boneMealPosition ~= nil then
  588.         boneMeal = turtle.getItemDetail(boneMealPosition)
  589.         turtle.select(boneMealPosition)
  590.        
  591.         if not boneMeal then
  592.             boneMealPosition = nil
  593.         end
  594.     end
  595.  
  596.     if boneMeal == nil and (hasFailedOnRetrievingBoneMealLastTime == true and allowRefill == true or hasFailedOnRetrievingBoneMealLastTime == false) then
  597.         -- We need to refill on boneMeal. Archive our current location.
  598.         local archivedX = xPosition
  599.         local archivedZ = zPosition
  600.        
  601.         TravelToPosition(1, 1) -- Travel to position in order to pick up boneMeal.
  602.         turtle.suckUp()
  603.         TravelToPosition(archivedX, archivedZ)
  604.         boneMealPosition = ScanForItemInInventoryByName(itemNameBoneMeal)
  605.        
  606.         if boneMealPosition ~= nil then
  607.             turtle.select(boneMealPosition)
  608.             hasFailedOnRetrievingBoneMealLastTime = false
  609.         else
  610.             hasFailedOnRetrievingBoneMealLastTime = true
  611.         end
  612.     end
  613. end
  614.  
  615. -- If the turtle is below 10% fuel, it needs to go to the chest to refuel.
  616. --      Inputs:
  617. --          N/A
  618. --      Outputs:
  619. --          N/A
  620. HandleFuel =
  621. function()
  622.     if turtle.getFuelLevel() / turtle.getFuelLimit() < .1 then
  623.         if turtle.getFuelLevel() > 0 then
  624.             print("Turtle is low on fuel - Refueling...")
  625.             local archivedX = xPosition
  626.             local archivedZ = zPosition
  627.             TravelToPosition(1, 2) -- Travel to position in order to pick up fuel.
  628.             turtle.suckDown() -- Suck up 3 times
  629.             turtle.suckDown()
  630.             turtle.suckDown()
  631.             TravelToPosition(archivedX, archivedZ) -- Return to original location.
  632.         end
  633.        
  634.         local fuelPosition = ScanForItemInInventoryByName(itemNameFuel)
  635.         while fuelPosition ~= nil do
  636.             turtle.select(fuelPosition)
  637.             turtle.refuel()
  638.             fuelPosition = ScanForItemInInventoryByName(itemNameFuel)
  639.         end
  640.     end
  641. end
  642.  
  643. -- Stores the item in the noted index at the storage location.
  644. --      Inputs:
  645. --          int index : The index of the stack to save.
  646. --      Outputs:
  647. --          N/A
  648. SaveStack =
  649. function(index)
  650.     if index ~= nil and turtle.getItemDetail(index) ~= nil then
  651.         local archivedX = xPosition
  652.         local archivedZ = zPosition
  653.         TravelToPosition(4, 1)
  654.         turtle.select(index)
  655.         turtle.dropDown()
  656.         TravelToPosition(archivedX, archivedZ)
  657.     end
  658. end
  659.  
  660. -- Create a redstone impulse at .9 seconds on the bottom of the turtle.
  661. --      Inputs:
  662. --          N/A
  663. --      Outputs:
  664. --          N/A
  665. redstoneImpulseOnBottom =
  666. function()
  667.     redstone.setOutput("bottom", true)
  668.     os.sleep(.9)
  669.     redstone.setOutput("bottom", false)
  670. end    
  671.  
  672. -- Sucks up a new seed.
  673. --      Inputs:
  674. --          int numOfSeedsToSuckUp : The number of seeds to suck up.
  675. --      Outputs:
  676. --          boolean true if it sucked up 2 seeds, 1 if it sucked up 1 seed.
  677. SuckUpNewSeed =
  678. function(numOfSeedsToSuckUp)
  679.     TravelToPosition(5, 1) -- Travel to the seed input chest
  680.     turtle.select(ScanForItemInInventoryByName(nil)) -- Select the first empty position.
  681.     local suckSuccess = turtle.suckUp(numOfSeedsToSuckUp) -- suck at most numOfSeedsToSuckUp items from the chest.
  682.    
  683.     while suckSuccess == false do
  684.         print("Waiting for "..textutils.serialize(numOfSeedsToSuckUp).." input seeds. Place a seed in the chest above the turtle.")
  685.         os.sleep(3)
  686.         suckSuccess = turtle.suckUp(numOfSeedsToSuckUp)
  687.     end
  688.    
  689.     return turtle.getItemCount() > 1 -- Evaluate whether we sucked up 1 or more seeds, and return true/false accordingly.
  690. end
  691.  
  692. -- Plant seed on the left side.
  693. --      Inputs:
  694. --          N/A
  695. --      Outputs:
  696. --          N/A
  697. PlantSeedOnLeft =
  698. function()
  699.     TravelToPosition(1, 3)
  700.     turtle.dropDown(1)
  701.     redstoneImpulseOnBottom()
  702.     EquipBoneMeal()
  703.     -- Have turtle place bone meal below itself 5 times.
  704.     if boneMealPosition ~= nil then
  705.         TravelToPosition(2, 3)
  706.         if boneMealPosition ~= nil then turtle.placeDown() end
  707.         EquipBoneMeal()
  708.         if boneMealPosition ~= nil then turtle.placeDown() end
  709.         EquipBoneMeal()
  710.         if boneMealPosition ~= nil then turtle.placeDown() end
  711.         EquipBoneMeal()
  712.         if boneMealPosition ~= nil then turtle.placeDown() end
  713.         EquipBoneMeal()
  714.         if boneMealPosition ~= nil then turtle.placeDown() end
  715.         EquipBoneMeal()
  716.         if boneMealPosition ~= nil then turtle.placeDown() end
  717.         EquipBoneMeal()
  718.         if boneMealPosition ~= nil then turtle.placeDown() end
  719.         EquipBoneMeal()
  720.         if boneMealPosition ~= nil then turtle.placeDown() end
  721.         EquipBoneMeal()
  722.         if boneMealPosition ~= nil then turtle.placeDown() end
  723.         EquipBoneMeal()
  724.         if boneMealPosition ~= nil then turtle.placeDown() end
  725.     end
  726. end
  727.  
  728. -- Plant seed on right side.
  729. --      Inputs:
  730. --          N/A
  731. --      Outputs:
  732. --          N/A
  733. PlantSeedOnRight =
  734. function()
  735.     TravelToPosition(5, 3)
  736.     turtle.dropDown(1)
  737.     redstoneImpulseOnBottom()
  738.     EquipBoneMeal()
  739.     -- Have turtle place bone meal below itself 5 times.
  740.     if boneMealPosition ~= nil then
  741.         TravelToPosition(4, 3)
  742.         if boneMealPosition ~= nil then turtle.placeDown() end
  743.         EquipBoneMeal()
  744.         if boneMealPosition ~= nil then turtle.placeDown() end
  745.         EquipBoneMeal()
  746.         if boneMealPosition ~= nil then turtle.placeDown() end
  747.         EquipBoneMeal()
  748.         if boneMealPosition ~= nil then turtle.placeDown() end
  749.         EquipBoneMeal()
  750.         if boneMealPosition ~= nil then turtle.placeDown() end
  751.         EquipBoneMeal()
  752.         if boneMealPosition ~= nil then turtle.placeDown() end
  753.         EquipBoneMeal()
  754.         if boneMealPosition ~= nil then turtle.placeDown() end
  755.         EquipBoneMeal()
  756.         if boneMealPosition ~= nil then turtle.placeDown() end
  757.         EquipBoneMeal()
  758.         if boneMealPosition ~= nil then turtle.placeDown() end
  759.         EquipBoneMeal()
  760.         if boneMealPosition ~= nil then turtle.placeDown() end
  761.     end
  762.  end
  763.  
  764. -- Employs the Computer Controlled Seed Analyzer at the current location to
  765. -- Analyze the current seed, and return a table for the seed's properties.
  766. --      Inputs:
  767. --          N/A
  768. --      Outputs:
  769. --          Table { int X, int Y, int Z, int Fitness }
  770. AnalyzeSeedAtCurrentLocation =
  771. function()
  772.     local analyzer = peripheral.wrap("bottom")
  773.     turtle.dropDown(1)
  774.     analyzer.analyze()
  775.     while not analyzer.isAnalyzed() do
  776.         os.sleep(.5)
  777.     end
  778.    
  779.     local x, y, z = analyzer.getSpecimenStats()
  780.     local retData = {X = x, Y = y, Z = z, Fitness = nil }
  781.     retData["Fitness"] = GetSeedFitness(retData)
  782.    
  783.     turtle.suckDown() -- Pick the seed back up
  784.    
  785.     return retData
  786. end
  787.  
  788. -- If it is determined that the state of the board no longer matches what we expect,
  789. -- let's reset our save data.
  790. --      Inputs:
  791. --          N/A
  792. --      Outputs:
  793. --          N/A
  794. ResetSaveData =
  795. function()
  796.     if loadedData == true then
  797.         generation = 2
  798.         currentNumberOfPerfectSeedsBred = 0
  799.         seed1 = {X = 1, Y = 1, Z = 1, Fitness = nil}
  800.         seed2 = {X = 1, Y = 1, Z = 1, Fitness = nil}
  801.         leftSeedName = ""
  802.         rightSeedName = ""
  803.         childSeedName = ""
  804.         loadedData = false
  805.     end
  806. end
  807.  
  808. -- Prepares for planting, if this station isn't already prepared.
  809. --      Inputs:
  810. --          N/A
  811. --      Outputs:
  812. --          N/A
  813. PrepareForPlanting =
  814. function()
  815.     redstone.setOutput("bottom", false) -- deactivate redstone output in case it's been left on...
  816.     HandleFuel()
  817.     EquipCropSticks()
  818.     TravelToPosition(2, 3)
  819.    
  820.     local success, item = turtle.inspectDown()
  821.     if not success then
  822.         turtle.placeDown()
  823.     end
  824.    
  825.     TravelToPosition(3, 3)
  826.    
  827.     local success, item = turtle.inspectDown()
  828.     if not success then
  829.         EquipCropSticks()
  830.         turtle.placeDown()
  831.         EquipCropSticks() -- Call equipCropSticks a 2nd time just in case we run out before.
  832.         -- Since turtles cannot actually place the double-crop sticks,
  833.         -- I need to have this turtle take advantage of the autonomous activator I placed a while ago.
  834.         turtle.forward()
  835.         turtle.dropDown(1)
  836.         redstoneImpulseOnBottom()
  837.         turtle.back()
  838.     end
  839.    
  840.     TravelToPosition(4, 3)
  841.    
  842.     local success, item = turtle.inspectDown()
  843.     if not success then
  844.         EquipCropSticks()
  845.         turtle.placeDown()
  846.     end
  847.    
  848.     -- At this point, we will have crop sticks properly placed on the ground. Let's check for the existance of seeds on the left/middle/right
  849.     TravelToPosition(2, 2)
  850.     local analyzer = peripheral.wrap("bottom")
  851.     local leftHasPlant = analyzer.hasPlant(frontCompassDirection)
  852.      
  853.     TravelToPosition(3, 2)
  854.     local analyzer = peripheral.wrap("bottom")
  855.     local middleHasPlant = analyzer.hasPlant(frontCompassDirection)
  856.      
  857.     TravelToPosition(4, 2)
  858.     local analyzer = peripheral.wrap("bottom")
  859.     local rightHasPlant = analyzer.hasPlant(frontCompassDirection)
  860.      
  861.     print("Left  Has Plant: "..textutils.serialise(leftHasPlant))
  862.     print("Mid   Has Plant: "..textutils.serialise(middleHasPlant))
  863.     print("Right Has Plant: "..textutils.serialise(rightHasPlant))
  864.    
  865.     if not leftHasPlant then
  866.         SuckUpNewSeed(1)
  867.         if leftSeedName ~= turtle.getItemDetail().name then
  868.             ResetSaveData()
  869.         end
  870.         leftSeedName = turtle.getItemDetail().name
  871.         print("Left Seed Name: "..textutils.serialise(leftSeedName))
  872.         TravelToPosition(2, 2)
  873.         seed1 = AnalyzeSeedAtCurrentLocation()
  874.         PlantSeedOnLeft()
  875.     end
  876.    
  877.     if not rightHasPlant then
  878.         SuckUpNewSeed(1)
  879.         if rightSeedName ~= turtle.getItemDetail().name then
  880.             ResetSaveData()
  881.         end
  882.         rightSeedName = turtle.getItemDetail().name
  883.         print("Right Seed Name: "..textutils.serialise(rightSeedName))
  884.         TravelToPosition(4, 2)
  885.         seed2 = AnalyzeSeedAtCurrentLocation()
  886.         PlantSeedOnRight()
  887.     end
  888. end
  889.  
  890. -- Has the turtle wait until it can detect that an offspring has been produced.
  891. --      Inputs:
  892. --          N/A
  893. --      Outputs:
  894. --          N/A
  895. WaitForOffspring =
  896. function()
  897.     TravelToPosition(3, 2) -- Travel to analyzer that detects if a plant is there.
  898.     local analyzer = peripheral.wrap("bottom")
  899.     local offspringFound = analyzer.hasPlant(frontCompassDirection)
  900.    
  901.     while not offspringFound do
  902.         os.sleep(5)
  903.         offspringFound = analyzer.hasPlant(frontCompassDirection)
  904.                
  905.         if not offspringFound then -- If we can't find the offspring, let's confirm it's possible, by checking if it's a cross crop. If it isn't, we need to fix it.
  906.             local isCrossCrop = analyzer.isCrossCrop(frontCompassDirection)
  907.             if not isCrossCrop then
  908.                 print("Crop Sticks missing at offspring location. Correcting.")
  909.                 TravelToPosition(3, 4)
  910.                 EquipCropSticks()
  911.                 turtle.dropDown(1)
  912.                 redstoneImpulseOnBottom()
  913.                 TravelToPosition(3, 2)
  914.             end
  915.            
  916.             if useBoneMealOnMiddlePosition then
  917.                 EquipBoneMeal()
  918.                 -- Have turtle place bone meal below itself 10 times.
  919.                 if boneMealPosition ~= nil then
  920.                     TravelToPosition(3, 3)
  921.                     for i = 1, 10, 1 do
  922.                         if boneMealPosition ~= nil then turtle.placeDown() end
  923.                         EquipBoneMeal()
  924.                     end
  925.                     TravelToPosition(3, 2)
  926.                 end
  927.             end
  928.         end
  929.     end
  930.    
  931.     print("Found Offspring!")
  932. end
  933.  
  934. -- Function to eliminate parent 1, and replace with the current offspring.
  935. --      Inputs:
  936. --          Table offspring { int X, int Y, int Z, int Fitness }
  937. --      Outputs:
  938. --          N/A
  939. PlantOffSpringOnSeed1 =
  940. function(offspring)
  941.     local index = ScanForItemInInventoryByName("seed", true)
  942.     seed1 = offspring
  943.    
  944.     TravelToPosition(2, 3)
  945.    
  946.     EquipCropSticks()
  947.     if turtle.getItemCount() == 64 then turtle.drop(1) end -- We have 64 crop sticks, so drop 1 to avoid making 2 stacks.
  948.     turtle.digDown()
  949.     turtle.placeDown()
  950.     turtle.select(index)
  951.     PlantSeedOnLeft()
  952.     PurgeInventoryOfExtraneousItems()
  953. end
  954.  
  955. -- Function to eliminate parent 2, and replace with the current offspring.
  956. --      Inputs:
  957. --          Table offspring { int X, int Y, int Z, int Fitness }
  958. --      Outputs:
  959. --          N/A
  960. PlantOffSpringOnSeed2 =
  961. function(offspring)
  962.     local index = ScanForItemInInventoryByName("seed", true)
  963.     seed2 = offspring
  964.    
  965.     TravelToPosition(4, 3)
  966.    
  967.     EquipCropSticks()
  968.     if turtle.getItemCount() == 64 then turtle.drop(1) end -- We have 64 crop sticks, so drop 1 to avoid making 2 stacks.
  969.     turtle.digDown()
  970.     turtle.placeDown()
  971.     turtle.select(index)
  972.     PlantSeedOnRight()
  973.     PurgeInventoryOfExtraneousItems()
  974. end
  975.  
  976. -- Function to reject our current offspring (Probably throw it away in a trash can or something...)
  977. --      Inputs:
  978. --          N/A
  979. --      Outputs:
  980. --          N/A
  981. RejectOffspring =
  982. function()
  983.     local index = ScanForItemInInventoryByName("seed", true)
  984.     ThrowStackAway(index)
  985. end
  986.  
  987. -- Function to save our offspring (Probably put into a chest or something...)
  988. -- Call this if the offspring, as well as both parents, are 10/10/10 seeds.
  989. --      Inputs:
  990. --          N/A
  991. --      Outputs:
  992. --          N/A
  993. SaveOffspring =
  994. function()
  995.     currentNumberOfPerfectSeedsBred = currentNumberOfPerfectSeedsBred + 1
  996.     local index = ScanForItemInInventoryByName("seed", true)
  997.     SaveStack(index)
  998. end
  999.  
  1000. -- Function to analyze the offspring seed, and determine if it should replace either parent or be rejected.
  1001. -- At this point, the seed has already been harvested/analyzed,
  1002. -- and we just need to determine whether we reject it, or replace one of our parents with it.
  1003. --      Inputs:
  1004. --          Table offspring { int X, int Y, int Z, int Fitness }
  1005. --      Outputs:
  1006. --          N/A
  1007. HarvestedOffspring =
  1008. function(offspring)
  1009.     print("HarvestedOffspring -> Get Fitness on Seed 1.")
  1010.     GetSeedFitness(seed1)
  1011.     print("HarvestedOffspring -> Get Fitness on Seed 2.")
  1012.     GetSeedFitness(seed2)
  1013.     print("HarvestedOffspring -> Get Fitness on Seed 3.")
  1014.     GetSeedFitness(offspring)
  1015.  
  1016.     -- If we have perfect genetics in both parents and our offspring, save our offspring.
  1017.     if seed1["Fitness"] == perfectFitnessValue and seed2["Fitness"] == perfectFitnessValue and offspring["Fitness"] == perfectFitnessValue then
  1018.         print("We have seeds with perfect genetics! Saving Seed.")
  1019.         SaveOffspring()
  1020.         return
  1021.     end
  1022.    
  1023.     -- This means that we have found ourselves a seed which needs to replace either of it's parents.
  1024.     if offspring["Fitness"] > seed1["Fitness"] or offspring["Fitness"] > seed2["Fitness"] then
  1025.         if seed1["Fitness"] <= seed2["Fitness"] then
  1026.             -- Seed 1 is worse than or equal to Seed 2, so let's replace Seed 1.
  1027.             print("Replacing Seed 1. Fitness: "..seed1["Fitness"].." -> "..offspring["Fitness"])
  1028.             PlantOffSpringOnSeed1(offspring)
  1029.         else
  1030.             -- Seed 2 is worse than seed 1, so let's replace Seed 2.
  1031.             print("Replacing Seed 2. Fitness: "..seed2["Fitness"].." -> "..offspring["Fitness"])
  1032.             PlantOffSpringOnSeed2(offspring)
  1033.         end
  1034.        
  1035.         generation = generation + 1
  1036.         print("\tGeneration: "..generation)
  1037.         return
  1038.     end
  1039.  
  1040.     if offspring["Fitness"] <= seed1["Fitness"] or offspring["Fitness"] <= seed2["Fitness"] then
  1041.         -- This means we have a bad seed, so let's reject it.
  1042.         generation = generation + 1
  1043.         print("Rejected Seed.\r\n\tGeneration: "..generation)
  1044.         RejectOffspring()
  1045.     end
  1046. end
  1047.  
  1048. -- Function to harvest the current offspring.
  1049. --      Inputs:
  1050. --          N/A
  1051. --      Outputs:
  1052. --          N/A
  1053. HarvestOffspring =
  1054. function()
  1055.     EquipCropSticks()
  1056.     if turtle.getItemCount() == 64 then turtle.drop(1) end -- Drop 1 crop stick since we need room for 1 when we harvest this seed. This is to avoid accidentally having 2 stacks of crop sticks.
  1057.     turtle.forward()
  1058.     turtle.digDown()
  1059.     turtle.placeDown()
  1060.     turtle.forward()
  1061.     turtle.dropDown(1)
  1062.     redstoneImpulseOnBottom()
  1063.     turtle.back()
  1064.     turtle.back()
  1065. end
  1066.  
  1067. -- Function to clean up after the turtle has finished.
  1068. -- (Basically just reinitializes the data.)
  1069. --      Inputs:
  1070. --          N/A
  1071. --      Outputs:
  1072. --          N/A
  1073. CleanUp =
  1074. function()
  1075.     currentNumberOfPerfectSeedsBred = 0
  1076.     seed1 = {X = 1, Y = 1, Z = 1, Fitness = nil} -- Stores the Left seed or "parent"
  1077.     seed2 = {X = 1, Y = 1, Z = 1, Fitness = nil} -- Stores the Right seed or "parent"
  1078.     generation = 1 -- Stores the number of generations it took to get to our current set of parents.
  1079.     leftSeedName = "" -- Stores the name of the seed type we are currently breeding.
  1080.     rightSeedName = "" -- Stores the name of the right seed type we are currently breeding.
  1081.     childSeedName = "" -- Stores the name of the child seed type we are currently breeding.
  1082.     EquipCropSticks() -- Equip Crop Sticks before we clean up after ourselves, to try to prevent accidentally creating duplicate stacks. This is because digging items puts them into the turtle's inventory at the slot that's currently selected.
  1083.     TravelToPosition(2, 3)
  1084.     turtle.digDown()
  1085.     TravelToPosition(3, 3)
  1086.     turtle.digDown()
  1087.     TravelToPosition(4, 3)
  1088.     turtle.digDown()
  1089.     PurgeInventoryOfExtraneousItems()
  1090. end
  1091.  
  1092. -- Loads pertinent Data.
  1093. --      Inputs:
  1094. --          N/A
  1095. --      Outputs:
  1096. --          N/A
  1097. Load =
  1098. function()
  1099.     if not fs.exists("MatthewC/Agricraft/Data/SeedBreederData") then return end
  1100.    
  1101.     local h = fs.open("MatthewC/Agricraft/Data/SeedBreederData", "r") -- "r" is read only
  1102.     local data = h.readAll()
  1103.    
  1104.     if data ~= nil then
  1105.         local parsedData = textutils.unserialize(data)
  1106.         currentNumberOfPerfectSeedsBred = parsedData["CurrentNumberOfPerfectSeedsBred"]
  1107.         seed1 = parsedData["Seed1"]
  1108.         seed2 = parsedData["Seed2"]
  1109.         generation = parsedData["Generation"]
  1110.         leftSeedName = parsedData["LeftSeedName"]
  1111.         rightSeedName = parsedData["RightSeedName"]
  1112.         childSeedName = parsedData["ChildSeedName"]
  1113.    
  1114.         loadedData = true
  1115.     else
  1116.         print("Attempted to load --- Data was nil")
  1117.     end
  1118.    
  1119.     -- No need to call close on h if it's read mode.
  1120.     h = fs.open("MatthewC/Agricraft/Data/SeedBreederSettings", "r") -- "r" is read only
  1121.     data = h.readAll()
  1122.    
  1123.     if data ~= nil then
  1124.         local parsedData = textutils.unserialize(data)
  1125.         if parsedData["NumberOfPerfectSeedsToBreed"] then numberOfPerfectSeedsToBreed = parsedData["NumberOfPerfectSeedsToBreed"] end
  1126.         if parsedData["BlockNameBorderRight"] then blockNameBorderRight = parsedData["BlockNameBorderRight"] end
  1127.         if parsedData["BlockNameBorderLeft"] then blockNameBorderLeft = parsedData["BlockNameBorderLeft"] end
  1128.         if parsedData["BlockNameBorderFront"] then blockNameBorderFront = parsedData["BlockNameBorderFront"] end
  1129.         if parsedData["BlockNameBorderBack"] then blockNameBorderBack = parsedData["BlockNameBorderBack"] end
  1130.         if parsedData["BlockNameSeedAnalyzer"] then blockNameSeedAnalyzer = parsedData["BlockNameSeedAnalyzer"] end
  1131.         if parsedData["ItemNameCropSticks"] then itemNameCropSticks = parsedData["ItemNameCropSticks"] end
  1132.         if parsedData["ItemNameFuel"] then itemNameFuel = parsedData["ItemNameFuel"] end
  1133.         if parsedData["ItemNameBoneMeal"] then itemNameBoneMeal = parsedData["ItemNameBoneMeal"] end
  1134.         if parsedData["ItemMetaDataBoneMeal"] then itemMetaDataBoneMeal = parsedData["ItemMetaDataBoneMeal"] end
  1135.         if parsedData["FrontCompassDirection"] then frontCompassDirection = parsedData["FrontCompassDirection"] end
  1136.         if parsedData["UseBoneMealOnCenter"] then useBoneMealOnCenter = parsedData["UseBoneMealOnCenter"] end
  1137.     end
  1138.    
  1139.     Save()
  1140. end
  1141.  
  1142. -- Saves the pertinent Data.
  1143. --      Inputs:
  1144. --          N/A
  1145. --      Outputs:
  1146. --          N/A
  1147. Save =
  1148. function()
  1149.     -- Create appropriate directories as necessary.
  1150.     if not fs.exists("MatthewC") then fs.makeDir("MatthewC") end
  1151.     if not fs.exists("MatthewC/Agricraft") then fs.makeDir("MatthewC/Agricraft") end
  1152.     if not fs.exists("MatthewC/Agricraft/Data") then fs.makeDir("MatthewC/Agricraft/Data") end
  1153.    
  1154.     local dataToSave =
  1155.     {
  1156.         CurrentNumberOfPerfectSeedsBred = currentNumberOfPerfectSeedsBred,
  1157.         Seed1 = seed1,
  1158.         Seed2 = seed2,
  1159.         Generation = generation,
  1160.         LeftSeedName = leftSeedName,
  1161.         RightSeedName = rightSeedName,
  1162.         ChildSeedName = childSeedName
  1163.     }
  1164.    
  1165.     local writer = fs.open("MatthewC/Agricraft/Data/SeedBreederData", "w") -- "w" is write Mode
  1166.     writer.write(textutils.serialise(dataToSave))
  1167.     writer.close()
  1168.    
  1169.     dataToSave =
  1170.     {
  1171.         NumberOfPerfectSeedsToBreed = numberOfPerfectSeedsToBreed,
  1172.         BlockNameBorderRight = blockNameBorderRight,
  1173.         BlockNameBorderLeft = blockNameBorderLeft,
  1174.         BlockNameBorderFront = blockNameBorderFront,
  1175.         BlockNameBorderBack = blockNameBorderBack,
  1176.         BlockNameSeedAnalyzer = blockNameSeedAnalyzer,
  1177.         ItemNameCropSticks = itemNameCropSticks,
  1178.         ItemNameFuel = itemNameFuel,
  1179.         ItemNameBoneMeal = itemNameBoneMeal,
  1180.         ItemMetaDataBoneMeal = itemMetaDataBoneMeal,
  1181.         FrontCompassDirection = frontCompassDirection,
  1182.         UseBoneMealOnCenter = useBoneMealOnCenter
  1183.     }
  1184.    
  1185.     writer = fs.open("MatthewC/Agricraft/Data/SeedBreederSettings", "w") -- "w" is write Mode
  1186.     writer.write(textutils.serialise(dataToSave))
  1187.     writer.close()
  1188. end
  1189.  
  1190. -- Main program entry point.
  1191. --      Inputs:
  1192. --          N/A
  1193. --      Outputs:
  1194. --          N/A
  1195. MainExecutionLoop =
  1196. function()
  1197.     Load()
  1198.    
  1199.     -- Special case to handle if the turtle was turned on the first time, search for coal in inventory and refuel off it.
  1200.     if turtle.getFuelLevel() == 0 then
  1201.         print("We are out of fuel. Attempting to refuel.")
  1202.         HandleFuel()
  1203.        
  1204.         if turtle.getFuelLevel() == 0 then
  1205.             print("\r\n\r\n***WARNING!!! NO FUEL DETECTED!!!***")
  1206.             print("\r\nPlease put coal or charcoal in my inventory, and restart the program.")
  1207.             return
  1208.         end
  1209.     end
  1210.    
  1211.     ResetLocationToCenter()
  1212.     while true do
  1213.         PurgeInventoryOfExtraneousItems()
  1214.         PrepareForPlanting()
  1215.        
  1216.         print("Current Number of bred Perfect Seeds: "..textutils.serialize(currentNumberOfPerfectSeedsBred))
  1217.         print("Number of perfect seeds to breed: "..textutils.serialize(numberOfPerfectSeedsToBreed))
  1218.        
  1219.         while currentNumberOfPerfectSeedsBred < numberOfPerfectSeedsToBreed do
  1220.             EquipBoneMeal(true) -- Call equip bonemeal, while allowing for refilling.
  1221.             print("Left Seed="..textutils.serialise(seed1))
  1222.             print("Right Seed="..textutils.serialise(seed2))
  1223.             print("Generation: "..textutils.serialise(generation))
  1224.             print("Number of perfect seeds bred: "..textutils.serialise(currentNumberOfPerfectSeedsBred))
  1225.             print("Waiting for Offspring")
  1226.             WaitForOffspring() -- Wait until we can harvest the offspring.
  1227.             print("Harvesting Offspring")
  1228.             HarvestOffspring()
  1229.             print("Detecting index in inventory that offspring was placed in")
  1230.             local offspringIndex = ScanForItemInInventoryByName("seed", true) -- Determine where in the turtle's inventory the seed is at. Note: performs a case-insensitive search.
  1231.            
  1232.             if offspringIndex ~= nil then
  1233.                 TravelToPosition(3, 2) -- Travel above a Seed Analyzer
  1234.                 turtle.select(offspringIndex) -- select the index that the seed is at.
  1235.                 print("Analyzing Offspring")
  1236.                 local offspringData = AnalyzeSeedAtCurrentLocation() -- analyze the seed at the current location.
  1237.                
  1238.                 if offspringData ~= nil then
  1239.                     print("Evaluating offspring")
  1240.                     print("offspring="..textutils.serialize(offspringData))
  1241.                     HarvestedOffspring(offspringData)
  1242.                 else
  1243.                     print("Anomaly detected: Offspring was nil. Purging Inventory and continuing.")
  1244.                     PurgeInventoryOfExtraneousItems()
  1245.                 end
  1246.             end
  1247.            
  1248.             os.sleep(.1)
  1249.             loadedData = false -- Set our flag for loadedData to false here...
  1250.             Save()
  1251.         end
  1252.        
  1253.         CleanUp()
  1254.     end
  1255. end
  1256.  
  1257.  
  1258.  
  1259. --------------------------------------------------------------------------------------------------
  1260. -- Unit Tests
  1261. --      Collection of test functions to confirm that this software works properly.
  1262. --------------------------------------------------------------------------------------------------
  1263.  
  1264. -- Test function to tavel to all possible locations.
  1265. -- Pass in true to require user intervention.
  1266. function TestTravelToPosition(waitForUserIntevention)
  1267.     print("Running Traveling Diagnostics")
  1268.  
  1269.     for x = 1, 5, 1 do
  1270.         for z = 1, 4, 1 do
  1271.             print("Traveling to X="..x..", Z="..z)
  1272.             TravelToPosition(x, z)
  1273.             if waitForUserInvervention then
  1274.                 print("Press Any Key to Continue")
  1275.                 os.pullEvent("key")
  1276.             end
  1277.         end
  1278.     end
  1279. end
  1280.  
  1281. --ResetLocationToCenter() -- IF ANY TEST METHODS ARE CALLED, THIS MUST BE CALLED FIRST!!!
  1282. --TestTravelToPosition()
  1283. --ThrowStackAway(15)
  1284. --SaveStack(16)
  1285. --EquipCropSticks()
  1286. --PrepareForPlanting()
  1287. --HandleFuel()
  1288. --WaitForOffspring()
  1289.  
  1290. --local data = ScanForItemInInventoryByName("seed", true)
  1291. --print("Data: "..textutils.serialise(data))
  1292. --os.sleep(10)
  1293.  
  1294. --------------------------------------------------------------------------------------------------
  1295. -- Post-Initialization
  1296. --      Initializes the rest of the data after our functions have been defined
  1297. --------------------------------------------------------------------------------------------------
  1298.  
  1299. -- Call GetSeedFitness to initialize the property in seed1 and seed2.
  1300. GetSeedFitness(seed1)
  1301. GetSeedFitness(seed2)
  1302.  
  1303. -- Calculate the perfect Fitness Value attainable.
  1304. perfectFitnessValue  = GetSeedFitness({X = 10, Y = 10, Z = 10, Fitness = nil})
  1305.  
  1306. --------------------------------------------------------------------------------------------------
  1307. -- Execution
  1308. --      Kicks off the actual program which needs to be executed.
  1309. --------------------------------------------------------------------------------------------------
  1310. print("Seed Breeder Initialized ---")
  1311. print("Perfect Fitness Allowable: "..perfectFitnessValue)
  1312. print("Perfect Seeds to breed: "..numberOfPerfectSeedsToBreed)
  1313.  
  1314. print("\r\n\r\nBeginning Main execution Loop: -- Breeding seeds.")
  1315. MainExecutionLoop()
  1316.  
  1317. print("\r\nProgram Terminated.")
  1318. print("Press any key to continue")
  1319. os.pullEvent("key")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement