Làm cách nào tôi có thể tạo một trình tạo ngẫu nhiên trực tiếp trên mạng mà bị sai lệch bởi các sự kiện trước đó?


37

Tôi đang tìm cách thực hiện một hệ thống dựa trên cơ hội bị sai lệch bởi sự kiện trước đó.

Bối cảnh: Vài năm trước, tôi nhớ một bản cập nhật cho World of Warcraft thông báo rằng họ đã triển khai một máy tính cơ hội mới có thể chống lại các chuỗi sự kiện đầy gai nhọn. (ví dụ: thực hiện các cuộc đình công quan trọng hoặc né tránh nhiều lần liên tiếp). Ý tưởng là trong trường hợp bạn né được một cú đánh, khả năng bạn né đòn tiếp theo sẽ bị giảm đi, nhưng nó sẽ hoạt động theo cả hai cách. Không né một đòn sẽ làm tăng cơ hội né đòn tiếp theo. Thủ thuật chính ở đây, là qua nhiều thử nghiệm, cơ hội né tránh vẫn sẽ tương ứng với tỷ lệ phần trăm được trao cho người chơi trong bảng thống kê của người đó.

Loại hệ thống này rất hấp dẫn tôi vào thời điểm đó, và bây giờ tôi đang ở trong tình huống cần một giải pháp như vậy.

Đây là những rắc rối của tôi:

  • Tôi đoán rằng tôi sẽ có thể tìm thấy các tài nguyên trực tuyến khi triển khai một hệ thống như vậy, nhưng tôi có thể chỉ thiếu các từ buzz liên quan để tìm thấy nó.
  • Ngoài ra tôi cần cách tiếp cận này để phù hợp với một hệ thống không phải là nhị thức (tức là hai kết quả), nhưng thay vào đó chứa 4 sự kiện loại trừ lẫn nhau.

Cách tiếp cận hiện tại của tôi tương tự như hệ thống vé xổ số. Khi một sự kiện xảy ra, tôi thay đổi các trọng số có lợi cho tất cả các sự kiện khác. Điều này có thể hoạt động nếu bốn sự kiện có ý nghĩa như nhau, nhưng trong trường hợp của tôi, cần phải phổ biến hơn nhiều. Nhưng vì sự kiện phổ biến xảy ra thường xuyên hơn, nó làm thay đổi trọng số của người khác cao hơn nhiều so với dự định và dường như tôi không thể tìm thấy các con số cho sự thay đổi trọng lượng cần thiết để giữ số lượng vé trung bình xung quanh các giá trị ban đầu mà sự kiện đó mang lại được.

Một vài gợi ý hướng hoặc một ví dụ cắt rõ ràng sẽ được đánh giá cao.


4
Nếu bạn muốn có một câu trả lời có sắc thái cao hoặc phức tạp, bạn có thể gặp nhiều may mắn hơn khi hỏi Toán học. Các nhà toán học thoải mái trả lời các câu hỏi phức tạp về xác suất. math.stackexchange.com
Kevin - Tái lập Monica


6
Một thay thế cho trang web Toán học nơi bạn có nhiều khả năng hiểu câu trả lời là Lập trình viên . Thiết kế thuật toán không đặc biệt theo chủ đề về Toán học và có lẽ bạn cần phải đưa ra một thiết kế ban đầu để có được đầu vào hữu ích.
Lilienthal

1
Tôi đồng ý với Kevin và Lilienthal rằng bạn có thể có câu trả lời tốt hơn ở đó, nhưng đọc câu trả lời của mklingen tôi nhận ra những gì được mô tả ở đây có thể được mô phỏng như một chuỗi Markov và đó có thể là một công cụ hữu ích cho các nhà phát triển trò chơi biết. Tôi sẽ cố gắng viết nó lên chi tiết hơn sau.
chào đón

1
Khi tôi đang chạy các số trên một số câu trả lời ở đây, tôi thấy có một số hạn chế khác nhau và giải pháp giải quyết tất cả chúng có thể phức tạp hơn những gì bạn cần. Một số chi tiết cụ thể hơn về trường hợp sử dụng của bạn có thể giúp thu hẹp các tùy chọn tốt nhất. Chẳng hạn, xác suất của các sự kiện của bạn khá giống nhau (ví dụ: 5 kết quả khác nhau với 20% cơ hội mỗi lần) hoặc rất khác nhau (ví dụ: 10% bỏ lỡ 80% đạt 10% quan trọng)? Bạn có muốn giảm thiểu các lần chạy (ví dụ: 3 lần bỏ lỡ liên tiếp) hoặc co cụm / chờ đợi (ví dụ: 3 lần bỏ lỡ trong 8 lần thử hoặc 20 lần thử trước khi tôi nhận được chỉ trích)?
DMGregory

Câu trả lời:


19

Về cơ bản, những gì bạn yêu cầu là một trình tạo sự kiện "bán ngẫu nhiên" tạo ra các sự kiện với các thuộc tính sau:

  1. Tỷ lệ trung bình mà tại đó mỗi sự kiện xảy ra được chỉ định trước.

  2. Sự kiện tương tự ít có khả năng xảy ra hai lần liên tiếp hơn là ngẫu nhiên.

  3. Các sự kiện không thể dự đoán đầy đủ.

Một cách để làm điều đó là trước tiên triển khai trình tạo sự kiện không ngẫu nhiên thỏa mãn mục tiêu 1 và 2, sau đó thêm một số tính ngẫu nhiên để đáp ứng mục tiêu 3.


