Дилер покер холдем


Это представляет собой таблицу (сервер) для Техасский Холдем.

Это не полный холдем игра, но это рабочий код, для чего он делает. Он тасует, раздает карты, предложения Совета, перемещает жалюзи, и собирает блайнды. Он не поддерживает реальные ставки, ни премии горшок. Это просто фейки горшок. Реальные ставки получает комплекс. Это в точку, я был бы признателен за комментарий.

В покер кнопка дилера перемещается вправо дилеров, которые игроки оставили (+1) (по часовой стрелке). На первый тур есть случайная ничья для кнопки. Есть 4 раундов ставок/дело. Малый блайнд находится слева от кнопки (+1) имеет обязательную ставку от СБ. Большого блайнда слева от ШБ имеет обязательную ставку ББ (обычно 2 раза ШБ). После ББ, делает первый ход в первом раунде. После первого круга в СБ первый акт. На первой же улице (предварительно) каждый игрок получает две закрытые карты. На второй улице (флоп) совет получает три карты. Поворот и правление река получает еще одну карту каждый. Я знаю, что это кажется сложным, но это, как она работает.

В хедз-ап (два игрока) вымажешься как дилер тоже в СБ. Это пока не касается головы.

Таблица имеет места. Этот код не использовать место. Упорядоченный список игроков сидений. Этот код перемещает кнопку напрямую к игроку и назначает приказом ставки напрямую к игроку.

Нет дилера в настоящем Кодексе. Стол выполняет действия дилера.

Это использует стандартную 52 карточную колоду и нет намерения когда-либо поддерживая другой палубе.

Это не сжечь карты, который не влияет на игру.

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

