首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >扑克经销商抱着他们

扑克经销商抱着他们
EN

Code Review用户
提问于 2018-03-19 00:28:52
回答 6查看 2.5K关注 0票数 10

这表示德州持有它们的表(服务器)。

这不是一个完全保持他们的游戏,但它是工作的代码,它所做的。它洗牌,处理孔牌,交易棋盘,移动百叶窗,收集百叶窗。它还不支持真正的赌博,也不奖励大麻。它只是装了个罐子。真正的赌博变得很复杂。在某一时刻,我希望能进行一次审查。

在扑克,按钮移动到经销商的右边,即玩家左边(+1) (顺时针方向)。在第一轮,有一个随机抽签按钮。有4轮投注/交易。那个小瞎子的按钮(+1)的左边有一个强迫的某人下注。某人左边的大瞎子被迫押注BB (通常是SB的2倍)。之后的BB是第一个行动在第一轮投注。在第一次押注某人之后,首先采取行动。在第一条街(预),每个玩家得到两张洞牌。在第二条街(失败),董事会得到三张卡片。转一圈,冲浪板再得到一张牌。我知道这听起来很复杂,但这就是它的工作原理。

在提个醒(两名球员),它变得混乱,因为经销商也是SB。这还不涉及提防问题。

桌子上有座位。此代码不使用座椅。按顺序排列的球员名单是座位。此代码将按钮直接移动到播放机,并将投注顺序直接分配给播放机。

这个代码里没有毒贩。表执行经销商的操作。

这使用了一个标准的52牌扑克牌,没有任何意图支持另一套。

这不会烧掉对游戏没有影响的牌。

不打算成为游戏级别的服务器,在那里钱是交换的。只是举办一些简单的家庭游戏。

代码语言:javascript
复制
public static void PokerPlayerTest()
{
    PokerTable pt = new PokerTable("Hook", new List { 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("");               
    }
}
代码语言:javascript
复制
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;
    }
}
代码语言:javascript
复制
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;
    }
}
代码语言:javascript
复制
public class PokerTable
{
    //pot and betting not yet implemented 
    //current PokerTable just deals
    Random rand = new Random();
    List deck = new List();
    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 Board { get; } = new List();
    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 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 pokerPlayers)
    {
        DealerName = dealerName;
        PokerPlayers = pokerPlayers;
        for(byte b = 0; b < 52; b++)
        {
            deck.Add(new PokerCard(b));
        }
    }
}

得到一些关于短枚举的(贬损)评论。当你为屏幕空间而战时,它们是很好的。扑克有一些标准的缩写。客户端可以自由地使用他们想要的任何文本或图像(并且应该使用)。

Can忽略这个,这是用于面向服务的体系结构(SAO)的。如果加上这一点,可能会使现有的答案失效,这是不公平的。

EN

回答 6

Code Review用户

回答已采纳

发布于 2018-03-19 09:41:46

我将对downrep_nation的第二个评论:sbbbrivr等是枚举元素(和成员)的糟糕名称。我更喜欢smallBlind bigBlindbuttonbtn看起来像过去的控件。我一直为类型使用首字母,但从未用于域概念,从river中删除“e”有什么好处呢?

这也是一个糟糕的标识符:PossPokerTable.Trun有拼写错误。

说到Trun,你为什么不使用你的Streets枚举?

代码语言:javascript
复制
if (street != 1)
{
    throw new ArgumentOutOfRangeException("wrong street");
}
street++

可能是

代码语言:javascript
复制
if (street != Street.Flop)
{
    throw new ArgumentOutOfRangeException("Wrong street: expected Flop, but received " + street.ToString());
}
street = Street.Turn;

这比依赖于枚举命令的细节要清晰得多(这一点根本没有文档记录)。当然,这取决于street是一个Streets,而不是byte,这一点也要清楚得多。

SetBettingOrder中:

代码语言:javascript
复制
int offset = street == Steets.Pre ? 3 : 1;

在您的代码中有大量的“添加一个可能的重置”,这严重破坏了逻辑,只是在maintaince期间需要担心更多的事情:

代码语言:javascript
复制
int tpos = btn + 1;
if(tpos == PokerPlayers.Count)
{
    tpos = 0;
}

tpos = (tpos + 1) % PokerPlayers.Count是一种更短的方法,但考虑到您经常需要它,我肯定会使它成为自己的功能:

代码语言:javascript
复制
private int NextPlayerIndex(int playerIndex)
{
    return (playerIndex + 1) % PokerPlayers.Count;
}

你也有很多建筑工人..。这句话毫无意义:

代码语言:javascript
复制
public PokerPlayer(string name){
    ID = 0;
    Name = name;
}

在哪个世界里,不需要指定ID是一件好事?这只是乞求被滥用。

考虑到您的构造函数中没有逻辑,我还希望看到一个'base‘构造函数,其他构造函数(老实说,我只会删除一个)调用它,而不是每个构造函数都维护自己的默认列表:

代码语言:javascript
复制
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有点奇怪,因为它有一个常见且不寻常的缺省值,但我假设这是调试的遗物,而不是在生产代码中出现的东西:如果出现了这样一个神奇的数字,那么它应该是一个常数,您可以在构造函数中引用它。

