Объектное представление раундов ставок в покере - PullRequest
1 голос
/ 18 ноября 2009

Я пишу HandConverter покерной руки. Это мой первый проект, и я пытаюсь сделать это с самого начала.

У меня уже есть большинство частей, таких как списки игроков, их позиции, размеры стеков, карты для разных досок, в какую игру играют и так далее, но я борюсь с представлением ставок, особенно с различными рейзами, ставки и несколько звонков от одного игрока.

Я обнаружил некоторые случаи, когда мое наивное решение на основе случая не работает, и оно действительно сложное, и мне это не нравится. Поскольку в настоящее время это работает для NL Hold'em, я думаю, что у меня будет больше обходных путей, если я захочу реализовать такие игры, как Stud, Razz и т. Д., Хотя структура ставок, скорее всего, такая же.

Пока я использую это представление и хотел бы улучшить особенно классы Round и Action. У вас есть предложения для меня?

public class HandHistory
{
    public GameInfo GameInfo;
    public TableInfo TableInfo;
    public List<Player> Players;
    public List<Round> Rounds;
    public string rawtext;
    public bool withHero;

}

public Round
{
    public List<Action> Action;
    public string Name;
    public decimal Potsize;
    public ulong Cards; //usually would have used a custom class, 
                        //but I need them in a ulong mask for some library I use
}

public class Action
{
    public Player Player;
    public string Type;
    public decimal Amount;
}

P.S. Я также использую список для хранения различных раундов, есть ли лучший способ, как наследовать класс раундов для флопа, терна и ривера, например?

Ответы [ 6 ]

2 голосов
/ 18 ноября 2009

Вместо строки для вашего Action.Type вы можете использовать перечисление:

enum BettingAction
{
   Check,
   Bet,
   Call,
   Raise,
   Fold
}
1 голос
/ 18 ноября 2009

Когда вы говорите первый проект, что вы имеете в виду? Я предполагаю, что вы студент или новичок в программировании.

При таком предположении я бы предложил выбрать что-то более простое, чем история покерных рук. Как и в программировании игр, на первом этапе программирования игры не стоит думать, что вы создаете последнюю версию Call of Duty. Вы начинаете с прорыва и двигаетесь вверх оттуда.

Если вы не хотите начинать с меньшего, чем я предлагаю, никогда не переходите на кодирование. Когда вы сделаете это, вы потратите больше времени на то, чтобы просто крутить колеса, а не что-то делать.

Например, сначала вы должны потратить время на разработку того, что будет делать ваша программа, а что нет. Постарайтесь быть как можно более полным. Это можно сделать из чего-то сложного, используя программу UML или просто, как ручку и бумагу.

Я бы сказал, что вы хотите, чтобы рука развивалась. Информация, которую вы хотите отслеживать. Как только вы действительно поймете это, ваши структуры данных начнут оживать.

Поскольку вы новичок в программировании, я бы начал писать доказательство концептуального кода. Затем переместите его в ваш окончательный проект. Под доказательством концепции я подразумеваю код, который вы просто тестируете, чтобы понять, как он работает. Например, как будет работать история рук? Можете ли вы создать какую-нибудь «фиктивную» историю и настроить ее? В идеале вы должны выполнить модульное тестирование, но давайте начнем с меньшего.

Важно знать, что вы создаете программу, как дом. Вы должны знать, что вы хотите, чтобы он делал, а не делал (синие отпечатки). Каков каждый шаг. И вы медленно строите другие части. Это процесс, который требует времени, но в конце концов он того стоит.

0 голосов
/ 16 декабря 2009

вместо подкласса Round в FlopRound TurnRound и т. Д., Я бы использовал атрибут Street в раунде, а также в Action.

static public enum Street {PREFLOP, FLOP, TURN, RIVER};

...

0 голосов
/ 28 ноября 2009

Термин Раунд немного двусмысленный. BettingRound делает это более очевидным. Я не вижу необходимости иметь здесь карты, имена и размеры. Potsize - это функция действий и изменений на протяжении всего раунда ставок. Места представляют игру немного лучше, чем список игроков, поскольку это позволяет вам представить игровое состояние (размеры стеков и т. Д.) Немного более наглядно. Я не вижу необходимости делать флоп, карты риверов, явно назначенные раундам - ​​просто используйте список карт и некоторые условные обозначения. например первые три карты = флоп ... первый круг торговли = флоп. Используйте некоторые методы расширения для удобства ссылки на флоп для холдема. Используйте ULONG версию карт путем конвертации, когда вам нужно использовать ее, а не загромождать модель своего домена.

