I've been playing with Tekkit 2.1.1, and wanted a good track laying program. I took a look over HTxL's excellent contribution, but found it didn't suit my intent: I wanted to lay track and follow terrain, whether flat or hilly, and not spend a lot of stone/dirt on bridges, nor spend a lot of time digging or making darksome tunnels under hills that I'd then have to supply oodles of torches for. Is it not enough that I'm supplying all these rails, after all?

So, my contribution is this: My TrackLayer program. Forgive the commented out debugging code - I was having some logic faults around the 'stepped off a cliff' case. You might like the pause() function for your own debugging tribulations.

Spoiler

--
-- tracklayer
-- places tracks for long distances
-- places powered rails and redstone torches
-- also places powered rails for up/down hills
-- minimizes digging, preferring to follow the terrain where possible
--
-- Unfortunately, this includes following the terrain into water
-- handle that in advance with another program
--
-- slot setup:
-- slot 1 - scratch - anything we hafta dig - ejected after every dig
-- slot 2-5 - rails - plain ol' unpowered classic
-- slot 6-7 - powered rails
-- slot 8 - redstone torches
-- slot 9 - building material - use this for stairs when we go off a cliff
--

--[[

local function pause(a)
	local e, p1, p2, p3, p4, p5
	if a then
		print(a)
	end
	e = "derp"
	p1 = "derp"
	while p1 ~= 57 do
		e, p1, p2, p3, p4, p5 = os.pullEvent()
	end
end

]]--

local function count(s)
	turtle.select(s)
	return turtle.getItemCount(s)
end

local function check(s)
	turtle.select(s)
	return (turtle.getItemCount(s) ~= 0)
end

local function dig()
	if turtle.detect() then
--		pause("dig!")
		turtle.select(1)
		turtle.dig()
		if check(1) then turtle.drop() end
	end
end

local function digup()
	if turtle.detectUp() then
--		pause("digup!")
		turtle.select(1)
		turtle.digUp()
		if check(1) then turtle.drop() end
	end
end

local function digdown()
	if turtle.detectDown() then
--		pause("digdown!")
		turtle.select(1)
		turtle.digDown()
		if check(1) then turtle.drop() end
	end
end

local function up()
	digup()
	return turtle.up()
end

local function down()
	digdown()
	return turtle.down()
end

local function forward()
	dig()
	return turtle.forward()
end

local back = turtle.back
local right = turtle.turnRight
local left = turtle.turnLeft


--types:
--0 - rail
--1 - powrail
--2 - RS torch
--3 - building crap

-- look the fuck out, it's short-circuit 'or' reliance to leave the right thing select()ed

local function havetype(t)
	if type(t) ~= "number" then
		error("havetype needs a number")
		return false
	end
	if t == 0 then
		return check(2) or check(3) or check(4) or check(5)
	elseif t == 1 then
		return check(6) or check(7)
	elseif t == 2 then
		return check(8)
	elseif t == 3 then
		return check(9)
	else
		error("havetype doesn't grok: ", t)
		return false
	end
end

local function counttype(t)
	if type(t) ~= "number" then
		error("counttype needs a number")
		return false
	end
	if t == 0 then
		if count(2) > 0 then
			return count(2)
		elseif count(3) > 0 then
			return count(3)
		elseif count(4) > 0 then
			return count(4)
		else
			return count(5)
		end
	elseif t == 1 then
		if count(6) > 0 then
			return count(6)
		else
			return count(7)
		end
	elseif t == 2 then
		return count(8)
	elseif t == 3 then
		return count(9)
	else
		error("counttype doesn't grok: ", t)
		return false
	end
end


local function put(t)
	if type(t) == "nil" then
		t = 0
	end
	if not havetype(t) then
		print("waiting for more mats, type ", t)
		while not havetype(t) do
			sleep(1)
		end
	end
	
	-- ugly hack to work around turtle API grabbing from other slots when current slot items won't place (ie. placing track over air w/ stone in another slot)
	local c = counttype(t)
--	pause(c)
	local rv = turtle.placeDown()
--	pause(counttype(t))
	if rv and c == counttype(t) then
		digdown()
		return false
	else
		return rv
	end
end

local function track(t)
	if not put(t) then
		-- must be a hill
		if turtle.detectDown() then
			up()
			put(1)
			return 1
		else
			down()
			if not put(1) then
				down()
				put(3)
				up()
				put(1)
			end
			return -1
		end
	end
	return 0
end



-------- void main(int argc, char ** argv)  or whatever

local argv = {...}

local i, j

i = 64
j = 8

if #argv > 0 then
	i = tonumber(argv[1])
	if i == nil or i < 1 then
		i = 64
	end
	j = tonumber(argv[2])
	if j == nil or j < 1 then
		j = 8
	end
end

print("Placing ", i, " rails.")
print("Powered at intervals of ", j, ".")

-- open by moving up a block, assuming we're placed on the ground at our starting location
up()

local rv

-- while I haven't built out to the parameter limit
while i > 0 do
--	pause(i)
	if i % j == 0 then
		print("i = ", i, " : powered rail")
		rv = track(1)
		right()
		forward()
		down()
		put(3)
		up()
		put(2)
		back()
		left()
	else
		rv = track(0)
	end
	-- move ahead
	forward()
	-- decrement counter
	i = i - 1
end

turtle.down()

If I get some time, I'll sort out creating a vid, but it's a pretty straightforward terrain follower, with some limitations to match Minecraft tracks.

As the comments in the code say, stuff the inventory as follows:
slot 1 - leave empty for scratch space when digging
slot 2-5 - rails - plain ol' unpowered classic
slot 6-7 - powered rails
slot 8 - redstone torches
slot 9 - building material - use this for stairs when we go off a cliff

It's still a little rough - I don't like some of the behavior (I select()ed slot 8, why are you placeDown()ing from slot 9?!? ARRGH!), but it's functional. Also, untested in wet environs - expect it to plunk down a lot of track that'll get washed away if there's no platform in advance.

Anyway, enough caveats and provisos! I've got tracks to go lay! :)/>/>

Hope this helps others enjoy their ComputerCraft time!