Đối với trình tạo sự kiện không ngẫu nhiên, chúng ta có thể sử dụng thuật toán phối màu đơn giản . Cụ thể, đặt p 1 , p 2 , ..., p n là khả năng tương đối của các sự kiện từ 1 đến n và đặt s = p 1 + p 2 + ... + p n là tổng các trọng số. Sau đó, chúng ta có thể tạo ra một chuỗi các sự kiện được phân bổ tối đa không ngẫu nhiên bằng thuật toán sau:

  1. Ban đầu, cho e 1 = e 2 = ... = e n = 0.

  2. Để tạo sự kiện, hãy tăng từng e i theo p i và xuất ra sự kiện ke k là lớn nhất (phá vỡ mọi mối quan hệ theo bất kỳ cách nào bạn muốn).

  3. Giảm e k theo s và lặp lại từ bước 2.

Ví dụ, với ba sự kiện A, B và C, với p A = 5, p B = 4 và p C = 1, thuật toán này tạo ra một cái gì đó giống như chuỗi đầu ra sau:

A B A B C A B A B A A B A B C A B A B A A B A B C A B A B A

Lưu ý cách chuỗi 30 sự kiện này chứa chính xác 15 As, 12 Bs và 3 Cs. Nó không hoàn toàn phân phối tối ưu - có một vài lần xuất hiện hai liên tiếp, điều này có thể tránh được - nhưng nó đã kết thúc.


Bây giờ, để thêm tính ngẫu nhiên cho chuỗi này, bạn có một số tùy chọn (không nhất thiết phải loại trừ lẫn nhau):

  • Bạn có thể làm theo lời khuyên của Philipp và duy trì một "sàn" N sự kiện sắp tới, cho một số N có kích thước phù hợp . Mỗi khi bạn cần tạo một sự kiện, bạn chọn một sự kiện ngẫu nhiên từ bộ bài, và sau đó thay thế nó bằng đầu ra sự kiện tiếp theo bằng thuật toán phối màu ở trên.

    Áp dụng điều này cho ví dụ trên, với N = 3, tạo ra:

    A B A B C A B B A B A B C A A A A B B A B A C A B A B A B A

    trong khi N = 10 mang lại kết quả tìm kiếm ngẫu nhiên hơn:

    A A B A C A A B B B A A A A A A C B A B A A B A C A C B B B

    Lưu ý cách các sự kiện phổ biến A và B kết thúc với nhiều lần chạy hơn do sự xáo trộn, trong khi các sự kiện C hiếm gặp vẫn diễn ra khá tốt.

  • Bạn có thể tiêm một số ngẫu nhiên trực tiếp vào thuật toán phối màu. Ví dụ: thay vì tăng e i theo p i trong bước 2, bạn có thể tăng nó theo p i × ngẫu nhiên (0, 2), trong đó ngẫu nhiên ( a , b ) là một số ngẫu nhiên phân bố đồng đều giữa ab ; điều này sẽ mang lại sản lượng như sau:

    A B B C A B A A B A A B A B A A B A A A B C A B A B A C A B

    hoặc bạn có thể tăng e i theo p i + ngẫu nhiên (- c , c ), sẽ tạo ra (cho c = 0,1 × s ):

    B A A B C A B A B A B A B A C A B A B A B A A B C A B A B A

    hoặc, với c = 0,5 × s :

    B A B A B A C A B A B A A C B C A A B C B A B B A B A B C A

    Lưu ý cách sơ đồ cộng gộp có hiệu ứng ngẫu nhiên hóa mạnh hơn nhiều đối với các sự kiện hiếm gặp C so với các sự kiện phổ biến A và B, so với phép nhân; điều này có thể hoặc không thể được mong muốn. Tất nhiên, bạn cũng có thể sử dụng một số kết hợp của các sơ đồ này hoặc bất kỳ điều chỉnh nào khác đối với số gia, miễn là nó bảo toàn thuộc tính rằng mức tăng trung bình của e i bằng p i .

  • Ngoài ra, bạn có thể làm nhiễu đầu ra của thuật toán phối màu bằng cách đôi khi thay thế sự kiện k đã chọn bằng một sự kiện ngẫu nhiên (được chọn theo trọng số thô p i ). Miễn là bạn cũng sử dụng cùng một k trong bước 3 như bạn xuất ra ở bước 2, quá trình phối màu sẽ vẫn có xu hướng thậm chí biến động ngẫu nhiên.

    Ví dụ: đây là một số ví dụ đầu ra, với 10% cơ hội cho mỗi sự kiện được chọn ngẫu nhiên:

    B A C A B A B A C B A A B B A B A B A B C B A B A B C A B A

    và đây là một ví dụ với 50% cơ hội của mỗi đầu ra là ngẫu nhiên:

    C B A B A C A B B B A A B A A A A A B B A C C A B B A B B C

    Bạn cũng có thể xem xét cho ăn một kết hợp của các sự kiện hoàn toàn ngẫu nhiên và dithered thành một boong / trộn hồ, như mô tả ở trên, hoặc có lẽ ngẫu nhiên các thuật toán dithering bằng cách chọn k ngẫu nhiên, như cân nặng của e i s (điều trị khối lượng tiêu cực như zero).

Thi thiên Dưới đây là một số chuỗi sự kiện hoàn toàn ngẫu nhiên, với cùng tỷ lệ trung bình, để so sánh:

A C A A C A B B A A A A B B C B A B B A B A B A A A A A A A
B C B A B C B A A B C A B A B C B A B A A A A B B B B B B B
C A A B A A B B C B B B A B A B A A B A A B A B A C A A B A

Tiếp tuyến: Vì đã có một số tranh luận trong các ý kiến về việc có cần thiết hay không, đối với các giải pháp dựa trên boong, để cho phép boong trống trước khi nó được nạp lại, tôi quyết định so sánh đồ họa của một số chiến lược lấp đầy boong:

Âm mưu
Cốt truyện của một số chiến lược để tạo ra các đồng xu bán ngẫu nhiên (với tỷ lệ trung bình là 50:50 trên đầu). Trục hoành là số lần lật, trục dọc là khoảng cách tích lũy so với tỷ lệ dự kiến, được đo bằng (đầu - đuôi) / 2 = đầu - lật / 2.

