Làm thế nào để trò chơi nhàn rỗi xử lý số lượng lớn như vậy?


31

Chỉ cần tự hỏi làm thế nào các trò chơi như Tap Titans và Cookie Clicker xử lý số lượng lớn như vậy.

Tôi đang cố gắng thực hiện một trò chơi nhàn rỗi tuy nhiên định dạng số lớn nhất được C # hỗ trợ là số thập phân.

Tôi đang tìm cách hỗ trợ lên tới 10 ^ 500; cần phải là điểm nổi

Làm thế nào tôi có thể xử lý này?

PS nó cần phải là nền tảng chéo, ví dụ như pc, mac, ios, android và tương thích với Unity


2
Nếu tôi nhớ chính xác, bạn có quyền truy cập vào mã của Cookie Clicker, vì vậy bạn chỉ cần kiểm tra xem ...
Vaillancourt

Không, tôi đã chặn Cookie Clicker khỏi tâm trí của tôi!
Arturo Torres Sánchez

2
Tôi đã xem nguồn được dịch ngược cho TimeClickers , một trò chơi Unity. Họ chỉ sử dụng double. Nếu đó là tôi, tôi đã sử dụng BigInteger .
BlueRaja - Daniel Pflughoeft

1
@VioletGiraffe: Tôi đồng ý và tôi muốn làm cho (chúng tôi?) Nghi ngờ cụ thể (để có thể giúp OP làm cho câu hỏi rõ ràng hơn): "Trò chơi nhàn rỗi" liên quan đến câu hỏi (điều này làm cho loại này như thế nào của trò chơi một trường hợp đặc biệt cho số lượng lớn)? Những loại số nào là " số lớn như vậy " (nổi bật bởi chính tôi) đề cập đến? Làm thế nào lớn nào bạn muốn số điện thoại để được?
HOẶC Mapper

bạn luôn có thể lưu trữ một số lượng lớn như vậy trong một chuỗi và dễ dàng thực hiện một hàm để thực hiện tính tổng trên chuỗi.
dev-masih

Câu trả lời:


40

Nếu bạn chỉ muốn lưu trữ số lượng lớn mà không có độ chính xác hoàn toàn, ví dụ: nếu bạn sẽ hiển thị 12.567.000.000.000 dưới dạng 12.567T (nghìn tỷ), bạn chỉ có thể sử dụng các giá trị nổi / thập phân tiêu chuẩn và hiển thị các số liệu quan trọng x đầu tiên , với hậu tố phù hợp như thế này. Khi bạn ở trong quãng tám, bạn có thực sự cần quan tâm đến từng số nguyên riêng lẻ không?


4
Đây thực sự có thể là câu trả lời hợp lý nhất và tôi khá chắc chắn Cookie Clicker chỉ sử dụng một dấu phẩy tiêu chuẩn trong JavaScript - trong trường hợp khi tôi "hack" nó (đọc: bị rối với bảng điều khiển) và khi con số đạt 1e308 thì nó đã nhảy lên thành "Vô cực" và tôi có thể tiến hành mua bất cứ thứ gì tôi muốn XD
Niet the Dark Absol

1
Tuyệt quá! Thực tế là văn bản nhảy đến "Vô cực" có cảm giác như nhà phát triển cũng đang phòng thủ mã hóa xung quanh sự kiện này. Ngoài ra, đơn giản là vua.
Ross Taylor-Turner

19
@RossTurner - Có lẽ không có mã hóa nào liên quan đến việc nó hiển thị văn bản "Vô cực" - vô hạn chỉ là một giá trị nổi có thể có và JavaScript biết cách hiển thị nó, giống như nhiều ngôn ngữ khác làm.
Jibb thông minh

Phao tiêu chuẩn (độ chính xác kép, 8 byte) sẽ không cho phép biểu thị các số lên tới 10 ^ 500 như câu hỏi ban đầu yêu cầu, nó sẽ lên tới ~ 10 ^ 300. Nếu điều đó là không đủ, người ta nên sử dụng các phao có độ chính xác gấp bốn lần có thể không cần thiết tùy thuộc vào ngôn ngữ.
Peteris

1
Những gì mọi lập trình viên nên biết về số dấu phẩy động
Steve

20

Bạn có thể sử dụng một cái gì đó như BigInteger , chỉ có sẵn trong .net 4.0 nếu tôi không nhầm (không được hỗ trợ bởi tất cả các nền tảng xây dựng thống nhất).

Tuy nhiên, có một số thư viện cố gắng mang chức năng này mà không có yêu cầu của .net4.0. Ví dụ ở đây .

