Need for predictable random generator

前端 未结 30 1125
情话喂你
情话喂你 2020-11-27 09:04

I\'m a web-game developer and I got a problem with random numbers. Let\'s say that a player has 20% chance to get a critical hit with his sword. That means, 1 out of 5 hits

30条回答
  •  心在旅途
    2020-11-27 09:47

    I agree with the earlier answers that real randomness in small runs of some games is undesirable -- it does seem too unfair for some use cases.

    I wrote a simple Shuffle Bag like implementation in Ruby and did some testing. The implementation did this:

    • If it still seems fair or we haven't reached a threshold of minimum rolls, it returns a fair hit based on the normal probability.
    • If the observed probability from past rolls makes it seem unfair, it returns a "fair-ifying" hit.

    It is deemed unfair based on boundary probabilities. For instance, for a probability of 20%, you could set 10% as a lower bound and 40% as an upper bound.

    Using those bounds, I found that with runs of 10 hits, 14.2% of the time the true pseudorandom implementation produced results that were out of those bounds. About 11% of the time, 0 critical hits were scored in 10 tries. 3.3% of the time, 5 or more critical hits were landed out of 10. Naturally, using this algorithm (with a minimum roll count of 5), a much smaller amount (0.03%) of the "Fairish" runs were out of bounds. Even if the below implementation is unsuitable (more clever things can be done, certainly), it is worth noting that noticably often your users will feel that it's unfair with a real pseudorandom solution.

    Here is the meat of my FairishBag written in Ruby. The whole implementation and quick Monte Carlo simulation is available here (gist).

    def fire!
      hit = if @rolls >= @min_rolls && observed_probability > @unfair_high
        false
      elsif @rolls >= @min_rolls && observed_probability < @unfair_low
        true
      else
        rand <= @probability
      end
      @hits += 1 if hit
      @rolls += 1
      return hit
    end
    
    def observed_probability
      @hits.to_f / @rolls
    end
    

    Update: Using this method does increase the overall probability of getting a critical hit, to about 22% using the bounds above. You can offset this by setting its "real" probability a little bit lower. A probability of 17.5% with the fairish modification yields an observed long term probability of about 20%, and keeps the short term runs feeling fair.

提交回复
热议问题