Вот так я вижу модель конкретной индивидуальной игры (то есть 1 флоп, ривер, терн и т. Д.). Еще предстоит проделать большую работу, чтобы смоделировать все игры (например, в лимитных играх для определения ставок используется маленькая ставка / большая ставка вместо блайндов).

карта публичного класса { общественный костюм костюм; публичный рейтинг ранг; public ulong ToCardMask (); }

public enum Suit
{
    Clubs,
    Diamonds,
    Hearts,
    Spades
}

public enum Rank
{
    Ace,
    Deuce,
    Trey,
    //...
    Jack,
    Queen,
    King
}

public class Game
{
    public GameInfo GameInfo;
    public TableInfo TableInfo;
    public List<BettingRound> BettingRounds;
    public List<Card> CommunityCards;
    public string Rawtext;
    public bool WithHero; //??
}

public static class GameExtensions
{
    public static BettingRound Flop(this Game game)
    {
        return game.BettingRounds[0];
    }

    public static List<Card> FlopCards(this Game game)
    {
        return game.CommunityCards.Take(3).ToList();
    }
}

public class GameInfo
{
    public GameType GameType;
    public GameBettingStructure BettingStructure; // Limit, PotLimit, NoLimit
    public Stakes Stakes; // e.g. { $1, $2 }
    public long Id;
    public List<Seat> Seats;
}

enum GameType // prob change to a class for extensibility
{
    HoldEm,
    Razz,
    StudHi,
    StudHiLo,
    OmahaHi,
    OmahaHiLo
}

enum GameBettingStructure
{
    Limit,
    PotLimit,
    NoLimit
}

class Stakes // probably needs some tweeking for stud games (e.g. bring-in ...)
{
    public Money Ante;
    public List<Money> Blinds;
}

public class Seat
{
    public Player Player;
    public Money InitialStackAmount;
    public Money FinalStackAmount; // convienience field can be calculated
    public List<Card> Hand;
}

class Money
{
    public decimal Amount;
    public Unit Unit;
}

enum Unit
{
    USD,
    EUR,
    AUD,
    TournamentDollars
}

public class Player
{
    public string Name;
}

public class TableInfo
{
    public string Name;
}

public class BettingRound
{
    public List<BettingAction> BettingActions;
}

public class BettingAction
{
    public abstract Money PotSizeAfter();
    public byte SeatNumber;
}

public class Fold : BettingAction { }
public class Call : BettingAction { }
public class BringIn : BettingAction { }
public class Complete : BettingAction { }
public class Bet : BettingAction
{
    public Money Amount;
}

public class Raise : Bet { }
0 голосов
/ 18 ноября 2009

Не совсем связанный с программированием ответ; но стили ставок для Разз или Стад несколько отличаются от Холдема.

1.) Жалюзи нет; скорее анте
2.) Открывающее лицо может либо внести ставку, либо завершить ставку
3.) Есть больше раундов торговли

У тебя довольно хорошее начало. Возможно, вы захотите создать List<Hands>, в котором будет List<Rounds>. В противном случае у вас будет огромный список раундов, и вы не сможете определить, когда одна рука началась / закончилась, а другая началась.

Я думаю, что вам, вероятно, нужно определить свои типы действий, и тогда вещи, вероятно, начнут становиться на свои места. Вот что я бы сделал для типов:

Проверка
Ставка
Сложите
Позвоните
Рейз (по сути колл и ставка)

Возможно, вам захочется подумать о реализации чего-то вроде «Prior Action» в вашем классе действий; так как каждый игрок реагирует на действия перед ними.

Вы также хотели бы рассмотреть некоторые нюансы игры; где игрок a ставит 500, а игрок b идет олл-ин на 250; поскольку, за исключением этого случая, колл должен соответствовать предыдущей ставке.

0 голосов
/ 18 ноября 2009

У карт могло бы быть лучшее имя, но я предполагаю, что вы имеете в виду общие карты. Я бы составил список карт, тогда подклассы терна и ривера имели бы только одну карту в списке. Я также предложил бы представлять карточки таким образом, чтобы это имело смысл для вас, а затем выполнять преобразование, когда вам нужно взаимодействовать с библиотекой.

...