public static void PokerPlayerTest()
{
    PokerTable pt = new PokerTable("Hook", new List<PokerPlayer> { new PokerPlayer("Peter0"), new PokerPlayer("Tinker1"), new PokerPlayer("Wendy2"), new PokerPlayer("Rianna3"), new PokerPlayer("Lady4") });
    for(int i = 0; i<10; i++)
    {
        pt.Shuffle();
        Debug.WriteLine(pt.ToString());
        pt.Flop();
        Debug.WriteLine(pt.ToString());
        pt.Trun();
        Debug.WriteLine(pt.ToString());
        pt.River();
        Debug.WriteLine(pt.ToString());
        Debug.WriteLine("");               
    }
}
public class PokerCard
{
    byte id;
    public enum Suits { heart, spade, diamond, club };
    public enum Ranks { two, three, four, five, six, seven, eight, nine, ten, jack, queen, king, ace };
    public Suits Suit { get { return (Suits)(id/13); } }
    public Ranks Rank { get { return (Ranks)(id%13); } }
    public override string ToString()
    {
        return $"{Rank} {Suit}";
    }
    public PokerCard(byte ID)
    {
        id = ID;
    }
}
public class PokerPlayer
{
    public enum Poss { sb, bb, btn, mid}
    //current PokerPlayer does not bet
    public int ChipCount { get; set; } = 200;
    public PokerCard[] HoleCards { get; } = new PokerCard[2];
    public int ID { get; }
    public int BettingOrder { get; set; } = 0; 
    public Poss Pos { get; set; } 
    public string Name { get; }
    public override string ToString()
    {
        return $"{Name} {HoleCards[0].ToString()}_{HoleCards[1].ToString()}  pos {Pos}  chips {ChipCount.ToString("N0")}";
    }
    public PokerPlayer (byte id, string name)
    {
        ID = id;
        Name = name;
    }
    public PokerPlayer(byte id, string name, int chipCount)
    {
        ID = id;
        Name = name;
        ChipCount = chipCount;
    }
    public PokerPlayer(string name)
    {
        ID = 0;
        Name = name;
    }
    public PokerPlayer(string name, int chipCount)
    {
        ID = 0;
        Name = name;
        ChipCount = chipCount;
    }
}
public class PokerTable
{
    //pot and betting not yet implemented 
    //current PokerTable just deals
    Random rand = new Random();
    List<PokerCard> deck = new List<PokerCard>();
    public enum Streets { pre, flop, turn, rivr }
    byte street = 0;
    byte cardNum = 0;
    int round = 0;
    int btn = 0;
    int sb = 1;
    int bb = 2;
    public PokerPlayer Button {  get { return PokerPlayers[btn]; } }
    public int Pot { get; set; } = 0;
    public Streets Street { get { return (Streets)street; } }
    public List<PokerCard> Board { get; } = new List<PokerCard>();
    public string BoardStr { get { return string.Join(", ", Board.Select(c => c.ToString())); } }
    public string PlayersStr { get { return string.Join(", ", PokerPlayers.OrderBy(p => p.BettingOrder).Select(p => p.ToString())); } }
    void SetBettingOrder()
    {
        int cnt = PokerPlayers.Count;
        int offset = street == 0 ? 3 : 1;
        for(int i = 0; i < PokerPlayers.Count; i++)
        {
            int bettingOrder = (i + 2*cnt - btn - offset) % cnt;
            PokerPlayers[i].BettingOrder = bettingOrder;
        }
    }
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        if(street == 0)
        {
            sb.AppendLine($"dealer {DealerName}  round {round}  button {Button.Name}\n  {Street} "); //{ PlayersStr}
        }
        else 
        {
            sb.AppendLine($"  {Street} {BoardStr}");
        }
        foreach (PokerPlayer pp in PokerPlayers.OrderBy(p => p.BettingOrder))
        {
            sb.AppendLine($"       {pp.ToString()}");
        }
        sb.Append($"       pot {Pot}");
        return sb.ToString();
    }
    public string DealerName { get; }
    public List<PokerPlayer> PokerPlayers { get; } 
    private void MoveButton()
    {
        if (round == 1)
        {                   
            btn = rand.Next(PokerPlayers.Count - 1);               
        }
        else
        {
            btn++;
            if(btn == PokerPlayers.Count)
            {
                btn = 0;
            }
        }
        foreach (PokerPlayer pp in PokerPlayers)
        {
            pp.Pos = PokerPlayer.Poss.mid;
        }              
        int tpos = btn + 1;
        if(tpos == PokerPlayers.Count)
        {
            tpos = 0;
        }
        PokerPlayers[tpos].Pos = PokerPlayer.Poss.sb;
        PokerPlayers[tpos].ChipCount -= sb;
        tpos ++;
        if (tpos == PokerPlayers.Count)
        {
            tpos = 0;
        }
        PokerPlayers[tpos].Pos = PokerPlayer.Poss.bb;
        PokerPlayers[tpos].ChipCount -= bb;
        PokerPlayers[btn].Pos = PokerPlayer.Poss.btn;
    }
    public void Shuffle()
    {
        //fisher yates shuffle
        street = 0;              
        round++;
        Pot = sb + bb;
        Board.Clear();
        MoveButton();
        SetBettingOrder();
        for (int b = deck.Count - 1; b > 0; b--)
        {
            int r = rand.Next(b);
            if(r != b)
            {
                PokerCard temp = deck[r];
                deck[r] = deck[b];
                deck[b] = temp;
            }
        }
        //no need for cut or burn cards cards
        cardNum = 0;
        foreach(PokerPlayer pp in PokerPlayers)
        {
            pp.HoleCards[0] = deck[cardNum];
            cardNum++;
            pp.HoleCards[1] = deck[cardNum];
            cardNum++;
        }
    }
    public void Flop()
    {
        if(street != 0)
        {
            throw new ArgumentOutOfRangeException("wrong street");
        }
        street++;
        SetBettingOrder();
        Board.Add(deck[cardNum]);
        cardNum++;
        Board.Add(deck[cardNum]);
        cardNum++;
        Board.Add(deck[cardNum]);
        cardNum++;
        Pot += Pot;
    }
    public void Trun()
    {
        if (street != 1)
        {
            throw new ArgumentOutOfRangeException("wrong street");
        }
        street++;
        Board.Add(deck[cardNum]);
        cardNum++;
        Pot += Pot;
    }
    public void River()
    {
        if (street != 2)
        {
            throw new ArgumentOutOfRangeException("wrong street");
        }
        street++;
        Board.Add(deck[cardNum]);
        Pot += Pot;
    }
    public PokerTable(string dealerName, List<PokerPlayer> pokerPlayers)
    {
        DealerName = dealerName;
        PokerPlayers = pokerPlayers;
        for(byte b = 0; b < 52; b++)
        {
            deck.Add(new PokerCard(b));
        }
    }
}

Получив несколько (пренебрежительное) комментарии о короткое перечисление. Когда вы боретесь за пространство экрана, они хорошие. Покер имеет некоторые стандартные сокращения. Клиент волен использовать любой текст или изображения, которые они хотят (и должны). table positions

