SHOW:
|
|
- or go back to the newest paste.
1 | --made by me | |
2 | --setup() made by orwell | |
3 | ||
4 | local tArgs = { ... } | |
5 | if #tArgs < 1 then | |
6 | error("Usage: blueprint <gunzipped schematic file>") | |
7 | end | |
8 | ||
9 | if not fs.exists("textutilsFIX") then | |
10 | shell.run("pastebin get 3wguFBXn textutilsFIX") | |
11 | end | |
12 | ||
13 | if not fs.exists("grid") then | |
14 | shell.run("pastebin get EjYUEQqx grid") | |
15 | end | |
16 | ||
17 | shell.run("grid") | |
18 | os.loadAPI("textutilsFIX") | |
19 | ||
20 | local filename = tArgs[1] | |
21 | ||
22 | if not fs.exists(filename) then | |
23 | error("File does not exist.") | |
24 | end | |
25 | ||
26 | - | function save(name,table) |
26 | + | function save(table,name) |
27 | local h = fs.open(name,"w") | |
28 | - | table = textutils.serialize(table) |
28 | + | table = textutilsFIX.serialize(table) |
29 | h.write(table) | |
30 | h.close() | |
31 | end | |
32 | ||
33 | function saveIns(name,table) | |
34 | local h = fs.open(name,"w") | |
35 | h.writeLine(name.." = {}") | |
36 | for i,coord in pairs(table) do | |
37 | h.writeLine(name.."["..i.."] = {"..table.concat(coord,",").."}") | |
38 | h.flush() | |
39 | end | |
40 | h.close() | |
41 | end | |
42 | ||
43 | function saveBlueprint(reference,slots,instructions,uniqueblocks,nTurtle) | |
44 | local fname = filename:gsub("%.(.*)","")..".blueprint" | |
45 | if nTurtle then | |
46 | fname = fname.."["..tostring(nTurtle).."]" | |
47 | end | |
48 | local h = fs.open(fname,"w") | |
49 | h.writeLine("reference ="..textutils.serialize(reference)..";") | |
50 | h.writeLine("slots = "..textutils.serialize(slots)..";") | |
51 | h.writeLine("uniqueblocks = "..textutils.serialize(uniqueblocks)..";") | |
52 | h.writeLine("instructions = "..textutilsFIX.serialize(instructions)..";") | |
53 | h.close() | |
54 | return fname | |
55 | end | |
56 | ||
57 | local block_id = {} | |
58 | ||
59 | block_id[0] = "Air" | |
60 | block_id[1] = "Stone" | |
61 | block_id[2] = "Grass" | |
62 | block_id[3] = "Dirt" | |
63 | block_id[4] = "Cobblestone" | |
64 | block_id[5] = "Wood Planks" | |
65 | block_id[6] = "Sapling" | |
66 | block_id[7] = "Bedrock" | |
67 | block_id[8] = "Water" | |
68 | block_id[9] = "Stationary water" | |
69 | block_id[10] = "Lava" | |
70 | block_id[11] = "Stationary lava" | |
71 | block_id[12] = "Sand" | |
72 | block_id[13] = "Gravel" | |
73 | block_id[14] = "Gold Ore" | |
74 | block_id[15] = "Iron (Ore)" | |
75 | block_id[16] = "Coal Ore" | |
76 | block_id[17] = "Wood" | |
77 | block_id[18] = "Leaves" | |
78 | block_id[19] = "Sponge" | |
79 | block_id[20] = "Glass" | |
80 | block_id[21] = "Lapis Lazuli (Ore)" | |
81 | block_id[22] = "Lapis Lazuli (Block)" | |
82 | block_id[23] = "Dispenser" | |
83 | block_id[24] = "Sandstone" | |
84 | block_id[25] = "Note Block Tile entity" | |
85 | block_id[26] = "Bed" | |
86 | block_id[27] = "Powered Rail " | |
87 | block_id[28] = "Detector Rail " | |
88 | block_id[29] = "Sticky Piston" | |
89 | block_id[30] = "Cobweb" | |
90 | block_id[31] = "Tall Grass" | |
91 | block_id[32] = "Dead Bush" | |
92 | block_id[33] = "Piston" | |
93 | block_id[34] = "Piston Extension" | |
94 | block_id[35] = "Wool" | |
95 | block_id[36] = "Block moved by Piston" | |
96 | block_id[37] = "Dandelionandelion" | |
97 | block_id[38] = "Rose" | |
98 | block_id[39] = "Brown Mushroom" | |
99 | block_id[40] = "Red Mushroom" | |
100 | block_id[41] = "Block of Gold" | |
101 | block_id[42] = "Block of Iron" | |
102 | block_id[43] = "Double Slabs" | |
103 | block_id[44] = "Slabs" | |
104 | block_id[45] = "Brick Block" | |
105 | block_id[46] = "TNT" | |
106 | block_id[47] = "Bookshelf" | |
107 | block_id[48] = "Moss Stone" | |
108 | block_id[49] = "Obsidian" | |
109 | block_id[50] = "Torch" | |
110 | block_id[51] = "Fire" | |
111 | block_id[52] = "Monster Spawner" | |
112 | block_id[53] = "Wooden Stairs" | |
113 | block_id[54] = "Chest" | |
114 | block_id[55] = "Redstone (Wire)" | |
115 | block_id[56] = "Diamond (Ore)" | |
116 | block_id[57] = "Block of Diamond" | |
117 | block_id[58] = "Crafting Table" | |
118 | block_id[59] = "Seeds" | |
119 | block_id[60] = "Farland" | |
120 | block_id[61] = "Furnace" | |
121 | block_id[62] = "Burning Furnace" | |
122 | block_id[63] = "Sign Post" | |
123 | block_id[64] = "Wooden Door" | |
124 | block_id[65] = "Ladders" | |
125 | block_id[66] = "Rails" | |
126 | block_id[67] = "Cobblestone Stairs" | |
127 | block_id[68] = "Wall Sign" | |
128 | block_id[69] = "Lever" | |
129 | block_id[70] = "Stone Pressure Plate" | |
130 | block_id[71] = "Iron Door" | |
131 | block_id[72] = "Wooden Pressure Plates" | |
132 | block_id[73] = "Redstone Ore" | |
133 | block_id[74] = "Glowing Redstone Ore" | |
134 | block_id[75] = "Redstone Torch" | |
135 | block_id[76] = "Redstone Torch" | |
136 | block_id[77] = "Stone Button " | |
137 | block_id[78] = "Snow" | |
138 | block_id[79] = "Ice" | |
139 | block_id[80] = "Snow Block" | |
140 | block_id[81] = "Cactus" | |
141 | block_id[82] = "Clay (Block)" | |
142 | block_id[83] = "Sugar Cane" | |
143 | block_id[84] = "Jukebox" | |
144 | block_id[85] = "Fence" | |
145 | block_id[86] = "Pumpkin" | |
146 | block_id[87] = "Netherrack" | |
147 | block_id[88] = "Soul Sand" | |
148 | block_id[89] = "Glowstone" | |
149 | block_id[90] = "Portal" | |
150 | block_id[91] = "Jack-O-Lantern" | |
151 | block_id[92] = "Cake Block" | |
152 | block_id[93] = "Redstone Repeater" | |
153 | block_id[94] = "Redstone Repeater" | |
154 | block_id[95] = "Stained Glass" | |
155 | block_id[96] = "Trapdoors" | |
156 | block_id[97] = "Hidden Silverfish" | |
157 | block_id[98] = "Stone Bricks" | |
158 | block_id[99] = "Huge brown and red mushroom" | |
159 | block_id[100] = "Huge brown and red mushroom" | |
160 | block_id[101] = "Iron Bars" | |
161 | block_id[102] = "Glass Pane" | |
162 | block_id[103] = "Melon" | |
163 | block_id[104] = "Pumpkin Stem" | |
164 | block_id[105] = "Melon Stem" | |
165 | block_id[106] = "Vines" | |
166 | block_id[107] = "Fence Gate" | |
167 | block_id[108] = "Brick Stairs" | |
168 | block_id[109] = "Stone Brick Stairs" | |
169 | block_id[110] = "Mycelium" | |
170 | block_id[111] = "Lily Pad" | |
171 | block_id[112] = "Nether Brick" | |
172 | block_id[113] = "Nether Brick Fence" | |
173 | block_id[114] = "Nether Brick Stairs" | |
174 | block_id[115] = "Nether Wart" | |
175 | block_id[116] = "Enchantment Table" | |
176 | block_id[117] = "Brewing Stand" | |
177 | block_id[118] = "Cauldron" | |
178 | block_id[119] = "End Portal" | |
179 | block_id[120] = "End Portal Frame" | |
180 | block_id[121] = "End Stone " | |
181 | block_id[126] = "Wood Slabs" | |
182 | block_id[128] = "Sandstone Stairs" | |
183 | block_id[134] = "Spruce Wood Stairs" | |
184 | block_id[135] = "Birch Wood Stairs" | |
185 | block_id[136] = "Jungle Wood Stairs" | |
186 | block_id[156] = "Quartz Stairs" | |
187 | block_id[159] = "Stained Clay" | |
188 | block_id[160] = "Stained Glass Pane" | |
189 | block_id[163] = "Acacia Wood Stairs" | |
190 | block_id[164] = "Dark Oak Wood Stairs" | |
191 | block_id[171] = "Carpet" | |
192 | block_id[172] = "Hardened Clay" | |
193 | block_id[256] = "Iron Ingotron Shovel" | |
194 | block_id[257] = "Iron Pickaxe" | |
195 | block_id[258] = "Iron Axe" | |
196 | block_id[259] = "Flint and Steel" | |
197 | block_id[260] = "Red Apple" | |
198 | block_id[261] = "Bow" | |
199 | block_id[262] = "Arrow" | |
200 | block_id[263] = "Coal" | |
201 | ||
202 | local woolColors = {} | |
203 | woolColors[0] = "White" | |
204 | woolColors[1] = "Orange" | |
205 | woolColors[2] = "Magenta" | |
206 | woolColors[3] = "Light Blue" | |
207 | woolColors[4] = "Yellow" | |
208 | woolColors[5] = "Lime" | |
209 | woolColors[6] = "Pink" | |
210 | woolColors[7] = "Gray" | |
211 | woolColors[8] = "Light Gray" | |
212 | woolColors[9] = "Cyan" | |
213 | woolColors[10] = "Purple" | |
214 | woolColors[11] = "Blue" | |
215 | woolColors[12] = "Brown" | |
216 | woolColors[13] = "Green" | |
217 | woolColors[14] = "Red" | |
218 | woolColors[15] = "Black" | |
219 | ||
220 | local woodTypes = {} | |
221 | woodTypes[0] = "Oak" | |
222 | woodTypes[1] = "Spruce" | |
223 | woodTypes[2] = "Birch" | |
224 | woodTypes[3] = "Jungle" | |
225 | woodTypes[4] = "Acacia" | |
226 | woodTypes[5] = "Dark Oak" | |
227 | ||
228 | local stairOrientation = {} | |
229 | stairOrientation[0] = "East" | |
230 | stairOrientation[1] = "West" | |
231 | stairOrientation[2] = "South" | |
232 | stairOrientation[3] = "North" | |
233 | stairOrientation[4] = "East Inverted" | |
234 | stairOrientation[5] = "West Inverted" | |
235 | stairOrientation[6] = "South Inverted" | |
236 | stairOrientation[7] = "North Inverted" | |
237 | ||
238 | local nonWoodenSlabs = { | |
239 | [0] = "Stone", | |
240 | [1] = "Sandstone", | |
241 | [2] = "Wooden", | |
242 | [3] = "Cobblestone", | |
243 | [4] = "Bricks", | |
244 | [5] = "Stone Bricks", | |
245 | [6] = "Nether Brick", | |
246 | [7] = "Quartz", | |
247 | [8] = "Inverted Stone", | |
248 | [9] = "Inverted Sandstone", | |
249 | [10] = "Inverted Wooden", | |
250 | [11] = "Inverted Cobblestone", | |
251 | [12] = "Inverted Bricks", | |
252 | [13] = "Inverted Stone Bricks", | |
253 | [14] = "Inverted Nether Brick", | |
254 | [15] = "Inverted Quartz", | |
255 | } | |
256 | ||
257 | local length = 0 | |
258 | local height = 0 | |
259 | local width = 0 | |
260 | local blocks = {} | |
261 | local data = {} | |
262 | ||
263 | function getBlockName(id, blockData) | |
264 | blockData = blockData or nil | |
265 | local str = nil | |
266 | if(block_id[id] == nil) then | |
267 | return tostring(id)..", "..tostring(blockData) | |
268 | else | |
269 | if(blockData) then | |
270 | if(id == 35) or (id == 159) or (id == 95) or (id == 160) or (id == 171) then | |
271 | str = tostring(woolColors[blockData]) .. " " .. tostring(block_id[id]) | |
272 | return str | |
273 | elseif id == 5 or id==17 or id==126 then | |
274 | str = tostring(woodTypes[blockData]).." "..tostring(block_id[id]) | |
275 | return str | |
276 | elseif id == 44 or id == 43 then | |
277 | str = tostring(nonWoodenSlabs[blockData]).." "..tostring(block_id[id]) | |
278 | return str | |
279 | end | |
280 | return block_id[id] | |
281 | end | |
282 | end | |
283 | end | |
284 | ||
285 | function getBlockId(x,y,z) | |
286 | return blocks[y + z*width + x*length*width + 1] | |
287 | end | |
288 | ||
289 | function getData(x,y,z) | |
290 | return data[y + z*width + x*length*width + 1] | |
291 | end | |
292 | ||
293 | function readbytes(h, n) | |
294 | for i=1,n do | |
295 | h.read() | |
296 | end | |
297 | end | |
298 | ||
299 | function readname(h) | |
300 | local n1 = h.read() | |
301 | local n2 = h.read() | |
302 | ||
303 | if(n1 == nil or n2 == nil) then | |
304 | return "" | |
305 | end | |
306 | ||
307 | local n = n1*256 + n2 | |
308 | ||
309 | local str = "" | |
310 | for i=1,n do | |
311 | local c = h.read() | |
312 | if c == nil then | |
313 | return | |
314 | end | |
315 | str = str .. string.char(c) | |
316 | end | |
317 | return str | |
318 | end | |
319 | ||
320 | function parse(a, h, containsName) | |
321 | local containsName = containsName or true | |
322 | local i,i1,i2,i3,i4 | |
323 | if a==0 then | |
324 | return | |
325 | end | |
326 | if containsName then | |
327 | name = readname(h) | |
328 | end | |
329 | ||
330 | if a==1 then | |
331 | readbytes(h,1) | |
332 | elseif a==2 then | |
333 | i1 = h.read() | |
334 | i2 = h.read() | |
335 | i = i1*256 + i2 | |
336 | if(name=="Height") then | |
337 | height = i | |
338 | elseif (name=="Length") then | |
339 | length = i | |
340 | elseif (name=="Width") then | |
341 | width = i | |
342 | end | |
343 | elseif a==3 then | |
344 | readbytes(h,4) | |
345 | elseif a==4 then | |
346 | readbytes(h,8) | |
347 | elseif a==5 then | |
348 | readbytes(h,4) | |
349 | elseif a==6 then | |
350 | readbytes(h,8) | |
351 | elseif a==7 then | |
352 | i1 = h.read() | |
353 | i2 = h.read() | |
354 | i3 = h.read() | |
355 | i4 = h.read() | |
356 | i = i1*256*256*256 + i2*256*256 + i3*256 + i4 | |
357 | if name == "Blocks" then | |
358 | for i=1,i do | |
359 | table.insert(blocks, h.read()) | |
360 | end | |
361 | elseif name == "Data" then | |
362 | for i=1,i do | |
363 | table.insert(data, h.read()) | |
364 | end | |
365 | else | |
366 | readbytes(h,i) | |
367 | end | |
368 | elseif a==8 then | |
369 | i1 = h.read() | |
370 | i2 = h.read() | |
371 | i = i1*256 + i2 | |
372 | readbytes(h,i) | |
373 | elseif a==9 then | |
374 | --readbytes(h,5) | |
375 | local type = h.read() | |
376 | i1 = h.read() | |
377 | i2 = h.read() | |
378 | i3 = h.read() | |
379 | i4 = h.read() | |
380 | i = i1*256*256*256 + i2*256*256 + i3*256 + i4 | |
381 | for j=1,i do | |
382 | parse(h.read(), h, false) | |
383 | end | |
384 | end | |
385 | end | |
386 | ||
387 | function forward() | |
388 | while not turtle.forward() do | |
389 | turtle.dig() | |
390 | end | |
391 | end | |
392 | ||
393 | function up() | |
394 | while not turtle.up() do | |
395 | turtle.digUp() | |
396 | end | |
397 | end | |
398 | ||
399 | function down() | |
400 | while not turtle.down() do | |
401 | turtle.digDown() | |
402 | end | |
403 | end | |
404 | ||
405 | function place() | |
406 | while not turtle.placeDown() do | |
407 | turtle.digDown() | |
408 | end | |
409 | end | |
410 | ||
411 | local function show_selected_slot(n) | |
412 | local w,h = term.getCursorPos() | |
413 | local itemData = turtle.getItemDetail(newSelect) | |
414 | if itemData then | |
415 | term.clearLine() | |
416 | term.setCursorPos(1,h) | |
417 | write(" "..itemData.name..", "..itemData.damage) | |
418 | else | |
419 | term.clearLine() | |
420 | term.setCursorPos(1,h) | |
421 | write(" ") | |
422 | end | |
423 | return itemData | |
424 | end | |
425 | ||
426 | local function setColor(color) | |
427 | if term.isColor() then | |
428 | term.setTextColor(color) | |
429 | end | |
430 | end | |
431 | ||
432 | function setup(filename) | |
433 | --input file | |
434 | --returns blocks,data | |
435 | --requires parse, getBlockName | |
436 | ||
437 | if not fs.exists(filename) then | |
438 | error("File "..tostring(filename).." does not exist.") | |
439 | end | |
440 | h = fs.open(filename, "rb") | |
441 | ||
442 | local a = 0 | |
443 | while (a ~= nil) do | |
444 | a = h.read() | |
445 | parse(a, h) | |
446 | end | |
447 | ||
448 | write("length: " .. length) | |
449 | write(" width: " .. width) | |
450 | write(" height: " .. height .. "\n") | |
451 | ||
452 | uniqueblocks={} | |
453 | for i,v in ipairs(blocks) do | |
454 | found = false | |
455 | for j,w in ipairs(uniqueblocks) do | |
456 | ||
457 | --[[if (w.blockID==v and (w.data==data[i] or w.blockID ~= 35)) then | |
458 | found = true | |
459 | w.amount = w.amount + 1 | |
460 | break | |
461 | end]]-- | |
462 | ||
463 | --for now, data is only accounted for when the block is whool | |
464 | if (w.blockID==v) and (w.data==data[i]) then | |
465 | found = true | |
466 | w.amount = w.amount + 1 | |
467 | break | |
468 | end | |
469 | end | |
470 | ||
471 | if found==false then | |
472 | uniqueblocks[#uniqueblocks+1] = {} | |
473 | uniqueblocks[#uniqueblocks].blockID = v | |
474 | uniqueblocks[#uniqueblocks].data = data[i] | |
475 | uniqueblocks[#uniqueblocks].amount = 1 | |
476 | end | |
477 | end | |
478 | ||
479 | if fs.exists("slots") then | |
480 | print("slots file discovered...") | |
481 | print("skipping setup") | |
482 | h.close() | |
483 | return | |
484 | end | |
485 | ||
486 | print("number of block types: " .. #uniqueblocks) | |
487 | for i,v in ipairs(uniqueblocks) do | |
488 | if (i%9)==0 then | |
489 | read() | |
490 | end | |
491 | ||
492 | local stacks = math.ceil( (v.amount/64) ) | |
493 | setColor(colors.white) | |
494 | write(" -" .. getBlockName(v.blockID, v.data)) | |
495 | setColor(colors.lightGray) | |
496 | write("("..v.blockID..","..v.data..")") | |
497 | setColor(colors.white) | |
498 | write(": ") | |
499 | ||
500 | if v.amount > 64 then | |
501 | setColor(colors.magenta) | |
502 | print(stacks.." stacks") | |
503 | else | |
504 | setColor(colors.cyan) | |
505 | print(v.amount) | |
506 | end | |
507 | end | |
508 | ||
509 | setColor(colors.white) | |
510 | ||
511 | read() | |
512 | ||
513 | ||
514 | print("Use arrowKeys and enter to select slots containing block the turtle will use for the printed blockType") | |
515 | setColor(colors.gray) | |
516 | print("press x to skip(not use) the specified blockType") | |
517 | setColor(colors.white) | |
518 | slots={} | |
519 | for i,block in ipairs(uniqueblocks) do | |
520 | local n = nil | |
521 | blockData = block.data | |
522 | ||
523 | setColor(colors.lightGray) | |
524 | write(" -in which slots is ") | |
525 | setColor(colors.lime) | |
526 | write(getBlockName(block.blockID, blockData)) | |
527 | setColor(colors.lightGray) | |
528 | print("("..block.blockID..","..blockData .. ") ?") | |
529 | setColor(colors.white) | |
530 | if not slots[block.blockID] then | |
531 | slots[block.blockID] = {} | |
532 | end | |
533 | slots[block.blockID][blockData] = {} | |
534 | show_selected_slot(turtle.getSelectedSlot()) | |
535 | --input none | |
536 | --output(n) | |
537 | ||
538 | --(oldWay) | |
539 | if tArgs[2] == "sim" or tArgs[2] == "simulate" then | |
540 | write(" ") | |
541 | str = read() | |
542 | n = tonumber(str) | |
543 | else | |
544 | n = numberSelector() | |
545 | end | |
546 | ||
547 | local itemData = show_selected_slot(n) | |
548 | if(n and itemData) then | |
549 | print() | |
550 | slots[block.blockID][blockData] = {itemData.name,itemData.damage} | |
551 | else | |
552 | local w,h = term.getCursorPos() | |
553 | term.clearLine() | |
554 | term.setCursorPos(1,h) | |
555 | print(" SKIPPING") | |
556 | slots[block.blockID][blockData] = {} | |
557 | end | |
558 | end | |
559 | ||
560 | h.close() | |
561 | - | save("slots",slots) |
561 | + | save(slots,"slots") |
562 | end | |
563 | ||
564 | function numberSelector() | |
565 | ||
566 | local function selectNext(newSelect) | |
567 | if newSelect >= 1 and newSelect <= 16 then | |
568 | turtle.select(newSelect) | |
569 | show_selected_slot(newSelect) | |
570 | end | |
571 | end | |
572 | ||
573 | local function ifKey(events,nKey,fn,...) | |
574 | if events[1] == "key" and events[2] == tonumber(nKey) then | |
575 | fn(...) | |
576 | end | |
577 | end | |
578 | ||
579 | local bRunning = true | |
580 | local bNothing = false | |
581 | while bRunning do | |
582 | local events = { os.pullEvent("key") } | |
583 | local newSelect | |
584 | local selected = turtle.getSelectedSlot() | |
585 | ||
586 | ifKey(events,203,function() newSelect = selected - 1 ; selectNext(newSelect) ; end) | |
587 | ifKey(events,205,function() newSelect = selected + 1 ; selectNext(newSelect) ; end) | |
588 | ifKey(events,200,function() newSelect = selected - 4 ; selectNext(newSelect) ; end) | |
589 | ifKey(events,208,function() newSelect = selected + 4 ; selectNext(newSelect) ; end) | |
590 | ifKey(events,28,function() bRunning = false ; end) | |
591 | ifKey(events,45,function() bNothing = true ; bRunning = false ; end) | |
592 | ifKey(events,15,function() bNothing = true ; bRunning = false; end) | |
593 | ||
594 | for i = 2,13 do | |
595 | ifKey(events,i,function() selectNext(i-1) end) | |
596 | end | |
597 | for i = 26,27 do | |
598 | ifKey(events,i,function() selectNext(i-13) end) | |
599 | end | |
600 | for i = 39,40 do | |
601 | ifKey(events,i,function() selectNext(i-24) end) | |
602 | end | |
603 | end | |
604 | if bNothing then | |
605 | return nil | |
606 | else | |
607 | return turtle.getSelectedSlot() | |
608 | end | |
609 | end | |
610 | ||
611 | -- [[ Iterators ]] -- | |
612 | ||
613 | function checkIfAir() | |
614 | --finds the location to place the next block | |
615 | while true do | |
616 | x,y,z = iterate(x,y,z,startx,starty,startz,height-1,width-1,length-1) | |
617 | --makes the turtle build faster by having to travel less | |
618 | blockID2 = getBlockId(x,y,z) -- temporary variable | |
619 | blockData2 = getData(x,y,z) -- temporary variable | |
620 | if slots[blockID2] then | |
621 | -- makes sure the next block to place at location is not air | |
622 | slot_2nd = slots[blockID2][blockData2] | |
623 | if slot_2nd then | |
624 | if #slot_2nd > 0 then | |
625 | recordObj(x,y,z) | |
626 | break | |
627 | end | |
628 | end | |
629 | end | |
630 | end | |
631 | end | |
632 | ||
633 | function check(x,y,z,startx,starty,startz) | |
634 | if x%2==startx%2 then | |
635 | oddx = true | |
636 | if y%2==starty%2 then | |
637 | oddy = true | |
638 | else | |
639 | oddy = false | |
640 | end | |
641 | else | |
642 | oddx = false | |
643 | if y%2==starty%2 then | |
644 | oddy = false | |
645 | else | |
646 | oddy = true | |
647 | end | |
648 | end | |
649 | return oddx,oddy | |
650 | end | |
651 | ||
652 | ||
653 | function Yiterate(x,y,z,startx,starty,startz,finalx,finaly,finalz) | |
654 | ||
655 | local height = finalx | |
656 | local width = finaly | |
657 | local length = finalz | |
658 | ||
659 | if oddx then | |
660 | if y < width then | |
661 | y = y + 1 | |
662 | elseif y == width then | |
663 | if x < height then | |
664 | x = x + 1 | |
665 | --elseif x == height then | |
666 | --x,y,z = "max","max","max" | |
667 | end | |
668 | end | |
669 | else | |
670 | if y <= starty then | |
671 | if x < height then | |
672 | x = x + 1 | |
673 | elseif x == height then | |
674 | x = "max" | |
675 | y = "max" | |
676 | z = "max" | |
677 | end | |
678 | else | |
679 | y=y-1 | |
680 | end | |
681 | end | |
682 | return x,y,z | |
683 | end | |
684 | ||
685 | function iterate(x,y,z,startx,starty,startz,finalx,finaly,finalz) | |
686 | ||
687 | local height = finalx | |
688 | local width = finaly | |
689 | local length = finalz | |
690 | ||
691 | ||
692 | local oddx,oddy = check(x,y,z,startx,starty,startz) | |
693 | if z == length and oddy then | |
694 | x,y,z = Yiterate(x,y,z,startx,starty,startz,finalx,finaly,finalz) | |
695 | elseif z == startz and oddy then | |
696 | z = z + 1 | |
697 | elseif z == startz and (not oddy) then | |
698 | x,y,z = Yiterate(x,y,z,startx,starty,startz,finalx,finaly,finalz) | |
699 | elseif z==length and (not oddy) then | |
700 | z = z - 1 | |
701 | ||
702 | elseif z < length then | |
703 | if oddy then | |
704 | z = z + 1 | |
705 | else | |
706 | z = z - 1 | |
707 | end | |
708 | end | |
709 | return x,y,z | |
710 | end | |
711 | ||
712 | -- [[ TSP_algorithm API ]] -- | |
713 | ||
714 | local w,h = term.getSize() | |
715 | ||
716 | local function calculateDistance(tNode1,tNode2) | |
717 | local turnCost = 0 | |
718 | local deltaY,deltaZ | |
719 | local y1 = tNode1[2] | |
720 | local z1 = tNode1[3] | |
721 | local y2 = tNode2[2] | |
722 | local z2 = tNode2[3] | |
723 | ||
724 | deltaZ = z2-z1 | |
725 | deltaY = y2-y1 | |
726 | ||
727 | if deltaZ == 0 or deltaY == 0 then | |
728 | turnCost = 0 | |
729 | else | |
730 | turnCost = 1 | |
731 | end | |
732 | ||
733 | return math.abs(deltaZ) + math.abs(deltaY) + turnCost | |
734 | --return math.sqrt( (z2-z1)^2 + (y2-y1)^2 ) | |
735 | end | |
736 | ||
737 | local function twoOptSwap(route, i, k) | |
738 | local new_route = {} | |
739 | for c = 1,i-1 do | |
740 | table.insert(new_route,route[c]) | |
741 | end | |
742 | for c = k,i,-1 do | |
743 | table.insert(new_route,route[c]) | |
744 | end | |
745 | for c = k+1,#route do | |
746 | table.insert(new_route,route[c]) | |
747 | end | |
748 | return new_route | |
749 | end | |
750 | ||
751 | local function calculateTotalDistance(route) | |
752 | local total = 0 | |
753 | for i = 1,#route-1 do | |
754 | total = total + calculateDistance(route[i],route[i+1]) | |
755 | end | |
756 | return total | |
757 | end | |
758 | ||
759 | local function display(route,distance) | |
760 | local l,h = term.getSize() | |
761 | shell.run("clear") | |
762 | ||
763 | for i = 1,#route-1 do | |
764 | paintutils.drawLine(route[i][2],route[i][3],route[i+1][2],route[i+1][3],colors.lime) | |
765 | end | |
766 | for i,coord in pairs(route) do | |
767 | term.setBackgroundColor(colors.yellow) | |
768 | term.setTextColor(colors.magenta) | |
769 | if coord[2] < l and coord[2] >= 1 and coord[3] >= 1 and coord[3] < h then | |
770 | term.setCursorPos(coord[2],coord[3]) | |
771 | local char = i + 64 | |
772 | if char > 190 then | |
773 | char = char - 190 | |
774 | end | |
775 | if char > 380 then | |
776 | char = char - 380 | |
777 | end | |
778 | term.write(string.char(char)) | |
779 | end | |
780 | end | |
781 | term.setBackgroundColor(colors.black) | |
782 | term.setTextColor(colors.white) | |
783 | term.setCursorPos(1,h) | |
784 | term.write(distance) | |
785 | end | |
786 | ||
787 | local route = {} | |
788 | route[1] = {1,28,3} | |
789 | route[2] = {1,36,13} | |
790 | route[3] = {1,20,8} | |
791 | route[4] = {1,8,8} | |
792 | route[5] = {1,44,5} | |
793 | route[6] = {1,32,13} | |
794 | route[7] = {1,20,17} | |
795 | --route[8] = {1,28,3} | |
796 | ||
797 | function tsp_algorithm(existing_route) | |
798 | local improve = 0 | |
799 | while improve < 3 do | |
800 | local best_distance = calculateTotalDistance(existing_route) | |
801 | for i = 2,#existing_route-1 do | |
802 | for k = i + 1, #existing_route do | |
803 | new_route = twoOptSwap(existing_route, i, k) | |
804 | new_distance = calculateTotalDistance(new_route) | |
805 | if new_distance < best_distance then | |
806 | improve = 0 | |
807 | existing_route = new_route | |
808 | best_distance = calculateTotalDistance(existing_route) | |
809 | display(existing_route,best_distance) | |
810 | sleep(0) | |
811 | end | |
812 | end | |
813 | end | |
814 | improve = improve + 1 | |
815 | end | |
816 | return existing_route, best_distance | |
817 | end | |
818 | ||
819 | -- [[ schematic --> blueprint ]] -- | |
820 | ||
821 | --turtles[i].instructions[n] = {x,y,z,id,data} | |
822 | --i = multiturtle ie 1,2,3,4 ; n = step ie 1 - 256 (no air) | |
823 | ||
824 | --fn splits 16x16 grid between 4 turtles returning startx,y,z and endx,y,z of 4 4x4 grids | |
825 | --fn takes each 4x4 grid and turns them into instructions[n] = {x,y,z,id,data} | |
826 | --fn for master turtle to setup all slave turtles with the instructions[n] table and goto/find/place functions | |
827 | ||
828 | function blueprint(startx,starty,startz,finalx,finaly,finalz) | |
829 | --uses iterator to make instructions[n] table | |
830 | local x,y,z = startx,starty,startz | |
831 | local instructions = {} | |
832 | local nTimes = (finalx+1-startx)*(finaly+1-starty)*(finalz+1-startz) | |
833 | for i=1,nTimes do | |
834 | if x == "max" then | |
835 | break | |
836 | end | |
837 | local id = getBlockId(x,y,z) | |
838 | local data = getData(x,y,z) | |
839 | if id > 0 then | |
840 | table.insert(instructions,{x,y,z,id,data}) | |
841 | end | |
842 | x,y,z = iterate(x,y,z,startx,starty,startz,finalx,finaly,finalz) | |
843 | end | |
844 | return instructions | |
845 | end | |
846 | ||
847 | function improveBlueprint(instructions,startx,starty,startz,finalx,finaly,finalz) | |
848 | local function instructions2layers(instructions) | |
849 | local layers = {} | |
850 | for x = startx,finalx do | |
851 | layers[x] = {} | |
852 | for n=1,#instructions do | |
853 | if instructions[n][1] == x then | |
854 | table.insert(layers[x],{unpack(instructions[n],1,3)}) | |
855 | end | |
856 | end | |
857 | end | |
858 | return layers | |
859 | end | |
860 | local function organize(layers) | |
861 | local startingPosition = {startx,starty,startz} | |
862 | for x = startx,finalx do | |
863 | table.insert(layers[x],1,startingPosition) | |
864 | layers[x] = tsp_algorithm(layers[x]) | |
865 | startingPosition = layers[x][#layers[x]] | |
866 | end | |
867 | return layers | |
868 | end | |
869 | ||
870 | local function layers2instructions(layers) | |
871 | local instructions = {} | |
872 | --organizedlayers only | |
873 | for x = startx,finalx do | |
874 | for i = 2,#layers[x] do | |
875 | table.insert(instructions,layers[x][i]) | |
876 | end | |
877 | end | |
878 | return instructions | |
879 | end | |
880 | ||
881 | local function add_id_and_data(instructions) | |
882 | for n = 1,#instructions do | |
883 | instructions[n][4] = getBlockId(unpack(instructions[n],1,3)) | |
884 | instructions[n][5] = getData(unpack(instructions[n],1,3)) | |
885 | end | |
886 | return instructions | |
887 | end | |
888 | ||
889 | local layers = instructions2layers(instructions) | |
890 | layers = organize(layers) | |
891 | local new_instructions = layers2instructions(layers) | |
892 | new_instructions = add_id_and_data(new_instructions) | |
893 | return new_instructions | |
894 | end | |
895 | ||
896 | function simulateIns(instructions) | |
897 | local w,h = term.getSize() | |
898 | local lastx = 0 | |
899 | shell.run("clr") | |
900 | for n = 1,#instructions do | |
901 | if lastx~=instructions[n][1] then | |
902 | term.setBackgroundColor(colors.black) | |
903 | shell.run("clr") | |
904 | end | |
905 | if instructions[n][2]+1 >= 1 and instructions[n][3]+1 >= 1 and instructions[n][2]+1 < w and instructions[n][3]+1 < h then | |
906 | term.setCursorPos(instructions[n][2]+1,instructions[n][3]+1) | |
907 | term.setBackgroundColor(2^instructions[n][5]) | |
908 | term.write(" ") | |
909 | end | |
910 | lastx = instructions[n][1] | |
911 | sleep(0) | |
912 | end | |
913 | end | |
914 | ||
915 | function orientation_check(reference,slots) | |
916 | for id,table in pairs(slots) do | |
917 | for data,table2 in pairs(table) do | |
918 | if table2 and table2[1] then | |
919 | if (table2[1]:find("stairs") or table2[1]:find("chest") or table2[1]:find("furnace")) then | |
920 | for n = 1,5 do | |
921 | term.scroll(1) | |
922 | sleep(0) | |
923 | end | |
924 | print("orientation required") | |
925 | print("what direction is the turtle facing?") | |
926 | local r | |
927 | while true do | |
928 | write(" ") | |
929 | if term.isColor() then | |
930 | term.setTextColor(colors.yellow) | |
931 | end | |
932 | r = read() | |
933 | r = tostring(r):lower() | |
934 | term.setTextColor(colors.white) | |
935 | if r ~= "south" and r~= "north" and r~= "west" and r~= "east" then | |
936 | print(r.. " not recognized, north/south/east/west?") | |
937 | else | |
938 | break | |
939 | end | |
940 | end | |
941 | ||
942 | reference.relativeDirection = r | |
943 | print("don't forget to include wrench in turtle!") | |
944 | reference.wrench = true | |
945 | return reference | |
946 | end | |
947 | end | |
948 | end | |
949 | end | |
950 | return reference | |
951 | end | |
952 | ||
953 | function multiturtle_check(reference) | |
954 | write("How many Turtles?: ") | |
955 | local n = read() | |
956 | n = tonumber(n) | |
957 | if n then | |
958 | if n == 1 then | |
959 | reference.multiturtle = false | |
960 | else | |
961 | reference.multiturtle = n | |
962 | end | |
963 | end | |
964 | print() | |
965 | return reference | |
966 | end | |
967 | ||
968 | local function Main() | |
969 | setup(filename) | |
970 | ||
971 | --save("blocks",blocks) | |
972 | --save("data",data) | |
973 | --save("uniqueblocks",uniqueblocks) | |
974 | ||
975 | reference = { | |
976 | startx = 0, | |
977 | starty = 0, | |
978 | startz = 0, | |
979 | finalx = height-1, | |
980 | finaly = width-1, | |
981 | finalz = length-1, | |
982 | height = height, | |
983 | width = width, | |
984 | length = length, | |
985 | wrench = false, | |
986 | multiturtle = false, -- otherwise its a number (1,2,4,8,12,etc), | |
987 | relativeDirection = "south", | |
988 | numChests = false, | |
989 | filename = false, | |
990 | returnx = 0, | |
991 | returny = 0, | |
992 | returnz = -1, | |
993 | } | |
994 | ||
995 | if not slots then | |
996 | slots = textutils.unserialize( fs.open("slots","r").readAll() ) | |
997 | end | |
998 | ||
999 | reference = orientation_check(reference,slots) | |
1000 | reference = multiturtle_check(reference) | |
1001 | ||
1002 | local instructions = blueprint(reference.startx,reference.starty,reference.startz,reference.finalx,reference.finaly,reference.finalz) | |
1003 | if reference.multiturtle then | |
1004 | local A1 = Class_Grid(instructions,reference.starty,reference.startz,reference.finaly,reference.finalz) | |
1005 | - | local startLocations = {nTurtleSplit(reference.multiturtle,A1)} |
1005 | + | startLocations = {nTurtleSplit(reference.multiturtle,A1)} |
1006 | - | for i,v in pairs(startLocations) do |
1006 | + | --[[for i,v in pairs(startLocations) do |
1007 | local nTurtle = i | |
1008 | local ref = reference | |
1009 | ref.starty = v.starty | |
1010 | ref.startz = v.startz | |
1011 | ref.finaly = v.finaly | |
1012 | ref.finalz = v.finalz | |
1013 | local ins = blueprint(ref.startx,v.starty,v.startz,ref.finalx,v.finaly,v.finalz) | |
1014 | if tArgs[2] == "tsp" then | |
1015 | ins = improveBlueprint(ins,ref.startx,ref.starty,ref.startz,ref.finalx,ref.finaly,ref.finalz) | |
1016 | end | |
1017 | - | |
1017 | + | |
1018 | print(ref.starty," ",ref.startz," ",ref.finaly," ",ref.finalz) | |
1019 | print(fname," saved") | |
1020 | end]] | |
1021 | local nTurtle = 1 | |
1022 | local v = startLocations[1] | |
1023 | local ref = reference | |
1024 | ref.starty = v.starty | |
1025 | ref.startz = v.startz | |
1026 | ref.finaly = v.finaly | |
1027 | ref.finalz = v.finalz | |
1028 | local ins = blueprint(ref.startx,v.starty,v.startz,ref.finalx,v.finaly,v.finalz) | |
1029 | if tArgs[2] == "tsp" then | |
1030 | ins = improveBlueprint(ins,ref.startx,ref.starty,ref.startz,ref.finalx,ref.finaly,ref.finalz) | |
1031 | end | |
1032 | local fname = saveBlueprint(ref,slots,ins,uniqueblocks,nTurtle) | |
1033 | print(ref.starty," ",ref.startz," ",ref.finaly," ",ref.finalz) | |
1034 | print(fname," saved") | |
1035 | else | |
1036 | ||
1037 | if tArgs[2] == "tsp" then | |
1038 | instructions = improveBlueprint(instructions,reference.startx,reference.starty,reference.startz,reference.finalx,reference.finaly,reference.finalz) | |
1039 | end | |
1040 | --textutils.pagedPrint(textutils.serialize(ins)) | |
1041 | --saveIns("instructions",ins) | |
1042 | local fname = saveBlueprint(reference,slots,instructions,uniqueblocks) | |
1043 | print(fname," saved") | |
1044 | --delete slots,reference,ins,uniqueblocks files | |
1045 | end | |
1046 | end | |
1047 | ||
1048 | Main() |