Як непрацюючі ігри обробляють таку велику кількість?


31

Цікаво, як такі ігри, як Tap Titans та Cookie Clicker, обробляють таку велику кількість.

Я намагаюся реалізувати простою гру, однак найбільший формат чисел, підтримуваний C #, є десятковим.

Я шукаю підтримки до 10 ^ 500; що має бути плаваючою точкою

Як я міг би впоратися з цим?

PS він повинен бути крос-платформою, тобто ПК, mac, ios, android та сумісним з Unity


2
Якщо я правильно пам’ятаю, у вас є доступ до коду Cookie Clicker, тож ви можете просто перевірити це ...
Vaillancourt

Ні, я вже заблокував Cookie Clicker з розуму!
Артуро Торрес Санчес

2
Я переглянув декомпільоване джерело для TimeClickers , гри Unity. Вони просто використовують double. Якби це я, я б використав BigInteger .
BlueRaja - Danny Pflughoeft

1
@VioletGiraffe: Я згоден, і я хотів би зробити свої (наші?) Сумніви конкретними (можливо, щоб допомогти ОП зробити питання яснішим): Що таке "простою гра" щодо питання (що робить цей вид гри особливий випадок для великої кількості)? На які типи чисел посилаються " такі великі числа" (підкреслив сам)? Якими великими ви хочете бути цифрами?
АБО Mapper

Ви завжди можете зберігати таку велику кількість у рядку та легко реалізовувати функцію для підведення підсумків у рядку.
dev-masih

Відповіді:


40

Якщо ви просто хочете зберігати великі числа без повної точності, наприклад, якщо ви збираєтеся показати 12,567,000,000,000 як 12,567T (трильйон), ви можете просто використовувати стандартні значення float / decimal і показати перші x значущі цифри, з відповідним суфіксом подобається це. Коли ви знаходитесь у octillions, чи вам справді потрібно дбати про кожне окреме ціле збільшення?


4
Це, мабуть, найрозумніша відповідь насправді, і я досить впевнений, що Cookie Clicker просто використовує стандартний float у JavaScript - випадок, коли я його "зламав" (читайте: заплутався з консолі) і коли число досягло 1e308, воно підскочило до "Нескінченності", і я міг би продовжувати купувати все, що хотів XD
Niet the Dark Absol

1
Чудово! Той факт, що текст переходить до "Нескінченності", відчуває, що розробник захисно кодував і цю подію. Також простота - це король.
Росс Тейлор-Тернер

19
@RossTurner - Напевно, кодування не було пов'язано з тим, щоб він відображав текст "Нескінченність" - нескінченність - це просто значення, яке може мати плаваючий потік, і JavaScript знає, як його відобразити, як і багато інших мов.
Jibb Smart

Стандартні поплавці (подвійна точність, 8 байт) не дозволять представляти числа до 10 ^ 500, як вимагає оригінальне запитання, воно підніметься до ~ 10 ^ 300. Якщо цього недостатньо, слід використовувати поплавці квадратичної точності, які можуть бути нетривіальними залежно від мови.
Петріс

1
Що повинен знати кожен програміст про числа з плаваючою комою: floating-point-gui.de
Стів

20

Ви можете використовувати щось на кшталт BigInteger , яке доступне лише в .net 4.0, якщо я не помиляюся (підтримується не всіма платформами збору єдності).

Є деякі бібліотеки, які намагаються надати цю функціональність без вимоги .net4.0. Наприклад тут .

Крім того, ви можете використовувати менші числа для подання більшого, відслідковуючи множник. Наприклад:

double value = 9;
enum Multiplier {
   Hundred,
   Thousand,
   Million,
   Billion,
   Trillion
}

Тепер, навіть якщо у вас є значення 9, якщо ви з'єднаєте його зі своїм множником, ви можете ефективно представити ці 9 як 9 трлн (або ввести "трильйон", або записати щось, що додасть нулі в кінці вашої вартості ).


Варто відзначити, що такі класи, як BigIntegerвикористання рядка або байта [], представляють число - таким чином, фактично можна створити власний клас, який просто додає і віднімає два "числа як рядки або байти" - ( зазвичай цей тип гри не відповідає Це вам не потрібно, але ви можете підтримувати множення чи ділення або інші більш вдосконалені функції ) - але вони повинні мати на увазі, що завжди існує фізичний обмеження, де у них може не вистачати пам'яті.
DoubleDouble

1
Кожен байт помножує розмір вашого номера на 256. Якщо у вас не вистачає пам’яті, намагаючись представити число, ваш номер все одно не мав реального значення. 256 ^ (2 мільярди) = 2 ^ 8 ^ (2 мільярди) = 2 ^ (16 мільярдів) ~ = 10 ^ (5 мільярдів) (wolframalpha зламався, намагаючись зробити останнє перетворення). Ви можете вказати окремі томи Планка у спостережуваному Всесвіті, використовуючи приблизно 150 цифр (<500 біт).
MichaelS

