Быстрая оценка покерной руки

Я пытаюсь использовать подход "оценщика рук RayW", чтобы получить оценку комбинации карт (5 лучших карт из 7 ). Однако у меня возникли некоторые проблемы с производительностью при использовании этого метода. Согласно источникам -, при таком подходе должно быть возможно оценить более 300 миллионов раздач в секунду! Мой результат — 10 миллов за 1,5 секунды, что в разы медленнее.

Идея «оценщика рук RayW» следующая:

Оценщик Two Plus Two состоит из большой таблицы поиска, содержащей около тридцати -двух миллионов записей (32 487 834, если быть точным ). Чтобы чтобы найти заданную покерную комбинацию из 7 -карт, вы прокладываете путь через этот table, выполняя один поиск на карточку. Когда вы дойдете до последней карты, полученное таким образом значение является официальным значением эквивалентности руки

вот как выглядит код:

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 #должен работать быстрее.Есть ли способ приблизиться хотя бы к 100 миллионам раздач за одну секунду?

То, что я пробовал до сих пор:

  • пытался использовать статические и не -статические методы -без разницы.
  • пытался использовать поиск по словарю вместо массива

    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 миллионов.

Есть ли другой способ повысить эффективность этой системы ранжирования рук?

19
задан Alex 7 May 2012 в 18:51
поделиться