Ngoài ra, bạn có thể sử dụng các số nhỏ hơn để biểu thị một số lớn hơn, bằng cách theo dõi hệ số nhân. Ví dụ:

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

Bây giờ, mặc dù bạn có giá trị là 9, nhưng nếu bạn kết hợp nó với số nhân của mình, bạn có thể biểu thị hiệu quả 9 đó là 9 nghìn tỷ (Hoặc bằng cách đặt "nghìn tỷ" hoặc viết một số thứ sẽ nối các số 0 ở cuối giá trị của bạn ).


Điều đáng chú ý là các lớp như BigIntegersử dụng đại diện của Chuỗi hoặc Byte [] của số - vì vậy, trong thực tế, người ta có thể tạo lớp riêng của mình, chỉ cần cộng và trừ hai "số là Chuỗi hoặc Byte" - ( thường là loại trò chơi này không Không cần nhưng bạn cũng có thể hỗ trợ nhân hoặc chia hoặc các chức năng nâng cao khác ) - nhưng họ phải nhớ rằng luôn có giới hạn vật lý nơi họ có thể hết bộ nhớ.
DoubleDouble

1
Mỗi byte nhân kích thước của số của bạn với 256. Nếu bạn hết bộ nhớ khi cố gắng đại diện cho một số, dù sao số của bạn không có bất kỳ giá trị thực nào. 256 ^ (2 tỷ) = 2 ^ 8 ^ (2 tỷ) = 2 ^ (16 tỷ) ~ = 10 ^ (5 tỷ) (wolframalpha đã cố gắng thực hiện chuyển đổi cuối cùng đó). Bạn có thể chỉ định các khối Planck riêng lẻ trong vũ trụ quan sát được bằng cách sử dụng như 150 chữ số (<500 bit).
MichaelS

11

Bạn có thể cần phải viết lớp riêng của mình để sử dụng trong Unity, nhưng nó sẽ không đặc biệt khó.

Trong nội bộ, nó có thể là một danh sách các số nguyên (chẳng hạn như a List<int>), với mỗi phần tử trong danh sách tương ứng với một nhóm gồm 9 chữ số. Mỗi số nguyên sẽ có phạm vi từ 0 đến 999 999 999. Một số nguyên có thể hỗ trợ hơn 2 tỷ một chút và tăng gấp đôi nếu không được ký, nhưng bạn sẽ muốn có mỗi "chữ số" tràn vào 1 000 000 000, bởi vì bạn cũng muốn để có thể dễ dàng chuyển đổi số lớn của bạn thành một chuỗi để hiển thị. Việc ghép các chữ số thập phân ( return group[i].ToString() + group[i-1].ToString() and so on) trở nên dễ dàng hơn so với việc tìm ra cách hiển thị tổng các nhóm nằm ngoài phạm vi của bất kỳ loại dữ liệu thông thường nào.

Vì vậy, int đầu tiên trong danh sách của bạn sẽ đại diện cho 1s. Tiếp theo sẽ là số tiền tỷ. Tiếp theo, số lượng tứ phương, và như vậy.

Phép cộng và phép trừ sẽ hoạt động giống như phép cộng và phép trừ bằng bút và giấy, trong đó bạn phải theo dõi tràn và mang nó đến "chữ số" tiếp theo, nhưng thay vì các chữ số có phạm vi 0-9, các chữ số của bạn nằm trong khoảng từ 0 đến 999 999 999.


10

Để xử lý số lượng lớn, tôi nhìn vào những gì tôi nghĩ là một ví dụ tốt như Tháp anh hùng . Góc trên bên trái:

1

2
(nguồn: mzstatic.com )

Không cần vào trò chơi, cách nó xử lý các con số tương đối đơn giản: Bạn thấy hai thùng số. Khi bạn lên cao hơn trong tòa tháp và kiếm được nhiều "vàng" hơn, hai thùng chỉ đơn giản là đại diện cho số lượng lớn hơn.

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

Khi trò chơi vượt qua T, nó chuyển sang a, b, c ... z, aa, ab, ...

56aa608z

Làm theo cách này, nó vẫn cho bạn biết bạn đã kiếm được bao nhiêu vàng ... trong khi không làm hỏng trò chơi một cách chi tiết.

Bạn có thực sự quan tâm đến hàng triệu khi số của bạn đã qua Trillions?

Liệu nó có giữ số trong Int, Big Int, Float, Double, Decimal, ...? Mảng tùy chỉnh? Khi bạn xử lý các con số theo cách "mờ" như vậy, tôi không nghĩ nó quan trọng ...

