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

[Question] Is there a way to create a variable based on input?

Started by OutlawBlue9, 20 April 2012 - 01:57 PM
OutlawBlue9 #1
Posted 20 April 2012 - 03:57 PM
I'm not sure if I'm wording this correctly and I'm having a hard time figuring out a simple way to explain it (or maybe I'm just over thinking this…) but here is what I want to do:

Generically speaking, I want to create a variable (a table in this instance, but hypothetically any type of variable) but name it based on user input.


io.read()
>VariableName

And then have a variable created and defined called VariableName.

Specifically speaking, I'm writing a program that will create users and corresponding passwords and permissions all through user input. So when someone creates a new user I want the program to create a new table based on their inputted username and have

username.password = InputtedPassword
username.permissions = admin

etc etc. If anyone has any insight to this let me know. If necessary I can post the code I have now but I figured it would be superfluous. Cheers!
virtualayu #2
Posted 20 April 2012 - 04:53 PM
you can do that : "variableName" = io.read() like user = io.read and pass = io.read()
OutlawBlue9 #3
Posted 20 April 2012 - 05:26 PM
I think you misunderstand me; with that example I have to actually name the variable myself in the code. I want the program to name the variable(which again in this case is a table) based on the input. So if the user inputs "MyNameIs" the code will take that and create a table named "MyNameIs" as well as define several speciic indexes (MyNameIs.password, MyNameIs.permissions, etc). Essentially creating the ability to self make any number of new variables based only on user input.
MysticT #4
Posted 20 April 2012 - 05:36 PM
You can, but you would have to store them in a table.

local tVars = {}
while true do
  local varName = read()
  local value = read()
  tVars[varName] = value
end
This would generate a table containing the variable names (wich are the indexes to the table) and it's corresponding value.
Example Output:

