前言

当我最初写游戏时,我经常使用标准Random()函数,然后写一堆if和else条件来我获得预期结果。如果结果不太好,我会写更多的条件进行过滤或者筛选,直到我觉得游戏变得有趣。最近我发现有更好的方法。内置的Random类并没有问题,问题是使用内置的Random类很难达到我们的预期效果。

现实生活中,以抛硬币为例,时而会抛出连续多次花或者字。那么如果在游戏中,可能表现为多次连续的暴击或是硬直,尽管有时暴击和硬直的概率很低,但依旧有可能连续出现,让人感觉诡异。那么为了解决类似的问题,前辈们想了很多种方法,比如说特殊值过滤等等。我们今天介绍的是Shuffle Bag技术,可以让你的随机数不那么随机,由你掌控。

什么是Shuffle Bag呢?

Shuffle Bag是一项让我们可以控制随机数分布的技术。

其主要原理为:

  • 设计一个特定分布数值的集合。
  • 把集合中数值转载至背包中。
  • 将背包中数值随机打乱。
  • 从背包中以任意顺序(从前往后,从后往前都无所谓)一个一个的抽取数值,抽完不放回,直到背包为空。
  • 背包为空后,将数据放回,并重新打乱,之后循环利用。
不难看出,Shuffle Bag 特性如下:
  1. 不会产生集合之外的数据。
  2. 它仍然具有随机性,元素出现的顺序还是随机的。
  3. 非重复抽取,如果数据集中某个元素只有一个,至多连续出现两次。

如何实现Shuffle Bag?

原文使用C#,这里使用Unity C#和泛型,大家可以很方便的转译为其他语言。实现并不是先把整个背包先随机打乱,而是每次抽取时,才进行一次随机交换,这样做可以分摊性能,不至于在背包数据较多时,打乱背包消耗某帧过多性能。
  1. using System.Collections.Generic;
  2.  
  3. using UnityEngine;
  4.  
  5. public class ShuffleBag<T> {
  6.  
  7. private List<T> data;
  8. private T currentItem;
  9. private int currentPosition = -1;
  10.  
  11. private int Capacity { get { return data.Capacity; } }
  12. public int Size { get { return data.Count; } }
  13.  
  14. public ShuffleBag(int initCapacity)
  15. {
  16. data = new List<T>(initCapacity);
  17. }
  18.  
  19. public void Add(T item, int amount)
  20. {
  21. for (int i = 0; i < amount; i++)
  22. data.Add(item);
  23.  
  24. currentPosition = Size - 1;
  25. }
  26.  
  27. public T Next()
  28. {
  29. if (currentPosition < 1)
  30. {
  31. currentPosition = Size - 1;
  32. currentItem = data[0];
  33.  
  34. return currentItem;
  35. }
  36.  
  37. var pos = Random.Range(0,currentPosition);
  38. currentItem = data[pos];
  39. data[pos] = data[currentPosition];
  40. data[currentPosition] = currentItem;
  41. currentPosition--;
  42.  
  43. return currentItem;
  44. }
  45. }

  

如何使用Shuffle Bag?

在我的项目中,我希望NPC播放受伤动画的概率为十分之一,并且我不希望看到他偶尔连续播放受伤动画多次,也不想长时间不播放受伤动画。

  1. ShuffleBag<bool> hurtBag = new ShuffleBag<bool>(10);
  2. hurtBag.Add(false, 9);
  3. hurtBag.Add(true, 1);
  4.   //当触发受伤时,调用以下逻辑
  5. if(hurtBag.Next())
  6. {
  7. Play();
  8. }

  

附录

附上参考的原文链接 Shuffle Bags: Making Random() Feel More Random  英文好的同学可以直接看原文 。另外,这个原文题目有些让人疑惑,所以我的译文标题做了一些更改。

