How to store more than one virtual currency in SQL - php

I have a table called users which currently contains column money of type integer which contains the amount of money the user currently has.
However, I would like to expand and have a couple of more currencies that are based on each other. 1 Gold = 10 Silver = 100 Bronze (or something like that). When you get 100 Bronze, they will convert into 1 Gold. The same with 10 Bronze = 1 Silver. All these currencies have their own column in my table. I have a hook function that is called on every request and updates the money, if possible.
I was told though I could use just one column money and then I can play with variables and take out the different currencies.
But my question is: What would be the best method?
In case the latter method is best: How do I put variables to an already existing object (an object which contains user data; I think it’s called stdClass or something like that)? $user->username, etc.?

Just store the equivalent number of bronze. Then use the following algorithm to get as much as possible converted to gold, from the remainder as much as possible to silver and the rest stays in bronze:
Set the number of gold to zero, silver to zero and bronze to whatever the database says.
Set the number of silver equal to the number of bronze divided by 10 (use integer division). Set the number of bronze equal to the number of bronze mod 10.
Set the number of gold equal to the number of silver divided by 10 (use integer division). Set the number of silver equal to the number of silver mod 10.
So if you have 9,327 bronze:
gold=0, silver=0, bronze=9,327
gold=0, silver=932, bronze=7
gold=93, silver=2, bronze=7

I've done something similar before, and I agree that you should just have the one column for "money", and compute other currencies as-needed. If you had separate columns, you'd have to rely on a trigger or application logic to keep them in-sync.

I would convert everything to bronze and just store that value. Any sort of transactions would also be converted to bronze first. The only time you need to convert to silver or gold would be for display.

One way is to only store all currency in Bronze.
That way if you have 123 Bronze you can convert them
123 / 100 //Gold with integer division which should be 1
Remaining are 123 - NumGold * 100 ie 23
so you have
23 / 10 // Silver with integer division should be 2
Remaining are 23 - NumSilver * 10 ie 3 bronze coins.
This was the SQL knows only about Bronze coins and showing them as Gold , Silver is all in the application layer

The accepted answer doesn’t account for values over 9999 since it will add 10 more to silver and give a false output.
The best solution is this:
var bronze, silver, gold;
var myMoney = 32141; // number from database
bronze = myMoney % 10;
myMoney = (myMoney - bronze) / 10;
silver = myMoney % 10;
gold = (myMoney - silver) / 10;
Output:
gold = 321
silver = 4
bronze = 1

Related

Picking Random Elements Based on Weight

Say we have an array of name and weight
Something like
Jane 5
John 3
Dane 0
Doe 1
If weight is 0, the name Dane should show up 1/10th of a time than if the weight is 1
The rest are proportional.
So name Jane will show up 5 more times than Doe
Maximum weight is 10
I am thinking of an efficient algorithm to pick names based on their weight.
The way I currently do is to just translate the weight into a very big array.
So Dane will have an entry. Jane will have 50 entries. And then I pick randomly where each entries have equal chance.
I am using PhP.
I wonder if there is a more efficient way.
You can use the following steps:
Firstly, sum the values of all weight.
Secondly, Generate random number in between 1 and the summation.
Now, we have a random number which is less than or equal of summation of all weight. But we need to have one of the weights. Besides, it should have higher chances to get the higher weight.
We can do this by subtracting all weights one by one from the the generated random number. If the resultant value is non-negative than it may have lower weight. If the resultant value is negative that it should be a higher weighted element.

A suitable scoring algorithm for 3 scores