代码语言:javascript
复制
`const int DefaultChipCount = 200`

或者,您可以使用一个可选的参数,并在失去一些灵活性的情况下放弃所有可怕的东西。

代码语言:javascript
复制
public PokerPlayer(byte id, string name, int chipCount = DefaultChipCount)

这意味着您不能在当前位置设置id的默认设置,但是如果它非常不重要,可能会有一个默认值,那么它就不是第一个参数。

同样,正如downrep_nation所说,对于某些方法所做的事情有很多困惑。尤其是洗牌数组(如在Shuffle中执行的)与Poker无关,我将实现这个完全独立的类,因为它本质上是一个通用的通用操作。事实上,我从//fisher yates shuffle评论的立场可以猜到,Shuffle最初只是想洗牌,但后来又被其他职责夸大了。

我将在一个稍微不同的方向上听取downrep_nation关于此代码的建议:

代码语言:javascript
复制
pp.HoleCards[0] = deck[cardNum];
cardNum++;

这应该被推到TakeCard() => cardNum++;方法中。然后,组装社区卡将给您提供以下内容,我认为它比downrep_nation的LINQ更具表现力:

代码语言:javascript
复制
for (int i = 0; i < magicNumber; i++)
    Board.Add(TakeCard);

这里的pokerPlayers参数有点吓人,因为您不知道它是从哪里来的,然后继续将它用于状态:

代码语言:javascript
复制
PokerTable(string dealerName, List pokerPlayers)

我会让它(和属性,特别是因为它是公共的)一个IReadOnlyList,并克隆它,只是为了确定。您不希望创建PokerTable的代码单方面更改此列表。

还有一些无聊的事情:

  • 只是个人偏好而已,但我会用空行填充您的代码,以将其拆分为一个但是。导航“分段”代码要容易得多:这也是我们在CR答案中使用项目点和水平规则的原因。
  • 我不太喜欢用枚举来命名东西:suitrank都是公共的,尽管在PokerCard之外是无用的,并且有一些看起来很私密的名字,也没有提供任何保护来防止“越界”查找。PokerCard看起来是一个拥有一些Debug.Assert语句的好地方,因此如果它提供了一个无效的id,它就可以立即抛出,给您一个有价值的调用堆栈,并提供一些文档。
  • 我还指定了所有成员的可见性(例如PokerCard.id):但显然这不是一个大问题(除非您正在与来自C++的人合作-可能/任何其他语言具有不同的默认值)
  • 我倾向于在Poss Pos中删除PokerPlayer,并在需要时只计算它,除非PokerPlayer类有充分的理由需要知道它的位置。
  • 我确信它们只是用于调试,但是ToString()方法没有多大意义。PokerPlayer可以在调用ToString()时返回一些未初始化的状态(Pos将是默认值)。
  • PokerTable中,DealerNamePokerPlayers定义在下面一些方法中,这会使寻找它们的人感到困惑。
  • 没有什么能阻止玩家进行负筹码计数(这是你注意到的只有玩家而不是座位的一部分,所以你不能驱逐资金耗尽的玩家)。
票数 7
EN

Code Review用户

发布于 2018-03-19 06:24:35

总的来说,代码似乎没问题。

但是有一些事情需要考虑,这与更干净的代码和坚实的原则有关。

首先,您的变量名称是混乱的,而不是指示性的。

代码语言:javascript
复制
sb, bb, btn, cardNum

对我来说没有任何意义,也许它们是扑克术语,但我不是扑克玩家,我是一个开发人员,我正在阅读您的代码。

与id存在一次是不一致的

代码语言:javascript
复制
ID and id

选择一种套管风格,并与之保持一致。

代码语言:javascript
复制
public Suits Suit { get { return (Suits)(id/13); } }

这可以写成

代码语言:javascript
复制
public Suits Suit => (Suits)(id/13);

这只是语法上的糖,只适用于成员,但不是必须的,而必须的是命名您的神奇数字。

我不知道13应该代表什么,考虑创建一个常量来存储这个值以便更好地理解,这会在代码中重复出现。

PokerPlayer类中,考虑使用函数参数的默认参数来删除某些代码重复。

另一点是坚实的原则,特别是SRP (单一责任)。

通过将图形逻辑和业务逻辑结合起来,您的函数破坏了SRP,这意味着函数应该或聚合不同的抽象来定义逻辑,或者负责使用代码及其底层数据结构进行低级工作。

此外,SRP通过实现低级别数组改组和处理抽象(如Shuffle() ),使函数更具有指示性和可测试性,是一个很好的例子。

尝试将这些函数划分为逻辑组件,并为它们编写测试。

Flop()中,您可以编写Pot *= 2来指示锅的加倍(吹毛求疵)

另外,可以用更容易阅读的Linq来代替它。

代码语言:javascript
复制
Board.Add(deck[cardNum]);
cardNum++;
Board.Add(deck[cardNum]);
cardNum++;
Board.Add(deck[cardNum]);
cardNum++;

代写

代码语言:javascript
复制
Board.AddRange(deck.Skip(cardNum).Take(magicNumber));
cardNum+=magicNumber;
票数 10
EN

Code Review用户

发布于 2018-03-19 13:07:28

票数 7
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/189899

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档