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

Counting order of inputs (array?)

Started by Ashton, 02 May 2013 - 10:11 PM
Ashton #1
Posted 03 May 2013 - 12:11 AM
ok, I'm working on an "infinite maze" it's a crossroads of all four directions (N/S/E/W) with pressure plates at the end that teleports the player to the opposite end and records the "exit", so in theory, I could track the player's "exits" and make as complex of a maze as I want, or change it as often as I want.

I want to track 4 inputs (most recent last four) And, for example, if they are N, N, W, N, then that triggers a teleportation, while N, N, N, S does not.

I've set up my program to count the inputs, and if any input exceeds 4 it teleports the player back to the start and resets the counter.

I am using the rs.getInput() command to determine which "direction" the player moved, and I can fill the four slots (if var1 = null, var1 = rs.input, if var1 != null, than (var2, var3, var4) —- not actual code, obviously) but what do I do once all four inputs are full? How to I tell it to begin recycling? I can recycle #1 by saying "if var4 =! null, then (var1) but after that, if I start over the code will begin to conflict because it will look for a "null" slot and there wont be one…

So, basically, how do I set it up to continually update the "last 4 inputs"?

current (severely incomplete) code (wrapping command block as a peripheral on bottom):


local N = 0
local S = 0
local E = 0
local W = 0
local cblock = peripheral.wrap("bottom")
local redo = cblock.setCommand("/tp @p 263 63 -149") cblock.runCommand() N=0 S=0 E=0 W=0 sleep(1)

--back is S,
--front is N,
--right is W,
--left is E

while true do

if rs.getInput("back") == "true" then S = S + 1 end
if rs.getInput("front") == "true" then N = N + 1 end
if rs.getInput("right") == "true" then W = W + 1 end
if rs.getInput("left") == "true" then E = E + 1 end

if S == 4 then redo() end
if N == 4 then redo() end
if E == 4 then redo() end
if W == 4 then redo() end

end

Current thoughts:

(note: warp1/etc would be a function to set and execute a command block /tp command)

local pos1 = null
local pos2 = null
local pos3 = null
local pos4 = null
local GetDir = null

if rs.getInput() == "back" then GetDir == "S" end
if rs.getInput() == "right" then GetDir == "W" end
if rs.getInput() == "left" then GetDir == "E" end
if rs.getInput() == "front" then GetDir == "N" end


if pos1 = null then pos1 = GetDir end


if pos2 = null then pos2 = GetDir end


if pos3 = null then pos3 = GetDir end


if pos4 = null then pos4 = GetDir end


if pos4 ~= null then pos1 = GetDir end

if (pos1=N) and (pos2=N) and (pos3=W) and (pos4=S) then Warp1() sleep(1) end

if (pos1=W) and (pos2=N) and (pos3=N) and (pos4=E) then Warp2() sleep(1) end

if (pos1=S) and (pos2=S) and (pos3=W) and (pos4=S) then Warp3() sleep(1) end


Thoughts on how to impliment this and where to go from here?
Mackan90096 #2
Posted 03 May 2013 - 05:39 AM
First of all.. Please put the code in code tags, as it will become easier for people to help you.
LBPHacker #3
Posted 03 May 2013 - 11:10 AM
You might want to declare "redo" as a function, not as the return value of cblock.setCommand…
local redo = function()
    cblock.setCommand("/tp @p 263 63 -149")
    cblock.runCommand()
    N=0
    S=0
    E=0
    W=0
    sleep(1)
end
Ashton #4
Posted 03 May 2013 - 09:16 PM
So… nobody has any clue how to make the 4 variables just loop? O_o

about the only thing I can do at this point is force the 5th teleport to always be a reset if the correct order is not obtained…

First of all.. Please put the code in code tags, as it will become easier for people to help you.

Sorry, used to people saying "spoiler anything long" I'll use the cod tags instead.

