Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Optimised way of creating random text fast?

Asked by
trecept 367 Moderation Voter
5 years ago
Edited 5 years ago

I'm trying to achieve a glitch effect on text where letters are constantly and quickly changing to random letters/numbers/symbols, but I'm not sure how to efficiently do this.

I was thinking of creating a table of stuff like

local letters = {"a", "A", "b", "B", "!", "L"} --etc

and then using math.random to pick a random letter/symbol/number from that table and copy pasting that to create a random string about 20 characters long,

string.Text = letters[math.random(1, #letters)]..letters[math.random(1, #letters)]..letters[math.random(1, #letters)]..letters[math.random(1, #letters)]..letters[math.random(1, #letters)]..letters[math.random(1, #letters)] --etc

but I feel like this method is really inefficient and would cause bad client lag. Is there any other way to make text change constantly (in a loop) to random letters/numbers/symbols very quickly (like 0.05 seconds) and for it to be optimised? Thanks

1 answer

Log in to vote
3
Answered by 5 years ago
Edited 5 years ago

Caution

You want to be careful with a problem like this. Strings in Lua are incredibly fast -- but not without sacrificing memory. Lua actually caches every unique string while the program is running (this is where the speed benefit comes from), therefore every new concatenation of a string is held in memory. For example, a .. b and b .. a would be considered two unique strings and they would both be cached (assuming that a ~= b).

This is because strings are treated as objects in Lua. If you create the same string twice, for example, letter = "A" and char = "A", both variables just become references to "A" in memory.

This is also why you can't change strings in Lua. Once you create a string, that's it! Set in stone. You can only create new strings that are modified versions of other strings.

Why is This Important?

Usually this isn't an issue, and you shouldn't have to worry about this. However, in circumstances where this concatenation is occurring in a tight or continuous loop, this is crucial to know. Due to the fact that Lua is caching every new unique string that's created, your program will eventually start to throttle if this is not accounted for.

Imagine a scenario where your program is generating 10000 unique string codes:

generate_codes(10000)
--> hW81kam173
--> LkkJw93j_l8M
--> 10Kau30fcm9
--> ...

This means your program is allocating memory for each one of those string objects. Yikes.

Solution I

A popular solution is to store the individual characters in a temporary table, then join them together with table.concat -- this will avoid caching the string in Lua. Here's an example:

local function randString(len)
    local chars = {}
    for i = 1, len do
        chars[i] = string.char(math.random(33, 126))
    end
    return table.concat(chars)
end

print(randString(5)) --> WkK2_

Now, depending on your desired outcome, you may require a different version of this solution. This function will take an integer (the length of the randomly generated string) and return a string with random characters that is length long.

The randomness of the string comes from picking a number between 33 and 126 (ASCII codes) and converting that code into a character by using string.char

Solution II

On the other hand, you may want to define a character set to pick random characters from instead of choosing between all the characters from 33-126. In this case, you could just pass an array and apply the same logic:

local function randString(len, charSet)
    local chars = {}
    for i = 1, len do
        chars[i] = charSet[math.random(#charSet)]
    end
    return table.concat(chars)
end

local charSet = {"a", "b", "c", "!"}
print(randString(5, charSet)) --> cbb!a

It's your preference. You could also create some hybrid of the two by returning random characters from 33-126 if no character set is given, or choose characters in a defined set when one is given. I'll leave that for you to do if you're interested (or you could post another question about it if you want some help!)

Just a tip...

For the second solution, I would recommend defining your character set early on in your code instead of passing a new table with the same characters every single time. For example...

local charSet = {"a", "b", "c", "!"}

-- ...
-- ...
-- ...

local function randString(len, charSet)
    local chars = {}
    for i = 1, len do
        chars[i] = charSet[math.random(#charSet)]
    end
    return table.concat(chars)
end

-- repeating use of `charSet`
print(randString(5, charSet)) --> cbb!a
print(randString(5, charSet)) --> ba!!c
print(randString(5, charSet)) --> baca
print(randString(5, charSet)) --> c!baa

Let me know if you have any questions!

0
Amazing! Thank you so much!! trecept 367 — 5y
0
about the char = "A" and string = "A" by references to A, does it actually cache new copies of it? Minhkhang2401 0 — 2y
0
Should I set the table back to nil after concatenating it to avoid memory leak? Minhkhang2401 0 — 2y
Ad

Answer this question