Можете игнорировать это
Это для сервис-ориентированной архитектуры (САО). Добавить, что, возможно, отменяет существующие ответы, которые не является справедливым.



1910
10
задан 19 марта 2018 в 12:03 Источник Поделиться
Комментарии
6 ответов

Я собираюсь второй downrep_nation комментарии: sb, bb, rivrи т. д. ужасные имена для элементов enum (и члены). Я бы многое предпочитают smallBlind bigBlindи button: btn похоже на управление из прошлого. Я использую инициалы для всех типов, но не для доменных понятий, и какая польза будет извлекать 'е' от river у кого-нибудь?

Это тоже страшная идентификатор: Poss. PokerTable.Trun есть орфографические ошибки.


Говоря о Труна, почему вы не используете свой Streets перечисление?

if (street != 1)
{
throw new ArgumentOutOfRangeException("wrong street");
}
street++

Может быть

if (street != Street.Flop)
{
throw new ArgumentOutOfRangeException("Wrong street: expected Flop, but received " + street.ToString());
}
street = Street.Turn;

Которая намного чище, чем в зависимости от детализации порядка перечисления (которые не документированы вообще). Это, конечно, зависит от street будучи Streetsне byte, что также значительно яснее.

В SetBettingOrder:

int offset = street == Steets.Pre ? 3 : 1;


Есть много выбрать одну, возможно, сбросить в коде, который сильно разбивает логику, и просто больше вещей, чтобы беспокоиться при поддержке:

int tpos = btn + 1;
if(tpos == PokerPlayers.Count)
{
tpos = 0;
}

Гораздо более короткий путь tpos = (tpos + 1) % PokerPlayers.Countно учитывая то, как часто вам это нужно, я бы определенно сделать это своей функцией:

private int NextPlayerIndex(int playerIndex)
{
return (playerIndex + 1) % PokerPlayers.Count;
}


У вас также есть великое множество конструкторов... это не имеет никакого смысла:

public PokerPlayer(string name){
ID = 0;
Name = name;
}

В каком мире не будет необходимости указывать ID быть хорошо? Это просто умоляет, чтобы быть неправильно.

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

public PokerPlayer(byte id, string name, int chipCount)
{
ID = id;
Name = name;
ChipCount = chipCount;
}

public PokerPlayer (byte id, string name) : this(id, name, 200)
{
// nix // I usually leave a short, semi-esoteric but recognisable comment to indicate there is meant to be nothing here when I have a pair of empty braces
}

Это означает, что при добавлении элемента необходимо только обновление базового конструктора и исправить все ошибки, что производит, а не беспокоиться о том, что не хватает каких-либо. В вашем конкретном случае, chipCount это немного странно, потому что есть обычные и необычные по умолчанию, но я предполагаю, что это пережиток отладки, а не то, что когда-нибудь появится в производственном коде: если такое магическое число, как представляется, это должен быть постоянный, который можно будет ссылаться в конструкторы.

`const int DefaultChipCount = 200`

Кроме того, вы можете использовать необязательный параметр, и угробить все страдаю из-за потери гибкости.

public PokerPlayer(byte id, string name, int chipCount = DefaultChipCount)

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


Опять как downrep_nation говорили, есть много путаницы о том, что некоторые из ваших методов сделать. Перетасовки массива (в исполнении в Shuffle) в частности имеет ничего общего с Pokerи я бы реализовать это совершенно отдельный класс, потому что он по сути своей общие цели и общая деятельность. Действительно, я думаю, с позиции комментарий //fisher yates shuffle что изначально Shuffle просто хочу, чтобы перемешать, а затем стал завышенным и с другими обязанностями.


Я возьму downrep_nation советую об этом коде в несколько ином направлении:

pp.HoleCards[0] = deck[cardNum];
cardNum++;

Это должно быть загнанным в TakeCard() => cardNum++; метод. Сборка карт тогда дает следующие, которых я считаю намного более выразительным, чем в LINQ downrep_nation это:

for (int i = 0; i < magicNumber; i++)
Board.Add(TakeCard);


В pokerPlayers параметр здесь-это своего рода страшно, потому что ты не знаешь откуда это приходит, и ты потом использовал ее для государства:

PokerTable(string dealerName, List<PokerPlayer> pokerPlayers)

