「RayW ハンド エバリュエーター」アプローチを使用して、カードの組み合わせスコア (7 枚中 5 枚のベスト カード) を取得しようとしています。ただし、この方法にはいくつかのパフォーマンスの問題があります。情報源によると、このアプローチを使用すると、1 秒あたり 3 億以上のハンドを評価できるはずです。私の結果は 1.5 秒で 10 ミルで、何倍も遅くなります。
「RayW ハンド エバリュエーター」の背後にある考え方は次のとおりです。
Two Plus Two エバリュエーターは、約 3200 万のエントリ (正確には 32,487,834) を含む大きなルックアップ テーブルで構成されています。特定の 7 カード ポーカー ハンドをルックアップするには、このテーブルのパスをたどり、カードごとに 1 回のルックアップを実行します。最後のカードに到達すると、得られた値がハンドの公式等価値です。
コードは次のようになります。
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 秒間に少なくとも 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 ミオです。
このハンド ランキング システムのパフォーマンスを向上させる他の方法はありますか?