3

编辑似乎我对游戏实际运作方式得到了不同的反应,并且在阅读了官方规则并与众多扑克伙伴交谈后,我想我自己也不知道规则。任何澄清将不胜感激。

我正在使用 MSVC++ 2010 Express 开发一个小型扑克游戏,并且一直在尝试想出一种方法来编写子底池系统。出于某种原因,我无法理解它应该如何工作,并且想知道 SO 是否可以发布一些方法来解决它。这是一种特殊情况,在德州扑克游戏中很可能会发生。

情况:

玩家 A 有 50 美元的筹码首先行动并决定全押。玩家 B 加注到 150 美元。玩家 C 只有价值 70 美元的筹码并决定全押。玩家 D 只有 20 美元并全押。现在,我如何设计一个子底池机制来跟踪所有这些。

据我了解,会发生什么:

玩家 A 用 50 美元创造主底池。你把 B 和 C 的 50 美元加起来,使主底池变成 150 美元。然后,您将玩家 B 剩余的 100 美元分成 80 美元和 20 美元。然后你为玩家 B 和 C 做一个价值 40 美元的子底池(玩家 C 从 70 美元中剩下的),然后你将玩家 B 的 80 美元返还给玩家 B,因为没有人可以覆盖它。玩家 D 的 20 美元赌注进入玩家 B,Cs 的 40 美元子底池现在价值 60 美元。* (或者这不会被添加?它不会被添加到任何投注中,因为它无法覆盖 50 美元的主底池,如果是这样,那么它们不会被添加到任何投注中*

现在,当它下降到评估时。如果玩家 A 赢了,他从玩家 A、B 和 C 那里赢得了 150 美元。接下来,玩家 B、C 和 D 用他们价值 60 美元的子底池继续比赛。

如果玩家 B 赢了,他就赢了一切。

如果玩家 C 赢了,他从玩家 A、B 和 C 那里赢得 150 美元。然后他向玩家 B 和 D 挑战 60 美元。

玩家 D 只能赢得 60 美元,而当玩家 A、B 和 C 的底池跌到这么远时,已经有人赢得了玩家 A、B 和 C 的底池。(取决于这是否被添加到 B 和 C 的底池中,因为它不包括主要的 50 美元下注)

一切都应该这样吗?我很难弄清楚如何跟踪每个赌注和子底池。任何想法或实现它的合乎逻辑的方法都会有很大帮助。感谢您的时间。:-)

我在考虑让每个赌注都成为一个唯一的 id,或者每轮都有一个 id,并将每个赌注添加到要评估的数组中,该数组也指向包含玩家信息的容器。我还必须考虑到一些玩家可能在子底池中并且已经在手牌并且弃牌,这意味着我也必须跟踪这一点。

4

4 回答 4

3

在这个例子中,主锅和副锅都计算错了。

规则:规则原则是每个玩家匹配对手的赌注,因为他在他的筹码中剩余的赌注。

计算:

1) 首先,我们考虑筹码最少的玩家(全押)。在当前示例中,这是玩家 D 拥有 20 美元。

2) 接下来我们从每个玩家 (A,B,C,D) 中总结出 20 美元,主底池形成等于 80 美元,由所有玩家争夺。

3) 玩家剩余筹码 A – $30, B – $130, C – $50, D – $0

4) 接下来我们考虑第二小的筹码,在当前示例中,玩家 A 还剩 30 美元。边池 1 的形成等于 $30(A) + $30(B) +$30(C)= $90。玩家 D 无法赢得这个边池,因为他的钱用完了。

5) 玩家剩余筹码 A – $0, B – $100, C – $20

6) 边池 2 的形成等于 $20(B) + $20(C)= $40。玩家 A 无法赢得这个边池,因为他的钱用完了。

7) 玩家 B 还剩 80 美元,这笔钱退还给他。

所以我们最终得到:

主底池 = 80 美元,由所有玩家 A、B、C、D 争夺

Side pot1 = $90,由 A,B,C 争夺

Side pot2 = $40,由 B,C 争夺

80 美元返还给玩家 B

于 2012-09-27T15:55:12.597 回答
0

你的例子自己说话。在第一次下注或每次下注与初始下注不同时都会创建一个子彩池。有一些属性:

  • 一个赌注是一个单独的子底池
  • 如果新的金额不同,现有的底池应该可以拆分
  • 相同数量的罐子可以合并