Я хотел бы сделать это (и собственность, особенно потому, что это публичное) в IReadOnlyList<PokerPlayer>и клонировать его, просто чтобы быть уверенным. Вы не хотите, чтобы код, который создан PokerTable в одностороннем порядке изменять этот список.


И немного разное/скучных вещей:


  • Просто личное предпочтение, на самом деле, но я бы заполняя код с пустой строки, чтобы разбить его, но. Это намного проще, чтобы перейти 'сегментированный' код: по этой же причине мы используем пуля точек и горизонтальные правила в КЛ ответы

  • Я не слишком люблю использование перечислений давать имена: suit и rank как государственные, так несмотря на то, что бесполезно за пределами PokerCard и имея частный просмотр имен, и не дают никакой защиты от 'вне границ' подстановки. PokerCard выглядит как отличное место, чтобы иметь несколько Debug.Assert заявлений, так что если это когда-либо с недопустимым идентификатором может бросить немедленно, давая вам ценные стека вызовов и предоставления некоторых документов.

  • Я также указать видимость всех членов (напр. PokerCard.id): но, очевидно, это не большие опасения (если вы работаете с кем-то иду от C++ может/любой другой язык с различными по умолчанию)

  • Я был бы склонен рвать Poss Pos в PokerPlayerи просто вычислить его, когда это необходимо, если PokerPlayer класс имеет веские причины должны знать свою позицию.

  • Я уверен, что они только для отладки, но ToString() методов не делает много смысла. PokerPlayer может возвращать несколько неинициализированном состоянии, когда ToString() называется (Pos будет значение по умолчанию).

  • В PokerTable, DealerName и PokerPlayers ниже излагаются некоторые методы, которые смущают тех, кто ищет их.

  • Ничто не мешает игроку из отрицательного количества чипов (это все часть того, что вы заметили, что у вас есть только игроки, а не мест, поэтому вы можете не выселять игроков, у которых закончились средства).

7
ответ дан 19 марта 2018 в 09:03 Источник Поделиться

В целом код выглядит ОК.

Но есть некоторые вещи, чтобы рассмотреть, что нужно делать с чистого кода и твердые принципы.

Во-первых, имена переменных путаете и не показателен.

sb, bb, btn, cardNum

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

Есть несоответствия с кодом один раз

ID and id

Выбрал стиль корпуса и остаться с ним

public Suits Suit { get { return (Suits)(id/13); } }

Это может быть записано как

public Suits Suit => (Suits)(id/13);

Что это просто синтаксический сахар для геттер только его участники, но не обязательно, что это должно, с другой стороны, называя свои магические числа

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

В PokerPlayer класс рекомендуется использовать по умолчанию аргументы в функцию параметров, вместо того, чтобы удалить часть кода повторения.

Еще один момент будут твердые принципы, особенно СРП (индивидуальная ответственность)

Ваши функции сломать ПСП делать много вещей, объединив оба графика-логики и бизнес-логики, т. е. функцию или совокупность различных абстракций, чтобы определить логику, или быть одной из причин снижения уровня выработок с кодом и его базовых структур данных.

Кроме того, СРП делает функции более показателен и проверяемым Shuffle() хороший пример того, как реализация низком уровне массива перетасовки и дело с абстракциями, как Board.Clear().

Попробуйте разделить эти функции на логические компоненты и писать тесты для них

В Flop() вы могли бы написать Pot *= 2 вместо того, чтобы указать, удвоение банка (придираться)

Кроме того, это может быть заменен легче читать по LINQ

Board.Add(deck[cardNum]);
cardNum++;
Board.Add(deck[cardNum]);
cardNum++;
Board.Add(deck[cardNum]);
cardNum++;

Вместо того, чтобы писать

Board.AddRange(deck.Skip(cardNum).Take(magicNumber));
cardNum+=magicNumber;

10
ответ дан 19 марта 2018 в 06:03 Источник Поделиться

