Augustas
This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
augustas656's read() replacement questions topic
Started by augustas656, 09 May 2014 - 09:49 PMPosted 09 May 2014 - 11:49 PM
Regards
Augustas
Augustas
Posted 10 May 2014 - 12:05 AM
Look in the APIs and bios.lua
Posted 10 May 2014 - 12:45 AM
Specifically, those files can be found inside your computercraft mod folder under assets\computercraft\lua\.
Posted 10 May 2014 - 02:07 AM
because I'm feeling in quite a charitable mood today, here you go, write, print and read as of ComputerCraft 1.6x (iirc)
Posted 11 May 2014 - 01:18 PM
So:
Or you can't?
functiont test()
function a()
print("a")
end
end
test.a()
or something?Or you can't?
Posted 11 May 2014 - 01:29 PM
no, well yes, well yes and no…
if you program correctly, then no. however using the example function declaration you have there, yes, but you don't invoke it like you think you do…
Correct programming convention (this will not allow invocation of function)
Incorrect programming convention (will allow invocation of function)
if you give more of a description as to why you want to do this we can give you further assistance as to a method of doing what you want, or potentially steer you down a better path.
if you program correctly, then no. however using the example function declaration you have there, yes, but you don't invoke it like you think you do…
Correct programming convention (this will not allow invocation of function)
local function foo() --# note the local
local function bar() --# note the local
print("bar")
end
bar() --# you can call it here
end
bar() --# but not here
Incorrect programming convention (will allow invocation of function)
local function foo()
function bar() --# note the lack of local, just like in your example
print("bar")
end
print("foo")
bar() --# you can call it here
end
bar() --# you can also call it here
but do you notice how we invoke it? we invoke it just like normal, meaning we may as well define it like so
local function foo()
print("foo")
end
local function bar()
print("bar")
end
bar()
and doing it like this reduces clutter in the global scope (which is why we should always use 'local' unless we want our functions to be accessed from the global scope)if you give more of a description as to why you want to do this we can give you further assistance as to a method of doing what you want, or potentially steer you down a better path.
Posted 11 May 2014 - 01:52 PM
You could also do it like this:
I dont think this would be useful in anyway, but yeah, its somewhat possible.
local function test(func)
if func == "a" then a()
elseif func == "b" then b()
elseif func == "c" then c() end
end
local function a()
print("a")
end
local function b()
print("b")
end
local function c()
print("c")
end
test("a")
test("c")
test("b")
I dont think this would be useful in anyway, but yeah, its somewhat possible.
Edited on 11 May 2014 - 12:03 PM
Posted 11 May 2014 - 01:54 PM
How is this related to declaring a function in another function?You could also do it like this:local function test(func) if func == "a" then a() elseif func == "b" then b() elseif func == "c" then c() end local function a() print("a") end local function b() print("b") end local function c() print("c") end test('a") test("c") test("b")
I dont think this would be useful in anyway, but yeah, its somewhat possible.
Edit:test('a") should be test("a") and it wouldn't work anyway, missing end of the if statement.
Edited on 11 May 2014 - 11:56 AM
Posted 11 May 2014 - 02:01 PM
I've found a slightly more helpful way using object-oriented programming, creating a table with values and functions, and I use the functions to change the values, I need this because I'm creating an API which creates a customised reader. Then you use this reader onto my read function to execute a customised read.
Thanks Anyway
Thanks Anyway
Posted 11 May 2014 - 02:05 PM
How is this related to declaring a function in another function?You could also do it like this:local function test(func) if func == "a" then a() elseif func == "b" then b() elseif func == "c" then c() end local function a() print("a") end local function b() print("b") end local function c() print("c") end test('a") test("c") test("b")
I dont think this would be useful in anyway, but yeah, its somewhat possible.
Edit:test('a") should be test("a") and it wouldn't work anyway, missing end of the if statement.
I'm sorry, it has been such a long time since I have programmed ComputerCraft stuff.
Also, the test('a") might work, but I'm not sure.
Posted 11 May 2014 - 02:09 PM
no it won't. also you will get an error 'cause you've got the order of functions around the wrong way, when declaring local functions you should declare them ABOVE where you invoke them.Also, the test('a") might work, but I'm not sure.
Posted 11 May 2014 - 02:19 PM
From your posted code I assume you want a function to be called through indexing another function. Using metatables, specifically __call metamethod, you can make a table callable like a function:
local class = {
test = "Hello";
foo = function ()
print("foo")
end;
}
local classMT = { --// metatable of 'class' table
__call = function (self, text) --// Define the '__call' metamethod
print(self.test, text)
end
}
setmetatable(class, classMT) --// Set 'classMT' to be 'class' metatable
class.foo() -->> foo
class() -->> Hello
class(" World!") -->> Hello World!
Edited on 11 May 2014 - 12:20 PM
Posted 11 May 2014 - 02:51 PM
I've created a function called multicompare(args) that throws an error if the amount of args is an uneven number or is below two, if not it will then run an for loop that compares all values on both sides. So like checks if a, b, c, d are equal to e, f, g, h. It can work with 2, 4, 6, 8, 10 and any amount of arguements. Comparing the first on the left with the first on the right side of the even amount of values.
I'm thinking was this wasteful, is there a way to compare multiple values like this easier? Because I've created a custom read function that allows you to customise how you want the read to end, the normal read() function will break if you press ENTER and return the finished string value. I've made it so you can select your own event, and parameters. I want to check if the event and all the parameters and equal to the event and all the parameters of a pullevent faster than a super-long if statement like this: if event == c.event and p1 == c.p1 and p2 == c.p2 and p3 == c.p3 then do something.
Regards
Augustas
I'm thinking was this wasteful, is there a way to compare multiple values like this easier? Because I've created a custom read function that allows you to customise how you want the read to end, the normal read() function will break if you press ENTER and return the finished string value. I've made it so you can select your own event, and parameters. I want to check if the event and all the parameters and equal to the event and all the parameters of a pullevent faster than a super-long if statement like this: if event == c.event and p1 == c.p1 and p2 == c.p2 and p3 == c.p3 then do something.
Regards
Augustas
Posted 11 May 2014 - 03:37 PM
Is this not the same criteria? 1 is an uneven number…the amount of args is an uneven number or is below two
There's not really any simpler way i can think of of the top of my head, personally i think it would be easier to manage if it compared arg 1 to 2 and 3 to 4 etc. The way i handle custom events in my read function, is it's own function. Basically you pass a function as a parameter, this function is called whenever an event is received, and passed the the event and all it's parameters. If the function returns true, the read ends. This makes it far more modular, than just if event and param.
Posted 11 May 2014 - 04:13 PM
The code is part of my API and since I don't want to give away too much of my API, I'm only giving the most relevant code, simple functions such as setPos are obviously setCursorPos, and findSize is getSize and findPos is getCursorPos etc etc.
To start off you have to create a reader, an object that has default values and you can change them by using the reader. functions. To begin with blink is setting if there's going to be a cursor blink or not, charlimit is how many characters you can write, the limit. Readlimit is how many characters are going to be displayed (not implemented yet), char is if the char is going to be hidden and if so then with what string replacing each letter. stop is the event with parameters that has to occur for the reader to terminate, as in finish reading the user's input, by default the read() function stops with pressing key ENTER (28).
For the stop function you don't have to include all the parameters required for the event, because let's say you have a "mouse_click" event and you don't care which button is going to be pressed, left mouse button, middle mouse button or right mouse button. So you can leave it out, which means it's going to be nil. The comparetables function that I use in the read accepts a paremeter called len, for length, which means how many places of both tables do I compare? So if there is going to be no button, there's going to be less parameters event, p1, p2, and no p3 because p3 defines button. The length for that being 3 because it's only event, p1 and p2.
For the char function, if you input false as the char, it will replace it with a pair of double quotes, meaning nothing will be typed at all. So you could do no blink and false which would literally mean you just input chars without seeing a blink or any sign of text. Like the most secret input.
I'm yet to implement the readlimit, although you can set it in the reader, but it won't affect the actual read function, currently I'm getting a malfunction where the cursor blink is always at the front, eventhough if you click right or left arrow keys and type it works, it's only the blink that always stays at the end and if you type extra text it will more forward, always being at the very end.
Code:
Regards
Augustas
To start off you have to create a reader, an object that has default values and you can change them by using the reader. functions. To begin with blink is setting if there's going to be a cursor blink or not, charlimit is how many characters you can write, the limit. Readlimit is how many characters are going to be displayed (not implemented yet), char is if the char is going to be hidden and if so then with what string replacing each letter. stop is the event with parameters that has to occur for the reader to terminate, as in finish reading the user's input, by default the read() function stops with pressing key ENTER (28).
For the stop function you don't have to include all the parameters required for the event, because let's say you have a "mouse_click" event and you don't care which button is going to be pressed, left mouse button, middle mouse button or right mouse button. So you can leave it out, which means it's going to be nil. The comparetables function that I use in the read accepts a paremeter called len, for length, which means how many places of both tables do I compare? So if there is going to be no button, there's going to be less parameters event, p1, p2, and no p3 because p3 defines button. The length for that being 3 because it's only event, p1 and p2.
For the char function, if you input false as the char, it will replace it with a pair of double quotes, meaning nothing will be typed at all. So you could do no blink and false which would literally mean you just input chars without seeing a blink or any sign of text. Like the most secret input.
I'm yet to implement the readlimit, although you can set it in the reader, but it won't affect the actual read function, currently I'm getting a malfunction where the cursor blink is always at the front, eventhough if you click right or left arrow keys and type it works, it's only the blink that always stays at the end and if you type extra text it will more forward, always being at the very end.
Code:
Spoiler
function compareTables(tbl1, tbl2, len)
local equal = true
for i = 1,len do
if tbl1[i] ~= tbl2[i] then
equal = false
break
end
end
end
local function uRead(reader)
term.setCursorBlink(reader.vBlink)
local str = ""
local x, y = findPos()
local pos = 1
local w, h = findSize()
if reader.vChar[1] then
function drawstr()
for i = 1,#str do
term.write(reader.vChar[2])
end
end
else
function drawstr()
term.write(str)
end
end
local function redraw()
setPos(x, y)
term.write(string.rep(" ", w - x + 1))
setPos(x, y) drawstr()
end
while true do
local e, p1, p2, p3, p4 = os.pullEvent()
local einfo = {e, p1, p2, p3, p4}
local rinfo = reader.vStop
if compareTables(einfo, rinfo, #rinfo) then
write("\n")
break
elseif e == "key" then
if p1 == 205 then
if pos <= str:len() then
pos = pos + 1
end
redraw()
elseif p1 == 203 then
if pos > 1 then
pos = pos - 1
end
redraw()
elseif p1 == 14 then
if pos > 1 then
pos = pos - 1
str = str:sub(1, pos - 1)..str:sub(pos + 1)
redraw()
end
end
elseif e == "char" then
str = str:sub(1, pos - 1)..p1..str:sub(pos)
pos = pos + 1
redraw()
end
redraw()
end
return str
end
function newReader()
local reader = {
["vBlink"] = true,
["vCharlimit"] = 0,
["vReadlimit"] = 0,
["vChar"] = {false, nil},
["vStop"] = {"key", 28},
}
function reader.blink(bool)
reader.vBlink = bool end
function reader.charlimit(limit)
reader.vCharlimit = limit end
function reader.readlimit(limit)
reader.vReadlimit = limit end
function reader.char(char)
if char == nil then
reader.vChar = {false, nil}
else
if char == false then
char = ""
else
char = tostring(char)
end
reader.vChar = {true, char}
end
end
function reader.stop(...)
reader.vStop = {...} end
function reader.run()
uRead(reader) end
return reader
end
Regards
Augustas
Posted 11 May 2014 - 04:24 PM
Basically if there's only 1 arugmenet or even amount, that means you are comparing like 1, 2, 3 and 4, 5 you can't do that, it's like an unfinished if statement if 1 == 4 and 2 == 5 and 3 == then. And you can't have 1 because you are comparing one with itself that's unecessary. So yeah. You understand what I maen?
Posted 11 May 2014 - 04:40 PM
I was trying to something similar, but ended up with a full class / object creation
This is to keep a list of coordinates:
Three objects are created within the function, but as it has global scope, the objects can be created anywhere.
It has the advantage of changing other properties automatically, for example if you change the direction using 0,1,2,3 the text equivalent is automatically changed as well.
This is to keep a list of coordinates:
function createCoordObject()
--[[
0 = go south (z increases)
1 = go west (x decreases)
2 = go north (z decreases
3 = go east (x increases)
compass[0] = "south"
compass[1] = "west"
compass[2] = "north"
compass[3] = "east"]]--
clsCoord = {} -- the table representing the class, which will double as the metatable for any instances
clsCoord.__index = clsCoord -- failed table lookups on the instances should fallback to the class table, to get methods
function clsCoord.new(coordName) --equivalent to VB class initialise
local self = setmetatable({}, clsCoord)
self.name = coordName
self.x = 0
self.y = 0
self.z = 0
self.facing = 0
self.compass = "south"
return self
end
function clsCoord.getX(self)
return self.x
end
function clsCoord.setX(self, newVal) -- property let in VB
self.x = newVal
end
function clsCoord.getY(self) -- property get in VB
return self.y
end
function clsCoord.setY(self, newVal)
self.y = newVal
end
function clsCoord.getZ(self)
return self.z
end
function clsCoord.setZ(self, newVal)
self.z = newVal
end
function clsCoord.getFacing(self)
return self.facing
end
function clsCoord.setFacing(self, newVal)
local direction = {}
direction[0] = "south"
direction[1] = "west"
direction[2] = "north"
direction[3] = "east"
self.facing = newVal
if self.facing < 0 then
self.facing = 3
elseif self.facing > 3 then
self.facing = 0
end
-- change self.compass to match
clsCoord.setCompass(self, direction[newVal])
end
function clsCoord.getCompass(self)
return self.compass
end
function clsCoord.setCompass(self, newVal)
local direction = {}
direction["south"] = 0
direction["west"] = 1
direction["north"] = 2
direction["east"] = 3
self.compass = newVal
-- set self.facing to match
clsCoord.setFacing(self, direction[newVal])
end
function clsCoord.goUp(blocks)
blocks = blocks or 1
self.y = self.y + blocks
end
function clsCoord.goDown(blocks)
blocks = blocks or 1
self.y = self.y - blocks
end
--[[uses:
location:getX() get current turtle x coordinate
location:getY() get current turtle y coordinate
location:getZ() get current turtle z coordinate
location:setX(xCoord) set current turtle x coordinate eg location:setX(-235)
location:setY(yCoord) set current turtle y coordinate eg location:setY(66)
location:setZ(zCoord) set current turtle z coordinate eg location:setZ(125)
location:getFacing() returns a number 0 - 3 representing direction of player
location:setFacing(facing) sets direction eg location:setFacing(1) (West)
location:getCompass() returns direction as text eg "north"
location:setCompass("X") sets direction using text eg location:setCompass("south")
location:goUp(X) increases Y coord by X
location:goDown(X) decreases Y coord by X
]]--
location = clsCoord.new("currentLocation")
coordHome = clsCoord.new("homeLocation")
mineEntrance = clsCoord.new("mineEntrance")
end
Three objects are created within the function, but as it has global scope, the objects can be created anywhere.
It has the advantage of changing other properties automatically, for example if you change the direction using 0,1,2,3 the text equivalent is automatically changed as well.
interestingLocation = clsCoord.new("Rocky Outcrop")
interestingLocation:setX(-243)
interestingLocation:setY(64)
interestingLocation:setZ(112)
interestingLocation:setFacing(3)
print("There is a "..interestingLocation:getName().." facing "..interestingLocation:getFacing().." ("..interestingLocation:getCompass()..")")
print("Its coordinates are x = "..interestingLocation:getX()..", y = "..interestingLocation:getY()..", z = "..interestingLocation:getZ())
> There is a Rocky Outcrop facing 3 (east)
> Its coordinates are x = -243, y = 64, z = 112
the output of interestingLocation:getCompass() is already set using the function within a function
clsCoord.setCompass(self, direction[newVal])
By the way this will not work if the shorthand version
clsCoord:setCompass(direction[newVal])
is used (colon instead of dot)Posted 11 May 2014 - 05:00 PM
I already understood what you meant, i'd suggest you read more closely.
Posted 11 May 2014 - 05:06 PM
You appear to have forgotten that term.write moves the cursor when it writes.
local function redraw()
setPos(x, y)
term.write(string.rep(" ", w - x + 1))
setPos(x, y) drawstr()
--move the cursor back to where it's supposed to be here
end
Posted 11 May 2014 - 05:14 PM
Updated Version:
Unlike the read() function, this for some reason doesn't move the entire string when there are characters out of bounds, so if I keep typing characters after the string has reached the end of the screen, it will go beyond the border and I will not see. How can I fix this!? So frustrating can't find the error, looked through my code and it's literally identical apart from the additions to the bios.lua one.
Edit: I highlited red where I think this problem occurs.
Spoiler
function compareTables(tbl1, tbl2, len)
local equal = true
for i = 1,len do
if tbl1[i] ~= tbl2[i] then
equal = false
break
end
end
return equal
end
local function uRead(reader)
term.setCursorBlink(reader.vBlink)
[color=#ff0000]local str = ""
local x, y = term.getCursorPos()
local pos = 1
local w, h = term.getSize()
if reader.vChar[1] then
function drawstr()
for i = 1,#str do
term.write(reader.vChar[2])
end
end
else
function drawstr()
term.write(str)
end
end
local function redraw()
setPos(x, y)
term.write(string.rep(" ", w - x + 1))
setPos(x, y)
drawstr()
setPos(x + pos - 1, y)
end[/color]
while true do
local e, p1, p2, p3, p4 = os.pullEvent()
local einfo = {e, p1, p2, p3, p4}
local rinfo = reader.vStop
if compareTables(einfo, rinfo, #rinfo) then
write("\n")
break
elseif e == "key" then
if p1 == 205 then
if pos <= str:len() then
pos = pos + 1
end
redraw()
elseif p1 == 203 then
if pos > 1 then
pos = pos - 1
end
redraw()
elseif p1 == 14 then
if pos > 1 then
pos = pos - 1
str = str:sub(1, pos - 1)..str:sub(pos + 1)
redraw()
end
end
[color=#ff0000] elseif e == "char" then
str = str:sub(1, pos - 1)..p1..str:sub(pos)
pos = pos + 1
redraw()
end[/color]
[color=#ff0000] redraw()[/color]
end
return str
end
function newReader()
local reader = {
["vBlink"] = true,
["vCharlimit"] = 0,
["vReadlimit"] = 0,
["vChar"] = {false, nil},
["vStop"] = {"key", 28},
}
function reader.blink(bool)
reader.vBlink = bool end
function reader.charlimit(limit)
reader.vCharlimit = limit end
function reader.readlimit(limit)
reader.vReadlimit = limit end
function reader.char(char)
if char == nil then
reader.vChar = {false, nil}
else
if char == false then
char = ""
else
char = tostring(char)
end
reader.vChar = {true, char}
end
end
function reader.stop(...)
reader.vStop = {...} end
function reader.run()
uRead(reader) end
return reader
end
Unlike the read() function, this for some reason doesn't move the entire string when there are characters out of bounds, so if I keep typing characters after the string has reached the end of the screen, it will go beyond the border and I will not see. How can I fix this!? So frustrating can't find the error, looked through my code and it's literally identical apart from the additions to the bios.lua one.
Edit: I highlited red where I think this problem occurs.
Edited on 11 May 2014 - 03:48 PM
Posted 11 May 2014 - 05:16 PM
Oh yeah I used that because just incase if there's 0 arguements, just as an error check.
Edit: I just solved my issue, I'm using two tables, and checking up to a defined length.
Edit: I just solved my issue, I'm using two tables, and checking up to a defined length.
Edited on 11 May 2014 - 03:17 PM
Posted 11 May 2014 - 06:06 PM
bios.lua in github, doesn't have the custom char parameter, you know when you can make your password hidden when inputing text by typing read("*") putting a string in the paremeters to replace each and every character. Yeah the bios.lua file doesn't have it, I'm asking this because I made a custom read function that has a problem, I've tried copying the github's bios.lua read function into my API but it still didn't work on that one aspect, it's that when I type the text can go outside of screen borders, keeps typing eventhough I can't see it. Whereas the normal read() works! So I'm confused, what's the problem here. Since they are different and that is because there isn't a parameter in the bios.lua file for a custom string replacing each character, I wanted to check maybe the script is different so it may fix my problem!
Regards
Augustas
Regards
Augustas
Posted 11 May 2014 - 06:18 PM
Thanks!
Posted 11 May 2014 - 06:18 PM
You're welcome.Thanks!
Posted 11 May 2014 - 06:59 PM
Without reading your code, I would say just do thisUpdated Version:Spoiler
function compareTables(tbl1, tbl2, len) local equal = true for i = 1,len do if tbl1[i] ~= tbl2[i] then equal = false break end end return equal end local function uRead(reader) term.setCursorBlink(reader.vBlink) [color=#ff0000]local str = "" local x, y = term.getCursorPos() local pos = 1 local w, h = term.getSize() if reader.vChar[1] then function drawstr() for i = 1,#str do term.write(reader.vChar[2]) end end else function drawstr() term.write(str) end end local function redraw() setPos(x, y) term.write(string.rep(" ", w - x + 1)) setPos(x, y) drawstr() setPos(x + pos - 1, y) end[/color] while true do local e, p1, p2, p3, p4 = os.pullEvent() local einfo = {e, p1, p2, p3, p4} local rinfo = reader.vStop if compareTables(einfo, rinfo, #rinfo) then write("\n") break elseif e == "key" then if p1 == 205 then if pos <= str:len() then pos = pos + 1 end redraw() elseif p1 == 203 then if pos > 1 then pos = pos - 1 end redraw() elseif p1 == 14 then if pos > 1 then pos = pos - 1 str = str:sub(1, pos - 1)..str:sub(pos + 1) redraw() end end [color=#ff0000] elseif e == "char" then str = str:sub(1, pos - 1)..p1..str:sub(pos) pos = pos + 1 redraw() end[/color] [color=#ff0000] redraw()[/color] end return str end function newReader() local reader = { ["vBlink"] = true, ["vCharlimit"] = 0, ["vReadlimit"] = 0, ["vChar"] = {false, nil}, ["vStop"] = {"key", 28}, } function reader.blink(bool) reader.vBlink = bool end function reader.charlimit(limit) reader.vCharlimit = limit end function reader.readlimit(limit) reader.vReadlimit = limit end function reader.char(char) if char == nil then reader.vChar = {false, nil} else if char == false then char = "" else char = tostring(char) end reader.vChar = {true, char} end end function reader.stop(...) reader.vStop = {...} end function reader.run() uRead(reader) end return reader end
Unlike the read() function, this for some reason doesn't move the entire string when there are characters out of bounds, so if I keep typing characters after the string has reached the end of the screen, it will go beyond the border and I will not see. How can I fix this!? So frustrating can't find the error, looked through my code and it's literally identical apart from the additions to the bios.lua one.
Edit: I highlited red where I think this problem occurs.
local tx, ty = term.getSize()
local cx, cy = term.getCursorPos()
if tx > cx then
term.setCursorPos(1, cy + 1)
end
Posted 11 May 2014 - 08:16 PM
I'm trying to make a multi-line supported read function, and I'm thinking to stop reading you press enter, to create a new line you hold shift and press enter, possible?
Regards
Augustas
Regards
Augustas
Posted 11 May 2014 - 09:26 PM
Threads merged. Stop creating new topics for different questions about the same piece of code.
Posted 13 May 2014 - 05:57 PM
I get an error: bios:114: bad arguement: number expected, got nil
Code: http://pastebin.com/wzgFB8Wx
Help please
Code: http://pastebin.com/wzgFB8Wx
Help please
Posted 13 May 2014 - 06:18 PM
My Bios (1.58) line 114 is just an end statement, so we obviously don't have the same one. Open up your own and have a look, it should point you in the right direction.
Posted 17 May 2014 - 05:43 PM
I have version 1.6 Beta pr2, it may have changed, no? Where do I find the bios file?
EDIT: Fixed it, in string.sub, I had an incorrect arguement.
EDIT: Fixed it, in string.sub, I had an incorrect arguement.
Edited on 17 May 2014 - 03:48 PM