PRD算法简介
PRD伪随机算法常用于游戏中的暴击算法。该算法使得暴击的产生既不完全靠运气,也不可以精确预测,属于两者间的折中。
PRD算法的表示非常简单:
P(N) = C * N
N表示当前攻击的次数,P(N)表示当前攻击的暴击率,C为概率增量。如果我们这次攻击产生了暴击,则需要将 N 重置为 1,如果这次攻击没有产生暴击,则 N + 1。
C可以通过实际概率P直接获得,即C和实际概率是一一对应关系,比如实际暴击概率P为0.5,那么C恒为0.3。
具体算法详细介绍在如下链接:游戏中常用的伪随机算法之PRD暴击算法
C#实现PRD算法
环境:使用VisualStudio创建控制台应用
代码如下:
class PRD
{
//总概率
public double p;
//概率增量
public double c;
// 根据 传入 C 值,计算该C值下,最小暴击范围的平均暴击率
private double PFromC(double c)
{
double dCurP = 0d;
double dPreSuccessP = 0d;
double dPE = 0;
int nMaxFail = (int)Math.Ceiling(1d / c);
for (int i = 1; i <= nMaxFail; ++i)
{
dCurP = Math.Min(1d, i * c) * (1 - dPreSuccessP);
dPreSuccessP += dCurP;
dPE += i * dCurP;
}
return 1d / dPE;
}
// 根据实际暴击概率P,计算概率增量C
public double CFromP(double p)
{
double dUp = p;
double dLow = 0d;
double dMid = p;
double dPLast = 1d;
while (true)
{
dMid = (dUp + dLow) / 2d;
double dPtested = PFromC(dMid);
if (Math.Abs(dPtested - dPLast) <= 0.00005d) break;
if (dPtested > p) dUp = dMid;
else dLow = dMid;
dPLast = dPtested;
}
return dMid;
}
//当前攻击的次数
private int attackCount = 1;
//返回是否暴击,如果没暴击则攻击次数加1,如果暴击了则攻击次数重置为1
public bool IsCriticalHit()
{
if (new Random().Next(1, 101) <= (int)(c * 100d) * attackCount)
{
attackCount = 1;
return true;
}
else
{
attackCount++;
return false;
}
}
}
class Program
{
static void Main(string[] args)
{
PRD prd = new PRD();
//设置暴击率为0.5
prd.p = 0.5;
Console.WriteLine("暴击率为" + (int)(prd.p * 100d) + "%");
//计算概率增量
prd.c = prd.CFromP(prd.p);
//按n键模拟攻击一次
int iCriticalHitCount = 0, iTotolCount = 0;
while (Console.ReadKey().Key == ConsoleKey.N)//检测到玩家按N键
{
if (prd.IsCriticalHit())
{
iCriticalHitCount++;
Console.WriteLine("暴击!!!!!!!!");
}
else
{
Console.WriteLine("未暴击");
}
iTotolCount++;
Console.WriteLine("总次数:" + iTotolCount + ",暴击次数" + iCriticalHitCount +
",总暴击率:" + (int)((double)iCriticalHitCount / (double)iTotolCount * 100d) + "%");
Console.WriteLine("----------------------------");
}
}
}