Общие замечания


  • Смурф именования: PokerCard, PokerPlayer, PokerTable, PokerPlayerTest легко может быть переименован в Card, Player, Table, PlayerTest без каких-либо недостатков.

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


    • Вы не должны сократить определений классов/перечисление.

    • Это более приемлемо сокращать имена переменных (в пределах разумного).

    • Position playerPosition; это хорошо. Position playerPos; приемлемо. Poss playerPosition; или Poss playerPoss; не хорошо.


  • Игрок с 1000 фишек в руке может выбрать только место 250 фишек по определенным покерным столом. Ваша текущая реализация предполагает, что игрок автоматически размещает все свои chipes на столе. Однако, я собираюсь предположить, что это просто выходит за рамки текущего приложения.


    • Я думаю, что это было бы неплохо в следующем упражнении вы узнаете, как отдельных данных, которые принадлежат игроку, и данные, которые принадлежат игроку место на столе. Это самая большая "ошибка" (заметьте кавычки), что вы сделали в вашем нынешнем подходе.



PokerCard

Хотя я согласен с enum для обоих масть и значение карты, я не согласен с некоторыми другими вещами.


  • Почему вы используете идентификатор типа byte? byte обычно не используется для данных моделей, которые не полагаются на двоичные данные.

  • Вместо того, чтобы использовать ID, чтобы потом calculcate масть и значение, просто выберите масть/величина напрямую и удалить идентификатор.


    • Ваша текущая реализация опирается на точное количество костюмов и ценностей, которые существуют в настоящее время. Я в курсе, что играть в карты не ожидается, чтобы добавить/удалить костюмы/значения в ближайшее время, но это принципиальная вещь. Не думайте, что сумма значений в enum-это никогда не изменится.


  • Я бы переименовал Rank для Value. Ранг означает, что они сортируются в порядке, но Туз simultaneuously функции как "+1", но и как "один" (т. е. Туз-2-3-4-5 является действительной прямой). Поэтому, Туз не правильно занял, так что технически это не ранг карты.

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

  • Небольшой комментарий: я поменял ToString() чтобы отразить, как английский, относится к игре в карты, например, "два из лопаты".

Пересмотренный класса:

public class PokerCard
{
public enum Suits { hearts, spades, diamonds, clubs };
public enum Values { two, three, four, five, six, seven, eight, nine, ten, jack, queen, king, ace };
public Suits Suit { get; set; }
public Values Value { get; set; }
public override string ToString()
{
return $"{Value} of {Suit}";
}

public PokerCard(Suits suit, Values value)
{
this.Suit = suit;
this.Value = value;
}
}


PokerPlayer


  • Конструктор принимает byte id но класс имеет собственность int ID. Выбрать тип и придерживаться его. Я предлагаю int как byte не все, что обычно используется в тех случаях, когда вы не обработки двоичных данных.

  • Мне понадобилось несколько минут, чтобы выяснить, что public enum Poss { sb, bb, btn, mid} был. Не использовать (нестандартный) аббревиатуры как определения типа. public enum Position { SmallBlind, BigBlind, DealerButton, None} было бы гораздо яснее. Некоторые замечания:


    • Position имеет один s, так Poss не интуитивное имя.

    • Poss Pos вы используете две разные сокращения одного и того же слова. Я предлагаю вам избежать этого. Будьте последовательны.

    • Я до сих пор не уверен, что mid имеет в виду. Я предполагаю, что это означает "ни один из других вариантов".


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


    • Назначение кнопки дилера должно произойти в PokerTable уровне, не PokerPlayer уровне. Представьте, если один игрок может играть на двух столах одновременно. Просто потому, что он был дилером за одним столом не значит, что он у дилера на другой стол.

    • Подобный аргумент может быть сделано по поводу чипов. Игрок с 1000 фишек в руке может выбрать только место 250 фишек по определенным покерным столом. Однако, я собираюсь предположить, что это просто выходит за рамки текущего приложения. Во всем, я думаю, что это было бы хорошее упражнение для вас, чтобы узнать, как отдельных данных, которые принадлежат игроку, и данных, относящихся к таблице.


  • Count чаще всего относится к количеству элементов в списке. ChipCount предполагает, что у вас есть список Chip класс объектов. Я бы переименовал это либо Chips или ChipsAmount.

  • Вы можете, услуги конструкторов, которые бы упростить код конструктора немного.

Я сделал новую главу о Poss и BettingOrder потому что изменения слишком большие, чтобы резюмировать здесь. Единственное, что может послужить примером являются прикован конструктора:

    public PokerPlayer (int id)
{
ID = id;
}
public PokerPlayer(int id, string name) : this(id)
{
Name = name;
}
public PokerPlayer(int id, string name, int chipCount) : this(id, name)
{
ChipCount = chipCount;
}

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