I have several objects, each object should be rated by [q]Quality, [v]Value and [s]Suitability by a user.
Currently I am retrieving the total average of each object by Score = (q+v+s/3) - That said I run into the popular issue where an object with 1 rating of 10,10,10 is rated higher than a object with 3 ratings of 10,9,9 | 9,10,10 | 10,10,8 - Not good!
I want to score each object by a total. Is there any algorithm that would be best suited? The end result will be in a PHP environment. An example could be roughly what Awwwards has currently for each of its websites listed.
I've looked around and can see similar requirements and the Bayesian method being suggested, I'm not sure how this would match my requirements though as the need for knowing a 'minimum'?
Digging around a bit more, I've found this - applied to some SQL would this work? Any issues?
<?php
$avg_num_votes = 17; // Average number of reviews on all objects
$avg_rating = 4.5; // Average review for all objects
$this_num_votes = 17; // Number of reviews on this object
$this_rating = 4; // Review for this object
$bayesian_rating = (($avg_num_votes * $avg_rating) + ($this_num_votes * $this_rating)) / ($avg_num_votes + $this_num_votes);
echo $bayesian_rating;
//(FR) = ((av * ar) + (v × r)) / (av + v)
//(FR) = ((17 * 4.5) + (17 * 4)) / (17 + 17)
//(FR) = (76.5 + 68) / 34
//(FR) = 162.5 / 34
//(FR) = 4.25
?>
Laplace smoothing is simple to implement, although you have to choose one parameter. It is what is being called "the Bayesian estimate" or "the Bayesian method" although that is not quite right, and there are many other techniques that more accurately implement Bayesian updating for different choices of prior distributions.
Choose M, called the number of "minimum" ratings by some. Calculate the average rating A over all categories. Give each object M average ratings in addition to the users' ratings. If you change M, this changes how much you trust a small sample. Larger values of M give less credit to small numbers of ratings.
You don't need to adjust this based on having three scores. Call the sum the rating.
For example, suppose the average rating anywhere is 25, you have chosen M=3, and you are comparing one object with 1 rating of 30 to an object with 7 ratings of 27. For the first, you calculate a smoothed rating of (30*1 + 25*3)/(1+3) = 26.25. The smoothed rating of the second is (27*7+25*3)/(7+3) = 26.4. So, the second object would have a slightly higher smoothed rating than the first.

3 Conditions + Random Order + Pagination (Code Igniter + MySQL)

