if statement not working in Lua for io.read - lua

I'm trying to make a 'simple' Y/N answer choice thing. (That you saw all the time on old programs) But an If Statement I'm using doesn't seem to want to work. I even print out the variable and it is nowhere near what i want to compare yet it still passes it.
--Porgram Functions
function check()
--Local Variables
local num = 0
local loop = true
io.write("Continue? (Y/N):")
--User input
local input = io.read()
while(loop==true) do
if (input=="y" or "Y") then
print("Ok!")
loop = true
num = 1
elseif (input=="n" or "N") then
print("Fine...")
num = 2
else
print("Invalid Answser!")
loop = true
num = 0
end
end
print(input)
return(num)
end
print (check())

I would've written your function like this:
function check()
io.write("Continue? (Y/N): ")
answer = io.read()
while( not (answer == "Y" or answer == "N") ) do
io.write("Invalid Answer! Try again (Y/N): ")
answer = io.read()
end
if answer == "Y" then
print("Ok!")
return 1
else
print("Fine...")
return 2
end
end
print(check())
Some examples of its use:
Continue? (Y/N): Huh?
Invalid Answer! Try again (Y/N): N
Fine...
2
>Exit code: 0
>lua -e "io.stdout:setvbuf 'no'" "a.lua"
Continue? (Y/N): Huh?
Invalid Answer! Try again (Y/N): Y
Ok!
1
A working version of your code would be:
function check()
local num = 0
local loop = true
io.write("Continue? (Y/N):")
while(loop==true) do
--User input
local input = io.read()
if (input == "y" or input == "Y") then
print("Ok!")
num = 1
loop = false --we want to stop looping if input is valid
elseif (input == "n" or input == "N") then
print("Fine...")
num = 2
loop = false --we want to stop looping if input is valid
else
print("Invalid Answser!")
-- loop = true no need to set looping to true again
num = 0
end
end
return(num)
end
The changes made were:
Get the user input inside the while loop, this way if the input is invalid and the loop goes again the same logic behind getting the input is used, we don't have to code two cases for getting input; one outside the loop the other within. It also pauses execution when the loop starts again, this was what was producing all that output!
input == "y" or "Y" doesn't do what you think. Instead it evaluates to (input == "y") or ("Y"), what you want it input == "y" or input == "Y".
You needed to set loop to false when the input was either "y" or "Y" or "n" or "N", otherwise the loop would continue.
Fourthly setting the loop to true inside the loop is unnecessary, it begins as true, and the only change you can make is to set it to false. And since each of the conditions are mutually exclusive i.e input being "y" or "Y" mutually exclusive to input being "n" or "N" or it being neither "y" or "Y" or "n" or "N". You don't need to worry about it being set to false unless you wanted the loop to end.

local function check()
io.write"Continue? (Y/N): "
local ans, num = {y = 1, n = 2}
repeat
num = ans[io.read():lower()] or 3
io.write(({"Ok!\n","Fine...\n","Invalid Answer! Try again (Y/N): "})[num])
until num < 3
return num
end
print (check())

Related

How can I use conditional statements to manipulate information while using io.write?

I want the player to be able to choose a character so I print a list of four characters.
print("Choose a character")
print("1. the rocker")
print("2. the vocalist")
print("3. the drummer")
print("4. the bassist")
I then use the io.write function to allow the player to make a choice between characters 1 and 4. I save the choice in the menu_option variable. I know that I would have to add some code for error handling but I am not worried about that at the moment
io.write('Which character do you choose?')
menu_option = io.read()
I now want to create some conditionals to create a variable that will define the title of the character that the player chose.
if menu_option == 1 then
character = ("the rocker")
elseif menu_option == 2 then
character = ("the vocalist")
elseif menu_option == 3 then
character = ("the drummer")
elseif menu_option == 4 then
character = ("the bassist")
end
This is where my code begins to fail. The write function is correctly writing the choice (from 1 to 4) to the menu_option variable but my if statement block is not correctly functioning. The character variable remains nil.
What am I doing wrong? Thanks for any help you all can give me.
The wrong is that io.read() always returning a string.
You expected a number in your if conditions.
Now you have to correct each if like #Egor wrote in the comment or do...
menu_option = tonumber(io.read())
...and let the if' check for numbers
After that you can do in case of NaN (Not a Number) or entering nothing (i.e. hit only RETURN/ENTER)...
io.write('Which character do you choose? ')
local menu_option = tonumber(io.read())
if menu_option == empty then menu_option = math.random(4) end
-- empty == nil but better (human) readable
...for a random selection.
Moreover i suggest using more local variable declarations so it looks like...
-- File: character.lua
local character = ''
print("Choose a character:")
print("[1] the rocker")
print("[2] the vocalist")
print("[3] the drummer")
print("[4] the bassist")
io.write('Which character do you choose? ')
local menu_option = tonumber(io.read())
if menu_option == empty then menu_option = math.random(4) end
if menu_option == 1 then
character = "the rocker"
elseif menu_option == 2 then
character = "the vocalist"
elseif menu_option == 3 then
character = "the drummer"
elseif menu_option == 4 then
character = "the bassist"
end
print('You choosed:',character:upper())
-- Possible return values...
-- return character:upper(), menu_option -- Two values: first=string second=number
-- return os.exit(menu_option) -- Number can examined on bash with ${?}
-- ^-> Example: lua character.lua || printf '%d\n' ${?}