var player1 = new PokerPlayer() { Name = "Inky" };
var player2 = new PokerPlayer() { Name = "Pinky", ID = 5 };
var player3 = new PokerPlayer() { Name = "Blinky", ChipCount = 500 };
var player4 = new PokerPlayer() { Name = "Clyde", ID = 5, ChipCount = 1500 };


PlayerPosition, BettingOrder, и учета данных, легкий для поддержания

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

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

Вы пропустили достаточно важные правила эффективного управления данными:

Расчетные значения должны быть вычислены на лету, не назначены вручную и менялись при необходимости.

Дело в том, что вы когда-нибудь следовать этому правилу, когда вы рассчитали карту по масти и значения на основе его ID. Вместо того чтобы задавать идентификатор, в костюме и (карты)стоимость ценностей; установить один из них и позволить другим быть рассчитана оттуда.

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

Если у вас есть упорядоченный список игроков, и была назначена для одного игрока в качестве дилера, Вы можете рассчитывать на все остальное:

//Manually set
List<PokerPlayer> Players { get; set; }

int CurrentDealerIndex { get; set; }

//Calculated - but can be used to set the index by passing a PokerPlayer
PokerPlayer CurrentDealer
{
get { return Players[CurrentDealerIndex]; }
set { CurrentDealerIndex = Players.IndexOf(value); }
}

Все остальное можно вычислить из этих данных:


  • Малый блайнд игрок индекса = CurrentDealerIndex + 1;

  • Большой блайнд игрок индекса = CurrentDealerIndex + 2;

  • Ставки того, можно ознакомиться, начиная с малого блайнда, игрок, и движутся через список игроков (для того, циклически), пока вы не раз проверено каждого игрока.

Примечание: Вы собираетесь использовать % (по модулю) оператор при расчете индексов в списке. Я опустил вычисления по модулю для объяснения, чтобы сохранить намерение легко понять.

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


PokerTable


  • Сохранить свои свойства в том же месте. Мне потребовалось некоторое время, чтобы найти List<PokerPlayer> PokerPlayers потому что вы положили между некоторые методы.

  • Я не совсем согласен с Streets перечисление. В этом нет необходимости.

  • Я согласен с разными методами, хотя я бы слегка переименовать их: DealHoleCards(), DealFlop(), DealTurn(), DealRiver().

  • throw new ArgumentOutOfRangeException("wrong street"); это некрасиво. Эти факторы (на мой взгляд ненужных) улица перечисление. Когда вы называете Flop() метод, вы должны уже знать , что это время, чтобы играть на префлопе! Это исключение будет выдано, если Вы играли флоп, когда вы не должны быть, что не должно когда-либо произойти в первую очередь. Ваш игровой логики должен знать, на какой улице он должен играть, а не просто сделать предположение.


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


  • Метод, который раздает карты не должны также обрабатывать раунде.


    • Вы, возможно, пропустили это, потому что у тебя нет раундов еще. Ты просто добавив произвольную сумму в банк.


  • Тасования колоды не относятся к таблице. Я предлагаю сделать посредника Deck класс, который держит все карты. Таким образом, вы инкапсулировать карта чертежей/тасу код в отдельный класс, таким образом, позволяя PokerTable класс, чтобы сосредоточиться исключительно на таблицы, связанные с логикой.

  • Если вы создаете DoBettingRound() метода, то можно определить одиночной игре как последовательность упомянутых методов. Это делает код легко читаемым.

В качестве простого примера:

public void PlayGame()
{
this.Deck = new Deck(); //shuffled during initialization

DealHoleCards();
DoBettingRound();

DealFlop();
DoBettingRound();

DealTurn();
DoBettingRound();

DealRiver();
DoBettingRound();

Showdown();
}

Обратите внимание, что это упрощенный пример. Вы хотите, чтобы на самом деле использовать здесь параметры метода, как первый раунд торговли (префлоп) начинается с другому игроку (большой блайнд + 1) по сравнению с другими раундов торговли (которое начнется с малого блайнда, игрок).
Я предлагаю сделать Способ public void PlayGame(PokerPlayer currentDealer) а затем расчета других игроков исходя из текущего дилера.

7
ответ дан 19 марта 2018 в 01:03 Источник Поделиться

