Lua level formula - math

I'm trying to calculate a players level depending on the players experience.
This is what I have in text:
Start at level 0 with 0 XP
To reach level 1, you need 50 XP.
One kill gives 10 XP.
So, 5 kills = 50 XP = level 1.
Now, level 2 should require 50 XP more than last level.
So, level 2 requires a total of 150 XP.
Level 1: 50 XP (5 kills total, 5 kills to go from level 0 to 1).
Level 2: 150 XP(15 kills total, 10 kills to go from level 1 to 2).
Level 3: 300 XP(30 kills total, 15 kills to go from level 2 to 3).
So far, all I got is this:
math.Round( xp / 50 )
This is 50 xp per level which isn't what I wanted; but I have really no idea where to go from here.
Simply put, I want each level to require 50 more XP than last level, and I need to get the level from an xp variable.

A quick math calculation shows that the experience point to reach level lv would be:
(1 + 2 + 3 + ... + lv) * 50
which equals:
lv * (lv + 1) / 2 * 50
So the question becomes to find the maximum non-negative integer lv that qualifies:
lv * (lv + 1) / 2 * 50 <= xp
That's the formula needs to be solved. And the math solution is:
lv <= (math.sqrt(xp * 4 / 25 + 1) - 1) / 2
Since you are looking for a non-negative integer, in the words of Lua, that's:
local lv = math.floor((math.sqrt(xp * 4 / 25 + 1) - 1) / 2)
You can wrap it to a function and give it a quick test like this:
function xp_to_lv(xp)
return math.floor((math.sqrt(xp * 4 / 25 + 1) - 1) / 2)
end
assert(0 == xp_to_lv(0))
assert(0 == xp_to_lv(49))
assert(1 == xp_to_lv(50))
assert(2 == xp_to_lv(260))
assert(3 == xp_to_lv(310))

Related

How to get the mid of 2 int32 number elegantly without overflow?

In some conditions like Segment Tree or Binary Search, I have to get the average value of 2 number.
An easy solution is mid = (a + b) / 2. But when it comes to a and b have the same plus-minus signs, The a + b thing will overflow. For example, 1234567 + 2147483647, -1234567 + (-2147483647) in int32 type.
I searched online and got to know mid = (b - a) / 2 + a, it can avoid the situation above, but still not perfect. When it comes to a and b have the different plus-minus signs, mid = (a + b) / 2 won't overflow but (b - a) / 2 + a will. For example, -2147483648 + 2147483647 in int32 type.
To thoroughly solve this problem, I've written the code in pic below. I divide the 2 situations by the plus-minus signs. (I use some bit operations to improve its efficiency.) But it is way too complex for such a simple problem, right?
Is there some elegant solution to this problem?
I tried to divide the problem to 2 situations and solve them respectively.
But I still want a more elegant solution.
Got the answer!
mid = (a & b) + ((a ^ b) >> 1)
a & b keeps the same bits that a and b have in common, they need not to be distributed averagely. Like when you find the average value of 102 and 110, you don't need to calculate the 100 they have in common. You can just keep that, and deal with the 2 and 10 part, distribute them averagely to 2 number. As (102 + 110) / 2 = (2 * 100 + 2 + 10) / 2 = 100 + (2 + 10) / 2 = 100 + 6 = 106.
(a ^ b) >> 1 deals with the "2 and 10 part", it gets all the bits that a and b don't have in common, and divide it by 2.
Adds up 2 parts above so we get the average value of a and b. Not a strict proof, though.

Jacobsthal number recursion formula