{
  ["User"] = "Pass",
  ["Someone"] = "1234"
}
This is the only way to do it, since creating variables with unknown names wouldn't let you access their value. The variable names aren't stored in the program anyway, so onces it's "compiled" the names doesn't matter (except globals, wich are stored in the global table, with it's name being the index).
OutlawBlue9 #5
Posted 20 April 2012 - 06:55 PM
@MysticT

Interesting…that definitely works great when there is only two different variables (username and pass) but I wonder if there is a way to make it fit well with a third parameter (re: permissions / admin status). I wonder if something like this would work?


local userlist = {}
while true do
	 local username = io.read()
	 local password = io.read()
	 userlist[username.pass] = password
	 userlist[username.adminstatus] = true
end

Would that turn whatever was input as username into a table within userlist with two indexes (pass and adminstatus) or would it just create a table named username with the same indexes?
MysticT #6
Posted 20 April 2012 - 07:21 PM
You can make the value a table, wich can store all the variables you want:

local tVars = {}
write("Enter your username: ")
local user = read()
write("Enter your password: ")
local pass = read("*")
tVars[user] = {}
tVars[user].pass = pass
tVars[user].adminstatus = true

Tables can be indexed in 2 ways (I don't remember now if there's another one, but I think there isn't):

local t = { "First", ["Second"] = 2 }
print(t[1]) -- "First"
print(t["Second"]) -- 2
print(t.Second) -- 2
OutlawBlue9 #7
Posted 20 April 2012 - 08:09 PM
@MysticT Great! I was close with my guess. Thanks a lot! Now granted I'm going to have to scour through my code and completely re-write portions of it, but it'll be worth it in the end to make it more efficient and easier to continue developing.

Man, I really wish Computercraft existed when I took my beginning C++ class 15 years ago. In just two days I've pretty much re-taught most of what I learned in that entire semester (and subsequently forgot…). Using Minecraft and Computercraft to teach kids the basics of coding is probably a genius idea….
OutlawBlue9 #8
Posted 20 April 2012 - 09:09 PM
Hm, alright I tested it out and implemented your recommendation but it doesn't seem to be working as intended. After the program asks for you to confirm the correct Username and Password (lines 51 - 61) it loops back up to home() (line 24) but continues back down to register a new user as if the table userlist was still empty. I tend to miss stupid things sometimes so it's probably that….



--os.pullEvent = os.pullEventRaw --Turned off for debugging purposes
version = "v.01"
userlist = {}
status = "Logged Out"
currentuser = "New User"
a=0
function homescreen()
  term.clear()
  term.setCursorPos(1,0)
  print(string.rep("*", 50))
  print("*Running OutSec "..version.."					  ".. textutils.formatTime( os.time(), false)) --currently displays Minecraft time, not real time
  print("*Status: "..status)
  if status == "Logged In"
   then
    term.setCursorPos(20,3)
    print("User: " ..currentuser)
  end
  print(string.rep("*", 50))
  term.setCursorPos(1,10)
end
homescreen()

function home()
homescreen()
usercheck = table.getn(userlist)
if usercheck == 0 and status == "Logged Out"
  then
   admin = true
   function newuser()
   
    if admin == true
	 then
	  homescreen()
	  print("Please register Admin:")
	  write("Enter Username:")
	 else
	  homescreen()
	  print("Please register User:")
	  write("Enter Username:")
    end
   
    newusername = io.read()
    write("Enter New Password:")
    newpassword = io.read()
   
    homescreen()
    print("Username: "..newusername)
    print("Password: "..newpassword)
    print("Confirm?[Y/N]")
    local event, k1 = os.pullEvent("key")
   
    if k1 == 21 --y
	 then
	  userlist[newusername] = {}
	  userlist[newusername].password = newpassword
	  userlist[newusername].adminstatus = admin
	  home()
	 elseif k1 == 49 then --n
	  newuser()
    end
   end
   newuser()
 
  elseif usercheck > 0 and status == "Logged Out" then
   function login()
    homescreen()
    write("Please enter Username:")
    loginid = io.read()
   
    if userlist[loginid] == nil
	 then
	  print("Invalid Username. Please try again.")
    end
   end
   login()
  
   function password()
    homescreen()
    if a>0
	 then
	  term.setCursorPos(1,9)
	  print("Incorrect Password. ("..x.."/3 attempts remaining.)")
    end
    write("Please enter password:")
    loginpass = io.read()
    if loginpass == userlist[loginid].password
	 then
	  status = "Logged In"
	  currentuser = loginid
	  print("Entry Authorized.")
	  sleep(2)
	  homescreen()
	 else
	  a = a+1
	  x = 3-a
	  if a < 3
	   then
	    password()
	   else
	    a=0
	    homescreen()
	    print("Too many failed attempts. Please wait.")
	    sleep(2)
	    login()
	  end
    end
   end
   password()
end
  
end
home()
MysticT #9
Posted 20 April 2012 - 11:51 PM
I haven't looked at the whole code, but I think the problem is that you are using the table.getn function, wich returns the size of the table, but only if it has numerical indexes. Your table has string indexes, so getn won't work (returning 0 always). You have to use the lenght operator (#):

local t = {}
t["User"] = "password"
t[1] = 5
print(#t) -- prints 2
t.key = "somValue"
print(#t) -- prints 3
It will work for any key type the table can contain, and it's shorter the using a function :)/>/>
OminousPenguin #10
Posted 21 April 2012 - 12:58 AM
Hi OutlawBlue9, I have a few comments which are intended to be helpful:

homescreen() seems to be called about twice as many times as is necessary just overwriting it's previous output with the same thing.

If you enter an invalid username, then the password function gets called anyway asking for the password.

a and x count the same thing but in different directions. I suggest getting rid of one of them.

Your code could do with a few loops. - http://lua.gts-stolberg.de/en/schleifen.php

If you'd like specific examples of changes you could consider making, I'd be happy to provide.
OutlawBlue9 #11
Posted 21 April 2012 - 07:41 AM
@MysticT - Great! I did not know that getn would not work for strings but it sounds like #table would work better than getn even if it wasn't so thanks for the heads up. A much more elegant solution. I implemented your suggestion but it still wasn't working so much but then I tried this:


if k1 == 21 --y
	 then
	  table.insert(userlist, newusername)
	  userlist[newusername] = {}
	  table.insert(userlist[newusername], "password")
	  userlist[newusername].password = newpassword
	  table.insert(userlist[newusername], "adminstatus")
	  userlist[newusername].adminstatus = admin
	  home()
	 elseif k1 == 49 then --n
	  newuser()
    end

and with the inclusion of the insert.table lines I got it functioning properly. Thanks!!! However now it seems I've created a new problem that I'm up against now where if I go through and enter in everything properly it all works fine and logs me in as the username, however if, after I register the new user, if I enter the password incorrectly 3 times it then does print("Too many failed attempts blah blah") and returns to the login function (as it should) but when I type in the username again it closes the program and returns to command prompt. Debugging is like playing a mole game huh? :)/>/>

@OminousPenguin -

As this program is MOSTLY (although having a neat little user database on my server is also useful) to teach me to program after a 15 year hiatus I welcome any and all suggestions / tips to improve efficiency or what have you! I was going to actually create a thread asking for just pure and simple recommendations such as this as I'm always a fan of limiting the focus of individual threads but thank you for your input none the less. But while we're here lets go down your suggestions:

1) I see your point and calling a function too often with no actual change or results is never a good idea and it definitely seems that way now, such as here:


function home()
homescreen()
if #userlist == 0 and status == "Logged Out"
  then
   admin = true
   function newuser()
   homescreen()
    if admin == true
	 then
	  print("Please register Admin:")
	  write("Enter Username:")
	 else
	  print("Please register User:")
	  write("Enter Username:")
    end

Obviously homescreen() has just been called at the beginning of home() and then immediately after in newuser() without any screen changes, however I plan to add in functionality that will call newuser() (and other such functions) at other times which will require a homescreen() flush so to speak. Granted I may have missed an occurrance that is currently and will forever be superfluous so feel free to cite specific example! Or maybe I just missed your point entirely :)/>/> Aside: It may look strange because it wasn't till after I wrote most of this code that I realized you do not have to call a function immediately after ending it (derp!) which is how every example worked in the tutorial I looked at so the function organization is a bit funky. If I were to re write this code (and I probably will do this at some point) I would have functions such as newuser() and login() defined outside of any other functions.

2) Thank's for the heads up! I had not noticed that (mostly because the code as it was wouldn't even run that far and I was preoccupied with the previous error!) but it is now fixed! login() is now called after the nil check and it works as intended (for the most part; see earlier section to MysticT about new bug…)

3) Valid point. changed the call to x in line 85 to 3-a which is all x is anyways as you point out.

4) I'm guessing you mean that some of my if statements could be made shorter with a for or while loop? Correct me if I'm wrong. If that is the case, in my mind the if statement seems simpler I suppose? But lets challenge that. Give me an example of where you would use a loop instead of what I have but don't say anything about how you would implement and I will challenge myself to make it more efficient by using a loop (best way for me to learn eh?)

Again thanks for your suggestions! I always welcome constructive criticism! Especially early on to help defeat long term bad habits. I might make this into a separate "Tear my code apart!!" thread in order to avoid OT discussions so reply there if you could!