I have a tricky issue to solve, let me see if you can help me...
Im developing a services directory using CodeIgniter + MySQL and, due to my client's business rules, theres 3 plan types. (Platinum, Gold and Silver - in this order from best to worse)
There is a table with the companies tha advertise in the directory, and each one of them may be paying one of this 3 plans.
The problem is:
I have to present the results following this rules:
1. Platinum comes first, than gold, than silver
2. Each range of results MUST BE random itself
Platinum 2
Platinum 1
Platinum 3
Gold 3
Gold 1
GOld 2
Silver 2
Silver 3
Silver 1
refresh and i get:
Platinum 1
Platinum 3
Platinum 2
Gold 2
Gold 1
GOld 3
Silver 2
Silver 1
Silver 3
The query in php is something like this:
// after a Select and several joins to filter city, provinces, service types
// i do this to randomize , order and group
$query = $this->db->order_by('plan.level', 'desc');
$query = $this->db->order_by('busines.id', 'random');
$query = $this->db->group_by('business.id');
return $query->result_array();
Until now, so far so good.
The problem is, with so many results, i have to paginate them :)
How can i do this keeping in mind that:
The plan priority must be the same through the pages
the results must be random within the plan "blocks"
BUT the pagination CANT repeat records through pages or omiss some results
i have to achieve something like this (e.g. with a 4 per page pagination)
Page I:
Platinum 1
Platinum 4
Platinum 5
Platinum 3
Page II:
Platinum 2
Gold 5
Gold 3
Gold 1
Page III:
Gold 4
Gold 2
Silver 2
Silver 5
Page IV:
Silver 1
Silver 3
Silver 4
and refreshing, randomly changing the position of records INSIDE THE PLAN BLOCKS, within the pages, without repeat or omiss results in the 4 pages, in this example.
Somebody can help me, please.
Its a challenge one ;) Thanks, Adriano.
Since the randomization of results has to be preserved across sessions (for pagination), why don't you store in PHP instead of MySQL?
An initial query to get the randomized queries in MySQL:
$this->db->select('id');
// The rest of your ActiveRecord query here, randomized
And perhaps storing the IDs in PHP:
$this->session->set_userdata('random_query', $array_of_random_ids);
Then querying it per page
$array_of_random_ids = $this->session->userdata('random_query');
$this->db->from('business');
$this->db->where_in('id', array_slice($array_of_random_ids, $page_number * $length, $views_per_page);
$this->db->limit($views_per_page, $page_number * $length);
And of course resetting the session later, if that's how you choose to do it.

Convert rating percent (50%) to the equivelant 5-star rating in PHP

I'm sure this is possible but my math isn't that fantastic.
I'm showing latest movies on my page and my application uses a 5-star rating system, however, the data I receive from a Web Service arrives as a percentage e.g. 50%.
Is there any way I can convert this percentage to a star rating equivalent, which in this case would be 50% = 2.5, allowing me to show 2.5 stars?
It seems fairly simple when I have 50% but if I get 94%, it confuses my poor little pea for a brain! Please help.
If you want to convert the 0..100 scale to a 0..5 scale, just divide by 20.
If you want it on a half-star boundary, then divide it by 10 instead and that's the number of half-stars you need.
Keep in mind I'm talking about integer division here, where the value is truncated (rounded down).
You may also want to consider rounding it more intelligently during the division, rather than truncating, so that something like 99% is 5 stars (not 4.5). This can be done by simply adding half the amount you're dividing by before the division, something like (in C):
int percent = 94;
int halfstars = (percent + 5) / 10;
This would give the following results for input values between 0 and 100 inclusive:
percent halfstars
------- ---------
0- 4 0
5- 14 1
15- 24 2
25- 34 3
35- 44 4
45- 54 5
55- 64 6
65- 74 7
75- 84 8
85- 94 9
95-100 10
The formula for finding the percentage of a number is fairly simple:
$percentInDecimalForm * $number
For example, a 94% rating would be:
.94 * 5 = 4.7
You just need to solve the following:
100% ---------- 5
94% ---------- x = (94 * 5) / 100 (=) x = 4.7
Now it's necessary to know the granularity of your star scale (how many times you can divide the star).
Since you mentioned 0.5 stars, I'm gonna assume your star granularity is 1 / 0.5 = 2, so just solve:
round(4.7 * 2) / 2 (=) 9 / 2 (=) 4.5

Mathematical problem help

I have some code where, if a user has referred X number of people, he will get X number of credits.
For example, referring 2 people = 1 credit. 4 people = 2 credits, and so on.
However where this gets tricky is, the numbers can be changed so he gets 1 credit per person, or 1 credit per 3 people, 1 credit for 5 people, etc.
If he gets 1 credits for 3 people, and he has referred 5 people, then I would like him to receive 1 credit, and have it stored that he still has 2 people for whom he didn't get any credits. So the next time he refers someone, it is 2 + 1 = 3, and he gets a credit.
My question is,
Given X = Number of people he needs to refer for 1 credit,
and Y = Number of people a user has refered,
(So X might be 3, as in 3 people per credit, and Y might be 6, in which case he should get 2 credits)
1) What's a straightforward formula or function which will X and Y, and return the number of credits which should be given to that person, and
2) Which will also give a remainder for the credits which can't be awarded yet. E.g if X is 3 and Y is 5, the credits would be 1, and remainder would be 2, so with the next referer Y will become 3 again and the user would get 1 credit?
1.)
creditsToPayout = Y/X; //use integer division to truncate, or floor result
remainderReferrals = Y % X; //remainder of Y / X, leftover referrals
You need integer division and modulus. For PHP see here for :
- intval($a / $b)
- $a % $b
If the number can change over time, what happens if, say, intially it is 3 people per credit. He refers 7 people and gets 2 credits with 1 person left over. Then the rule is changed to 4 people per credit. Under that rule he would only get 1 credit with 3 people left over. Do you take a credit back? I'm guessing not, that the new rule only applies to new credits. So I think you need to keep on your database or whatever, the number of credits received, and the number of referrals left that was not sufficient to make a credit. The number of un-credited referrals would then go up and down over time, as he makes new referrals and as they are "exchanged" for credits.
Frankly I think it would be simpler if you could make the rule be X credits per referral rather than X referrals per credit, and then just increase the cost of whatever it is you buy with the credits. Like, if the rule is 1 credit for 5 referrals, and when you get 10 credits you get a free iPod or whatever, then you need 50 referrals to get an iPod. So change it to 1 credit per referral and it takes 50 credits to get an iPod. Then you'd never have to deal with the fractions. But maybe you're not making up the rules and this is all irrelevant.
Number of credits = FLOOR(Y/X)
Remainder = Y-(X*FLOOR(Y/X))

Categories