View difference between Paste ID: beQ1GqeR and umA53Z9F
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()