Я написал полную версию этого в C# для запуска многостоловые турниры, подгоняя игроков и столов, как игроки выбывают и т. д.
(Я сделал это, чтобы проверить некоторые стратегии для разных слепых/временных структур).

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

Поэтому, чтобы помочь с этим я предлагаю следующее начало:


  • Создать классы для все, что вы можете и использовать их как отдельные
    объекты в реальном мире сценариев, только выполняя свои
    функциональность (соц).

  • Создать класс карта, которая будет содержать значение, костюм и описание
    карты (11, "ч", "Джх").

  • Создать класс колода, который будет содержать карты (у вас может быть вариант
    позже, что есть разные карты).

  • Генерировать все 52 карты и положить их в колоду. (Множественные таблицы
    требуется несколько колод).

  • Создать перетасуйте обычную колоду. Называют его в начале каждого
    руку.

  • Создаем дилерскую класс, который будет проводить колоды и раздачи карт (по
    крайней мере).

  • Создать класс Player, который имеет имя и CurrentChips

  • Создать класс горшок - будет несколько горшков, так что вам нужно массив
    из них трек, который игрок имеет право на какой горшок. Добавить к
    Горшок, возьмите из горшка по мере необходимости.

  • Создать место, которое будет держать игрока, положение (СБ, ББ, БТН),
    текущей ставке, и чипсы.

  • Создать таблицу, которая имеет множество мест (2 - 10), колода, доска
    Карт, массив горшок, БТН, СБ и ББ положения (вращающийся вокруг
    Мест), текущие блайнды, текущие ставки/рейза, подсаживать к закону и т. д.

  • Добавить игрока на место. Предположим, все фишки игрока
    поставить на стол (если в кэш-игре, то брать фишки у игрока и
    добавить их место).

  • Интернет-карты для сидений.

  • Переместите жалюзи вокруг мест в таблице и получите ставки от
    независимо от места в жалюзи.

  • Когда есть ставки, поставить ставку в банк и снять эту сумму с
    сиденье.

  • Когда рука занимает место, добавить фишки действующим горшки к
    Чипы сиденья.

  • Когда игрок перемещается из одной таблицы в другую, берем опилки из
    сиденья, добавить их обратно в фишки игрока, удалить игрока из
    сиденье. Теперь, когда место вакантно, другой игрок может просто поп и падение их фишки на место и продолжить. (В
    Дилер или стол не волнует, кто за столом, просто фишки из
    Сиденья).

Без классы за все, что вы можете думать, там будет бардак логики пытаюсь отслеживать, что происходит на столе. Таким образом, вы можете сохранить логику сводится к каждому классу, где они не волнует то, что происходит, они просто делают свое - чуть-и просто.

Я надеюсь, что это помогает, и удачи с проектом.

Редактировать


Я думаю, что это имеет большую часть этого материала.

Это может сделать, но это все в большой кусок кода. Вам нужно разбить его на составные части.

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

В настоящее время у вас есть только два класса, чтобы хранить все, что происходит в покер.
И есть много больше, чтобы пойти; сравнение руки победителей, мультипотах, ББ/СБ без руки, побег, слепой изменения структуры, статуса турнира и т. д.

В PokerPlayer У вас есть:


  • Position (Poss) (должно быть по TableSeat объекта)

  • ChipCount (должны быть Playerс фишками в кармане, но не
    фишки у них на Table для Hand. Вы не можете взять
    фишки из своего кармана за ставку...)

  • Cards (должно быть в Hand на Seat. Это будет включать в себя
    PlayerС карты добавлены карты)

  • BettingOrder (должно быть прослежено на Table по Seat)

  • Перечислимый (Position) в каждом Player (должны быть глобальными).
    Там может быть до 10 позиций, поэтому выбрав один из четырех будет предела
    обработка букмекерской. Затем используйте Positionна Seats,
    не PlayerС

  • А Player является частью Tableони сидят на Seatи Seat
    является частью Table

В PokerTable у вас есть:


  • Перечислимый (Streets) в каждом Table (должны быть глобальными)

  • DealerName (Players не дилеры, дилер присоединится к Tableдля
    интернет, и Баттон дилера перемещается по таблице, чтобы указать, что
    Seat является последним)

  • Shuffle (шарканье-это функция Deckдолжна быть на
    Deck объект, или лучше все-таки отдельную функцию, которая принимает
    Deck и возвращает его тасуется)

  • Flop, Turn, River (при работе с Card, "удалить" его из
    Deck. Не только инкремент счетчика; Если вы пропустите шаг, или
    инкремент слишком много раз, вы будете иметь неожиданные результаты).