11

Можливо, вам потрібно буде написати власний клас для використання в Unity, але це не буде особливо важко.

Внутрішньо це може бути список цілих чисел (наприклад, а List<int>), причому кожен елемент у списку відповідає групі з 9 цифр. Кожне ціле число матиме діапазон від 0 до 999 999 999. Ціле число може підтримувати трохи більше 2 мільярдів і подвоювати це, якщо воно не підписане, але ви хочете, щоб переливання кожного "цифри" було на 1 000 000 000, тому що ви також хочете щоб легко перетворити велике число у рядок для відображення. Простіше об'єднати, що вже є десятковими цифрами ( return group[i].ToString() + group[i-1].ToString() and so on), ніж зрозуміти, як відобразити суму груп, що знаходяться поза діапазону будь-якого регулярного типу даних.

Отже, перший int у вашому списку представлятиме собою 1s. Наступною буде кількість мільярдів. Наступний, кількість квадрильйонів тощо.

Додавання і віднімання буде працювати так само, як складання і віднімання рукописного паперу, де потрібно стежити за переповненням і переносити його до наступної "цифри", але замість цифр з діапазоном 0-9 ваші цифри варіюються від 0 до 999 999 999.


10

Для обробки великих чисел, я хотів би подивитися на те , що я думаю , що це хороший приклад , як вежі героя . Лівий верхній кут:

1

2
(джерело: mzstatic.com )

Не вступаючи в геймплей, спосіб обробки чисел порівняно простий: ви бачите два відра чисел. Коли ви піднімаєтесь вище у вежі та робите більше "золота", два відра просто представляють більшу кількість.

120 
120M320K - 120 Million
120B631M - 120 Billion
120T134B - 120 Trillion

Після того, як гра проходить T, вона переходить у a, b, c ... z, aa, ab, ...

56aa608z

Роблячи це таким чином, він все ще дає змогу дізнатися, скільки золота ви "заробили" ..., не занурюючи гру в деталі.

Ви дійсно переймаєтеся Мільйонами, коли ваше число минуло Трильйони?

Чи зберігає це число в Int, Big Int, Float, Double, Decimal, ...? Спеціальний масив? Коли ви обробляєте цифри таким "нечітким" способом, я не думаю, що це має значення ...

Все, що, мабуть, має значення - це найважливіша частина - у цьому випадку перші 6 ... Після цього МОЖЕ наступні 3 або 6 - оскільки заробив декілька сотень К може перекинутися на Мільйони - але там отримує бал, коли заробляти кілька сотень К не вплинуть на вас, коли ви натиснете T ... набагато менше аа і далі.

Ваш пробіг буде змінюватися (залежно від того, що ви хочете / потребуєте) ... Я просто подумав, що я поставив би 2с на те, що, на мою думку, є хорошим / простим прикладом.

Редагувати:

Подальші думки щодо того, як я б запровадив систему нумерації: я мав би число з 3-ма важливими частинами: XXXX.YYY (...) xZZZ.

X is the most significant digits, 
Y trailing 
Z the multiplier (multiple of 3).

Отже 120.365x1 було б 120k365 ... 120.365x2 було б 120M365K ... і т. Д. Натисніть на 4 провідні (1200.365x2), а потім просто оберніть числа 1.200365 (...) x3. Бам. У вас є 1B200M.

XY легко впишеться в десятковий або поплавковий ... з Z сидить поруч із ним як int / unsigned int.

За допомогою поплавця ви зможете зберегти значну - але все більш неважливу - кількість цифр після крапки.

Z легко представляє легко зрозумілий блок чисел:

K = 1
M = 2
B = 3
T = 4
a = 5 
...
z = 31 (I may be off on this)
aa = 32
...
az = 58
ba = 59
...
...

1

А найпростіший спосіб обробляти велику кількість - це просто мати більше одного значення INTEGER, а потім здійснити будь-який перелив. Якщо у вас 16-бітове значення INT (від 0 до 65535) і ви хочете мати більше, використовуйте два 16-бітні значення INT підряд. Подумайте про це як про значення BYTE (від 0 до 255), але використовуйте лише 99 значень. Як тільки він набере 100, перетягніть його на наступне вище значення BYTE на стільки цифр, скільки вважаєте корисним. З сучасними комп’ютерами GHZ навіть неохайне кодування подібне.

