This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
djfergy's profile picture

Help with elevator program

Started by djfergy, 30 June 2016 - 08:52 PM
djfergy #1
Posted 30 June 2016 - 10:52 PM
So i am creating a 2 part elevator program using frames that works but not the way i want it to. The way is it supposed to work is that when i hit the call button from a floor it should go straight to that floor in which the call button was pushed. Instead it stops at each floor. I do know that the problem is the while statement but for the life of me i cannot firgure out how to isolate each of the functions. The green wire is for going up and the rred wire is for going down. All of the other wires are just inputs and sensors.

local side = "left"
function flr1()
  if redstone.testBundledInput(side,colors.black) == true then
    redstone.setBundledOutput(side,colors.red)
    sleep(3)
  end
  if redstone.testBundledInput(side,colors.white) == true then
    redstone.setBundledOutput(side,0)
  end
  --sleep(.1)
end
function flr2()
  if redstone.testBundledInput(side,colors.gray) == true and
  redstone.testBundledInput(side,colors.white) == true then
    redstone.setBundledOutput(side,colors.green)
    sleep(3)
  end
 
  if redstone.testBundledInput(side,colors.gray) == true and
  redstone.testBundledInput(side,colors.cyan) == true then
    redstone.setBundledOutput(side,colors.red)
    sleep(3)
  end
 
  if redstone.testBundledInput(side,colors.lightGray) == true then
    redstone.setBundledOutput(side,0)
  end
  --sleep(1)
end
function flr3()
  if redstone.testBundledInput(side,colors.blue) == true then
    redstone.setBundledOutput(side,colors.green)
    sleep(3)
  end
 
  if redstone.testBundledInput(side,colors.cyan) == true then
    redstone.setBundledOutput(side,0)
  end
  --sleep(.1)
end
while true do
  flr1()
  flr2()
  flr3()
  sleep(.1)
end
LBPHacker #2
Posted 01 July 2016 - 09:03 AM
It stops at each floor because your program doesn't wait until the elevator gets to where it should be, it instead just waits for 3 seconds after asserting either the green or the red wire and after it, it goes back into the infinite loop.

I suggest two changes:
  • Make it all event driven: don't poll the input, wait for "redstone" events instead
  • Use tables: store the floors and relevant data in tables, iterate those tables when a redstone event occurs
This is the code I had in mind
local side = "left"
local direction = {
	up = colors.green,
	down = colors.red
}
local floors = {
	[1] = {
		call = colors.black,
		here = colors.white
	},
	[2] = {
		call = colors.gray,
		here = colors.lightGray
	},
	[3] = {
		call = colors.blue,
		here = colors.cyan
	}
}

local function waitForChange()
	os.pullEvent("redstone")
end

while true do
	waitForChange()

	local targetFloor, currentFloor
	-- This iterates through the floor objects defined above
	-- and checks if any of their call lines is asserted.
	for ix = 1, #floors do
		if rs.testBundledInput(side, floors[ix].call) then
			targetFloor = ix
		end
		if rs.testBundledInput(side, floors[ix].here) then
			currentFloor = ix
		end
	end

	-- It's guaranteed that currentFloor is set, because
	-- at this point the elevator must be on a floor. Unless
	-- the program somehow crashed while the elevator was going,
	-- in which case you'd have to fix the elevator anyway.
	-- It's not guaranteed that targetFloor ever gets set.
	-- In case it doesn't, we just skip over the move code.
	if targetFloor then
		print("Called from floor " .. targetFloor .. ", currently on " .. currentFloor)
		if targetFloor < currentFloor then
			print("  Going down")
			rs.setBundledOutput(side, direction.down)
		elseif targetFloor > currentFloor then
			print("  Going up")
			rs.setBundledOutput(side, direction.up)
		else
			print("  Going nowhere")
		end

		while true do
			waitForChange()
			if rs.testBundledInput(side, floors[targetFloor].here) then
				break
			end
		end

		rs.setBundledOutput(side, 0)
	end
end

Code works and is tested. It should give you an idea of how I think it should work.