Các đường màu đỏ và màu xanh lá cây trên cốt truyện hiển thị hai thuật toán không dựa trên boong để so sánh:

  • Đường màu đỏ, phối màu xác định : kết quả số chẵn luôn luôn đứng đầu, kết quả số lẻ luôn luôn là đuôi.
  • Dòng màu xanh lá cây, lật ngẫu nhiên độc lập : mỗi kết quả được chọn độc lập ngẫu nhiên, với 50% cơ hội đầu và 50% cơ hội đuôi.

Ba dòng khác (xanh lam, tím và lục lam) hiển thị kết quả của ba chiến lược dựa trên cỗ bài, mỗi chiến lược được thực hiện bằng một cỗ bài gồm 40 lá bài, ban đầu chứa 20 thẻ "đầu" và 20 thẻ "đuôi":

  • Dòng màu xanh lam, điền vào khi trống : Thẻ được rút ngẫu nhiên cho đến khi bộ bài trống, sau đó bộ bài được nạp lại với 20 thẻ "đầu" và 20 thẻ "đuôi".
  • Dòng màu tím, điền vào khi trống một nửa : Thẻ được rút ngẫu nhiên cho đến khi bộ bài còn lại 20 thẻ; sau đó bộ bài được xếp lên trên với 10 thẻ "đầu" và 10 thẻ "đuôi".
  • Dòng Cyan, điền liên tục : Thẻ được rút ngẫu nhiên; rút thăm được đánh số chẵn được thay thế ngay lập tức bằng thẻ "đứng đầu" và rút số lẻ bằng thẻ "đuôi".

Tất nhiên, cốt truyện ở trên chỉ là một nhận thức duy nhất về một quá trình ngẫu nhiên, nhưng nó mang tính đại diện hợp lý. Cụ thể, bạn có thể thấy rằng tất cả các quy trình dựa trên boong có độ lệch giới hạn và nằm khá gần với đường màu đỏ (xác định), trong khi đường màu xanh lá cây hoàn toàn ngẫu nhiên cuối cùng lại đi lang thang.

(Trên thực tế, độ lệch của các đường màu xanh lam, tím và lục lam so với 0 bị giới hạn bởi kích thước boong: đường màu xanh không bao giờ có thể trôi xa hơn 10 bước so với 0, đường màu tím chỉ có thể cách xa 0 bước và dòng màu lục lam có thể trôi xa nhất là 20 bước so với số 0. Tất nhiên, trong thực tế, bất kỳ dòng nào thực sự đạt đến giới hạn của nó là rất khó xảy ra, vì có xu hướng mạnh mẽ để chúng trở về gần hơn nếu chúng đi lang thang quá xa tắt.)

Nhìn thoáng qua, không có sự khác biệt rõ ràng giữa các chiến lược dựa trên boong khác nhau (mặc dù, trung bình, đường màu xanh nằm gần đường màu đỏ hơn và đường màu lục lam ở xa hơn một chút), nhưng kiểm tra kỹ hơn đường màu xanh không tiết lộ một mô hình xác định riêng biệt: cứ sau 40 lần vẽ (được đánh dấu bằng các đường thẳng đứng màu xám chấm), đường màu xanh chính xác đáp ứng đường màu đỏ ở mức 0. Các đường màu tím và lục lam không bị hạn chế nghiêm ngặt và có thể tránh xa số 0 tại bất kỳ điểm nào.

Đối với tất cả các chiến lược dựa trên bộ bài, tính năng quan trọng giúp duy trì sự thay đổi của chúng là thực tế là, trong khi các thẻ được rút ngẫu nhiên từ bộ bài, bộ bài được nạp lại một cách xác định. Nếu các thẻ được sử dụng để nạp lại bộ bài được chọn ngẫu nhiên, tất cả các chiến lược dựa trên bộ bài sẽ trở nên không thể phân biệt với lựa chọn ngẫu nhiên thuần túy (đường màu xanh lá cây).


Câu trả lời rất hay. Thêm các yếu tố ngẫu nhiên vào thuật toán phối màu dường như thẳng tiến. :)
Sonaten

Quyết định đi với câu trả lời của bạn. :) Nhưng tôi khuyên bạn nên đặt phần bổ sung của tổng quan phương pháp lên hàng đầu. Những gì tôi sẽ làm, dựa trên câu trả lời của bạn là thử cả giải pháp "Đỏ" và "Tím".
Sonaten

53

Đừng tung xúc xắc, đánh bài.

Lấy tất cả các kết quả có thể có của RNG của bạn, đưa chúng vào danh sách, xáo trộn ngẫu nhiên và trả lại kết quả theo thứ tự ngẫu nhiên. Khi bạn ở cuối danh sách, lặp lại.

Các kết quả sẽ vẫn được phân phối đồng đều, nhưng các kết quả riêng lẻ sẽ không lặp lại trừ khi cuối cùng của danh sách cũng là kết quả đầu tiên của danh sách tiếp theo.

Khi điều này hơi khó đoán trước đối với khẩu vị của bạn, bạn có thể sử dụng một danh sách nhân nvới số lần kết quả có thể và đặt từng kết quả có thể vào đó nlần trước khi xáo trộn. Hoặc bạn có thể cải tổ lại danh sách trước khi nó được lặp lại hoàn toàn.


1
tra cứu "túi xáo trộn" (trên trang web này ngay cả)
jhocking

3
Đây là cách nhiều trò chơi Tetris tránh để người chơi bị bỏ đói vì những mảnh chìa khóa quá lâu. Điều quan trọng là làm trống túi / bộ bài như Philipp gợi ý trước khi lắp thẻ mới nếu bạn muốn kiểm soát các lần xuất hiện trong một khoảng thời gian đã đặt. Bằng cách chèn lại thẻ khi bạn đi (hoặc điều chỉnh lại trọng lượng), bạn có thể bóp méo phân phối xác suất theo những cách khó tính toán và dễ bị sai.
DMGregory

