zoukankan      html  css  js  c++  java
  • 游戏中的随机算法

    1.从一个数组中随机取出一个元素
    1 var element = myArray[Random.Range(0, myArray.Length)];
    2.PRD伪随机算法, 通常用来计算暴击率
    1 using System;
    2 using System.Collections;
    3 using System.Collections.Generic;
    4 using UnityEngine;
    5 using UnityEditor;
    6 using System.IO;
    7 using System.Text;
    8 using System.Threading;
    9 
    10 public class PRDCalcC : EditorWindow
    11 {
    12     private static readonly string obj = "lock";
    13     private static Dictionary<int, int> prdDic = new Dictionary<int, int>();
    14     private string infoStr = "";
    15     private string dataStr = "数据运算中....";
    16 
    17     [MenuItem("Tools/PRD_C")]
    18     static void ShowWindow()
    19     {
    20         GetWindow<PRDCalcC>();
    21     }
    22 
    23     private void OnGUI()
    24     {
    25         EditorGUILayout.BeginVertical();
    26         if (GUILayout.Button("运算数据"))
    27         {
    28             // 计算 1% - 100% 暴击率范围所有的 PRD C值
    29             for (int i = 0; i <= 100; ++i)
    30             {
    31                 int j = i;
    32                 // 创建线程负责具体计算 C 值
    33                 Thread thread = new Thread(() =>
    34                 {
    35                     double p = i * 1d / 100d; // 显示给玩家的暴击率
    36                     double c = CFromP(p); // PRD算法 暴击增量
    37                     int ic = (int)Math.Round(c * 100, 0); // 将百分数小数转换为整数
    38                     lock (obj)
    39                     {
    40                         prdDic[j] = ic; // 计算结果存放在字典中
    41                     }
    42                 });
    43                 thread.Start();
    44             }
    45         }
    46         GUILayout.Label(dataStr);
    47         if (prdDic.Count == 101)
    48         {
    49             dataStr = "数据运算完毕";
    50             if (GUILayout.Button("点击生成配置文件"))
    51             {
    52                 try
    53                 {
    54                     CreateXml();
    55                     infoStr = "配置文件生成成功!";
    56                 }
    57                 catch (Exception e)
    58                 {
    59                     infoStr = "配置文件生成失败!错误为:" + e;
    60                 }
    61             }
    62         }
    63 
    64         GUILayout.Label(infoStr);
    65 
    66         EditorGUILayout.EndVertical();
    67     }
    68 
    69     // 生成 XML 文件
    70     private void CreateXml()
    71     {
    72         string path = EditorUtility.OpenFolderPanel("选择目标文件夹", "", "") + @"/prd.xml";
    73         StringBuilder sb = new StringBuilder();
    74         sb.Append(@"<?xml version=""1.0"" encoding=""UTF - 8"" standalone=""yes""?>");
    75         sb.Append('
    ');
    76         sb.Append(@"<root xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">");
    77         sb.Append('
    ');
    78 
    79         string xml = null;
    80         lock (obj)
    81         {
    82             // 在主线程中 从字典中拿出多线程放入的数据,进行解析
    83             foreach(var pair in prdDic)
    84             {
    85                 sb.Append("<item>
    ");
    86                 sb.Append("    <p>" + pair.Key + "</p>
    ");
    87                 sb.Append("    <c>" + pair.Value + "</c>
    ");
    88                 sb.Append("</item>
    ");
    89             }
    90             xml = sb.ToString();
    91             sb.Clear();
    92             xml.Remove(xml.Length - 1);
    93         }
    94         using(FileStream fs = Directory.Exists(path) ? File.OpenWrite(path) : File.Create(path))
    95         {
    96             byte[] bytes = Encoding.UTF8.GetBytes(xml);
    97             fs.Write(bytes, 0, bytes.Length);
    98             fs.Flush();
    99             fs.Close();
    100         }
    101         lock (obj)
    102         {
    103             prdDic.Clear();
    104         }
    105     }
    106 
    107     // 根据 传入 C 值,计算该C值下,最小暴击范围的平均暴击率
    108     private static double PFromC(double c)
    109     {
    110         double dCurP = 0d;
    111         double dPreSuccessP = 0d;
    112         double dPE = 0;
    113         int nMaxFail = (int)Math.Ceiling(1d / c);
    114         for (int i = 1; i <= nMaxFail; ++i)
    115         {
    116             dCurP = Math.Min(1d, i * c) * (1 - dPreSuccessP);
    117             dPreSuccessP += dCurP;
    118             dPE += i * dCurP;
    119         }
    120         return 1d / dPE;
    121     }
    122 
    123     // 根据传入的暴击率,计算 PRD 算法中的系数 C
    124     private static double CFromP(double p)
    125     {
    126         double dUp = p;
    127         double dLow = 0d;
    128         double dMid = p;
    129         double dPLast = 1d;
    130         while (true)
    131         {
    132             dMid = (dUp + dLow) / 2d;
    133             double dPtested = PFromC(dMid);
    134 
    135             if (Math.Abs(dPtested - dPLast) <= 0.00005d) break;
    136 
    137             if (dPtested > p) dUp = dMid;
    138             else dLow = dMid;
    139 
    140             dPLast = dPtested;
    141         }
    142 
    143         return dMid;
    144     }
    145 }
    3.洗牌算法
    1 /// <summary>
    2 /// Knuth-Durstenfeld Shuffle算法,效率最高,会打乱原数组,时间复杂度O(n) 空间复杂度O(1)
    3 /// </summary>
    4 /// <typeparam name="T">数组类型</typeparam>
    5 /// <param name="_array">目标数组</param>
    6 public void KnuthDurstenfeldShuffle<T>(T[] _array)
    7 {
    8     int rand;
    9     T tempValue;
    10     for (int i = 0; i < _array.Length; i++)
    11     {
    12         rand = Random.Range(0, _array.Length - i);
    13         tempValue = _array[rand];
    14         _array[rand] = _array[_array.Length - 1 - i];
    15         _array[_array.Length - 1 - i] = tempValue;
    16     }
    17 }
    4.权重概率算法
    1 //probs为权重数组, 且权重由大到小排序
    2 float Choose (float[] probs) {
    3     float total = 0;
    4     foreach (float elem in probs) {
    5         total += elem;
    6     }
    7     float randomPoint = Random.value * total;
    8     for (int i= 0; i < probs.Length; i++) {
    9         if (randomPoint < probs[i]) {
    10             return i;
    11         }
    12         else {
    13             randomPoint -= probs[i];
    14         }
    15     }
    16     return probs.Length - 1;
    17 }

    5.在一个空心圆范围内随机生成物体

    1 using UnityEngine;
    2 using System.Collections;
    3 
    4 public class RandomRadius : MonoBehaviour {
    5     public GameObject prefabs;
    6     // Use this for initialization
    7     void Start () {
    8         for (int i = 0; i < 1000; i++) {
    9             Vector2 p = Random.insideUnitCircle*3;
    10             Vector2 pos = p.normalized*(2+p.magnitude);
    11             Vector3 pos2 = new Vector3(pos.x,0,pos.y);
    12             Instantiate(prefabs,pos2,Quaternion.identity);
    13         }
    14     }
    15 }

     6.从一个数组中随机选择指定个数且不重复的元素

     1 int[] spawnPoints = {1, 5, 6, 8, 9, 20, 15, 10, 13};
     2 
     3 int[] ChooseSet (int numRequired) {
     4     int[] result = new Transform[numRequired];
     5     int numToChoose = numRequired;
     6     for (int numLeft = spawnPoints.Length; numLeft > 0; numLeft--) {
     7         float prob = (float)numToChoose/(float)numLeft;
     8         if (Random.value <= prob) {
     9             numToChoose--;
    10             result[numToChoose] = spawnPoints[numLeft - 1];
    11             if (numToChoose == 0) {
    12                 break;
    13             }
    14         }
    15     }
    16     return result;
    17 }
    7.在一个球体内生成随机点
    1 var randWithinRadius = Random.insideUnitSphere * radius;

     8.遵循高斯分布的随机算法(lua实现)

     1 function randomNormalDistribution()
     2     local u, v, w, c = 0, 0, 0, 0
     3     while(w == 0 or w >= 1)
     4     do
     5         --//获得两个(-1,1)的独立随机变量
     6         u = math.random() * 2 - 1
     7         v = math.random() * 2 - 1
     8         w = u * u + v * v
     9     end
    10     --//这里就是 Box-Muller转换
    11     c = math.sqrt((-2 * math.log(w)) / w)
    12     --//返回2个标准正态分布的随机数,封装进一个数组返回
    13     --//当然,因为这个函数运行较快,也可以扔掉一个
    14     --//return [u*c,v*c];
    15     return u * c
    16 end
    17 
    18 function getNumberInNormalDistribution(mean, std_dev)
    19     return mean + (randomNormalDistribution() * std_dev)
    20 end
    21 --//参数1表示期望值, 参数二表示差值范围
    22 getNumberInNormalDistribution(180, 10)

     

  • 相关阅读:
    TWinHttp之二
    日志池
    TWinHTTP
    TJSONTableObject跨平台解析JSON
    TSQLTableJSON解析JSON
    TDocVariantData解析JSON
    Vue.js常用指令汇总(v-if//v-show//v-else//v-for//v-bind//v-on等)
    VUE -- 十分钟入门 Less
    VUE -- ejs模板的书写
    Go VUE --- vuejs在服务器部署?
  • 原文地址:https://www.cnblogs.com/tqw1215/p/14759919.html
Copyright © 2011-2022 走看看