Bubble Sort algorithm in Lua will not work

I am currently learning Lua, and I am attempting to create a bubble sort algorithm with it. However, I am unable to get this to work. Is anyone able to point out why?
Some details I can point out are that, on shorter lists such as lists 3 elements long, the algorithm does succeed in sorting it but then continues to sort it as if it was not sorted. On longer lists such as lists 5 elements long, the program does not sort it at all. I have gotten this information by making the program print the list every time two elements are swapped.
user_input = 0
list = {}
while user_input ~= "SORT" do
print("Input number value, or input SORT to start sort")
user_input = io.read()
if user_input ~= "SORT" then
table.insert(list, user_input)
end
end
done = false
while done == false do
done = true
for k, v in pairs(list) do
if k ~= 1 then
if list[k] < list[k - 1] then
list[k], list[k - 1] = list[k - 1], list[k]
done = false
for k, v in pairs(list) do
io.write(v .. " ")
end
print()
end
end
if k == 1 then
if list[k] < list[table.maxn(list)] then
list[k], list[table.maxn(list)] = list[table.maxn(list)], list[k]
done = false
for k, v in pairs(list) do
io.write(v .. " ")
end
print()
end
end
end
end
io.write("RESULT: ")
for k, v in pairs(list) do
io.write(v .. " ")
end
print()
In Lua there are 2 functions for creating iterators for tables pairs and ipairs
With pairs the order produced is indeterminate, it will returned all key, value pairs but the order can not be garenteed.
You can find this under next in the reference manual for Lua 5.1
example: {1,2,3,4,5} the output could be 5,2,4,1,3
the order of ipairs is 1 to the first nil it will not return any non-integer keys.
example: {1,2,3,nil,5} would give you 1,2,3
Using pairs your algorithm's output could be correct but could appear incorrect due to the ordering from pairs
You want you use ipairs to evaluate your algorithm's output, so that it will be ordered by index.
Your algorithm does not perform a bubble sort as it is now, I can include corrections for that if you want. For this initial answer I think clearing up what would create an inconsistent output should point you in the right direction.
A bubble sort should "sort" 1 index at a time, the first pass will get the last value of the array sorted. then each pass after sorts following position. for example:
before first pass 2,1,3,4,5,8,7,6
after first pass 1,2,3,4,5,7,6,8
Wikipedia has great pages for sorting algorithms with gif images that can really help understand how it should function: Bubble Sort
You're using pairs() instead of ipairs()
plus your code has an extra maxn() routine that isn't needed.
#! /usr/bin/env lua
local user_input = 0
local list = {}
while user_input ~= 'sort' do
print( 'Input number value, or input SORT to start sort' )
user_input = io.read() :lower()
-- the word 'sort' doesn't return a number, thus no final insertion
table.insert( list, tonumber( user_input ) )
end
local found_swap = true
while found_swap do
found_swap = false
for i = 2, #list do
if list[i] < list[i -1] then
list[i], list[i -1] = list[i -1], list[i]
found_swap = true
end
end
end
io.write( 'RESULT: ' )
for i, v in ipairs( list ) do
io.write( v ..' ' )
end
print()
here's my implementation, a couple notes:
My version of lua (luau) supports type checking etc. so you may need to remove : table from the paramater. (If you'd like to find more out about luau - here's the link: https://roblox.github.io/luau/ - it's really cool)
local function bubbleSort(t: table)
local function check(i, v)
local nextNum = t[i+1]
if nextNum and (nextNum < v) then
t[i] = nextNum
t[i + 1] = v
return true
end
end
local changeMade
repeat
changeMade = false
for i, v in next, t do
changeMade = check(i, v) or changeMade
end
until changeMade == false
end
local tableForSorting = {2,5,4} --2,4,5
bubbleSort(tableForSorting)
print(tableForSorting)
Hope this is of some help and shows how you can really slim down your codebase and it still work exactly the same! The reason yours wasn't working - as others - have mentioned is pairs() doesn't consistently order the list the same way.
In practise we use pairs() for dictionaries while we use ipairs() for arrays. You'll notice i'm using next in this example, next is exactly the same as ipairs(). Drop a question below if you have any follow up questions :)!