2
@DMGregory: Trên thực tế, việc trộn các thẻ mới trước khi bỏ bài là hoàn toàn tốt (và trên thực tế, tôi khuyên bạn nên làm điều này để làm cho kết quả tự nhiên hơn và khó dự đoán hơn). Điều quan trọng là đảm bảo rằng phần (trung bình) của các thẻ mới được xáo trộn vào cỗ bài bằng với phần mong muốn mà bạn muốn rút ra khỏi nó.
Ilmari Karonen

4
Illmari Karonen: khi bạn thay thế các mặt hàng, bạn có thể mất các lợi ích của túi xáo trộn về mặt hạn chế các kết quả giống hệt nhau hoặc khoảng cách dài giữa các kết quả cụ thể. Nếu tỷ lệ thay thế của bạn bằng với phân phối xác suất mục tiêu, thì giờ đây bạn có thể ở cùng một vị trí với việc tạo ra từng kết quả một cách độc lập. Nếu nó không bằng phân phối xác suất mục tiêu, thì bạn có thể cảnh báo xác suất hiệu quả theo những cách khó dự đoán và cân bằng phù hợp - người hỏi mô tả đấu tranh với chính xác vấn đề này.
DMGregory

2
Đồng ý với @DMGregory. Bằng cách xáo trộn trong các thẻ mới, bạn vô hiệu hóa chính hệ thống. Hệ thống xử lý thẻ đặc biệt và hoàn toàn phù hợp với kết quả mong muốn. Chẳng hạn, khi bạn loại bỏ một nữ hoàng (để sử dụng các thẻ truyền thống chẳng hạn) khỏi bộ bài, xác suất vẽ một nữ hoàng sẽ giảm và xác suất rút một lá bài khác với một nữ hoàng sẽ tăng lên. Đó là một hệ thống tự điều chỉnh, nếu bạn muốn.
Volte 27/2/2015

17

Bạn có thể thử một đồ thị ngẫu nhiên Markov . Hãy xem xét từng sự kiện có thể xảy ra là một nút trong biểu đồ. Từ mỗi sự kiện, tạo một liên kết đến sự kiện khác có thể có sau sự kiện đó. Mỗi liên kết này có trọng số bởi một thứ gọi là xác suất chuyển tiếp . Sau đó, bạn thực hiện bước đi ngẫu nhiên của biểu đồ theo mô hình chuyển tiếp.

Chẳng hạn, bạn có thể có một biểu đồ biểu thị kết quả của một cuộc tấn công (đòn chí mạng, né tránh, v.v.). Khởi tạo nút bắt đầu thành một nút được chọn ngẫu nhiên theo số liệu thống kê của người chơi (chỉ cần "tung xúc xắc"). Sau đó, trong cuộc tấn công tiếp theo, quyết định điều gì xảy ra tiếp theo với mô hình chuyển đổi.

Cần phải cẩn thận để quyết định làm thế nào để cân trọng lượng chuyển tiếp. Đối với một điều, tất cả các chuyển đổi từ một nút cần phải tăng đến xác suất là 1. Một điều đơn giản bạn có thể làm là thực hiện chuyển đổi từ mọi nút sang mọi nút khác, với trọng số tương đương với xác suất xảy ra các sự kiện đó một tiên nghiệm , cho rằng sự kiện hiện tại không thể xảy ra một lần nữa.

Chẳng hạn, nếu bạn có ba sự kiện:

  Critical, P = 0.1
  Hit,      P = 0.3
  Miss,     P = 0.6

Bạn có thể thiết lập mô hình chuyển đổi sao cho một lần nhấn quan trọng không xảy ra một lần nữa chỉ bằng cách phân phối lại khối lượng xác suất của nó cho các sự kiện khác một cách thống nhất:

  Critical -> Critical,   P = 0.0
  Critical -> Hit,        P = 0.35
  Critical -> Miss,       P = 0.65

EDIT: Như các ý kiến ​​nói dưới đây, mô hình này không đủ phức tạp để có được hành vi mong muốn. Thay vào đó, bạn có thể phải thêm nhiều trạng thái bổ sung!


1
Kế hoạch xem xét lại mà bạn đề xuất không bảo tồn các xác suất mong muốn của từng tiểu bang. Thực hiện một bài kiểm tra thực nghiệm với những con số này, việc bỏ lỡ xảy ra khoảng 41% thời gian và quan trọng khoảng 25%, thoát khỏi các giá trị đầu vào. Việc chuyển sang các trạng thái còn lại tỷ lệ thuận với xác suất của họ (ví dụ: Hoa hậu có 25% cơ hội đến Crit và 75% cơ hội đến Hit) sẽ tốt hơn một chút, với tỷ lệ bỏ lỡ 44% và crit 17%, nhưng vẫn còn không phản ánh các xác suất mong muốn trong đầu vào.
DMGregory