Звичайно, є альтернатива, яка трохи швидша.
Якщо ви додаєте 18 кілька разів до числа, швидше просто відняти 2 і додати 20. 18, 36, 54, 72, 90, 108, ... 18 = 20 + (- 2).
Він працює і в Binary. (Однакові десятичні значення у двійковій) 10010, 100100, 110110, 1001000
DEC (18) = BIN (10010)
За винятком більш легкого бінарного розбору, потрібно думати про 18 = 16 + 2
DEC (16 + 2) = BIN (10000 + 00010). Якщо значення було 15, подумайте про це як додавання 16 у двійковому і відніманні 1 (10000-00001).

Таким чином, ви можете зберегти кількість фрагментів до керованих лімітів на значення.
Якщо ви використовуєте метод неохайного кодування для обмеження основного 16-бітного значення INT (від 0 до 65535) до 4-значного десяткового обмеження (від 0 до 9999), тоді все, що вам потрібно зробити, це коли значення перевищує межу 9999, відніміть з нього 9999 і перенесіть його до наступного відрізка значення (оскільки ви в основному робите "додавання та підрахунок" з числами порівняно з реальними двійковими обчисленнями).

В ідеалі ви просто використовувати СИМБОЛІЧНУ МАТУ, яку ви дізналися в школі. Як це працює. Якщо у вас є десятковий символ 1, і ви додаєте його до 1, ви отримуєте десятковий символ 2. Причина, яку я називаю цим символом, полягає в тому, що ви могли використовувати будь-яку серію символів із таблицею пошуку "Якщо символ X (1) додається до символу X (4) ТОГО вихідний символ X (5) ". Символ X (1) може бути зображенням кішки, а символ X (4) може бути ознакою ПОСТОЯННОСТІ, але це не має значення. У вас є ваші символи, основний посібник того, що відбувається, тоді ці символи поєднуються (на кшталт таблиць множення, які ви запам’ятали, як дитина), і який символ повинен бути результатом цієї операції. Використовуючи Symbolic Math, ви можете додати нескінченну кількість цифр, а ніколи насправді не називати числові межі вашого процесора.

Один із способів зробити це в простому кодуванні - це мати кожну представлену цифру, з якою ви хочете працювати, як єдину одиницю у великому розмірному масиві. Якщо ви хочете представити 4096 десяткових цифр (не більше 2-х цифр на одиницю вікна), тоді ви виділите 2 набори масивів масиву 4096 BYTE. Збереження значення 1098874 використовує масив як (1) (0) (9) (8) (8) (7) (4). Якщо ви додали до нього значення 7756, ви перетворили б його в (7) (7) (5) (6) і потім додали. Результатом буде (1) (0) (9) (15) (15) (12) (10), який ви потім віднімете вправо-вліво зсувом, поки всі знакові поля не будуть нормалізовані і становлять значення (0 до 9). Найправіше значення (10) буде відніматися 10, і отримане значення буде дорівнювати нулю (0), і це перенесло б значення (1) до наступного лівого поля (12), щоб воно становило (13), яке тоді матиме 10 віднімаємо, щоб перетворити його на (3).


7
-1 за ТОГО
МАЛО

5
Привіт @Gridlock, я щойно помітив, що ти абсолютно новий користувач - ласкаво просимо. Я повинен уточнити, що мій потік не є постійним; це задумано як конструктивна критика. Ваша відповідь, яку ви надіслали, і я буду більш ніж радий змінити її на резюме, коли ви внесете виправлення, яке я вимагаю. Також майте на увазі, що SE - це не форум; хороша відповідь не читається, а потім забувається, але, швидше, виплачує дивіденди. Перегляд ваших відповідей тут і там допомагає громаді та вашому представнику. Я сподіваюся, що я вас не злякав; ще раз, ласкаво просимо, і я сподіваюся, ви скористаєтесь моєю порадою.
Сліп Д. Томпсон

1
Ще одна пропозиція, яку я запропоную, - це використання базового форматування Markdown замість "all-caps". Якщо загортати текст у задніх посиланнях ( `text`text), це зробить монорозміщенням, що підходить для фрагментів коду, назв функцій, даних тощо. Якщо загортання тексту в підкресленнях чи зірочках зробить його курсивом ( _text_або *text*текстом ) та подвійним підкресленням або подвійним підкресленням або зірочки стануть жирними ( __text__або **text**текстовими ).
Сліп Д. Томпсон

0

У вас є декілька змінних, а потім ви самі контролюєте додавання та переповнення між ними. Таким чином ви можете мати будь-яку кількість цифр. Об'єднайте 10 000 32-бітних цілих чисел, і ви маєте число з 32 000 біт, якщо це те, що вам потрібно. У жодній мові програмування немає обмежень. Єдине обмеження - це те, що ти вмієш з'ясувати.


Тим, хто дав знищення, ви могли б пояснити, чому? Навіть якщо це не популярне рішення або не потребує зусиль, воно все одно є рішенням, яке може дозволити вам робити те саме на мовах / платформах, які не підтримують doubleабо BigInteger.
TomTsagk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.