using System;
using System.Linq;
using System.Collections.Generic;
public static class Consts
{
public const double eps = 0.001;
}
public class MyRotation: PaladinRotation
{
public MyRotation (bool hasDp, bool has4pc, double executionTime, double crit, double haste)
:base (hasDp, has4pc, executionTime, crit, haste)
{
}
public override void Step()
{
// buff expires soon
if (FreeEF && FreeEF.Time <= Hasted(3))
{
CastEF();
}
else if (DP && DP.Time <= Hasted(3))
{
CastEF();
}
else if (FreeLoD && FreeLoD.Time <= Hasted(3))
{
CastLoD();
}
//capped
else if (HolyPower == 5)
{
CastEF();
}
//HS
else if (HS)
{
CastHS();
}
// buff expires soon if we wait 0.5s for HS
else if (DP && DP.Time <= Hasted(3) + 0.5)
{
CastEF();
}
else if (FreeEF && FreeEF.Time <= Hasted(3) + 0.5)
{
CastEF();
}
else if (FreeLoD && FreeLoD.Time <= Hasted(3) + 0.5)
{
CastLoD();
}
//wait 0.5s for HS
else if (HS.Time < 0.5)
{
CastNothing(HS.Time);
}
//free casts
else if (DP && DP.Time >= Hasted(1.5))
{
CastEF();
}
else if (FreeEF && FreeEF.Time >= Hasted(1.5))
{
CastEF();
}
else if (FreeLoD && FreeLoD.Time >= Hasted(1.5))
{
CastLoD();
}
//3 hp LoD
else if (HolyPower >= 3)
{
CastEF();
}
//IoL HL
else if (IoL)
{
CastHL();
}
//wait 1s for HS
else if (HS.Time < 1)
{
CastNothing(HS.Time);
}
//HL filler least priority
else
{
CastHL();
}
}
}
public class Timer
{
public Timer(List<Timer> timers, double defaultTime)
{
_defaultTime = defaultTime;
_active = false;
_time = 0;
timers.Add(this);
}
private bool _active;
private double _time;
private double _defaultTime;
public double Time
{
get
{
return _time;
}
}
protected bool Active
{
get
{
return _active;
}
}
public void Set()
{
_time = _defaultTime;
_active = true;
}
public void Reset()
{
_active = false;
_time = 0;
}
public
void Update
(double time) {
if(!_active) return;
if(_time < Consts.eps) Reset();
if (TimeoutHandler!=null) TimeoutHandler();
}
public Action TimeoutHandler;
}
public class Buff: Timer
{
public Buff
(List
<Timer
> timers
, double time): base
(timers
, time) {
}
public static implicit operator bool(Buff b)
{
return b.Active;
}
}
public class Cooldown: Timer
{
public Cooldown
(List
<Timer
> timers
, double time): base
(timers
, time) {
}
public static implicit operator bool(Cooldown cd)
{
return !cd.Active;
}
}
public class PaladinRotation
{
private List<Timer> _timers = new List<Timer>();
private double _time = 0;
private readonly double _maxTime;
protected readonly Buff FreeEF;
protected readonly Buff FreeLoD;
protected readonly Buff DoubleHS;
protected readonly Buff DP;
protected readonly Buff IoL;
protected readonly Cooldown HS;
protected int HolyPower = 0;
protected readonly bool Has4pc;
protected readonly bool HasDP;
protected readonly double Crit;
protected readonly double Haste;
protected readonly double _hasteMult;
private readonly Result _result = new Result();
public void CastHS()
{
if (!HS) throw new Exception("hs cd");
if (DoubleHS)
{
DoubleHS.Reset();
}
else
{
HS.Set();
}
if (HolyPower < 5) HolyPower++;
if (Roll(Crit * 2)) IoL.Set();
AddTime(Hasted(1.5));
_result.HSCount++;
}
public void CastHL()
{
if(IoL)
{
IoL.Reset();
AddTime(Hasted(1));
if (Roll(10)) DoubleHS.Set();
AddTime(1 - Hasted(1));
_result.IoLHL++;
}
else
{
if (Roll(10)) DoubleHS.Set();
AddTime(Hasted(2.5));
}
_result.HLCount++;
}
public void CastEF()
{
if (FreeEF && FreeEF.Time >= Hasted(1.5))
{
FreeEF.Reset();
}
else if (DP && DP.Time >= Hasted(1.5))
{
DP.Reset();
}
else if (HolyPower >= 3)
{
HolyPower -= 3;
}
else
{
throw new Exception("1HP EF gay attempt");
}
AddTime(Hasted(1.5));
if (HasDP && Roll(25)) DP.Set();
if (Has4pc && Roll(20)) FreeLoD.Set();
_result.EFCount++;
}
public void CastLoD()
{
if (FreeLoD && FreeLoD.Time >= Hasted(1.5))
{
FreeLoD.Reset();
}
else if (DP && DP.Time >= Hasted(1.5))
{
DP.Reset();
}
else if (HolyPower >= 3)
{
HolyPower -= 3;
}
else
{
throw new Exception("1HP LoD gay attempt");
}
AddTime(Hasted(1.5));
if (HasDP && Roll(25)) DP.Set();
if (Has4pc && Roll(25)) FreeEF.Set();
_result.LoDCount++;
}
public
void CastNothing
(double time) {
}
public bool Roll(double chance)
{
return RandomHelper.R.NextDouble() < chance / 100;
}
public
double Hasted
(double time) {
return time * _hasteMult
; }
public PaladinRotation(bool hasDp, bool has4pc, double executionTime, double crit, double haste)
{
HasDP = hasDp;
Has4pc = has4pc;
_maxTime = executionTime;
Crit = crit;
Haste = haste;
_hasteMult = 1 / (1 + Haste / 100);
FreeEF = new Buff(_timers, 10);
FreeLoD = new Buff(_timers, 10);
DP = new Buff(_timers, 8);
DoubleHS = new Buff(_timers, 15);
IoL = new Buff(_timers, 15);
HS = new Cooldown(_timers, Hasted(6));
}
public
void AddTime
(double time) {
if (time <= Consts.
eps) throw new Exception
("time interval " + time.
ToString()); foreach (var timer in _timers)
{
}
_result.TotalTime = _time;
}
public virtual void Step()
{
}
public Result Execute()
{
while(_time < _maxTime) Step();
return _result;
}
}
public static class RandomHelper
{
public static void Init()
{
R = new Random();
}
public static Random R;
}
public class Result
{
public int LoDCount;
public int EFCount;
public int HSCount;
public int HLCount;
public double TotalTime;
public double WaitTime;
public int IoLHL;
public override string ToString()
{
return string.Format("LoD: {0}, EF: {1}, HS: {2}, HL: {3}", LoDCount, EFCount, HSCount, HLCount);
}
}
public class Test
{
public static void WriteResults(List<Result> results)
{
Console.WriteLine(string.Format("iter: {0} LoD: {1:F1}, EF: {2:F1}, HS: {3:F1}, HL: {4:F1}, IoLHL: {5:F1}, Time: {6:F2}s, Wait: {7:F2}s",
results.Count,
results.Average(u=>u.LoDCount),
results.Average(u=>u.EFCount),
results.Average(u=>u.HSCount),
results.Average(u=>u.HLCount),
results.Average(u=>u.IoLHL),
results.Average(u=>u.TotalTime),
results.Average(u=>u.WaitTime)
));
}
public static void Main()
{
try
{
RandomHelper.Init();
List<Result> results1 = new List<Result>();
List<Result> results2 = new List<Result>();
List<Result> results3 = new List<Result>();
List<Result> results4 = new List<Result>();
Console.WriteLine ("10k iter, no DP, no 4pc, 600s, 25% crit, 25% haste");
for (int i=0; i<10000; i++)
{
var rotation = new MyRotation(false, false, 600, 25, 25);
var result = rotation.Execute();
results1.Add(result);
}
WriteResults(results1);
Console.WriteLine ("10k iter, DP, no 4pc, 600s, 25% crit, 25% haste");
for (int i=0; i<10000; i++)
{
var rotation = new MyRotation(true, false, 600, 25, 25);
var result = rotation.Execute();
results2.Add(result);
}
WriteResults(results2);
Console.WriteLine ("10k iter, no DP, 4pc, 600s, 25% crit, 25% haste");
for (int i=0; i<10000; i++)
{
var rotation = new MyRotation(false, true, 600, 25, 25);
var result = rotation.Execute();
results3.Add(result);
}
WriteResults(results3);
Console.WriteLine ("10k iter, DP, 4pc, 600s, 25% crit, 25% haste");
for (int i=0; i<10000; i++)
{
var rotation = new MyRotation(true, true, 600, 25, 25);
var result = rotation.Execute();
results4.Add(result);
}
WriteResults(results4);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}