所以对于 Subpot 类的想法:

  • 一个子彩池由一个独特的金额和几个玩家组成
  • 一个赌注是一个单独的子底池
  • 两个相同数量(金钱)的子罐可以合并形成一个新的子罐(如套)
  • 一个 subpot 可以拆分为两个 supbot,其中amount = amount1 + amount2;
  • 每次添加新赌注时,首先按差额平分,然后合并相同数量的底池。IE

    //laughable attempt
    class Subpot{
      int amount; //oops i mean bet
      int pot; //actually function = amount x participants
      std::vector<Players*> participants;
    
      bool split(int amounta, int amountb, Subpot& a, Subpot& b);
      static bool merge(Subpot& a, Subpot& b , Subpot& dest);
    }
    

现在每次有新手牌时,您都会使用之前稳定的一组子池,然后创建下一代子池

  • 创建子锅手
  • 添加到子锅的集合(什么集合?见下文)
  • 拿下注较小的那个
  • 拆分所有存在于大小 betSmall 的底池中,并下注 - betSmall
  • 合并大小为 betSmall 的
  • 如果我没记错的话,你现在有一套稳定的 subPot
于 2012-09-27T08:00:25.010 回答
0

我这样做的方法是制作一个单独的容器来保存下注,跟踪谁下注和下注多少。

std::list<std::map<PlayerID, Chips>> wagers;
unsigned n_raises;  // to keep track of number of raises, useful in limit holdem

我假设您有一手活跃玩家的列表/数组。

现在,如果玩家打电话,您只需将他的 ID 和筹码数量插入列表后面的地图中。

如果玩家加注,您在列表后面的地图中插入一个 ID 和匹配的筹码数量,然后推回另一张地图。您在这个新的背面插入筹集的金额。n_raises并相应地更新to_call

插入玩家的赌注时,您需要从列表的开头进行迭代,并在您第一次遇到该玩家没有筹码的地图时开始插入。前面可能有多次加注,所以你显然不能总是只插入最后一张地图。

棘手的情况是玩家没有足够的筹码来支付完整的跟注。在这种情况下,您会找到他用完筹码的地图,在其后插入一张新地图,然后转移玩家在此新地图中无法覆盖的所有筹码(其他玩家的)。(在这种情况下我们不更新n_raises)。

以下是 4 个玩家 A、B、C、D 的样子:

Player A bet 100

    map0:  (A,100)    

Player B calls:

    map0: (A, 100) (B,100)

Player C raises to 300:

    map0: (A, 100) (B,100) (C,100)
    map1: (C, 200)

Player D calls:

    map0: (A, 100) (B,100) (C,100) (D,100)
    map1: (C, 200) (D,200)

Player A's turn, he folds.
Player B calls, but he's got only 50 left:

    map0: (A, 100) (B,100) (C,100) D(100): 
    map1: (B, 50) (C, 50) (D,50)           <--- here we have split the map in two   
    map2: (C, 150) (D, 150)

The betting round is over.

您可以为每一轮下注设置一个单独的列表,或者只有一个并保留一个迭代器的副本以开始新一轮。

现在很容易分锅。您确定最好的手,然后开始弹出列表前面的地图,同时拥有最好的手的玩家参与地图。如果在那之后列表是空的,你就完成了。否则,确定第二好的手并重复。

在上面的例子中,如果玩家 B 最终拿到最好的牌,你推给他 map0 和 map1。map2 将分配给 C 和 D 的获胜者。

让我们试试你的例子:

玩家 A 有 50 美元的筹码首先行动并决定全押。玩家 B 加注到 150 美元。玩家 C 只有价值 70 美元的筹码并决定全押。玩家 D 只有 20 美元并全押。

map0: (A,50)
---------------------
map0: (A,50) (B,50)
map1: (B,100)
---------------------
map0: (A,50) (B,50) (C, 50)
map1: (B,20) (C,20)
map2: (B,80)
--------------------
map0: (A,20) (B,20) (C,20) (D,20)
map1: (A,30) (B,30) (C,30)
map2: (B,20) (C,20)
map3: (B,80)

我认为这与我们在实际扑克桌上的操作方式非常相似,如果我要编写扑克游戏,我可能会采用这种方式。希望能帮助到你 :)

于 2012-09-27T10:11:45.487 回答
0

抱歉发布了 necro,但我用 C# 写了一个解决锅分发的方法: https ://dotnetfiddle.net/P0wgR5

这种算法的好处是,在支付时,您​​只需要每个玩家的三条信息。他们投入底池的筹码数量、牌力以及是否弃牌。这不是立即直观的,因为这不是庄家处理边池的方式,但它会正确拆分底池,丢弃任何拆分的筹码(例如:100 分三路输掉一个筹码)。

这是我在 C# 中为拆分罐而编写的代码:

