Large numbers in Texas Hold'em Poker
Server-side application of the online poker engine developed by us works with the Java backend, MySQL database (and, optionally, MongoDB, that can be used for the cache and sessions storage), Facebook Game Client (PHP5) and flash client (ActionScript3).
One of our clients got seriously carried away by organizing bonuses, sales, and other actions, the purpose of which was to motivate users to purchase poker chips. This has significantly improved sales but resulted in a serious problem - hyperinflation.
To date, players operate in sums with millions of digits. The problem went so far that we ran out of existing names of numbers and had to invent custom ones - game numbers with lots of zeros.
The danger of the game currency inflation
Game developers have only positive reinforcements in their arsenal of the means of motivation. They cannot force players to incur losses and suffering, as they have the opportunity at any time to leave the game and go to another. But, as a result, online games almost from the beginning faced the problem of gaming values inflation.
Depreciation of the game currency leads to a loss of motivation, interest in the game and players leaving for the competitors. To keep the interest, the game owners have at least to maintain, if not increase, the rate of inflation, which leads to the second problem - the software restrictions on the sizes of the numbers.
Software limitations
The maximum number in ActionScript3 contains 15-17 orders and 64 in the database. At the moment, the game uses numbers without restrictions on the number of characters, but the database restrictions are very difficult to evade.
The client did not want to give up large numbers, that’s why we had to find a solution to problem of big numbers in Java. In the end, after the series of long and productive discussions, we resorted to the next solution.
If the game does not use the numbers less than million (or they cannot spend such money), then we can safely store the number in the database in millions - 1 mln, 10 mln, 1000 mln and so on... When the number rolls over the 15 available characters, their place is occupied by billions/trillions, and so on, all for the same reason: lesser sums cannot be spent or earned.
That is, we always use the period to 15 characters, and when we lack the 15 digits to record the number, we round numbers (discarding the not used part), and "shift" the 15 digits to the next category (billions, trillions, etc.)
Periodically, when the numbers are close to the "frames" and smaller amounts do not have any value, we must "move" the limits (acceptable range) - 15 digits can be shifted to the left by 3, 6, 9 or 12 digits.
But, given the current rate of inflation, the limits had to be moved quite often. We began to look for options to increase the number frames.
The only way to do converting more rarely is to increase the limits with the help of BigInteger/BigDecimal classes in Java/ActionScript3 and GMP in PHP.
If Java/ActionScript3 supported the operator overloading , the implementation would be simpler, and without drastic changes to the existing code. A classic example would be a library for processing complex numbers. They, as well as the usual numeric types, support the arithmetic operations, and natural would be creating the "plus", "minus", "multiply", "split" operators for this type, designating them by the same characters as for the other numerical types. The ban on the use of certain elements in the language forces to create the multiple functions with names like ComplexPlusComplex, IntegerPlusComplex, ComplexMinusFloat and so on.
As a result, it was necessary to rewrite all math operations to the appropriate BigInteger object type method calls: add, subtr, mul, div etc.
For example, a mathematical expression that looks like this:
(buyValue - from) * dWidth / interval + dStart;
Becomes like this:
buyValue.subtract(from).multiply(dWidth).divide(interval).toNumber() + dStart;
Or was:
buyValue = Math.Round(k * interval / smallBet)*smallBet+ from;
Became:
buyValue = new BigDecimal(k).multiply(interval).divide(smallBet, 0, RoundingMode.HALF_UP).toBigInteger().multiply(smallBet).add(from).
The code became less compact and neat but is not limited to the values of the numbers now.