View difference between Paste ID: ujc8q3PQ and B2ysGWsA
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]
22
-- type should be either dome or sphere
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]
31
radius = tonumber(arg[2])
32
33
cost_only = false
34
blocks = 0
35
if arg[3] == "-c" then
36
  cost_only = true
37
end
38
39
-- Navigation features
40
-- allow the turtle to move while tracking its position
41
-- this allows us to just give a destination point and have it go there
42
43
positionx = radius
44
positiony = radius
45
facing = 0
46
47
function turnRightTrack()
48
  turtle.turnRight()
49
  facing = facing + 1
50
  if facing >= 4 then
51
    facing = 0
52
  end
53
end
54
55
function turnLeftTrack()
56
  turtle.turnLeft()
57
  facing = facing - 1
58
  if facing < 0 then
59
    facing = 3
60
  end
61
end
62
63
function safeForward()
64
  success = false
65
  while not success do
66
    success = turtle.forward()
67
    if not success then
68
      print("Blocked attempting to move forward.")
69
      print("Please clear and press enter to continue.")
70
      io.read()
71
    end
72
  end
73
end
74
75
function safeBack()
76
  success = false
77
  while not success do
78
    success = turtle.back()
79
    if not success then
80
      print("Blocked attempting to move back.")
81
      print("Please clear and press enter to continue.")
82
      io.read()
83
    end
84
  end
85
end
86
87
function safeUp()
88
  success = false
89
  while not success do
90
    success = turtle.up()
91
    if not success then
92
      print("Blocked attempting to move up.")
93
      print("Please clear and press enter to continue.")
94
      io.read()
95
    end
96
  end
97
end
98
99
function moveY(targety)
100
  if targety == positiony then
101
    return
102
  end
103
  
104
  if (facing ~= 0 and facing ~= 2) then -- check axis
105
    turnRightTrack()
106
  end
107
  
108
  while targety > positiony do
109
    if facing == 0 then
110
      safeForward()
111
    else
112
      safeBack()
113
    end
114
    positiony = positiony + 1
115
  end
116
  
117
  while targety < positiony do
118
    if facing == 2 then
119
      safeForward()
120
    else
121
      safeBack()
122
    end
123
    positiony = positiony - 1
124
  end
125
end
126
127
function moveX(targetx)
128
  if targetx == positionx then
129
    return
130
  end
131
  
132
  if (facing ~= 1 and facing ~= 3) then -- check axis
133
    turnRightTrack()
134
  end
135
  
136
  while targetx > positionx do
137
    if facing == 1 then
138
      safeForward()
139
    else
140
      safeBack()
141
    end
142
    positionx = positionx + 1
143
  end
144
  
145
  while targetx < positionx do
146
    if facing == 3 then
147
      safeForward()
148
    else
149
      safeBack()
150
    end
151
    positionx = positionx - 1
152
  end
153
end
154
155
function navigateTo(targetx, targety)
156
  -- Cost calculation mode - don't move
157
  if cost_only then
158
    return
159
  end
160
  
161
  if facing == 0 or facing == 2 then -- Y axis
162
    moveY(targety)
163
    moveX(targetx)
164
  else
165
    moveX(targetx)
166
    moveY(targety)
167
  end
168
end
169
170
cslot = 1
171
function placeBlock()
172
  -- Cost calculation mode - don't move
173
  blocks = blocks + 1
174
  if cost_only then
175
    return
176
  end
177
  
178
  if turtle.getItemCount(cslot) == 0 then
179
    foundSlot = false
180
    while not foundSlot do
181
      for i = 1,9 do
182
        if turtle.getItemCount(i) > 0 then
183
          foundSlot = i
184
          break
185
        end
186
      end
187
      if not foundSlot then
188
        -- No resources
189
        print("Out of building materials. Please refill and press enter to continue.")
190
        io.read()
191
      end
192
    end
193
    cslot = foundSlot
194
    turtle.select(foundSlot)
195
  end
196
  
197
  turtle.placeDown()
198
end
199
200
-- Main dome and sphere building routine
201
202
width = radius * 2 + 1
203
sqrt3 = 3 ^ 0.5
204
boundary_radius = radius + 1.0
205
boundary2 = boundary_radius ^ 2
206
207
if type == "dome" then
208
  zstart = radius
209
elseif type == "sphere" then
210
  zstart = 0
211
else
212
  print("Usage: sdbuild <shape> <radius> [-c]")
213
  os.exit(1)
214
end
215
zend = width - 1
216
217
-- This loop is for each vertical layer through the sphere or dome.
218
for z = zstart,zend do
219
  if not cost_only then
220
    safeUp()
221
  end
222
  print("Layer " .. z)
223
  cz2 = (radius - z) ^ 2
224
  
225
  limit_offset_y = (boundary2 - cz2) ^ 0.5
226
  max_offset_y = math.ceil(limit_offset_y)
227
  
228
  -- We do first the +x side, then the -x side to make movement efficient
229
  for side = 0,1 do
230
    -- On the right we go from small y to large y, on the left reversed
231
    -- This makes us travel clockwise around each layer
232
    if (side == 0) then
233
      ystart = radius - max_offset_y
234
      yend = radius + max_offset_y
235
      ystep = 1
236
    else
237
      ystart = radius + max_offset_y
238
      yend = radius - max_offset_y
239
      ystep = -1
240
    end
241
    
242
    for y = ystart,yend,ystep do
243
      cy2 = (radius - y) ^ 2
244
      
245
      remainder2 = (boundary2 - cz2 - cy2)
246
      
247
      
248
      if remainder2 >= 0 then
249
        -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
250
        max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
251
        
252
        -- Only do either the +x or -x side
253
        if (side == 0) then
254
          -- +x side
255
          xstart = radius
256
          xend = radius + max_offset_x
257
        else
258
          -- -x side
259
          xstart = radius - max_offset_x
260
          xend = radius - 1
261
        end
262
        
263
        -- Reverse direction we traverse xs when in -y side
264
        if y > radius then
265
          temp = xstart
266
          xstart = xend
267
          xend = temp
268
          xstep = -1
269
        else
270
          xstep = 1
271
        end
272
        
273
        for x = xstart,xend,xstep do
274
          cx2 = (radius - x) ^ 2
275
          distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
276
          -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
277
          if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
278
            offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
279
            for i=1,6 do
280
              offset = offsets[i]
281
              dx = offset[1]
282
              dy = offset[2]
283
              dz = offset[3]
284
              if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
285
                -- This is a point to use
286
                navigateTo(x, y)
287
                placeBlock()
288
                break
289
              end
290
            end
291
          end
292
        end
293
      end
294
    end
295
  end
296
end
297
298
-- Return to where we started in x,y place and turn to face original direction
299
-- Don't change vertical place though - should be solid under us!
300
navigateTo(radius, radius)
301
while (facing > 0) do
302
  turnLeftTrack()
303
end
304
305
print("Blocks used: " .. blocks)