我正在尝试使用“RayW 手牌评估器”方法来获得卡片组合分数(7 张中的 5 张最佳卡片)。但是,我在使用这种方法时遇到了一些性能问题。据消息人士称——使用这种方法,每秒必须能够评估超过 3 亿只手!我的结果是 1.5 秒内 10 次磨机,这要慢很多倍。
“RayW 手部评估器”背后的理念如下:
二加二评估器由一个包含大约 3200 万个条目(准确地说是 32,487,834 个)的大型查找表组成。为了查找给定的 7 张牌手,您可以在这张表中追踪一条路径,每张牌执行一次查找。当您到达最后一张牌时,所获得的值就是该手牌的官方等值值
这是代码的样子:
namespace eval
{
public struct TPTEvaluator
{
public static int[] _lut;
public static unsafe void Init() // to load a table
{
_lut = new int[32487834];
FileInfo lutFileInfo = new FileInfo("HandRanks.dat");
if (!lutFileInfo.Exists)
{throw new Exception("Handranks.dat not found");}
FileStream lutFile = new FileStream("HandRanks.dat", FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096);
byte[] tempBuffer = new byte[32487834 * 4];
lutFile.Read(tempBuffer, 0, 32487834 * 4);
fixed (int* pLut = _lut)
{ Marshal.Copy(tempBuffer, 0, (IntPtr)pLut, 32487834 * 4);}
tempBuffer = null;
}
public unsafe static int LookupHand(int[] cards) // to get a hand strength
{
fixed (int* pLut = _lut)
{
int p = pLut[53 + cards[0]];
p = pLut[p + cards[1]];
p = pLut[p + cards[2]];
p = pLut[p + cards[3]];
p = pLut[p + cards[4]];
p = pLut[p + cards[5]];
return pLut[p + cards[6]];
}
}
}
}
这就是我测试这种方法的方式:
private void button4_Click(object sender, EventArgs e)
{
int[] str = new int[] { 52, 34, 25, 18, 1, 37, 22 };
int r1 = 0;
DateTime now = DateTime.Now;
for (int i = 0; i < 10000000; i++) // 10 mil iterations 1.5 - 2 sec
{ r1 = TPTEvaluator.LookupHand(str);} // here
TimeSpan s1 = DateTime.Now - now;
textBox14.Text = "" + s1.TotalMilliseconds;
}
我相信这个方法最初是用 C++ 实现的,但是 C# 端口应该工作得更快。有什么办法可以在一秒钟内接近至少 1 亿手牌?
到目前为止我尝试了什么:
- 尝试使用静态和非静态方法 - 没有区别。
尝试使用字典查找而不是数组
public void ArrToDict(int[] arr, Dictionary<int, int> dic) { for (int i = 0; i < arr.Length; i++) { dic.Add(i, arr[i]); } } public unsafe static int LookupHandDict(int[] cards) { int p = dict[53 + cards[0]]; p = dict[p + cards[1]]; p = dict[p + cards[2]]; p = dict[p + cards[3]]; p = dict[p + cards[4]]; p = dict[p + cards[5]]; return dict[p + cards[6]]; }
10 次手的经过时间几乎慢了 6 倍。
据一位人士说 - 他通过删除“不安全”代码将性能提高了 200 个。我尝试做同样的事情,但结果几乎相同。
public static int LookupHand(int[] cards) { int p = _lut[53 + cards[0]]; p = _lut[p + cards[1]]; p = _lut[p + cards[2]]; p = _lut[p + cards[3]]; p = _lut[p + cards[4]]; p = _lut[p + cards[5]]; return _lut[p + cards[6]]; }
这是报价:
在删除了“不安全”的代码部分并在 c# 版本中进行了一些小调整后,它现在也在 310 mio 左右。
有没有其他方法可以提高这个手牌排名系统的性能?