public BoardSituation(BoardSituation prevSituation, ulong cards, string playerName, int decision)
 {
     PreviousSituation = prevSituation;
     Cards             = cards;
     Street            = Hand.Cards(Cards).Count();
     PlayerName        = playerName;
     Decision          = decision;
     if (prevSituation != null)
     {
         Deep = prevSituation.Deep + 1;
         if (Cards == prevSituation.Cards)
         {
             MaxBet     = prevSituation.MaxBet;
             RaiseCount = prevSituation.RaiseCount;
         }
         int bet = GetPlayerCurrentBet(playerName);
         if (bet > prevSituation.MaxBet)
         {
             MaxBet = bet;
             if (Deep > 2)
             {
                 RaiseCount++;
             }
         }
     }
 }
        private static TableLog HandRound(StackPlayers sPlayers, TableInfo tInfo, bool showLog)
        {
            ulong     dead  = 0UL;
            ulong     board = 0UL;
            TableLog  log   = new TableLog(showLog);
            GameState state = GameState.STARTINFO;

            log.Add(state,
                    "Hand ID - " + tInfo.HandId + ", small blind - " + tInfo.SmallBlind + ", players count - " + sPlayers.Count + ", button seats on - " + (tInfo.Button + 1));
            for (int p = 0; p < sPlayers.Count; p++)
            {
                log.Add(state,
                        "Seat " + (p + 1) + ": " + sPlayers[p].Agent.GetName() + " has stack - " + sPlayers[p].Stack);
            }
            #region Streets
            List <Action> streets = new List <Action>
            {
                () =>
                {
                    // Раздаем карты
                    for (int p = 0; p < sPlayers.Count; p++)
                    {
                        sPlayers[p].Hand = Hand.RandomHand(dead, 2);
                        dead            |= sPlayers[p].Hand;
                        if (sPlayers[p].Agent.GetType() == typeof(Player))
                        {
                            log.Add(state, sPlayers[p].Agent.GetName() + " pocket cards are " + Hand.MaskToString(sPlayers[p].Hand));
                        }
                    }
                    state = GameState.PREFLOP;
                    log.Add(state, "*** " + state.ToString() + " ***");
                },
                () =>
                {
                    ulong flop = Hand.RandomHand(dead, 3);
                    board = flop;
                    dead |= flop;
                    state = GameState.FLOP;
                    log.Add(state, "*** FLOP *** [" + Hand.MaskToString(flop) + "]");
                },
                () =>
                {
                    ulong turn = Hand.RandomHand(dead, 1);
                    state = GameState.TURN;
                    log.Add(state, "*** TURN *** [" + Hand.MaskToString(board) + "]  [" + Hand.MaskToString(turn) + "]");
                    board |= turn;
                    dead  |= turn;
                },
                () =>
                {
                    ulong river = Hand.RandomHand(dead, 1);
                    state = GameState.RIVER;
                    log.Add(state, "*** RIVER *** [" + Hand.MaskToString(board) + "]  [" + Hand.MaskToString(river) + "]");
                    board |= river;
                }
            };
            #endregion
            // Создаем начальную ситуацию с пустым столом
            BoardSituation currentSituation = null;
            foreach (var street in streets)
            {
                street();
                currentSituation = new BoardSituation(currentSituation, board, "", -1);
                EmulatorPlayer player;
                while (player = sPlayers.GetNextPlayer(currentSituation, tInfo))
                {
                    int decision = -1;
                    // Если нужно ставить блайды - ставим, иначе запрашиваем ставку у агента
                    if (currentSituation.Deep == 0)
                    {
                        decision = tInfo.SmallBlind;
                    }
                    else if (currentSituation.Deep == 1)
                    {
                        decision = tInfo.SmallBlind * 2;
                    }
                    else
                    {
                        decision = player.Agent.GetDecision(currentSituation, tInfo);
                    }
                    //Проверяем верность ставки
                    int currentBet = currentSituation.GetPlayerCurrentBet(player.Agent.GetName());
                    if (decision >= 0)
                    {
                        if (decision + currentBet < currentSituation.MaxBet ||
                            sPlayers.GetNotFoldedAndNotAllInInGamePlayers() == 1 ||
                            currentSituation.RaiseCount == 3)
                        {
                            decision = currentSituation.MaxBet - currentBet;
                        }
                    }
                    if (decision > player.Stack)
                    {
                        decision = player.Stack;
                    }
                    else if (decision < -1)
                    {
                        decision = -1;
                    }
                    // Добавляем ситуацию в дерево
                    currentSituation = new BoardSituation(currentSituation, board, player.Agent.GetName(), decision);
                    log.Add(state, player.Agent.GetName() + ": " + currentSituation.GetActionString(tInfo));
                }
                if (sPlayers.IsGameOver(currentSituation, tInfo, ref log))
                {
                    break;
                }
            }
            log.Add(GameState.ENDINFO, "Game Over");
            return(log);
        }
        public EmulatorPlayer GetNextPlayer(BoardSituation currentSituation, TableInfo tInfo)
        {
            // Меняем стэк сходившего игрока
            if (currentSituation.Decision > 0)
            {
                players[GetIndexPlayerByName(currentSituation.PlayerName)].Stack -= currentSituation.Decision;
            }
            else if (currentSituation.Decision == -1 && currentSituation.PlayerName != "")
            {
                players[GetIndexPlayerByName(currentSituation.PlayerName)].Folded = true;
            }

            int sbPlayer = 0;

            if (players.Count > 2)
            {
                sbPlayer = GetNextIndexInGame(tInfo.Button);
            }
            else
            {
                sbPlayer = tInfo.Button;
            }
            if (currentSituation.Deep == 0)
            {
                return(players[sbPlayer]);
            }
            else if (currentSituation.Deep == 1)
            {
                return(players[GetNextIndexInGame(sbPlayer)]);
            }

            // Если игроков в игре и не сбросивших меньше 2х, круг закончен
            if (players.Count(p => p.Folded == false) < 2)
            {
                return(null);
            }

            int curIndex  = GetNextIndexInGame(currentSituation.PlayerName);
            int?prevIndex = null;

            if (currentSituation.PlayerName == "")
            {
                curIndex = GetNextIndexInGame(tInfo.Button);
            }
            else
            {
                prevIndex = GetIndexPlayerByName(currentSituation.PlayerName);
            }
            // Если текущий игрок выставился, берем следующего
            while (prevIndex != curIndex && (players[curIndex].Stack == 0 || players[curIndex].Folded))
            {
                if (prevIndex == null)
                {
                    prevIndex = curIndex;
                }
                curIndex = GetNextIndexInGame(curIndex);
            }
            if (curIndex == prevIndex)
            {
                return(null);
            }
            int curBet = currentSituation.GetPlayerCurrentBet(players[curIndex].Agent.GetName());

            // Если ставки заколированы и игрок уже ходил, круг закончен
            if (curBet == currentSituation.MaxBet && (currentSituation.GetActionsCount(players[curIndex].Agent.GetName()) > 0 ||
                                                      players.Count(p => p.Stack > 0 && p.Folded == false) <= 1))
            {
                return(null);
            }
            return(players[curIndex]);
        }
        public bool IsGameOver(BoardSituation currentSituation, TableInfo tInfo, ref TableLog log)
        {
            if (players.Count(p => !p.Folded) < 2 || Hand.Cards(currentSituation.Cards).Count() == 5)
            {
                int pot         = currentSituation.GetPot();
                var lastPlayers = players.Where(p => !p.Folded).ToList();
                if (lastPlayers.Count == 1)
                {
                    lastPlayers[0].Stack += pot;
                    log.Add(GameState.ENDINFO, lastPlayers[0].Agent.GetName() + " won " + pot + " chips.");
                }
                else
                {
                    var bets = new List <Bets>();
                    for (int i = 0; i < lastPlayers.Count; i++)
                    {
                        var b = new Bets();
                        b.HandValue = Hand.Evaluate(currentSituation.Cards | lastPlayers[i].Hand);
                        b.Bet       = currentSituation.GetPlayerPot(lastPlayers[i].Agent.GetName());
                        b.Name      = lastPlayers[i].Agent.GetName();
                        bets.Add(b);
                    }
                    var foldedPlayers = players.Where(p => p.Folded).ToList();
                    var foldedBets    = new List <int>();
                    for (int i = 0; i < foldedPlayers.Count; i++)
                    {
                        foldedBets.Add(currentSituation.GetPlayerPot(foldedPlayers[i].Agent.GetName()));
                    }

                    while (pot > 0)
                    {
                        var max       = bets.Max(b => b.HandValue);
                        var maxValues = bets.Where(b => b.HandValue == max).OrderBy(b => b.Bet).ToList();
                        int win       = maxValues[0].Bet;
                        int foldedPot = 0;
                        for (int i = 0; i < foldedBets.Count; i++)
                        {
                            if (foldedBets[i] < win)
                            {
                                foldedPot    += foldedBets[i];
                                foldedBets[i] = 0;
                            }
                            else
                            {
                                foldedPot     += win;
                                foldedBets[i] -= win;
                            }
                        }
                        int sidePot = 0;
                        for (int i = 0; i < bets.Count; i++)
                        {
                            if (bets[i].Name != maxValues[0].Name)
                            {
                                if (bets[i].Bet < win)
                                {
                                    sidePot    += bets[i].Bet;
                                    bets[i].Bet = 0;
                                }
                                else
                                {
                                    sidePot     += win;
                                    bets[i].Bet -= win;
                                }
                            }
                        }
                        win += foldedPot + sidePot;
                        for (int i = 0; i < maxValues.Count; i++)
                        {
                            var p = lastPlayers.First(mp => mp.Agent.GetName() == maxValues[i].Name);
                            p.Stack += win / maxValues.Count;
                            log.Add(GameState.ENDINFO, p.Agent.GetName() + " won " + (win / maxValues.Count) + " chips with " + Hand.DescriptionFromHandValueInternal(maxValues[i].HandValue) + ".");
                        }
                        pot -= win;
                        if (win % maxValues.Count != 0)
                        {
                            int            mod           = win % maxValues.Count;
                            int            button        = tInfo.Button;
                            EmulatorPlayer p             = null;
                            var            winnigPlayers = maxValues.Select(v => v.Name).ToList();
                            while (!winnigPlayers.Contains((p = players[GetNextIndexInGame(button)]).Agent.GetName()))
                            {
                                button = GetNextIndexInGame(button);
                            }
                            p.Stack += mod;
                        }
                        bets.Remove(maxValues[0]);
                    }
                }
                for (int i = 0; i < allPlayers.Count; i++)
                {
                    if (allPlayers[i].Stack == 0)
                    {
                        allPlayers[i].InGame = false;
                    }
                    else
                    {
                        allPlayers[i].Folded = false;
                    }
                }
                if (allPlayers.Sum(p => p.Stack) != 1500)
                {
                }
                return(true);
            }
            return(false);
        }