1

我正在写一个扑克手的 HandConverter。这是我的第一个项目,我试图从一开始就做。

我已经掌握了大部分内容,例如玩家名单、他们的位置、筹码量、不同棋盘的牌、正在玩什么游戏等等,但我在下注的表现形式上遇到了困难,尤其是不同的加注、下注和倍数来自同一玩家的电话。

我发现了一些我基于案例的天真解决方案不起作用的情况,而且它真的很复杂,我不喜欢它。由于它目前适用于 NL 德州扑克,我认为如果我想实现像 Stud、Razz 等游戏,尽管下注结构可能相同,我会有更多的变通方法要做。

现在我使用这种表示,我想特别改进RoundAction类。你对我有什么建议吗?

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;
}

PS我也使用一个列表来存储不同的回合,有没有更好的方法比如继承翻牌、转牌和河牌的回合类?

4

6 回答 6

2

您可以使用枚举来代替 Action.Type 的字符串:

enum BettingAction
{
   Check,
   Bet,
   Call,
   Raise,
   Fold
}
于 2009-11-18T18:31:17.460 回答
1

当您说第一个项目时,您是什么意思?我猜你是学生或编程新手。

在这种假设下,我建议选择比扑克牌历史更简单的东西。就像在游戏编程中一样,在您编写游戏的第一枪就考虑创建最新的《使命召唤》是不合理的。你从突破开始,然后从那里向上移动。

如果您不希望开始时比我建议的更小,请不要跳入编码。当你这样做时,你会花更多的时间只是转动你的轮子,而不是完成一些事情。

例如,您应该首先花时间设计您的程序可以做什么和不可以做什么。尽量做到完整。这可以通过使用 UML 程序或简单的笔和纸来完成。

我会流出来你想要一只手如何进步。您要跟踪的信息。一旦你真正理解了这一点,你的数据结构就会开始变得生动起来。

由于您是编程新手,我将开始编写概念验证代码。然后将其移至您的最终项目。我所说的概念证明的意思是代码,你只是在测试一个想法,看看它是如何工作的。例如,手牌历史如何运作?您可以创建一些“模拟”历史并进行设置吗?理想情况下,您会进行单元测试,但让我们从小一点开始。

重要的是要知道您正在构建一个程序,就像一所房子一样。你需要知道你想让它做什么和不做什么(蓝图)。每一步是什么。你慢慢地建立在其他部分上。这是一个需要时间的过程,但最终是值得的。

于 2009-11-18T18:32:27.257 回答
0

卡片可以有一个更好的名字,但我假设你的意思是公共卡片。我会把它做成一张牌列表,然后转牌和河牌的子类只会在列表中出现一张牌。我还建议以对您有意义的方式表示卡片,然后在您需要与库交互时进行转换。

于 2009-11-18T18:33:40.827 回答
0

不是真正与编程相关的答案;但 Razz 或 Stud 的投注风格在几个方面与 Hold 'em 不同。

1.) 没有百叶窗;而不是 antes
2.) 开局的人可以带入或完成下注
3.) 下注轮数更多

你有一个很好的开始。您可能想要创建一个List<Hands>其中包含的List<Rounds>内容。否则,您将拥有大量回合列表,而无法判断一只手何时开始/结束以及另一手何时开始。

我认为您可能需要定义您的操作类型,然后事情可能会开始到位。这是我对类型的要求:

过牌
下注
弃牌跟注
加注
(本质上是跟注和下注)

可能还想考虑在您的动作类上实现诸如“优先动作”之类的东西;因为每个玩家都在对他们面前的动作做出反应。

您还想解决游戏的一些细微差别;其中玩家 a 下注 500,玩家 b 全押 250;因为除了在这种情况下,跟注需要与之前的赌注相匹配。

于 2009-11-18T18:35:41.947 回答
0

回合这个词有点含糊。BettingRound 使它更加明显。我认为这里不需要卡片、姓名和罐子大小。Potsize 是整个下注回合中的动作和变化的函数。席位比玩家列表更能代表游戏,因为这使您可以更明显地代表游戏状态(筹码量等)。我不认为有必要在翻牌圈、河牌圈明确分配给回合的牌——只需使用一张牌列表和一些惯例。例如,前三张牌 = 翻牌……第一轮下注 = 翻牌。使用一些扩展方法,以便于参考翻牌获得德州扑克。当你需要使用它时,通过转换使用 ulong 版本的卡片,而不是弄乱你的域模型。

这就是我如何看待特定个人游戏的模型(即 1 次翻牌、河牌、转牌等)。为所有游戏建模仍有大量工作要做(例如限注游戏使用小注/大注而不是盲注来定义赌注)。

public class Card { public Suit Suit; 公共等级等级;公共 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 { }
于 2009-11-28T17:24:52.653 回答
0

而不是将 Round 子类化为 FlopRound TurnRound 等,我会在 round 内以及 Action 内使用 Street 属性。

静态公共枚举街 {PREFLOP, FLOP, TURN, RIVER};

...

于 2009-12-16T12:50:19.463 回答