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) |