I'm creating a game and currently have to deal with some math.randomness.
As I'm not that strong in Lua, how do you think
Can you make an algorithm that uses math.random with a given percentage?
I mean a function like this:
function randomChance( chance )
-- Magic happens here
-- Return either 0 or 1 based on the results of math.random
end
randomChance( 50 ) -- Like a 50-50 chance of "winning", should result in something like math.random( 1, 2 ) == 1 (?)
randomChance(20) -- 20% chance to result in a 1
randomChance(0) -- Result always is 0
However I have no clue how to go on, and I completely suck at algorithms
I hope you understood my bad explanation of what I'm trying to accomplish
With no arguments, the math.random function returns a number in the range [0,1).
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> =math.random()
0.13153778814317
> =math.random()
0.75560532219503
So simply convert your "chance" to a number between 0 and 1: i.e.,
> function maybe(x) if math.random() < x then print("yes") else print("no") end end
> maybe(0.5)
yes
> maybe(0.5)
no
Or multiply the result of random by 100, to compare against an int in the range 0-100:
> function maybe(x) if 100 * math.random() < x then print(1) else print(0) end end
> maybe(50)
0
> maybe(10)
0
> maybe(99)
1
Yet another alternative is to pass the upper and lower limits to math.random:
> function maybe(x) if math.random(0,100) < x then print(1) else print(0) end end
> maybe(0)
0
> maybe(100)
1
I wouldn't mess around with floating-point numbers here; I'd use math.random with an integer argument and integer results. If you pick 100 numbers in the range 1 to 100 you should get the percentages you want:
function randomChange (percent) -- returns true a given percentage of calls
assert(percent >= 0 and percent <= 100) -- sanity check
return percent >= math.random(1, 100) -- 1 succeeds 1%, 50 succeeds 50%,
-- 100 always succeeds, 0 always fails
end
Related
I am seeing some unexpected behaviour when using a table as an array in pico8 lua when compared to regular PUC-Rio lua
If I run the following code using PUC-Rio lua5.4.4 (ubuntu)
local t={}
for i=1,10 do t[i] = i*10 end
t[2]=nil
t[4]=nil
t[6]=nil
t[8]=nil
print()
for i=1,#t do print(t[i]) end
I get the expected output
10
nil
30
nil
50
nil
70
nil
90
100
However if i run the same code with pico-8 I get:
10
This appears triggered only when I delete (ie set to nil) the t[8] element. if I comment out that line then I get the expected on pico8
10
nil
30
nil
50
nil
70
80
90
100
It appears, in pico8 lua, that the #t size of the array changes to 1 when the t[8] element is set to nil.
Both are expected results, the length operator # in lua returns a number n where t[n] ~= nil and t[n+1] == nil, if there are holes (nil value) inside, the result is undefined.
To find the maximum numeric index, in lua 5.1 you can use table.maxn, in other versions you have to write one.
table.maxn = function(t)
local n = 0
for k, v in pairs(t) do
if type(k) == 'number' and k > n then
n = k
end
end
return n
end
It seem that the size operator #t is just not well defined in lua in the presence of nil values.
https://www.lua.org/pil/19.1.html
"undefined behaviour" in a scripting language.. Nice.
I'm having problem returning spesific amount of decimal numbers from this function, i would like it to get that info from "dec" argument, but i'm stuck with this right now.
Edit: Made it work with the edited version bellow but isn't there a better way?
local function remove_decimal(t, dec)
if type(dec) == "number" then
for key, num in pairs(type(t) == "table" and t or {}) do
if type(num) == "number" then
local num_to_string = tostring(num)
local mod, d = math.modf(num)
-- find only decimal numbers
local num_dec = num_to_string:sub(#tostring(mod) + (mod == 0 and num < 0 and 3 or 2))
if dec <= #num_dec then
-- return amount of deciamls in the num by dec
local r = d < 0 and "-0." or "0."
local r2 = r .. num_dec:sub(1, dec)
t[key] = mod + tonumber(r2)
end
end
end
end
return t
end
By passing the function bellow i want a result like this:
result[1] > 0.12
result[2] > -0.12
result[3] > 123.45
result[4] > -1.23
local result = remove_decimal({0.123, -0.123, 123.456, -1.234}, 2)
print(result[1])
print(result[2])
print(result[3])
print(result[4])
I tried this but it seems to only work with one integer numbers and if number is 12.34 instead of 1.34 e.g, the decimal place will be removed and become 12.3. Using other methods
local d = dec + (num < 0 and 2 or 1)
local r = tonumber(num_to_string:sub(1, -#num_to_string - d)) or 0
A good approach is to find the position of the decimal point (the dot, .) and then extract a substring starting from the first character to the dot's position plus how many digits you want:
local function truncate(number, dec)
local strnum = tostring(number)
local i, j = string.find(strnum, '%.')
if not i then
return number
end
local strtrn = string.sub(strnum, 1, i+dec)
return tonumber(strtrn)
end
Call it like this:
print(truncate(123.456, 2))
print(truncate(1234567, 2))
123.45
1234567
To bulk-truncate a set of numbers:
local function truncate_all(t, dec)
for key, value in pairs(t) do
t[key] = truncate(t[key], dec)
end
return t
end
Usage:
local result = truncate_all({0.123, -0.123, 123.456, -1.234}, 2)
for key, value in pairs(result) do
print(key, value)
end
1 0.12
2 -0.12
3 123.45
4 -1.23
One could use the function string.format which is similar to the printf functions from C language. If one use the format "%.2f" the resulting string will contain 2 decimals, if one use "%.3f" the resulting string will be contain 3 decimals, etc. The idea is to dynamically create the format "%.XXXf" corresponding to the number of decimal needed by the function. Then call the function string.format with the newly created format string to generate the string "123.XXX". The last step would be to convert back the string to a number with the function tonumber.
Note that if one want the special character % to be preserved when string.format is called, you need to write %%.
function KeepDecimals (Number, DecimalCount)
local FloatFormat = string.format("%%.%df", DecimalCount)
local String = string.format(FloatFormat, Number)
return tonumber(String)
end
The behavior seems close to what the OP is looking for:
for Count = 1, 5 do
print(KeepDecimals(1.123456789, Count))
end
This code should print the following:
1.1
1.12
1.123
1.1235
1.12346
Regarding the initial code, it's quite straight-forward to integrate the provided solution. Note that I renamed the function to keep_decimal because in my understanding, the function will keep the requested number of decimals, and discard the rest.
function keep_decimal (Table, Count)
local NewTable = {}
local NewIndex = 1
for Index = 1, #Table do
NewTable[NewIndex] = KeepDecimal(Table[Index], Count)
NewIndex = NewIndex + 1
end
return NewTable
end
Obviously, the code could be tested easily, simply by copy and pasting into a Lua interpreter.
Result = keep_decimal({0.123, -0.123, 123.456, -1.234}, 2)
for Index = 1, #Result do
print(Result[Index])
end
This should print the following:
0.12
-0.12
123.46
-1.23
Edit due to the clarification of the need of truncate:
function Truncate (Number, Digits)
local Divider = Digits * 10
local TruncatedValue = math.floor(Number * Divider) / Divider
return TruncatedValue
end
On my computer, the code is working as expected:
> Truncate(123.456, 2)
123.45
I would like to know how to display a score using a spritesheet. My game is about point collecting and I want to have this energybar to fill up. When the energybar is full an empty one pops up, the full one will disappear for end-game purposes. The spritesheet I have consists of 70 png images.
I could build it up using if-statements but there has to be a better way. Otherwise it would look something like this
if score == 0 then
display.newImage("00.png", x, y)
end
if score == 1 then
display.newImage("01.png", x, y)
end
if score == 2 then
display.newImage("02.png", x, y)
end
if score == 3 then
display.newImage("03.png", x, y)
end
...
if score == 70 then
display.newImage("70.png", x, y)
end
When the score is 71 it displays "01.png"
Since there seems to be a direct relation between score value and filename you are using (meaning that 00 -> '00.png', 1 -> '01.png', ... 70 -> '70.png' etc), and after score=70, the whole sequence repeats, one way of doing this would be to firstly, getting rid of multiplies of 70, then just appending 0 in front for single digit score. Here's a function that does just that:
-- Given a score, returns correct picture name
-- eg. for score = 01 returns 01.png
local function getFilenameFromScore(score)
while true do
if score < 71 then break end
-- get rid of multiplies of 70 by reducing score by 70
-- until it's 0-70
score = score - 70
end
-- if score is between 0 and 9 (one digit, so length is 1)
-- add 0 in front
-- this could also be done with modulo %
if string.len(score) == 1 then
score = '0' .. score
end
-- append .png and return
return score .. '.png'
end
And later, show score as follows:
local scorePicture = getFilenameFromScore(score)
display.newImage(scorePicture, x, y)
Here, scorePicture will depend on score value in the way you described.
I'm trying to calculate the sum of the prime numbers in a given number. For instance, for the number 123456, the result will be 10 because 2+3+5 = 10.
I tried to write a code that does that in Lua but I had some issues.
First, here is the code:
function isPrime(num)
if(num == 1 or (num ~= 2 and num%2 == 0)) then
return false
end
for i=3, math.sqrt(num), 2 do
if(num%i == 0) then
return false
end
end
return true
end
function sumOfPrimes(num)
local sum = 0
for digit in string.gmatch(num,"%d") do
local prime = isPrime(digit)
if(isPrime(digit)) then
sum = sum + digit
end
print(digit)
end
return sum
end
function main()
print(sumOfPrimes(123456))
end
main()
It returnes 9 instead of 10. Another thing I've noticed is it adds 1 also to sum, but 1 isn't a prime. What's the problem here?
string.gmatch returns a string, you need to convert it to number before doing calculations
Btw, you are doing the prime validation twice on your loop.
This is a fixed version (returns 10 as expected):
...
function sumOfPrimes(num)
local sum = 0
for digit in string.gmatch(num, "%d") do
digit = tonumber(digit) --needed conversion
local prime_digit = isPrime(digit)
if prime_digit then
sum = sum + digit
end
end
return sum
end
Here is my Lua code for taking user input, and checking if the number entered is prime. My issue is that the program thinks that any even number is not prime, and any odd number is.
print("Enter a number.")
local number = io.read("*n")
function prime(n)
for i = 2, n^(1/2) do
if (n % i) == 0 then
return false
end
return true
end
end
if prime(number) == true then
print("Your number is prime!")
end
if prime(number) == false then
print("Your number is not prime!")
end
Move return true out of the loop.
Hence:
function prime(n)
for i = 2, n^(1/2) do
if (n % i) == 0 then
return false
end
end
return true
end
You return true too soon. You return true as soon as any i meets the condition. You must place the return after the loop.
I know it's an old post but since it's near the top on google I figured it can't hurt to post up my prime finder. It basically does a few simple checks of the obvious stuff and then loops through whats left in a similar fashion to the first example in Jon Ericson' post. Haven't benchmarked it but it seems to cope well enough.
--returns true if prime
function isPrime(n)
local n = tonumber(n)
--catch nil, 0, 1, negative and non int numbers
if not n or n<2 or (n % 1 ~=0) then
return false
--catch even number above 2
elseif n>2 and (n % 2 == 0) then
return false
--primes over 5 end in 1,3,7 or 9
--catch numbers that end in 5 or 0 (multiples of 5)
elseif n>5 and (n % 5 ==0) then
return false
--now check for prime
else
--only do the odds
for i = 3, math.sqrt(n), 2 do
--did it divide evenly
if (n % i == 0) then
return false
end
end
--can defeat optimus
return true
end
end
If you are going to be checking primality, you might as well pick an efficient algorithm. As one answer (cryptically) pointed out, all even numbers greater than 2 are not prime. Therefore, you can short-circuit the check for half the numbers, which doubles the speed to check any particular number:
function check_prime (x)
-- Negative numbers, 0 and 1 are not prime.
if x < 2 then
return false
end
-- Primality for even numbers is easy.
if x == 2 then
return 2
end
if x%2 == 0 then
return false
end
-- Since we have already considered the even numbers,
-- see if the odd numbers are factors.
for i = 3, math.sqrt(x), 2 do
if x%i == 0 then
return false
end
end
return x
end
There are all sorts of optimizations we could apply, but let's take a shot at doing this in a more Lua manner:
function sieve (x)
if x < 2 then
return false
end
-- Assume all numbers are prime until proven not-prime.
local prime = {}
prime[1] = false
for i = 2, x do
prime[i] = true
end
-- For each prime we find, mark all multiples as not-prime.
for i = 2, math.sqrt(x) do
if prime[i] then
for j = i*i, x, i do
prime[j] = false
end
end
end
return prime
end
To use the sieve function:
prime = sieve(number)
if prime[number] then
print("Your number is prime!")
else
print("Your number is not prime!")
end
In my tests, the sieve version is about 6 times faster than the previous algorithm for generating all the primes less than 1 million. (Your mileage may vary.) You can easily check the primality of all numbers less than number at no extra cost. On the other hand, it uses more memory and if you really want check the primality of just one number, it's less efficient.
I would check for primes by dividing the number with 2 and checking if the floor of the division is equal to the division. It looks like this.
if (input/2 == math.floor(input/2)) then
print("is prime")
else
print("is not prime")
end