You might want to declare "redo" as a function, not as the return value of cblock.setCommand…
local redo = function()
	cblock.setCommand("/tp @p 263 63 -149")
	cblock.runCommand()
	N=0
	S=0
	E=0
	W=0
	sleep(1)
end

Been a while since I programmed and that was a very different lanaguage. I'll do that.
LBPHacker #5
Posted 04 May 2013 - 02:51 AM
Threw this together in the early morning - hopefully it works, but if it doesn't, you still got a bunch of comments to learn from…
Spoiler
local warp1 = function()
    print("Yay warp 1!") -- or whatever
    sleep(1)
end

local warp2 = function()
    print("Yay warp 2!")
    sleep(1)
end

local warp3 = function()
    print("Yay warp 3!")
    sleep(1)
end

local recent = {0, 0, 0, 0}
local warps = { -- two dimensional table for the win!
    -- {direction_1, direction_2, direction_3, direction_4, function_to_call}
    {2, 2, 4, 1, ["func"] = warp1}, -- try 1, 4, 2, 2 (so reverse) if it doesn't work at first
    {4, 2, 2, 3, ["func"] = warp2}, -- leave ["func"] as it is, please
    {1, 1, 4, 1, ["func"] = warp3} -- warpX is the NAME of the function here (and that function should include the sleep as well)
}
-- S is 1, N is 2, E is 3 and W is 4, but now everything is 0
-- by the way, in Lua, NULL is "nil"

local push = function(direction)
    -- this pushes the most recent direction to the top if the "recent" table (that's recent[1]),
    -- and the other records go 1 index down, so recent[4] = recent[3]; recent[3] = recent[2], etc.
    for i = #recent - 1, 1, -1 do recent[i + 1] = recent[i] end
    recent[1] = direction
end

local reset = function()
    cblock.setCommand("tp @p 263 63 -149") -- notice the lack of / (so it's not necessary)
    cblock.runCommand()
    recent = {0, 0, 0, 0}
    sleep(1)
end

while true do
    os.pullEvent("redstone") -- waits until something happens on the restone inputs
    if rs.getInput("back") then
        push(1)
    elseif rs.getInput("right") then
        push(2)
    elseif rs.getInput("left") then
        push(3)
    elseif rs.getInput("front") then
        push(4)
    end
    -- used if-elseif-end block here, because this way only one direction will get
    -- into the "recent" table, even if more than one restone input is active
    local resetNeeded = true
    -- resetNeeded stays true if every direction in "recent" are the same
    for i = 1, #recent - 1 do resetNeeded = (recent[i] == recent[i + 1]) and resetNeeded end

    if resetNeeded then
        reset()
    else
        for i = 1, #warps do
            local warpNeeded = true
            for j = 1, #recent do warpNeeded = (recent[j] == warps[i][j]) and warpNeeded end
            if warpNeeded then
                pcall(warps[i]["func"])
                reset() -- I think it's necessary
            end
        end
    end
end
Ashton #6
Posted 04 May 2013 - 02:52 PM
Well… the code is good (except I'm getting an error about trying to index a nil value, but that's not important now) however, after running the gamut 10 times, I only got the correct response once. While the redstone/PC/CommandBlock is a great tool the redstone wiring and pressure-plates are just WAY too unreliable to use… if I were to export this as a single-player map it might work, but as it is, the redstone doesn't always transmit, is delayed, etc, so I either get no input or sometimes inputs out of order due to lag spikes… (I even tried placing buttons 2 blocks from the PC and using those for the redstone signals, still didn't get the right response unless I pressed, waited, watched and if the redstone didn't activate, hit it a second time…)

I'm severely dissapointed, this mod has SO MUCH potential to revolutionize dungeon building since it can allow the creation of macros/scripts that straight redstone doesn't allow… but the game itself is too unstable for it to work reliably… looks like I'm going to have to go back to building a physical maze… maybe if RedPower ever releases a new update I'll try the cables to see if they're more reliable than the redstone…

Thanks though! I really do appreciate it :)/>