Multi-threading functions in Computer Craft

I'm working on a project where I want to update the clock on screen say every 5 seconds unless the user inputs something. This is the code I have so far,
function thread1()
term.clear()
term.setCursorPos(1,1)
write (" SteveCell ")
local time = os.time()
local formatTime = textutils.formatTime(time, false)
write (formatTime)
print ("")
print ("")
for i=1,13 do
write ("-")
end
print("")
print ("1. Clock")
print ("2. Calender")
print ("3. Memo")
print ("4. Shutdown")
for i=1,13 do
write ("-")
end
print ("")
print ("")
write ("Choose an option: ")
local choice = io.read()
local choiceValid = false
if (choice == "1") then
-- do this
elseif (choice == "2") then
-- do that
elseif (choice == "3") then
-- do this
elseif (choice == "4") then
shell.run("shutdown")
else
print ("Choice Invalid")
os.sleep(2)
shell.run("mainMenu")
end
end
function thread2()
localmyTimer = os.startTimer(5)
while true do
local event,timerID = os.pullEvent("timer")
if timerID == myTimer then break end
end
return
end
parallel.waitForAny(thread1, thread2)
shell.run("mainMenu")
Unfortunately it's not working. If someone could help me with this, I would really appreciate it. Thanks :)
You want to do something like this (Im not doing the correct on screen drawing, only the time)
local function thread1_2()
-- both threads in one!
while true do
local ID_MAIN = os.startTimer(5)
local ID = os.startTimer(0.05)
local e = { os.pullEvent() }
if e[1] == "char" then
-- Check all the options with variable e[2] here
print( string.format( "Pressed %s", e[2] ) )
break -- Getting out of the 'thread'
elseif e[1] == "timer" and e[2] == ID then
ID = os.startTimer(0.05) -- shortest interval in cc
redrawTime() -- Redraw and update the time in this function!!!
elseif e[1] == "timer" and e[2] == MAIN_ID then
break
end
end
end
Also, ask this in the proper forum, you have more chance getting an answer there!
Another note, get more into event handling, it really helps.
FYI Lua doesn't have 'multi-threading' as in executing multiple routines simultaneously. What it does have is 'thread parking.' You can switch between routines (yielding) and switch back and it will resume where it left off, but only a single routine will be active at any given time.
This is my go-to Lua reference, which explains in detail:
http://lua-users.org/wiki/CoroutinesTutorial

How Do I Have A Function Return more than true or false?

-- For Example; I have this>
function test()
input = io.read()
if input == "1" then
return -- value one
elseif input == "2" then
return -- value two
elseif input == "3" then
return -- value three
end
end
-- Please note that the values must be able to be called separately :D
How about:
function test()
input = io.read()
if input == "1" then
return 1 -- value one
elseif input == "2" then
return 2 -- value two
elseif input == "3" then
return 3 -- value three
end
end
lol its late..
function test()
return tonumber(io.read())
end

Comparing two index tables by index-value in lua