Вы должны думать о все эти вещи, как объекты реального мира, чтобы разбить их на составные элементы и функциональные возможности (соц - разделение, СРП - единая ответственность Принципала).

Такой мысли:


  • Игрок может перемещаться от стола к столу

  • Колоду карт можно выбросить и использовать другой

  • Колода тасуется, ничего тасует колоду

  • Игрок не перемещает позицию за столом

  • Кнопка дилера движется вокруг места на столе

Приведет вас к созданию класса для каждого "вещь" нужно работать.

Пример:

Создать Table что есть:


  • Коллекция Seats

  • Коллекция Pots

  • А Deck

  • А Board

  • Для отслеживания текущей ставки/рейза

  • Слежения за текущим Seat сделать ставку

  • Слежения за текущим Seatвсе еще в руке

И разорвать эти вниз:


  • А Seat имеет статус; оккупированных, из рук, фишки, оставшиеся, текущая
    ставки и т. д.

  • А Deck есть Cardы, которые могут быть перетасованы, и только CardС
    остальные, которые не были рассмотрены еще

  • А Shuffle процедуру, которая принимает Deck и возвращает его тасуется

4
ответ дан 19 марта 2018 в 04:03 Источник Поделиться

Код не тест на количество игроков. Нужно иметь как минимум 2 игроков. Стандартная таблица ограничено до 10 игроков. Колода будет поддерживать 23 игроков.

Фиксированные жалюзи 1 и 2, то будет сложно перейти на турнир, где блайнды растут. Нет места также мог бы сделать перемещение таблиц и объединение таблиц сложнее. В настоящее время турнирная таблица выходит за рамки.

Нет теста, что имена игроков уникальны.

0
ответ дан 19 марта 2018 в 05:03 Источник Поделиться

Вы действительно не нужно shuffle метод. Вы можете просто deck объект draw метод, который случайным образом выбирает карту из колоды. Всякий раз, когда вам нужна карта, draw карту из deckи часть draw метод удалив соответствующие карты от deck. Если у вас есть восемь игроков, вам необходимо нарисовать 21 карт. Я полагаю, что концептуально это хорошо "перемешать" в 21 карты необходимо, прежде чем рассматривать любой из, а также другие 31 карт в "случайном порядке", но я лично не вижу особой ценности в этом всем, что только для того, чтобы подражать более внимательно, как "реальный мир" покер реализуется.

Вы, кажется, используете bb для установки и ценности. Вы должны различать два, например bb_player против bb_size. Линии Pot = sb + bb - это очень странно. Видимо ты инициализации горшок с жалюзи, но вы снимаете жалюзи из стека кто-нибудь чип? Вы должны иметь способ ставки, и "силы" двух слепых игроков для вызова этого метода. Кроме того, названный метод "перемешивания", который делает кучу вещей, иных, чем тасу, таких как инициализация горшок, плохо именования.

Я думаю, что ставки-порядок должен быть атрибутом стола, а не игроки. Там нет необходимости для игрока объект, чтобы знать, что его ставки порядок; если игрок хочет таким видом информации, вы можете просто передать им всю таблицу конфигурации (то есть, я вижу игрока, спрашивая: "что букмекерская порядок", но я не вижу игрока просят просто "то, что мои ставки заказом?"). На столе должно быть слепым методом, который регулирует тоталы чип на ББ и СБ, и он должен иметь метод, который просит игрок, чтобы действовать. Оба этих методов должны знать, что приказ Ставки, и говорить игрокам, когда придет их черед действовать. Если объекты игрок знает, кто сидит слева и справа, то вы можете просто в таблице попросить игрока действовать, а потом спрашивать на следующий игрок и т. д. Вместо того, чтобы делать btn++вы можете сделать button_player = button_player.leftи тогда вам не придется делать if(btn == PokerPlayers.Count){btn = 0;}. Под капотом, это сложнее, но концептуально это проще; кнопка просто передвигается влево. Другие вещи, такие как пари может двигаться подобным образом.

Добавление 2*УНТ в ряд и затем с результатом мод УНТ-это немного странная; (x+k*y) % y должны дать х для каждого K.

-2
ответ дан 19 марта 2018 в 08:03 Источник Поделиться