/// <summary> /// Runs a betting round starting from the given player /// </summary> /// <param name="startingPlayer">The index of the player in the round order to start from</param> private void doRaise(int startingPlayer) { // update player cards WaitSynchronizePlayers(); // check if there are any players which can bet if (!RoundPlayersAreAllIn) { // the current player int curPlayer = startingPlayer; // a counter to count the number of players who checked. it reverts to 0 after each raise int allCheck = 0; // a counter to count the number of raise actions, it simply increases on each player int raiseCount = 0; // the raise limit for this round, it is calculated using the initial playingPlayers count * the raise limit. // this way each player will have (RaiseLimit) opportunities to raise. int curRaiseLimit = playingPlayers.Count * RaiseLimit; // a flag which marks an "all in" round in which all of the players are obligated to either go "all in" or fold bool isAllInMode = false; // loop as long as there are round players & there are players which need to call/check while (allCheck != playingPlayers.Count && HasRoundPlayers) { // Get the current player according to the round order Player player = safeGetPlayer(curPlayer); // skip the player if the player has folded if (playingPlayers.Contains(player)) { // check that this player has any money to gamble with or the player is "all in" if (player.Money > 0) { // create a new betting action for this player PlayerBettingAction action = GetPlayerBettingAction(player, isAllInMode, raiseCount < curRaiseLimit); // call derived class to provide the player bet WaitPlayerBettingAction(player, action); // check raise restrictions in case of a raise: if (action.Action == BetAction.Raise) { // assure the raise is higher than the SmallRaise if (action.RaiseAmount < SmallRaise) { action.Raise(SmallRaise); } // assure the current raise amount does not exceed the player money if (action.RaiseAmount + action.CallAmount > player.Money) { action.Raise(player.Money - action.CallAmount); } } // action handling: switch (action.Action) { case BetAction.CheckOrCall: pot.Call(player); if (isAllInMode && player.Money > 0) // in "all in" mode, the player must play all of the player money { pot.Raise(player, player.Money); } ++allCheck; // increase the check count to progres, so when all players check the round will continue break; case BetAction.Raise: // raise the player raise amount pot.Raise(player, action.RaiseAmount); // reset the check count so other players will have to call/check allCheck = 1; break; case BetAction.Fold: // remove the player from the pot, game & playingPlayers pot.Fold(player); game.FoldPlayer(curPlayer); playingPlayers.Remove(player); break; } /* * if (action.Action != BetAction.Fold && tournamentMode) * { * isAllInMode = action.IsAllInMode || player.Money == 0; * } */ // Notify derived classes on player action NotifyPlayerAction(player, action.Action, action.CallAmount, action.RaiseAmount); } else // player has no money so the player can't raise, // the player is "all in" so the player doesn't need to fold. { ++allCheck; } // In debug mode, verify that the playing players contributed the same amount of money to the pot. Invariant.VerifyPotIsEven(this, player, pot); } // move the current player to the next in the current round order. curPlayer = (curPlayer + 1) % roundOrder.Count; // increase the raise counter (which is never zeroed) to restrict the raise limit ++raiseCount; } Invariant.VerifyPlaingPlayersBet(playingPlayers, pot); Invariant.VerifyPotIsEven(this, pot); // reset the current round raise pot.ResetRaise(); } }
/// <summary> /// Called by the client to get the current player betting action. Derived classes must implement it and respond with a /// proper action /// </summary> /// <param name="player">The player which needs to bet</param> /// <param name="action">The action to use to pass the player response</param> public override void WaitPlayerBettingAction(PokerEngine.Player player, PokerEngine.Engine.PlayerBettingAction action) { currentStrategy.Bet(player, action); }
/// <summary> /// Called by the engine when a player needs to make a bet. /// Derived classes must place player betting logic in overriden implementation. /// </summary> /// <param name="player">The current player which needs to bet</param> /// <param name="action">The player betting action which contains the current betting restrictions</param> /// <remarks> /// The action must be used to notify the engine of the player action. In the derived implementation take notice to /// the action <see cref="PlayerBettingAction.IsAllInMode"/>, <see cref="PlayerBettingAction.CanRaise"/> and /// <see cref="PlayerBettingAction.RaiseAmount"/> (which holds the minimal raise amount at first) /// </remarks> protected abstract void WaitPlayerBettingAction(Player player, PlayerBettingAction action);