I'm attempting to compare two tables of equal length with a function, since I don't know of any other way to do so. However, with the following function, it fails to register, and I've no clue why. I'm hoping someone can provide insight to this problem or has a better way of comparing the two tables.
The tables are being populated with the following code:
str = "parameters determined by program (all digits)"
tableone = {}
for word in str:gmatch("%d") do table.insert(tableone,word) end
It's identical for both tables, except, of course, the individual table names. The tables are being populated properly, and display properly when I print them. Here are two tables for the sake of this question:
tableone = {}
tabletwo = {}
for i=1,4 do table.insert(tableone, i) end
for i=1,4 do table.insert(tabletwo, i) end
Obviously, these two tables are going to be equal to each other. The function I wrote to compare the index tables is as follows:
function comparetables(t1, t2)
matchct = 0
for i=1,#t1 do
if t1[i] == t2[i] then
matchct = matchct + 1
end
if matchct == #t1 then
return true
end
end
I tried doing
print(comparetables(tableone,tabletwo))
to see if it'll print "true" but no luck. To me, it seems like it should work without a problem. Yet it doesn't. What am I missing? I've tried searching for something like a table.compare function that someone may have already written, but no such luck in finding one. Thanks for any suggestions!
Additional information:
The reason I'm comparing tables is for a mastermaind-type game. That means the following three rules must apply when comparing tables. The function I created was to just get me started, thinking I could work from there.
When comparing the tables, if the numbers match, Ccount increases by 1.
When comparing tables, if the value exists in a different index position, increment Pcount by 1
For example, with a table of values {1, 3, 3, 4} and a guess of {4, 4, 3, 1}, it would return Pcount of 2 (the one 4 and the 1) and a Ccount of 1 (the three in the third position). I think one of the hardest parts is going to be getting the comparison to recognize that the second 4 in the guess should not increment the Pcount at all.
A slight variant on your code that should work is:
function comparetables(t1, t2)
if #t1 ~= #t2 then return false end
for i=1,#t1 do
if t1[i] ~= t2[i] then return false end
end
return true
end
However I use something more like this: It checks the types of the arguments, their metatables, and a few other cases.
-- This is not clever enough to find matching table keys
-- i.e. this will return false
-- recursive_compare( { [{}]:1 }, { [{}]:1 } )
-- but this is unusual enough for me not to care ;)
-- It can also get stuck in infinite loops if you use it on
-- an evil table like this:
-- t = {}
-- t[1] = t
function recursive_compare(t1,t2)
-- Use usual comparison first.
if t1==t2 then return true end
-- We only support non-default behavior for tables
if (type(t1)~="table") then return false end
-- They better have the same metatables
local mt1 = getmetatable(t1)
local mt2 = getmetatable(t2)
if( not recursive_compare(mt1,mt2) ) then return false end
-- Check each key-value pair
-- We have to do this both ways in case we miss some.
-- TODO: Could probably be smarter and not check those we've
-- already checked though!
for k1,v1 in pairs(t1) do
local v2 = t2[k1]
if( not recursive_compare(v1,v2) ) then return false end
end
for k2,v2 in pairs(t2) do
local v1 = t1[k2]
if( not recursive_compare(v1,v2) ) then return false end
end
return true
end
Here's an example of it in use:
print( recursive_compare( {1,2,3,{1,2,1}}, {1,2,3,{1,2,1}} ) ) -- prints true
print( recursive_compare( {1,2,3,{1,2,1}}, {2,2,3,{1,2,3}} ) ) -- prints false
If you're comparing objects that are more objecty than tabley in an Object oriented sense, then I'd look at implementing the functions in the lua OO way.
Something like this should do the trick:
GameState = {}
GameState.mt = {}
GameState.mt.fns = {}
GameState.mt.__index = GameState.mt.fns
function GameState.new(a,b,c,d)
-- TODO: put argument checks here...
local retval = {}
retval[1] = a
retval[2] = b
retval[3] = c
retval[4] = d
setmetatable(retval, GameState.mt)
return retval
end
function GameState.mt.fns.print( self )
print(" GameState: ", self[1], self[2], self[3], self[4] )
end
function GameState.mt.__tostring( self )
return "GameState: "..self[1].." "..self[2].." "..self[3].." "..self[4]
end
function GameState.mt.__eq(self, other)
-- Check it's actually a GameState, and all its bits match
return getmetatable(other)==GameState.mt and
(self[1] == other[1]) and
(self[2] == other[2]) and
(self[3] == other[3]) and
(self[4] == other[4])
end
Then you'd use it like this:
state1 = GameState.new(1,2,3,4)
state2 = GameState.new(1,2,3,4)
print("State 1 is:")
state1:print()
print("State 2 is:")
print(state2)
print( "state1 == state2 : ", state1 == state2 )
print( "Changing state 2")
state2[1]=2
print( "state1 == state2 : ", state1 == state2 )

Resources