using System;
using System.Collections.Generic;

public class Player
{
    public ulong potCommitment;
    public uint handStrength;
    public ulong chipsRemaining;
    public bool folded = false;
    public Player(ulong pc, uint hs, ulong chipsBehind, bool isFolded): this(pc, hs, chipsBehind)
    {
        folded = isFolded;
    }

    public Player(ulong pc, uint hs, ulong chipsBehind)
    {
        potCommitment = pc;
        handStrength = hs;
        chipsRemaining = chipsBehind;
    }
}

public class Program
{
    public static List<Player> winners = new List<Player>();
    public static List<Player> players = new List<Player>();
    public static void Main()
    {
        players.Add(new Player(50, 100, 0));
        players.Add(new Player(150, 80, 0));
        players.Add(new Player(70, 100, 0));
        players.Add(new Player(20, 150, 0));
        
        // Loop through players until no unclaimed chips in pot.
        while (PotChipsRemaining(players) > 0)
            PayOutWinners(CalculateAndSortWinners(players), players);

        // Refund folded players if remaining chips in pot
        foreach (var player in players)
        {
            player.chipsRemaining += player.potCommitment;
            player.potCommitment = 0;
        }

        Console.WriteLine($"***********************\nFinal results:");
        PotChipsRemaining(players);
    }

    // TODO: Split Pots
    public static List<Player> CalculateAndSortWinners(List<Player> playersInHand)
    {
        uint highHand = 0;
        // Get highHand, skipping folded players and those without any commitment left
        foreach (var player in players) if (player.potCommitment > 0 && !player.folded)
        {
            if (player.handStrength > highHand)
            {
                winners.Clear();
                highHand = player.handStrength;
                winners.Add(player);
            }
            else if (player.handStrength == highHand)
            {
                winners.Add(player);
            }
        }

        winners.Sort((x, y) => x.potCommitment.CompareTo(y.potCommitment));
        return winners;
    }

    public static void PayOutWinners(List<Player> winners, List<Player> playersInHand)
    {
        ulong collectedSidePot;
        ulong currentCommitment, collectionAmount;
        List<Player> paidWinners = new List<Player>();
        // for each playerPot in winners
        foreach (var playerPot in winners)
        {
            collectedSidePot = 0;
            currentCommitment = playerPot.potCommitment;
            // Collect it from all players who have money in pot
            foreach (var player in playersInHand) if (player.potCommitment > 0)
                {
                    collectionAmount = Math.Min(currentCommitment, player.potCommitment);
                    player.potCommitment -= collectionAmount;
                    collectedSidePot += collectionAmount;
                }

            int winnersToPay = 0;
            
            foreach (var player in winners) if (paidWinners.IndexOf(player) == -1) winnersToPay++;

            Console.WriteLine($"collectedSidePot: {collectedSidePot}  winnersToPay: {winnersToPay}");
            // Pay unpaid winners, tip dealer with remainder...
            foreach (var player in winners) if (paidWinners.IndexOf(player) == -1)
            {
                player.chipsRemaining += collectedSidePot / (ulong)winnersToPay;
                if (player.potCommitment <= 0)
                {
                    paidWinners.Add(player);
                    Console.WriteLine($"Player {players.IndexOf(player)} paid out.");
                }
            }
        }
        winners.Clear();
    }

    // Only count potchips for unfolded players. Also prints status to Console.
    public static ulong PotChipsRemaining(List<Player> playersInHand)
    {
        ulong tally = 0;
        foreach (var player in playersInHand) if (!player.folded)
            {
                Console.WriteLine($"Player {players.IndexOf(player)} chips: {player.chipsRemaining}  Commitment: {player.potCommitment} \tHandStrength: {player.handStrength}\tFolded: {player.folded}");
                tally += player.potCommitment;
            }

        foreach (var player in playersInHand) if (player.folded)
                Console.WriteLine($"Player {players.IndexOf(player)} chips: {player.chipsRemaining}  Commitment: {player.potCommitment} \tHandStrength: {player.handStrength}\tFolded: {player.folded}");

        return tally;
    }
}

您的示例没有手牌优势,但这是您的结果的一种排列:

Final results:
Player A chips: 45    HandStrength: 100    Folded: False
Player B chips: 80    HandStrength: 80    Folded: False
Player C chips: 85    HandStrength: 100    Folded: False
Player D chips: 80    HandStrength: 150    Folded: False

(我正在更新这个问题,因为尽管它很古老,但没有编码答案,而且这个页面在搜索结果中仍然很高)

于 2021-10-12T00:02:40.677 回答