How do the green and red wires work though? Does the elevator just move by itself when they are asserted? Is there a circuit generating the pulses needed by the frame motors? I assumed there is one, so the above code does too.
Edited on 01 July 2016 - 07:07 AM
djfergy #3
Posted 01 July 2016 - 12:03 PM
Spoiler
it's just a tad overcomplicated frame elevator lol. yes they use timers. i'll give your code a shot tomorrrow. thanks a bunch!
djfergy #4
Posted 20 July 2016 - 03:51 AM
Apologies for double post. I need help again! So the call program works great but that was only half of elevator programming. The second half is a button monitor that allows you to select which floor to go to and then takes you there. I have an example of the monitor below.
Spoiler
In my test world, I only have 3 levels currently built. There are six floors just to test the size and spacing. I am using a modified version of direwolf20's button api to make the buttons function correctly. Now I just need to make the elevator move correctly. This is what I have so far.
Spoiler

os.loadAPI("button")
local m = peripheral.wrap("monitor_13")
m.clear()
function fillTable()
  button.setTable("1", flr1, 2,4,2,4)
  button.setTable("2", flr2, 7,9,2,4)
  button.setTable("3", flr3, 12,14,2,4)
  button.setTable("4", flr4, 2,4,7,9)
  button.setTable("5", flr5, 7,9,7,9)
  button.setTable("B", bsemnt, 12,14,7,9)
  button.screen()
end
function getClick()
  event,side,x,y = os.pullEvent("monitor_touch")
  button.checkxy(x,y)
end
function flr1()
  button.flash("1")
  sleep(1)
  while  rs.testBundledInput("top", colors.white) ~= true do
    rs.setBundledOutput("top", colors.red)
  end
 
  if rs.testBundledInput("top", colors.white) == true then
    rs.setBundledOutput("top", 0)
  end
end
function flr2()
  button.flash("2")
  sleep(1)
 
end
function flr3()
  button.flash("3")
  sleep(1)
end
function flr4()
  button.flash("4")
end
function flr5()
  button.flash("5")
end
function bsemnt()
  button.flash("B")
end
fillTable()
while true do
  getClick()
end
and for reference here is the button api
Spoiler

local mon = peripheral.wrap("monitor_13")
mon.setTextScale(0.5)
mon.setTextColor(colors.white)
local button={}
mon.setBackgroundColor(colors.black)
function clearTable()
   button = {}
   mon.clear()
end
			  
function setTable(name, func, xmin, xmax, ymin, ymax)
   button[name] = {}
   button[name]["func"] = func
   button[name]["active"] = false
   button[name]["xmin"] = xmin
   button[name]["ymin"] = ymin
   button[name]["xmax"] = xmax
   button[name]["ymax"] = ymax
end
function funcName()
   print("You clicked buttonText")
end
	   
function fillTable()
   setTable("ButtonText", funcName, 5, 25, 4, 8)
end	
function fill(text, color, bData)
   mon.setBackgroundColor(color)
   local yspot = math.floor((bData["ymin"] + bData["ymax"]) /2)
   local xspot = math.floor((bData["xmax"] - bData["xmin"] - string.len(text)) /2) +1
   for j = bData["ymin"], bData["ymax"] do
	  mon.setCursorPos(bData["xmin"], j)
	  if j == yspot then
		 for k = 0, bData["xmax"] - bData["xmin"] - string.len(text) +1 do
		    if k == xspot then
			   mon.write(text)
		    else
			   mon.write(" ")
		    end
		 end
	  else
		 for i = bData["xmin"], bData["xmax"] do
		    mon.write(" ")
		 end
	  end
   end
   mon.setBackgroundColor(colors.black)
end
	
function screen()
   local currColor
   for name,data in pairs(button) do
	  local on = data["active"]
	  if on == true then currColor = colors.blue else currColor = colors.cyan end
	  fill(name, currColor, data)
   end
end
function toggleButton(name)
   button[name]["active"] = not button[name]["active"]
   screen()
end	
function flash(name)
   toggleButton(name)
   screen()
   sleep(0.25)
   toggleButton(name)
   screen()
end
											
function checkxy(x, y)
   for name, data in pairs(button) do
	  if y>=data["ymin"] and  y <= data["ymax"] then
		 if x>=data["xmin"] and x<= data["xmax"] then
		    data["func"]()
		    return true
		    --data["active"] = not data["active"]
		    --print(name)
		 end
	  end
   end
   return false
end
	
function heading(text)
   w, h = mon.getSize()
   mon.setCursorPos((w-string.len(text))/2+1, 1)
   mon.write(text)
end
	
function label(w, h, text)
   mon.setCursorPos(w, h)
   mon.write(text)
end
Do I need to use table again? I'm not very familiar with how they work at all….