pruby

sdbuild_layers

Jan 13th, 2013
727
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Dome and sphere builder.
  2. -- Copyright (C) 2012 Timothy Goddard
  3. --
  4. -- Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. -- this software and associated documentation files (the "Software"), to deal in
  6. -- the Software without restriction, including without limitation the rights to
  7. -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  8. -- the Software, and to permit persons to whom the Software is furnished to do so,
  9. -- subject to the following conditions:
  10. --
  11. -- The above copyright notice and this permission notice shall be included in all
  12. -- copies or substantial portions of the Software.
  13. --
  14. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  16. -- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  17. -- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  18. -- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  19. -- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20. --
  21. -- usage: sdbuild <radius> [-c] [-sz <start layer>] [-ez <end layer>]
  22. -- to build a dome, call sdbuild <radius> -sz <radius>
  23. -- radius is distance from centre - total width is actually 2 * radius + 1
  24. -- the structure will be built with its lowest point on the level the turtle is at
  25. -- the block the turtle starts on will be the horizontal centre
  26. -- if -c is passed, will only calculate number of blocks required and not build
  27.  
  28. local arg = { ... }
  29.  
  30. radius = tonumber(arg[1])
  31.  
  32. cost_only = false
  33. blocks = 0
  34.  
  35. -- Navigation features
  36. -- allow the turtle to move while tracking its position
  37. -- this allows us to just give a destination point and have it go there
  38.  
  39. positionx = radius
  40. positiony = radius
  41. facing = 0
  42.  
  43. function turnRightTrack()
  44.   turtle.turnRight()
  45.   facing = facing + 1
  46.   if facing >= 4 then
  47.     facing = 0
  48.   end
  49. end
  50.  
  51. function turnLeftTrack()
  52.   turtle.turnLeft()
  53.   facing = facing - 1
  54.   if facing < 0 then
  55.     facing = 3
  56.   end
  57. end
  58.  
  59. function safeForward()
  60.   success = false
  61.   while not success do
  62.     success = turtle.forward()
  63.     if not success then
  64.       print("Blocked attempting to move forward.")
  65.       print("Please clear and press enter to continue.")
  66.       io.read()
  67.     end
  68.   end
  69. end
  70.  
  71. function safeBack()
  72.   success = false
  73.   while not success do
  74.     success = turtle.back()
  75.     if not success then
  76.       print("Blocked attempting to move back.")
  77.       print("Please clear and press enter to continue.")
  78.       io.read()
  79.     end
  80.   end
  81. end
  82.  
  83. function safeUp()
  84.   success = false
  85.   while not success do
  86.     success = turtle.up()
  87.     if not success then
  88.       print("Blocked attempting to move up.")
  89.       print("Please clear and press enter to continue.")
  90.       io.read()
  91.     end
  92.   end
  93. end
  94.  
  95. function moveY(targety)
  96.   if targety == positiony then
  97.     return
  98.   end
  99.  
  100.   if (facing ~= 0 and facing ~= 2) then -- check axis
  101.     turnRightTrack()
  102.   end
  103.  
  104.   while targety > positiony do
  105.     if facing == 0 then
  106.       safeForward()
  107.     else
  108.       safeBack()
  109.     end
  110.     positiony = positiony + 1
  111.   end
  112.  
  113.   while targety < positiony do
  114.     if facing == 2 then
  115.       safeForward()
  116.     else
  117.       safeBack()
  118.     end
  119.     positiony = positiony - 1
  120.   end
  121. end
  122.  
  123. function moveX(targetx)
  124.   if targetx == positionx then
  125.     return
  126.   end
  127.  
  128.   if (facing ~= 1 and facing ~= 3) then -- check axis
  129.     turnRightTrack()
  130.   end
  131.  
  132.   while targetx > positionx do
  133.     if facing == 1 then
  134.       safeForward()
  135.     else
  136.       safeBack()
  137.     end
  138.     positionx = positionx + 1
  139.   end
  140.  
  141.   while targetx < positionx do
  142.     if facing == 3 then
  143.       safeForward()
  144.     else
  145.       safeBack()
  146.     end
  147.     positionx = positionx - 1
  148.   end
  149. end
  150.  
  151. function navigateTo(targetx, targety)
  152.   -- Cost calculation mode - don't move
  153.   if cost_only then
  154.     return
  155.   end
  156.  
  157.   if facing == 0 or facing == 2 then -- Y axis
  158.     moveY(targety)
  159.     moveX(targetx)
  160.   else
  161.     moveX(targetx)
  162.     moveY(targety)
  163.   end
  164. end
  165.  
  166. cslot = 1
  167. function placeBlock()
  168.   -- Cost calculation mode - don't move
  169.   blocks = blocks + 1
  170.   if cost_only then
  171.     return
  172.   end
  173.  
  174.   if turtle.getItemCount(cslot) == 0 then
  175.     foundSlot = false
  176.     while not foundSlot do
  177.       for i = 1,9 do
  178.         if turtle.getItemCount(i) > 0 then
  179.           foundSlot = i
  180.           break
  181.         end
  182.       end
  183.       if not foundSlot then
  184.         -- No resources
  185.         print("Out of building materials. Please refill and press enter to continue.")
  186.         io.read()
  187.       end
  188.     end
  189.     cslot = foundSlot
  190.     turtle.select(foundSlot)
  191.   end
  192.  
  193.   turtle.placeDown()
  194. end
  195.  
  196. -- Main dome and sphere building routine
  197.  
  198. width = radius * 2 + 1
  199. sqrt3 = 3 ^ 0.5
  200. boundary_radius = radius + 1.0
  201. boundary2 = boundary_radius ^ 2
  202.  
  203. zstart = 0
  204. zend = width - 1
  205.  
  206. for argn=2,#arg do
  207.   if arg[argn] == "-c" then
  208.     cost_only = true
  209.   elseif arg[argn] == "-sz" then
  210.     zstart = tonumber(arg[argn + 1]) - 1
  211.     argn = argn + 1
  212.   elseif arg[argn] == "-ez" then
  213.     zend = tonumber(arg[argn + 1]) - 1
  214.     argn = argn + 1
  215.   else
  216.     print("Unrecognised argument: " .. arg[argn])
  217.     print("Usage: sdbuild <radius> [-c] [-sz <start layer>] [-ez <end layer>]")
  218.     os.exit(1)
  219.   end
  220. end
  221.  
  222. -- This loop is for each vertical layer through the sphere or dome.
  223. for z = zstart,zend do
  224.   if not cost_only then
  225.     safeUp()
  226.   end
  227.   print("Layer " .. z)
  228.   cz2 = (radius - z) ^ 2
  229.  
  230.   limit_offset_y = (boundary2 - cz2) ^ 0.5
  231.   max_offset_y = math.ceil(limit_offset_y)
  232.  
  233.   -- We do first the +x side, then the -x side to make movement efficient
  234.   for side = 0,1 do
  235.     -- On the right we go from small y to large y, on the left reversed
  236.     -- This makes us travel clockwise around each layer
  237.     if (side == 0) then
  238.       ystart = radius - max_offset_y
  239.       yend = radius + max_offset_y
  240.       ystep = 1
  241.     else
  242.       ystart = radius + max_offset_y
  243.       yend = radius - max_offset_y
  244.       ystep = -1
  245.     end
  246.    
  247.     for y = ystart,yend,ystep do
  248.       cy2 = (radius - y) ^ 2
  249.      
  250.       remainder2 = (boundary2 - cz2 - cy2)
  251.      
  252.      
  253.       if remainder2 >= 0 then
  254.         -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
  255.         max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
  256.        
  257.         -- Only do either the +x or -x side
  258.         if (side == 0) then
  259.           -- +x side
  260.           xstart = radius
  261.           xend = radius + max_offset_x
  262.         else
  263.           -- -x side
  264.           xstart = radius - max_offset_x
  265.           xend = radius - 1
  266.         end
  267.        
  268.         -- Reverse direction we traverse xs when in -y side
  269.         if y > radius then
  270.           temp = xstart
  271.           xstart = xend
  272.           xend = temp
  273.           xstep = -1
  274.         else
  275.           xstep = 1
  276.         end
  277.        
  278.         for x = xstart,xend,xstep do
  279.           cx2 = (radius - x) ^ 2
  280.           distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
  281.           -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
  282.           if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
  283.             offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
  284.             for i=1,6 do
  285.               offset = offsets[i]
  286.               dx = offset[1]
  287.               dy = offset[2]
  288.               dz = offset[3]
  289.               if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
  290.                 -- This is a point to use
  291.                 navigateTo(x, y)
  292.                 placeBlock()
  293.                 break
  294.               end
  295.             end
  296.           end
  297.         end
  298.       end
  299.     end
  300.   end
  301. end
  302.  
  303. -- Return to where we started in x,y place and turn to face original direction
  304. -- Don't change vertical place though - should be solid under us!
  305. navigateTo(radius, radius)
  306. while (facing > 0) do
  307.   turnLeftTrack()
  308. end
  309.  
  310. print("Blocks used: " .. blocks)
Advertisement
Add Comment
Please, Sign In to add comment