пятница, 19 декабря 2008 г.

Покер, Функциональное программирование, C#

есть файл, содержащий статистическу информацию о наиболее прибыльных руках в 6max Texac Hold'em.
Примерно вот такой:
Hand SB BB UTG MP CO Btn
AAo 2.62 2.26 2.05 2.58 2.53 2.38
KKo 1.28 1.88 1.63 1.53 1.75 1.81
QQo 1.23 0.88 1.26 0.89 1.07 1.39
JJo 0.77 0.90 0.69 0.83 0.94 1.03
TTo 0.40 0.51 0.56 0.80 0.65 0.87
99o 0.14 0.14 0.26 0.45 0.46 0.39
88o 0.03 0.46 0.16 0.35 0.33 0.13
77o 0.07 -0.05 0.03 0.16 0.09 0.13

Задача - выбрать 13% наиболее доходных рук для игры на UTG и вывести их в "компактном" формате, т.е. вместо "AA","KK","QQ" и т.д. до "88" просто вывести "88+".

Конечный результат должен выглядеть как-то так:
88+,A8s+,...,AJo+,...

Нуу...вот код, решающий эту задачу:

using (StreamReader sr = new StreamReader(@"e:\hands_stat_6x.txt"))

{

    int sum = 0;

    var res = sr.lines()

        .skip(1)

        .map(x => x.Split())

        .map(x => F.tuple(x[0], x[3].to_double())).ToList()

        .sort((x, y) => x.item2==y.item2? 0 : x.item2 < y.item2 ? 1 : -1)

        .filter(x => { sum += (x.item1[0] == x.item1[1]) ? 6 : (x.item1[2] == 's') ? 4 : 12; return sum < ((52 * 51 / 2) * 13 / 100); })

        .ToList();

 

    Console.WriteLine("{0},{1}",

        res.filter(x => x.item1[1] == x.item1[0]).last().item1 + "+"

        , ",".join(

            "so".ToCharArray().SelectMany(suit=>

                "AKQJT9876".ToCharArray()

                .map(x => res.filter(y => y.item1[0] == x && y.item1[1] != x && y.item1[2] == suit).ToList())

                .filter(x => x.Count > 0).map(x => x.last().item1 + "+")

            )));

}


Это разумеется не весь код, я использую свои наработки для работы с tuples, свои функции типа map,skip,fold,filter и т.д. Будем считать что подобные функции есть в .NET (их там нет, и я считаю это недоразумением).

Результирующий код меня впечатлил...
Стоит обратить внимание на то что в коде явно объявлена всего одна переменная. И та вспомогательная... А ведь C# все еще строго типизированный язык:)

Да-да, это write-only код. И отлаживать сложно. Чистое эстетство. Но именно возможность писать такой код привлекает меня в C#. Также как в С++ меня привлекает возможность писать while(*p++). Даже если в реальной работе я этой возможностью пользоваться буду редко и осторожно - коллег жалко).