Advertisement
Machuga14

Minecraft Agricraft AutoBreeder (Turtles)

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