Tôi đã quên quy tắc bayes :( Sẽ tính toán lại sau. Có thể không thể duy trì phân phối xác suất trước vì mô hình chuyển đổi khi nó bỏ qua các trình tự có thể như CCHM hoặc CHHM hoặc MMHM rất có thể, v.v.
mklingen

Ràng buộc "không lặp lại" có thể trói tay bạn ở đây, liên quan đến trọng lượng cực cao & thấp. Nếu bạn muốn 1 trong 10 lần thử là quan trọng, cách duy nhất phương pháp này có thể đáp ứng đó là xen kẽ 5 lượt truy cập và 5 lượt truy cập, làm biến dạng xác suất trúng và bỏ lỡ về mức trung bình của chúng. Không có trình tự mà không bỏ lỡ liên tiếp có thể đáp ứng các yêu cầu của đầu vào ở đây.
DMGregory

4
@mklingen, tôi đồng ý với DMGregory, "hoàn toàn không lặp lại" là không mong muốn ở đây. Thay vào đó, họ muốn xác suất của chuỗi dài có cùng kết quả sẽ ít xảy ra hơn so với xác suất ngẫu nhiên thống nhất. Bạn có thể làm điều này với Chuỗi Markov (được chỉ đạo) trông giống như thế này . Điều này sử dụng nhiều trạng thái để thể hiện các sự kiện lặp đi lặp lại trong đó xác suất chuyển từ "Lượt 1" sang "Lượt 2" và "Lượt 2" sang "Lượt 3+" giảm xuống và xác suất chuyển trở lại thành "Lượt 1" và "Crit 1 "đi lên.
chào đón

@nwellcome đó là một ý tưởng tuyệt vời.
mklingen

3

Đây là một triển khai tôi đã tạo trong C # sẽ:

  • Kích hoạt các sự kiện dựa trên xác suất
  • Điều chỉnh các xác suất đó để giảm cơ hội tái diễn
  • Không đi quá xa xác suất ban đầu

Tôi đã thêm một vài bình luận để bạn có thể thấy những gì tôi đang làm.

    int percentageEvent1 = 15; //These are the starter values. So given a scenario, the
    int percentageEvent2 = 40; //player would have around a 15 percent chance of event
    int percentageEvent3 = 10; //one occuring, a 40 percent chance of event two occuring
    int percentageEvent4 = 35; //10 percent for event three, and 35 percent for event four.

    private void ResetValues()
    {
        percentageEvent1 = 15;
        percentageEvent2 = 40;
        percentageEvent3 = 10;
        percentageEvent4 = 35;
    }

    int resetCount = 0; //Reset the probabilities every so often so that they don't stray too far.

    int variability = 1; //This influences how much the chance of an event will increase or decrease
                           //based off of past events.

    Random RandomNumberGenerator = new Random();

    private void Activate() //When this is called, an "Event" will be activated based off of current probability.
    {
        int[] percent = new int[100];
        for (int i = 0; i < 100; i++) //Generate an array of 100 items, and select a random event from it.
        {
            if (i < percentageEvent1)
            {
                percent[i] = 1; //Event 1
            }
            else if (i < percentageEvent1 + percentageEvent2)
            {
                percent[i] = 2; //Event 2
            }
            else if (i < percentageEvent1 + percentageEvent2 + percentageEvent3)
            {
                percent[i] = 3; //Event 3
            }
            else
            {
                percent[i] = 4; //Event 4
            }
        }
        int SelectEvent = percent[RandomNumberGenerator.Next(0, 100)]; //Select a random event based on current probability.

        if (SelectEvent == 1)
        {
            if (!(percentageEvent1 - (3 * variability) < 1)) //Make sure that no matter what, probability for a certain event
            {                                                //does not go below one percent.
                percentageEvent1 -= 3 * variability;
                percentageEvent2 += variability;
                percentageEvent3 += variability;
                percentageEvent4 += variability;
            }
        }
        else if (SelectEvent == 2)
        {
            if (!(percentageEvent2 - (3 * variability) < 1))
            {
                percentageEvent2 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent3 += variability;
                percentageEvent4 += variability;
            }
        }
        else if (SelectEvent == 3)
        {
            if (!(percentageEvent3 - (3 * variability) < 1))
            {
                percentageEvent3 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent2 += variability;
                percentageEvent4 += variability;
            }
        }
        else
        {
            if (!(percentageEvent4 - (3 * variability) < 1))
            {
                percentageEvent4 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent2 += variability;
                percentageEvent3 += variability;
            }
        }

        resetCount++;
        if (resetCount == 10)
        {
            resetCount = 0;
            ResetValues();
        }

        RunEvent(SelectEvent); //Run the event that was selected.
    }

Hy vọng điều này sẽ giúp, xin vui lòng đề xuất cải tiến mã này trong các ý kiến, cảm ơn!


1
Kế hoạch xem xét lại này có xu hướng dẫn các sự kiện để được trang bị. Đặt lại các trọng số theo định kỳ thực sự chỉ là một hỗ trợ ban nhạc nhằm hạn chế mức độ xấu của nó, trong khi đảm bảo rằng 1 trong 10 cuộn không có lợi ích gì cả từ việc xem lại. Ngoài ra, một lưu ý thuật toán: bạn đang lãng phí rất nhiều công việc bằng cách điền vào một bảng gồm 100 mục để thực hiện lựa chọn ngẫu nhiên của bạn. Thay vào đó, bạn có thể tạo ra một cuộn ngẫu nhiên và sau đó lặp lại 4 kết quả của bạn, tổng hợp xác suất của chúng khi bạn đi. Ngay khi cuộn nhỏ hơn tổng, bạn có kết quả của bạn. Không cần điền vào bảng.
DMGregory

3

Hãy để tôi khái quát câu trả lời của mklingen một chút. Về cơ bản, bạn muốn triển khai Fallacy của Gambler , mặc dù tôi sẽ cung cấp một phương pháp tổng quát hơn ở đây:

Nói rằng có nthể có các sự kiện với xác suất p_1, p_2, ..., p_n. Khi sự kiện ixảy ra, xác suất của nó sẽ giảm theo một yếu tố 0≤a_i≤1/p_i(cái sau là quan trọng, nếu không, bạn kết thúc với xác suất lớn hơn một và các sự kiện khác phải có xác suất âm , về cơ bản có nghĩa là " chống ". thông thường a_i<1. Ví dụ a_i=p_i, bạn có thể chọn , điều đó có nghĩa là xác suất xảy ra sự kiện lần thứ hai là xác suất ban đầu sự kiện xảy ra chính xác hai lần liên tiếp, ví dụ: lần tung đồng xu thứ hai sẽ có xác suất 1/4 thay vì 1/2. Mặt khác, bạn cũng có thể có một số a_i>1, điều đó có nghĩa là kích hoạt một "đột quỵ may mắn / bất hạnh".

Tất cả các sự kiện khác sẽ vẫn có thể xảy ra như nhau liên quan đến nhau, tức là tất cả chúng phải được định cỡ lại bởi cùng một yếu tố b_isao cho tổng của tất cả các xác suất bằng một, tức là

1 = a_i*p_i + b_i*(1-p_i)  # Σ_{j≠i) p_j  = 1 - p_i
 b_i = (1 - a_i*p_i) / (1 - p_i).   (1)

Cho đến nay, rất đơn giản. Nhưng bây giờ, hãy thêm một yêu cầu khác: Xem xét tất cả các chuỗi có thể có của hai sự kiện, xác suất một sự kiện được trích xuất từ ​​đó sẽ là xác suất ban đầu.

Để cho

        / p_i * b_i * p_j  (ji)
p_ij = <
        \ a_i * (p_i     (j=i)

biểu thị xác suất của sự kiện jxảy ra sau sự kiện ivà lưu ý rằng p_ij≠p_jitrừ khi b_i=b_j (2)(theo (1)ngụ ý a_j = 1 - a_i*p_i + (1-a_i)*p_i/p_j). Đây cũng là điều mà định lý của Bayes yêu cầu và điều này cũng bao hàm

Σ_j p_ij = p_i * b_i * (1 - p_i) + a_i * (p_i
         = b_i * p_i + (a_i - b_i) * (p_i
         = p_i  # using (1)

đúng như mong muốn Chỉ cần lưu ý làm thế nào điều này có nghĩa là một a_isửa chữa tất cả những người khác.


Bây giờ hãy xem điều gì xảy ra khi chúng ta áp dụng quy trình này nhiều lần, tức là cho các chuỗi từ ba sự kiện trở lên. Về cơ bản, có hai tùy chọn cho việc lựa chọn xác suất gian lận của sự kiện thứ ba:

a) Quên về sự kiện đầu tiên và giàn khoan như thể chỉ có sự kiện thứ hai xảy ra, tức là

         / p_ij * a_j * p_j  (j=k)
p_ijk = <
         \ p_ij * b_j * p_l  (jk)

Lưu ý rằng điều này thường vi phạm Bayes, vì ví dụ p_jik≠p_ikjtrong hầu hết các trường hợp.

b) Sử dụng sử dụng xác suất p_ij(cố định i) làm xác suất mới pi_jmà từ đó bạn có được xác suất mới pi_jkcho sự kiện kxảy ra tiếp theo. Cho dù bạn có sửa đổi ai_jhay không là tùy thuộc vào bạn, nhưng hãy lưu ý rằng cái mới bi_jchắc chắn là khác nhau do sửa đổi pi_j. Sau đó, một lần nữa, sự lựa chọn ai_jcó lẽ bị hạn chế bằng cách yêu cầu tất cả các hoán vị ijkxảy ra với cùng một xác suất. Hãy xem ...

         / p_ij * bi_j * pi_k  (jk)
p_ijk = <
         \ (p_ij * ai_j      (j=k)

         / b_i * bi_j * p_i * p_j * pi_k  (ijki)
         | b_i * ai_j * p_i * (p_j      (ij=k)
      = <  a_i * (p_i * bi_i * pi_k     (i=jk)
         | b_i * p_i * bi_j * p_k * pi_i  (i=kj)
         \ a_i * ai_i * (p_i * pi_i     (i=k=j)

và hoán vị theo chu kỳ của chúng, phải bằng nhau cho các trường hợp tương ứng.

Tôi sợ sự tiếp tục của tôi về điều này sẽ phải chờ một thời gian ...


Thử nghiệm điều này theo kinh nghiệm, điều này vẫn dẫn đến một biến dạng khỏi xác suất đầu vào qua nhiều lần chạy. Ví dụ, nếu a_i / p_i = 0,5, (và sử dụng các số từ câu trả lời của mklingen), tỷ lệ bỏ lỡ đầu vào là 60% trở thành tỷ lệ quan sát là 50,1% và tỷ lệ quan trọng đầu vào là 10% được quan sát là 13,8%. Bạn có thể xác minh điều này bằng cách lấy ma trận chuyển tiếp kết quả lên công suất cao. Chọn tỷ lệ của a_i: p_i gần hơn với 1 dẫn đến ít biến dạng hơn, nhưng cũng kém hiệu quả hơn trong việc giảm các lần chạy.
DMGregory

@DMGregory điểm tốt: bạn không thể đơn giản nắm quyền hạn của ma trận chuyển tiếp. Tôi sẽ mở rộng câu trả lời của tôi sau này
Tobias Kienzler 27/2/2015

@DMGregory Tôi bắt đầu mô tả toàn bộ quá trình (biến thể b)), nhưng nó khá tẻ nhạt và tôi hiện đang thiếu thời gian: /
Tobias Kienzler 27/2/2015

1

Tôi nghĩ rằng lựa chọn tốt nhất là sử dụng lựa chọn vật phẩm có trọng số ngẫu nhiên. Có một triển khai cho C # ở đây , nhưng chúng cũng có thể dễ dàng tìm thấy hoặc thực hiện cho các ngôn ngữ khác.

Ý tưởng sẽ là giảm trọng lượng của một tùy chọn mỗi khi nó được chọn và tăng nó mỗi khi nó không được chọn.

Ví dụ: nếu bạn giảm trọng lượng của tùy chọn đã chọn NumOptions-1và tăng trọng số của mọi tùy chọn khác thêm 1 (hãy cẩn thận để loại bỏ các vật có trọng lượng <0 và gặt lại chúng khi chúng tăng lên trên 0) , mọi tùy chọn sẽ được chọn khoảng cùng số lần trong một khoảng thời gian dài, nhưng các tùy chọn được chọn gần đây sẽ ít có khả năng được chọn hơn.


Vấn đề với việc sử dụng một thứ tự ngẫu nhiên, như được đề xuất bởi nhiều câu trả lời khác, là sau mỗi tùy chọn nhưng một lựa chọn đã được chọn, bạn có thể dự đoán chắc chắn 100% lựa chọn nào sẽ được chọn tiếp theo. Điều đó không ngẫu nhiên lắm.


1

Câu trả lời của tôi là không chính xác, bài kiểm tra của tôi là thiếu sót.

Tôi để lại câu trả lời này ở đây để thảo luận và bình luận chỉ ra những sai sót trong thiết kế này, nhưng thử nghiệm thực tế là không chính xác.

Những gì bạn đang tìm kiếm là một trọng số có trọng số: các trọng số cho bốn kết quả có thể của bạn cần được điều chỉnh thêm (có trọng số) theo các kết quả trước đó, trong khi vẫn giữ nguyên các trọng số phù hợp.

Cách dễ nhất để thực hiện điều này là thay đổi tất cả các trọng số cho mỗi cuộn bằng cách giảm trọng lượng cho giá trị cụ thể được cuộn và tăng các trọng số khác .

Ví dụ: giả sử bạn có 4 trọng số: Fumble, Miss, Hit và Crit. Cũng cho biết trọng lượng tổng thể mong muốn của bạn đối với họ là Fumble = 10%, Miss = 50%, Hit = 30% và Crit = 10%.

Nếu bạn sử dụng trình tạo số ngẫu nhiên (RNG) để tạo ra các giá trị trong khoảng từ 1 đến 100, sau đó so sánh giá trị đó với vị trí nằm trong phạm vi này (1-10 Fumble, 11-60 miss, 61-90 hit, 91-100 crit ), bạn đang tạo một cuộn riêng lẻ.

Nếu, khi bạn thực hiện cuộn đó, bạn sẽ ngay lập tức điều chỉnh các phạm vi đó dựa trên giá trị cuộn, bạn sẽ tính trọng số cho các cuộn trong tương lai, nhưng bạn cũng cần giảm trọng lượng cuộn bằng tổng số lượng mà bạn tăng các trọng số khác. Vì vậy, trong ví dụ của chúng tôi ở trên, bạn sẽ giảm trọng lượng cuộn xuống 3 và tăng trọng lượng khác thêm 1 mỗi trọng lượng.

Nếu bạn làm điều này cho mỗi cuộn, bạn sẽ vẫn có cơ hội vệt, nhưng chúng sẽ giảm đi rất nhiều, vì với mỗi cuộn bạn sẽ tăng cơ hội rằng các cuộn trong tương lai sẽ là bất cứ thứ gì khác ngoài cuộn hiện tại. Bạn có thể tăng hiệu ứng này, và do đó làm giảm thêm cơ hội của các vệt, bằng cách tăng / giảm trọng lượng theo một yếu tố lớn hơn (ví dụ: giảm dòng điện xuống 6 và tăng thêm 2 lần nữa).

Tôi đã chạy một ứng dụng nhanh để xác nhận cách tiếp cận này và sau 32000 lần lặp với các trọng số đó, nó tạo ra các biểu đồ sau. Biểu đồ trên hiển thị 4 trọng số ngay lập tức tại mỗi cuộn và biểu đồ phía dưới hiển thị tổng số của từng loại kết quả được cuộn lên đến điểm đó.

Như bạn có thể thấy, các trọng số dao động nhẹ xung quanh các giá trị mong muốn của chúng, nhưng các trọng số tổng thể vẫn nằm trong phạm vi mong muốn và sau khi các số bắt đầu ban đầu được xử lý, kết quả phù hợp với tỷ lệ phần trăm mong muốn của chúng tôi gần như hoàn hảo.

Lưu ý rằng ví dụ này được tạo bằng lớp .NET System.Random, đây không thực sự là một trong những RNG tốt hơn ngoài đó, vì vậy bạn có thể có được kết quả chính xác hơn bằng cách sử dụng RNG tốt hơn. Cũng lưu ý rằng 32000 là kết quả tối đa tôi có thể vẽ bằng công cụ này, nhưng công cụ kiểm tra của tôi có thể tạo ra hơn 500 triệu kết quả với cùng một mẫu tổng thể.


Lưu ý rằng điều này chỉ hoạt động nếu +1 của bạn / -3 được áp dụng tương ứng với các trọng số ban đầu, thay vì các trọng số được sử dụng gần đây nhất. (Liên tục sửa đổi các trọng số đồng đều như thế này làm cho chúng trôi về phía được trang bị). Mặc dù điều này giữ xác suất trên mục tiêu trong thời gian dài, nhưng rất ít để giảm số lần chạy. Cho rằng tôi đã bỏ lỡ một lần, cơ hội tôi sẽ bỏ lỡ hai lần liên tiếp là 22% với sơ đồ này, so với 25% với các trận hòa độc lập. Tăng sự thay đổi trọng lượng để có hiệu ứng lớn hơn (giả sử + 3 / -9) dẫn đến sai lệch xác suất dài hạn.
DMGregory

Trên thực tế, dữ liệu được trình bày ở trên đang áp dụng + 1 / -3 cho trọng số gần đây nhất mỗi khi một cuộn được xử lý. Vì vậy, nếu bạn bỏ lỡ một lần với trọng lượng 50% ban đầu, trọng lượng bỏ lỡ tiếp theo sẽ là 47% và nếu bạn bỏ lỡ lần nữa, trọng lượng sau đây sẽ là 44%, v.v. Nó không giảm các lần chạy (số liệu riêng biệt là theo dõi các lần chạy, được tìm thấy giảm 24% số lần chạy), nhưng chúng vẫn không thể tránh khỏi vì sơ đồ này vẫn có cơ hội mạnh để rời khỏi mỗi 4 trọng số với xác suất khác không ( ví dụ: Bốn crits liên tiếp sẽ khiến trọng lượng crit không có cơ hội xảy ra).
David C Ellis

Nếu đó là ý định của bạn, thì việc thực hiện của bạn có lỗi. Nhìn vào biểu đồ - Trọng lượng fumble chỉ bao giờ bị trả lại trong khoảng từ 7 đến 11, không có giá trị nào bên ngoài. Tôi đã chạy một mô phỏng bằng cách sử dụng sửa đổi liên tục mà bạn mô tả và các biểu đồ rất khác nhau, với xác suất của mỗi trạng thái hội tụ tới 25% mỗi lần trong hàng trăm thử nghiệm đầu tiên.
DMGregory

Dangit, thực sự nó đã bị lỗi như bạn chỉ ra. Vâng, tấn công câu trả lời này.
David C Ellis

@DavidCEllis bạn đang nói rằng việc thực hiện của bạn là thiếu sót, hay chính ý tưởng là gì? Trực giác của tôi trở thành mô hình mà bạn mô tả (điều chỉnh xác suất giảm khi rút ra, dần dần khôi phục tất cả các xác suất về giá trị ban đầu của chúng theo thời gian) và nó vẫn có ý nghĩa với tôi.
dimo414

0

Bạn có thể làm những gì thực chất là một bộ lọc. Theo dõi các sự kiện trong quá khứ. Xác suất là một số bộ lọc được áp dụng cho các sự kiện đó. Bộ lọc thứ 0 là xác suất cơ bản, nếu 0 thì bạn né được, nếu 1 bạn thất bại. Giả sử cơ sở là 25% và bộ lọc giảm một nửa mỗi lần lặp. Bộ lọc của bạn sau đó sẽ là:

[.25 .125 .0625 .03125] 

Hãy tiếp tục nếu bạn muốn. Xác suất tổng thể của sơ đồ này cao hơn một chút so với xác suất cơ bản là 0,25. Trong thực tế, xác suất, được đưa ra cùng một sơ đồ, là (tôi đang gọi x xác suất thực, p là đầu vào xác suất):

x=p+(1-x)*(p/2+p/4+p/8)

Giải cho x, người ta tìm thấy câu trả lời là p(1+1/2+1/4+1/8)/(1+p(1/2+1/4+1/8), hoặc cho trường hợp cụ thể của chúng tôi , x=0.38461538461. Nhưng những gì bạn thực sự muốn là tìm p, cho x. Điều đó hóa ra là một vấn đề khó khăn hơn. Nếu bạn giả sử một bộ lọc vô hạn, vấn đề sẽ trở thành x+x*p=2*p, hoặc p=x/(2-x). Vì vậy, tăng bộ lọc của bạn, sau đó bạn có thể giải quyết một số p, trung bình sẽ cho bạn kết quả tương tự, nhưng với tốc độ phụ thuộc vào mức độ thành công gần đây đã xảy ra.

Về cơ bản, bạn sử dụng các giá trị trước đó để xác định ngưỡng chấp nhận là gì trong vòng này và lấy một giá trị ngẫu nhiên. Sau đó tạo ra giá trị ngẫu nhiên tiếp theo cho bộ lọc.


-1

Giống như bạn đề xuất chính mình, một trong những cách tiếp cận này là thực hiện ngẫu nhiên có trọng số. Ý tưởng là tạo ra một bộ tạo số ngẫu nhiên (hoặc kết quả) trong đó trọng số và kết quả có thể được sửa đổi.

Đây là một triển khai thực hiện điều này trong Java.

import java.util.Map;
import java.util.Random;

/**
 * A psuedorandom weighted outcome generator
 * @param <E> object type to return
 */
public class WeightedRandom<E> {

    private Random random;
    private Map<E, Double> weights;

    public WeightedRandom(Map<E, Double> weights) {
        this.random = new Random();
        this.weights = weights;
    }

    /**
     * Returns a random outcome based on the weight of the outcomes
     * @return
     */
    public E nextOutcome() {
        double totalweight = 0;

        // determine the total weigth
        for (double w : weights.values()) totalweight += w;

        // determine a value between 0.0 and the total weight
        double remaining = random.nextDouble() * totalweight;

        for (E entry : weights.keySet()) {
            // subtract the weight of this entry
            remaining -= weights.get(entry);

            // if the remaining is smaller than 0, return this entry
            if (remaining <= 0) return entry;
        }

        return null;
    }

    /**
     * Returns the weight of an outcome
     * @param outcome the outcome to query
     * @return the weight of the outcome, if it exists
     */
    public double getWeight(E outcome) {
        return weights.get(outcome);
    }

    /**
     * Sets the weight of an outcome
     * @param outcome the outcome to change
     * @param weight the new weigth
     */
    public void setWeight(E outcome, double weight) {
        weights.put(outcome, weight);
    }
}

EDIT Trong trường hợp bạn muốn tự động điều chỉnh các trọng số, ví dụ: tăng cơ hội A khi kết quả là B. Bạn có thể,

  1. Thay đổi hành vi của nextOutcome()phương thức, do đó, nó thay đổi trọng số theo kết quả
  2. Sử dụng setWeight()để sửa đổi trọng lượng theo kết quả.

Tôi nghĩ rằng bạn có thể đã đọc sai câu hỏi: OP không hỏi làm thế nào để tạo ra kết quả ngẫu nhiên có trọng số, nhưng làm thế nào để điều chỉnh các trọng số để giảm khả năng kết quả tương tự xảy ra nhiều lần liên tiếp.
Ilmari Karonen

Tôi hiểu rồi, tôi đã thay đổi một số câu trả lời của mình để giải thích điều đó có thể như thế nào khi sử dụng hệ thống này.
erikgaal
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.