I have a very simple (and stupid :) question:
How do I get from this expression:
To this recursion formula?
I do not want any complete solution, but maybe you can help me to understand it with just a few tips.
Thx, and a nice day :)
This is very similar to [Wikipedia]: Fibonacci number, and is a typical [Wikipedia]: Mathematical induction example.
Starting from the assumption that the formula is true for (a given) n (let's call this P(n)):
Jn = 2 * Jn - 1 + (-1)n - 1
then, using the above equality and the function definition, you must prove P(n + 1) - that the formula is also true for (the consecutive) n + 1. This is the one in your question:
Jn + 1 = 2 * Jn + (-1)n
Since this is a programming site (and I'm too lazy calculating the first few values manually), here's some Python code that does that for us:
>>> def j(n):
... if n <= 0:
... return 0
... elif n == 1:
... return 1
... else:
... return j(n - 1) + 2 * j(n - 2)
...
>>>
>>> for i in range(15):
... print("{:2d} - {:4d}".format(i, j(i)))
...
0 - 0
1 - 1
2 - 1
3 - 3
4 - 5
5 - 11
6 - 21
7 - 43
8 - 85
9 - 171
10 - 341
11 - 683
12 - 1365
13 - 2731
14 - 5461
From the above, it's kind of noticeable by the naked eye that the formula is true. Now the induction mechanism should be applied: start from P(n) and using the function definition (3rd branch) get to P(n + 1). That might not be trivial, considering there's a level 2 dependency (most of the terms that will eventually reduce each other, but I didn't try it to see how "visible" that would be). You could check [SO]: Recursive summation of a sequence returning wrong result (#CristiFati's answer), for more details on a simpler problem.
Note:
Given the current coefficients, I must mention recursion's characteristic equation (check [Wikipedia]: Constant-recursive sequence) that would give a non recurring formula for Jn:
Jn = Jn - 1 + 2 * Jn - 2 translates to: x2 = x1 + 2 * x0 -> x2 - x - 2 = 0 (which has -1 and 2 as roots), and from here (using Binet (or Moivre) formula):
Jn = (2n - (-1)n) / 3 (denominator value is: 2 - -1)
Let the computer do some calculations from us (check that previous implementation results match this one's):
>>> def j_simpl(n):
... return (2 ** n - (-1) ** n) / 3
...
>>>
>>> print(all(j(i) == j_simpl(i) for i in range(20)))
True

Google Foobar Fuel Injection Perfection

Problem:
Fuel Injection Perfection
Commander Lambda has asked for your help to refine the automatic quantum antimatter fuel injection system for her LAMBCHOP doomsday device. It's a great chance for you to get a closer look at the LAMBCHOP - and maybe sneak in a bit of sabotage while you're at it - so you took the job gladly.
Quantum antimatter fuel comes in small pellets, which is convenient since the many moving parts of the LAMBCHOP each need to be fed fuel one pellet at a time. However, minions dump pellets in bulk into the fuel intake. You need to figure out the most efficient way to sort and shift the pellets down to a single pellet at a time.
The fuel control mechanisms have three operations:
Add one fuel pellet Remove one fuel pellet Divide the entire group of fuel pellets by 2 (due to the destructive energy released when a quantum antimatter pellet is cut in half, the safety controls will only allow this to happen if there is an even number of pellets) Write a function called solution(n) which takes a positive integer as a string and returns the minimum number of operations needed to transform the number of pellets to 1. The fuel intake control panel can only display a number up to 309 digits long, so there won't ever be more pellets than you can express in that many digits.
For example: solution(4) returns 2: 4 -> 2 -> 1 solution(15) returns 5: 15 -> 16 -> 8 -> 4 -> 2 -> 1
Test cases
Inputs: (string) n = "4" Output: (int) 2
Inputs: (string) n = "15" Output: (int) 5
my code:
def solution(n):
n = int(n)
if n == 2:
return 1
if n % 2 != 0:
return min(solution(n + 1), solution(n - 1)) + 1
else:
return solution(int(n / 2)) + 1
This is the solution that I came up with with passes 4 out of 10 of the test cases. It seems to be working fine so im wondering if it is because of the extensive runtime. I thought of applying memoization but im not sure how to do it(or if it is even possible). Any help would be greatly appreciated :)
There are several issues to consider:
First, you don't handle the n == "1" case properly (operations = 0).
Next, by default, Python has a limit of 1000 recursions. If we compute the log2 of a 309 digit number, we expect to make a minimum of 1025 divisions to reach 1. And if each of those returns an odd result, we'd need to triple that to 3075 recursive operations. So, we need to bump up Python's recursion limit.
Finally, for each of those divisions that does return an odd value, we'll be spawning two recursive division trees (+1 and -1). These trees will not only increase the number of recursions, but can also be highly redundant. Which is where memoization comes in:
import sys
from functools import lru_cache
sys.setrecursionlimit(3333) # estimated by trial and error
#lru_cache()
def solution(n):
n = int(n)
if n <= 2:
return n - 1
if n % 2 == 0:
return solution(n // 2) + 1
return min(solution(n + 1), solution(n - 1)) + 1
print(solution("4"))
print(solution("15"))
print(solution(str(10**309 - 1)))
OUTPUT
> time python3 test.py
2
5
1278
0.043u 0.010s 0:00.05 100.0% 0+0k 0+0io 0pf+0w
>
So, bottom line is handle "1", increase your recursion limit, and add memoization. Then you should be able to solve this problem easily.
There are more memory- and runtime-efficient ways to solve the problem, which is what Google is testing for with their constraints. Every time you recurse a function, you put another call on the stack, or 2 calls when you recurse twice on each function call. While they seem basic, a while loop was a lot faster for me.
Think of the number in binary - when ever you have a streak of 1s >1 in length at LSB side of the number, it makes sense to add 1 (which will flip that streak to all 0s but add another bit to the overall length), then shift right until you find another 1 in the LSB position. You can solve it in a fixed memory block in O(n) using just a while loop.
If you don't want or can't use functools, you can build your own cache this way :
cache = {}
def solution_rec(n):
n = int(n)
if n in cache:
return cache[n]
else:
if n <= 1:
return 0
if n == 2:
return 1
if n % 2 == 0:
div = n / 2
cache[div] = solution(div)
return cache[div] + 1
else:
plus = n + 1
minus = n - 1
cache[plus] = solution(n + 1)
cache[minus] = solution(n - 1)
return min(cache[plus], cache[minus]) + 1
However, even if it runs much faster and has less recursive calls, it's still too much recursive calls for Python default configuration if you test the 309 digits limit.
it works if you set sys.setrecursionlimit to 1562.
An implementation of #rreagan3's solution, with the exception that an input of 3 should lead to a subtraction rather than an addition even through 3 has a streak of 1's on the LSB side:
def solution(n):
n = int(n)
count = 0
while n > 1:
if n & 1 == 0:
n >>= 1
elif n & 2 and n != 3:
n += 1
else:
n -= 1 # can also be: n &= -2
count += 1
return count
Demo: https://replit.com/#blhsing/SlateblueVeneratedFactor

Distributing teams into units

Really struggling to solve this problem correctly.
my solution, that correctly solves some of the test cases is here:
Really hoping that someone can help me understand what's missing, or point me to solutions that I can learn from
Problem Description:
administration is considering to house each team in several units with at least 5 people per unit. A team can have from 5 to 100 members, depending on the sport they do. For example, if there are 16 team members, there are 6 ways to distribute the team members into units: (1) one unit with 16 team members; (2) two units with 5 and 11 team members, respectively; (3) two units with 6 and 10 team members, respectively; (4) two units with 7 and 9 team members, respectively; (5) two units with 8 team members each; (6) two units with 5 team members each plus a third unit with 6 team members. This list might become quite lengthy for a large team size.
In order to see how many choices to distribute the team members there are, the administration would like to have a computer program that computes for a number n the number m(n) of possible ways to distribute the team members into the units allocated, with at least 5 people per unit. Note that equivalent distributions like 5 + 5 + 6, 5 + 6 + 5 and 6 + 5 + 5 are counted only once. So m(16) = 6 (as seen above), m(17) = 7 (namely 17, 5 + 12, 6 + 11, 7 + 10, 8 + 9, 5 + 5 + 7, 5 + 6 + 6) and m(20) = 13.
The computer program should read the number n and compute m(n).
The recursion is pretty simple: We can count the partitions of n items that include the lower bound, and those that don't, and add them together. If we include the lower bound (lb), then there are n - lb more items to place, and our lower bound hasn't changed. If we're not including it, then there are still n items to place, but our lb has increased. Our base cases are simple: when the lower bound is higher than the number of items, there are no partitions. When they're equal, there is one. This code should do it:
def count (n, lb):
if (lb > n):
return 0
if (lb == n):
return 1
return count (n - lb, lb) + count (n, lb + 1)
count (20, 5) #=> 13
If you want to test different values, you can use a JS version of this:
const count = (n, lb) =>
lb > n
? 0
: lb == n
? 1
: count (n - lb, lb) + count (n, lb + 1)
console .log (count (20, 5))
And if you want to see the actual values instead of the counts, you can run this variant:
const count = (n, lb) =>
lb > n
? []
: lb == n
? [[n]]
: [
... count (n - lb, lb) .map (r => [lb, ...r]),
... count (n , lb + 1)
]
console .log (count (17, 5))

Looking for a logic to keep a fraction in a range

I need to write some code that can calculate a variable which shows the preference of a consumer to buy a component for his laptop. The preference changes by the tax (T) and the importance of prices on people's purchases (PriceI). I need to include both T and PriceI to find the person's willingness (W) for purchasing a laptop. Tax changes in a slider ranging from 50 Cent to $6 . I want to keep the variable W in a range from 1 to 2, where 1 is when the tax is on its default, minimum values which is 50 cent.
So There are 2 variables that have influence on W:
50<T<600
0.6 < PriceI < 9
Since I want 1<W<2, I thought it should work if I first normalize all the data by dividing them by their max, then in order to find a fraction to be between 1 and 2, I made the numerator to be less than 4 and the denominator to be less than 2, hoping to have the result between 1 to 2 :
to setup-WCalculator
ask consumers [
set PP ((PriceI / 9) * 2)
set TT ((T / 600) * 4)
set W TT / PP
]
end
However, Netlogo makes both PP and TT zero while they should be a small value like 0.15! Does the logic for finding W make sense?
Thanks,
Normalization is normally done with a formula such as
TT = (T - Tmin) / (Tmax - Tmin)
or here
TT = (T - 50) / (600 - 50)
That gives a normalized value between 0 and 1 as T ranges between 50 and 600. If you want TTT to range between 1 and x, where x is > 1, then you can set
TTT = 1.0 + TT * (x - 1.0)
So
TTT = 1.0 + TT * (4.0 - 1.0) = 1.0 + TT * 3.0
will give you a value between 1 and 4.

Resources