View difference between Paste ID: SUJsjAqi and KBJ1wDz0
SHOW: | | - or go back to the newest paste.
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 <type> <radius> [-c]
21+
-- usage: sdbuild <radius> [-c] [-sz <start layer>] [-ez <end layer>]
22-
-- type should be either dome or sphere
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-
type = arg[1]
30+
radius = tonumber(arg[1])
31-
radius = tonumber(arg[2])
31+
32
cost_only = false
33
blocks = 0
34
35-
if arg[3] == "-c" then
35+
36-
  cost_only = true
36+
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 type == "dome" then
207+
  if arg[argn] == "-c" then
208-
  zstart = radius
208+
    cost_only = true
209-
elseif type == "sphere" then
209+
  elseif arg[argn] == "-sz" then
210-
  zstart = 0
210+
    zstart = tonumber(arg[argn + 1]) - 1
211-
else
211+
    argn = argn + 1
212-
  print("Usage: sdbuild <shape> <radius> [-c]")
212+
  elseif arg[argn] == "-ez" then
213-
  os.exit(1)
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)