Related
I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!
--encode
function strToBytes(str)
local bytes = { str:byte(1, -1)
for i = 1, #bytes do
bytes[i] = bytes[i] + 100
end
return table.concat(bytes, ',')
end
--decode
function bytesToStr(str)
local function gsub(c)return string.char(c - 100) end
return str:gsub('(%d+),?', gsub) end
implemented :
str = "hello world"
strbyte = strToBytes(str)
bytestr = bytesToStr(strbyte)
print(strbyte)
Output :
204,201,208,208,211,132,219,211,214,208,200
print(bytestr)
Output :
"Hello world"
Hi, I need improving my code above. Actually encode and decode functions is work fine, but I need a little bit change.
I want to make encode functions similar like code above, but, the results is table like below :
{204,201,208,208,211,132,219,211,214,208,200}
Then, same as like my first decode functions, all bytes inside the table should be back to "hello world".
I hope my purpose and explanation above is easy to understand. Thanks in advance for any help and suggestions.
Update explanation :
It is a little bit complicated to explain what is my purposes. But I will try to explain as good as I can.
I am trying to make scripts encoder. Encode functions is in encoder scripts side, and decode function is in encoded scripts side. So I must write concatenate decode function before encoded string.
To clearly my explanation, encoder scripts will load undecode source code.
file = io.open(path, "r")
local data = file:read("*l")
The problem is, table cant concatenate with string.
local data = encode(str)--the result is byte array
local data = "decode("..data..")"
file:write(data)
file:close()
local data = string.dump(load(data),true,true)
My first purpose is to hide some important string, because string.dump result is not hide all string.
My second purpose is, to make an obsfucated code using byteArray.
Any solution or suggestion?
SOLVED
function strToBytes(str)
local byteArray= { str:byte(1, -1) }
for i = 1, #byteArray do
byteArray[i] = byteArray[i] + 100
encoded = '{' ..table.concat(byteArray, ',') .. '}'
end
return "load(string.dump(load(bytesToStr("..encoded.."))))()\n"
end
Thank you so much... 👍
Your code was very close to what you were looking for.
--encode
function strToBytes(str)
local byteArray= { str:byte(1, -1) }
for i = 1, #byteArray do
byteArray[i] = byteArray[i] + 100
end
return '{' .. table.concat(byteArray, ',') .. '}'
end
For the encode I removed the table.concat and now just return the byteArray
--decode
function bytesToStr(byteArray)
local output = "" --initialize output variable
for _,b in ipairs(byteArray) do --use ipairs to preserve order
output = output .. string.char(b - 100) --convert each byte to a char and add to output
end
return output
end
For the decode I use a for loop with ipairs to iterate over each byte and concatenate the values into an output variable.
-- test
str = "hello world!"
strbyte = strToBytes(str)
bytestr = 'return bytesToStr(' .. strbyte .. ')'
strBack = string.dump(load(bytestr),true,true)
print(strbyte)
print(bytestr)
print(load(strBack)())
Test output:
{204,201,208,208,211,132,219,211,214,208,200,133}
return bytesToStr({204,201,208,208,211,132,219,211,214,208,200,133})
hello world!
I need a bit of help with tables.
function t (data)
local t = {}
for _, l in ipairs(data) do t[l] = true end
return t
end
local data = t {['b2'] = '-9 on block, KND on hit, 16f startup.'};
io.write('What do you want to know?', '\n');
re = io.read();
if data[re] then
print('Yo');
end
What I'm trying to do, is if I put in something that's in the data table (in this case I put in b2 when it tells me what I want to know), it will print '-9 on block, KND on hit, 16f startup'.
I have no idea why you need the function t. The table itself is a associative array data structure. A cleaner version of code is like this:
local data = {b2 = '-9 on block, KND on hit, 16f startup.'}
print('What do you want to know?')
re = io.read()
if data[re] then
print(data[re])
end
Note the use of print instead of io.write and I also removed all the useless semicolons.
I have a really noob question for you today. Please keep in mind that this is my first project in Razor so don't be too harsh :)
The problem happens when I print variables to a template.
When it's a simple string I have no problem, but when it's a number it just doesn't print the value.
Works
string url = #CurrentPage.Site.Replace("http://", "").Replace("https://", "");
#url
// prints - www.google.pt
Doesn't work
string num = #CurrentPage.Telefone.Replace(" ", "");
#CurrentPage.Telefone
// prints - 123 456 789
Can anyone explain why this happens?
Thanks :)
You might consider checking this Quick Reference:
http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx/
#{
string num = #CurrentPage.Telefone.Replace(" ", "");
}
#CurrentPage.Telefone
You have to surround the num with () otherwise the razor engine thinks you are trying to add an email adress or something like that.
just put #CurrentPage.Telefone ;)
Try this:
string num = #CurrentPage.Telefone.Replace(" ", "");
#CurrentPage.Telefone
// prints - 123 456 789
Attempt to use #Html.Raw(num) instead of #num
Right now I'm trying to use Lua to receive variables from barcodes sent out from an outside source. When I run this, there is a variable rotation from the local function rot(input) that appears to be "buggy". If I run this code exactly as it is with the print statements below, the rotation will appear and disappear. Please help me understand why this may happen?
Please note: There are two aspects of this code that I'm currently working on. A) Code128 is not properly retrieving the variables. B)My code can definitely be shortened. But I'm new and learning as I go. The main purpose for this thread is to help me understand why code will sometimes display the desired result, then won't the next minute?
Thank you.
Edited: I've updated the code a bit to make it cleaner. Condensed all of my string.match statements into tables with other barcode related fields. Still learning and looking to make it even more cleaner. I love learning this, but am still having the same problem with my local function rot(input) and getting intermittent results. Any help is greatly appreciated!
local function rot(input)
rotTable = {["R"] = "cw", ["I"] = "180", ["B"] = "ccw"}
for k,v in pairs (rotTable) do
if input == k then
rotation = v
else
rotation = ""
end
end
return rotation
end
local function barCode(input)
local bcID = string.match(input,"%^(B%w)")
if bcID == "BY" then
bcID = string.match(input,"%^BY.*%^(B%w)")
end
local bcTable = {
["BC"] = {"code128", 10, string.match(input,"%^BY.*%^BC(%u),(%d*),(%u),%u,%u%^FD(.*)%^FS")},
["B2"] = {"bc2of5i", 20, string.match(input,"%^B2(%u),(%d*),(%u),%u,%u%^FD(.*)%^FS")},
["BE"] = {"ean13", 10, string.match(input,"%^BE(%u),(%d*),(%u),%u%^FD(.*)%^FS")},
["B8"] = {"ean8", 10, string.match(input,"%^B8(%u),(%d*),(%u),%u%^FD(.*)%^FS")},
["B3"] = {"code39", 10, string.match(input,"%^B3(%u),%u,(%d*),(%u),%u%^FD(.*)%^FS")},
["BU"] = {"upc_a", -1, string.match(input,"%^BU(%u),(%d*),(%u),%u%,%u^FD(.*)%^FS")}
}
for k,v in pairs (bcTable) do
if bcID == k then
bcFields = v
bcType, qzone, bcR, bcH, bcHr, bcData = unpack(bcFields)
end
end
hPos = 0
vPos = 0
bcOutput = '<'..bcType..' qzone=\"'..qzone..'\" hbb=\"0\" vbb=\"0\" bbwidth=\"1\" hpos=\"'..hPos..'\" vpos=\"'..vPos..'\" rotation = \"'..rot(bcR)..'\" bgcolor=\"0\" barcolor=\"255\" textcolor=\"255\" barwidth=\"1\" height=\"8\">'..bcData..'</'..bcType..'>'
return bcOutput
end
print(barCode("^BY3^BCN,102,N,N^FDCHF05000042^FS"))
print(barCode("^B2B,110,N,N,N^FD45681382^FS"))
print(barCode("^BUN,183,N,N,N^FD61414199999^FS"))
print(barCode("^B8I,146,N,N^FD212345645121^FS"))
print(barCode("^BEB,183,N,N^FD211234567891^FS"))
I'm not sure what is wrong with your code, if anything, but rot can be written more simply as
local rotTable = {["R"] = "cw", ["I"] = "180", ["B"] = "ccw"}
local function rot(input)
return rotTable[input] or ""
end
In general, you shouldn't need to search Lua tables. For instance, the loop for k,v in pairs (bcTable) do can be replace by indexing as in the code above.