Tất cả những gì có khả năng là vấn đề quan trọng nhất - trong trường hợp này là 6 phần đầu ... Sau đó, MAYBE 3 hoặc 6 tiếp theo - kể từ khi kiếm được vài trăm K có thể chuyển sang Hàng triệu - nhưng có một điểm kiếm được Một vài trăm K sẽ không ảnh hưởng đến bạn khi bạn nhấn T ... ít hơn nhiều aa và hơn thế nữa.

Số dặm của bạn sẽ thay đổi (tùy thuộc vào những gì bạn muốn / cần) ... Chỉ cần nghĩ rằng tôi đã đưa ra 2c của mình về những gì tôi nghĩ là một ví dụ tốt / đơn giản.

Chỉnh sửa:

Suy nghĩ thêm về cách tôi sẽ triển khai hệ thống đánh số: Tôi có một số có 3 phần quan trọng: XXXX.YYY (...) xZZZ.

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

Vì vậy, 120.365x1 sẽ là 120k365 ... 120.365x2 sẽ là 120M365K ... vv Nhấn vào 4 số dẫn đầu (1200.365x2), sau đó chỉ cần xoay các số 1.200365 (...) x3. B Bam. Bạn có 1B200M.

XY sẽ dễ dàng phù hợp với số thập phân hoặc số nổi ... với Z ngồi cạnh nó dưới dạng int / unsign int.

Với một số float, bạn có thể giữ một số lượng lớn - nhưng ngày càng không quan trọng - số chữ số sau dấu chấm.

Z sẽ dễ dàng đại diện cho một khối số dễ hiểu:

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

Và cách dễ dàng để xử lý số lượng lớn chỉ đơn giản là có nhiều hơn một giá trị INTEGER sau đó CHĂM SÓC bất kỳ tràn. Nếu bạn có giá trị INT 16 bit (0 đến 65535) và bạn muốn có nhiều hơn thế, hãy sử dụng hai giá trị INT 16 bit liên tiếp. Hãy nghĩ về nó giống như có giá trị BYTE (0 đến 255) nhưng chỉ sử dụng tối đa 99 chữ số giá trị. Khi nó đạt 100, sau đó cuộn nó sang giá trị BYTE cao hơn tiếp theo cho bao nhiêu chữ số mà bạn thấy hữu ích. Với các máy tính GHZ ngày nay, ngay cả mã hóa cẩu thả như thế cũng tốt.

Tất nhiên, có một sự thay thế nhanh hơn một chút.
Nếu bạn thêm 18 liên tục vào một số, sẽ nhanh hơn khi chỉ cần trừ 2 và thêm 20. 18, 36, 54, 72, 90, 108, ... 18 = 20 + (- 2).
Nó hoạt động trong Nhị phân quá. (Các giá trị thập phân giống nhau trong Nhị phân) 10010, 100100, 110110, 1001000
DEC (18) = BIN (10010)
Ngoại trừ việc phân tích nhị phân dễ dàng hơn, bạn cần nghĩ đến 18 = 16 + 2
DEC (16 + 2) = BIN (10000 + 00010). Nếu giá trị là 15, thì hãy nghĩ về nó như thêm 16 vào nhị phân và trừ đi 1 (10000-00001).

Theo cách này, bạn có thể giữ các khối số đến giới hạn có thể quản lý trên mỗi giá trị.
Nếu bạn đang sử dụng phương pháp mã hóa cẩu thả để giới hạn giá trị INT 16 bit cơ bản (0 đến 65535) đến giới hạn thập phân 4 chữ số (0 đến 9999) thì tất cả những gì bạn phải làm là khi giá trị vượt quá giới hạn 9999, trừ 9999 từ nó và mang nó đến khối giá trị tiếp theo (vì về cơ bản bạn đang thực hiện "thêm & phụ" với các số so với tính toán nhị phân thực).