Shuffle Bags让你的随机不那么随机的更多相关文章

  1. 随机采样和随机模拟:吉布斯采样Gibbs Sampling实现文档分类

    http://blog.csdn.net/pipisorry/article/details/51525308 吉布斯采样的实现问题 本文主要说明如何通过吉布斯采样进行文档分类(聚类),当然更复杂的实 ...

  2. Atitit.并发测试解决方案(2) -----获取随机数据库记录 随机抽取数据 随机排序 原理and实现

    Atitit.并发测试解决方案(2) -----获取随机数据库记录 随机抽取数据 随机排序 1. 应用场景 1 2. 随机抽取数据原理 1 3. 常用的实现方法:::数据库随机函数 1 4. Mssq ...

  3. 随机采样和随机模拟:吉布斯采样Gibbs Sampling实现高斯分布参数推断

    http://blog.csdn.net/pipisorry/article/details/51539739 吉布斯采样的实现问题 本文主要说明如何通过吉布斯采样来采样截断多维高斯分布的参数(已知一 ...

  4. 5随机到7随机的C++实现

    一.5随机到7随机 //给定条件 int Rand1To5(){ + ; } //实现代码,使用插空法和筛的过程 int Rand1To7(){ ; do{ tmp = (Rand1To5() - ) ...

  5. 随机总数字里面选取随机数字进行随机排序案例(JAVA实现)

    随机总数字里面选取随机数字进行随机排序案例,案例如下: 代码code: package com.sec; import java.util.Arrays; import java.util.Scann ...

  6. scrapy抓取拉勾网职位信息(六)——反爬应对(随机UA,随机代理)

    上篇已经对数据进行了清洗,本篇对反爬虫做一些应对措施,主要包括随机UserAgent.随机代理. 一.随机UA 分析:构建随机UA可以采用以下两种方法 我们可以选择很多UserAgent,形成一个列表 ...

  7. sql server随机排序和随机取出n条数据

    问题:博主在2010-2011学年,广东技术师范大学大四的时候,去过红海人力集团面试数据库职位,很清楚记得当时有一道笔试题目是:编写sql从表里面随机取出10条记录. 解决方案:在sql server ...

  8. 7. 进行图片的数据补全和增强(随机亮度,随机饱和度,随机翻转) Image.open(进行图片的读入) 2.ImageEnhance.Brightness(亮度变化) 3.ImageEnhance.Contrast(饱和度变化) 4.enhance_image.transpose(图片随机翻转) 5.enhance_image.save(进行图片保存)

    1.Image.open(image_path)  进行图片的打开 参数说明:image_path 表示图片的路径 2. ImageEnhance.Brightness(image)  # 进行图片的 ...

  9. JMeter - 生成随机数/随机字符串/随机变量/随机日期

    1. Random - 随机数 1.1 作用 1.2 声明 1.3 例子 2. __RandomDate - 随机日期 2.1 作用 2.2 声明参数 2.3 例子 3. RandomString - ...

随机推荐

  1. 智能指针shared_ptr新特性shared_from_this及weak_ptr

    enable_shared_from_this是一个模板类,定义于头文件<memory>,其原型为: template< class T > class enable_shar ...

  2. hadoop学习;hdfs操作;执行抛出权限异常: Permission denied;api查看源代码方法;源代码不停的向里循环;抽象类通过debug查找源代码

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u010026901/article/details/26587251 eclipse快捷键alt+s ...

  3. S1 商品信息管理系统

    #include <iostream> #include <cstdio> #include <cstdlib> #include <iomanip> ...

  4. windows配置cider和clojure clj

    windows配置cider和clojure clj */--> pre.src {background-color: #292b2e; color: #b2b2b2;} windows配置ci ...

  5. Java动态代理学习

    动态代理类 Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法: Objec ...

  6. Debian 8 时间同步

    每天执行一次 sudo ntpdate ntp.ubuntu.com 逐渐觉得麻烦了,有没有自动执行的方法? 在Linux中用户可以执行例行性的工作,使用crontab这个命令. 步骤: 1.在终端中 ...

  7. C++之指针指向二维数组

    一维指针通经常使用指针表示,其指向的地址是数组第一元素所在的内存地址,例如以下 int ary[4][5]; int(*aryp)[5] = ary; 那么ary[4]相当于int(*aryp).下面 ...

  8. iOS开发过程中易犯的小错误

    addGestureRecognizer(_:) 一个手势对象只绑定一个view // 只有最后一个imgv有点击事件 let tap = UITapGestureRecognizer(target: ...

  9. 从0开始学golang--1--部署本地服务器

    部署自己的本地服务器. 找了个三方包项目:beego.看了下还不错. 上代码....: 首先直接安装三方包,CMD下:go get github.com/astaxie/beego 安装成功后会在pk ...

  10. 20155211 Exp1 PC平台逆向破解(5)M

    20155211 Exp1 PC平台逆向破解(5)M 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入 ...