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

java.lang.ArrayIndexOutOfBoundsException

Started by MrabEzreb, 30 April 2014 - 03:35 PM
MrabEzreb #1
Posted 30 April 2014 - 05:35 PM
What is this? The code is supposed to open/close a drawbridge from TMech T-flip-flop style. WHAT IS GOING ON?

drawbridge = false
function updateBundle(side, new, old)
  cur = rs.getBundledOutput(side)
  if new then
    cur = colors.combine(cur, new)
  end
  if old then
    cur = colors.subtract(cur, old)
  end
  rs.setBundledOutput(side, cur)
end
function testIfDraw()
  if rs.testBundledInput("left", colors.brown) then
    drawbridge = not drawbridge
    updateDrawbridge()
    sleep(1)
  end
end
function updateDrawbridge()
  if drawbridge == false then
    updateBundle("left", colors.yellow)
    sleep(0.5)
    updateBundle("left", colors.orange)
  elseif drawbridge == true then
    updateBundle("left", nil, colors.orange)
    sleep(0.5)
    updateBundle("left", nil, colors.yellow)
  end
end
while rs.getInput("top") do
  testIfDraw()
end
CometWolf #2
Posted 30 April 2014 - 06:51 PM
Im not suprised it crashes, since it never yields unless it's being told to open, i am however suprised by the error. Are you sure this is the entire code, and you're not running it multiple times with shell.run or something silly like that?
MrabEzreb #3
Posted 01 May 2014 - 09:30 PM
The actual code to run it is in testIfDraw() which is in a while loop. You think I should use an event?
CometWolf #4
Posted 01 May 2014 - 09:47 PM
Im saying it needs to yield somewhere within that loop, even if you're not opening the bridge. How you choose to do that is up to you, but yes the logical solution would be to use events.
MrabEzreb #5
Posted 02 May 2014 - 12:07 AM
So, it would work if I did this:

drawbridge = false
function updateBundle(side, new, old)
  cur = rs.getBundledOutput(side)
  if new then
    cur = colors.combine(cur, new)
  end
  if old then
    cur = colors.subtract(cur, old)
  end
  rs.setBundledOutput(side, cur)
end
function testIfDraw()
  if rs.testBundledInput("left", colors.brown) then
    drawbridge = not drawbridge
    updateDrawbridge()
    sleep(1)
  end
end
function updateDrawbridge()
  if drawbridge == false then
    updateBundle("left", colors.yellow)
    sleep(0.5)
    updateBundle("left", colors.orange)
  elseif drawbridge == true then
    updateBundle("left", nil, colors.orange)
    sleep(0.5)
    updateBundle("left", nil, colors.yellow)
  end
end
while rs.getInput("top") do
  testIfDraw()
  if drawbridge then
    print("Drawbridge Open")
  else
    print("Drawbridge Closed")
  end
end
CometWolf #6
Posted 02 May 2014 - 12:19 AM
You added 2 print statements… Why would that change anything?
MrabEzreb #7
Posted 02 May 2014 - 12:50 AM
how do I make it yeild?
CometWolf #8
Posted 02 May 2014 - 12:58 AM
The logical solution would be to use events.
You think print is an event?

When i say events, i am refering to os.pullEvent(). In this instance, os.pullEvent"redstone" would make the most sense. Alternatively, you could make use of sleep. Basically what you need to yield is to call coroutine.yield(), which os.pullEvent happens to do. sleep in turn calls os.pullEvent, hence it being a viable option.
http://computercraft.info/wiki/Os.pullEvent
MrabEzreb #9
Posted 02 May 2014 - 12:58 AM
okay. But would print() say "I am still working, keep running me"?
CometWolf #10
Posted 02 May 2014 - 01:17 AM
A blank print would not say that, no…
Bomb Bloke #11
Posted 02 May 2014 - 01:59 AM
As in, no, it's not a "keep-alive ping" that you need here. More like the opposite.

When you plonk down two computers and open them up, they look and act like two separate computers, each running a Lua interpretor. The truth is that, behind the facade, there's only one Lua interpretor for your world, no matter how many computers or turtles are in it.

This interpretor treats each system as a separate co-routine. They're boxed off so that they can't interact with each other directly.

Now here's the catch - the interpretor can only run one co-routine at a time. There's no true multitasking going on here - when one of your computers is doing something, the others aren't.

The solution is that every time a co-routine has to pause, the interpretor takes that opertunity to switch to the next one. For example, if a system is waiting for you to type something, or whatever for the next moment on which the cursor blinks, or waiting for a turtle to finish moving… it's yielding, and this is what allows ComputerCraft to quickly divert processing power to all the systems in your world and maintain the illusion that they're all running at once.

Thing is, it's possible to write code that doesn't pause - for example, you can shove as many "print" statements into your script as you like, Lua will execute all of them and then straight away move on to the next line of the same script. Create an infinite loop that doesn't pause, and ComputerCraft will never see an opportunity to let other systems in the world do anything. This breaks the illusion, as suddenly every system in the world stops working, waiting for that one script to give up control.

For this reason, if a script runs for more then ten seconds without yielding, ComputerCraft will crash that script.

Currently your "testIfDraw()" function, which is called over and over in a loop, reads like this:

function testIfDraw()
  if rs.testBundledInput("left", colors.brown) then
    drawbridge = not drawbridge
    updateDrawbridge()
    sleep(1)
  end
end

If the colour brown is active to the left, then this will sleep for at least a second every time the loop repeats. If it's not, then the script never sleeps. There's no pause, and so it'll crash if you don't hit the switch at least once every ten seconds.

You could move/add sleep statements to deal with this, but os.pullEvent() offers a more elegant solution - you can rig it to specifically pause your script until a redstone input changes.

For example, assuming your drawbridge is being toggled with a button:

function testIfDraw()
  -- Sit and wait until the input turns on:
  while not rs.testBundledInput("left", colors.brown) do
    os.pullEvent("redstone")
    if not rs.getInput("top") then error() end  -- Quit if the top redstone signal was lost.
  end  

  -- Toggle the bridge:
  drawbridge = not drawbridge
  updateDrawbridge()

  -- Sit and wait until the input turns off, if it hasn't already:
  while rs.testBundledInput("left", colors.brown) do os.pullEvent("redstone") end  
end

Beats me what the deal with the "out of bounds" error is. Wouldn't be lucky enough to have any more of the error, like an API name or a line number?
MrabEzreb #12
Posted 18 May 2014 - 09:19 PM
nope. What I gave is what it gave me.