Lý tưởng nhất là bạn chỉ cần sử dụng TRIỆU CHỨNG mà bạn đã học ở trường. Cái này hoạt động ra sao. Nếu bạn có ký hiệu thập phân là 1 và bạn thêm nó vào 1 thì bạn sẽ có ký hiệu thập phân là 2. Lý do tôi gọi đây là ký hiệu là bạn có thể sử dụng bất kỳ chuỗi ký hiệu nào với bảng tra cứu "Biểu tượng IF X (1) được thêm vào ký hiệu X (4) THEN đầu ra ký hiệu X (5) ". Biểu tượng X (1) có thể là hình ảnh của một con mèo và biểu tượng X (4) có thể là dấu hiệu PERCENT, nhưng không thành vấn đề. Bạn có các biểu tượng của mình, một quy tắc cơ bản về những gì xảy ra sau đó các biểu tượng đó được kết hợp (giống như các bảng nhân mà bạn đã ghi nhớ khi còn bé) và biểu tượng nào phải là kết quả của hoạt động đó. Với việc sử dụng Toán học tượng trưng, ​​bạn có thể thêm vô số chữ số trong khi không bao giờ thực sự gọi các giới hạn số của bộ xử lý của mình.

Một cách để làm điều này trong mã hóa dễ dàng là có từng chữ số được biểu diễn mà bạn muốn làm việc với tư cách là một đơn vị trong một mảng có kích thước lớn. Nếu bạn muốn đại diện cho 4096 chữ số thập phân (không quá 2 chữ số trên mỗi hộp đơn vị), thì bạn phân bổ 2 bộ 4096 vị trí mảng BYTE. Lưu trữ giá trị của 1098874 sẽ sử dụng mảng như (1) (0) (9) (8) (8) (7) (4). Nếu bạn đã thêm giá trị của 7756 vào nó, bạn sẽ chuyển đổi nó thành (7) (7) (5) (6) và sau đó thêm. Kết quả sẽ là (1) (0) (9) (15) (15) (12) (10) mà sau đó bạn sẽ trừ sang phải sang trái cho đến khi tất cả các hộp chữ số được chuẩn hóa thành giá trị của (0 đến 9). Giá trị ngoài cùng bên phải (10) sẽ bị trừ 10 và giá trị kết quả sẽ bằng 0 (0) và sẽ mang giá trị (1) đến hộp bên trái của (12) để tạo thành (13) mà sau đó sẽ có 10 trừ đi để làm cho nó thành (3).


7
-1 cho NHIỀU
VÀNG

5
Xin chào @Gridlock, tôi mới nhận thấy rằng bạn là một người dùng hoàn toàn mới được chào đón. Tôi nên làm rõ rằng downvote của tôi không vĩnh viễn; nó nhằm mục đích phê bình mang tính xây dựng. Có giá trị cho câu trả lời bạn đã cung cấp và tôi sẽ rất vui khi thay đổi nó thành một upvote sau khi bạn thực hiện chỉnh sửa mà tôi yêu cầu. Ngoài ra, hãy nhớ rằng SE không phải là một diễn đàn; một câu trả lời tốt không được đọc và sau đó bị lãng quên mà thay vào đó trả cổ tức đại diện theo thời gian. Xem lại câu trả lời của bạn ở đây & ở đó giúp cộng đồng và đại diện của bạn. Tôi hy vọng tôi đã không làm bạn sợ; một lần nữa, chào mừng và tôi hy vọng bạn sẽ sử dụng lời khuyên của tôi.
Slipp D. Thompson

1
Một gợi ý khác tôi sẽ đưa ra là sử dụng một số định dạng Markdown cơ bản thay vì tất cả các chữ hoa. Gói văn bản trong backticks ( `text`text) sẽ làm cho nó mono-spaced, thích hợp cho khối mã, tên hàm, dữ liệu, vv văn bản gói trong dấu gạch dưới hoặc dấu hoa thị sẽ làm cho nó nghiêng ( _text_hoặc *text*văn bản ), và nhấn đúp dấu gạch dưới hoặc đôi dấu hoa thị sẽ làm cho nó đậm ( __text__hoặc **text**văn bản ).
Slipp D. Thompson

0

Những gì bạn làm là có một vài biến được kết hợp, và sau đó bạn tự kiểm soát việc thêm và tràn giữa chúng. Bạn có thể có bất kỳ số chữ số theo cách đó. Kết hợp 10.000 số nguyên 32 bit và bạn có một số với 32.000 bit, nếu đó là những gì bạn cần. Không có giới hạn trong bất kỳ ngôn ngữ lập trình. Giới hạn duy nhất là những gì bạn có thể tìm ra.


Đối với những người đã đưa xuống, bạn có thể giải thích tại sao? Ngay cả khi đây không phải là một giải pháp phổ biến, hoặc một giải pháp không cần nỗ lực, thì đó vẫn là một giải pháp và một giải pháp có thể cho phép bạn làm điều tương tự ngay cả trên các ngôn ngữ / nền tảng không hỗ trợ doublehoặc BigInteger.
TomTsagk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.