private Decision MakeDecisionAgainstSingleVillain(PostflopStatusSummary statusSummary, PostflopPlayerSummary villain) { var boardStatus = statusSummary.BoardStatus; var heroHoles = statusSummary.Me.Holes; var villainRange = _rangeEstimator.EstimateRange(statusSummary, villain); var heroRange = GetVillainGuessOnHeroRange(statusSummary.Me); var rawBoardSpectrum = _boardSpectrumMaker.MakeSpectrum(boardStatus); var villainBoardSpectrum = _boardSpectrumFilter.FilterAgainstRange(rawBoardSpectrum, villainRange); var heroBoardSpectrum = _boardSpectrumFilter.FilterAgainstRange(rawBoardSpectrum, heroRange); var heroEquityAgainstVillainRange = villainBoardSpectrum.GetEquity(heroHoles); var villainHolesCombos = villainRange.GetAliveGrids().SelectMany(g => g.Grid.EnumerateAllCombos()); foreach (var villainHoles in villainHolesCombos) { var villainEquityAgainstHeroRange = heroBoardSpectrum.GetEquity(villainHoles); var fightResult = villainBoardSpectrum.Fight(heroHoles, villainHoles); var bettingDecisionEnum = MakeBettingDecisionBasedOnEquitiesComparison(heroEquityAgainstVillainRange, villainEquityAgainstHeroRange, fightResult); //todo accumulate them to make the final decision } throw new NotImplementedException(); }
private double CalculateRequiredEquity(PostflopStatusSummary statusSummary) { // calculate the required equity to call the raise // based on the PotSize // PotOdds int currentPotSize = statusSummary.PotSize; int chipsToCall = statusSummary.ChipsToCall; double potOdds = (double)chipsToCall / (currentPotSize + chipsToCall); //todo consider the implied odds? return(potOdds); }
public Decision MakeDecision(PostflopStatusSummary statusSummary) { if (statusSummary.AliveVillains.Count == 1) { var villain = statusSummary.AliveVillains[0]; return(MakeDecisionAgainstSingleVillain(statusSummary, villain)); } else { return(MakeDecisionAgainstMultipleVillains(statusSummary)); } }
private PlayerRange EstimateFlopRange(PostflopStatusSummary statusSummary, PostflopPlayerSummary villainSummary) { var preflopRange = EstimateRange(statusSummary.BigBlindSize, villainSummary.PreflopDecisions, villainSummary.Position); var boardModel = new BoardModel(statusSummary.BoardStatus); foreach (var grid in preflopRange.GetAliveGrids()) { var gridGrade = boardModel.GetGridGrade(grid.Grid); MarkGrid(villainSummary, GetPlayerStatusInRound(), gridGrade, grid.Grid); } return(preflopRange); }
public PlayerRange EstimateRange(PostflopStatusSummary statusSummary, PostflopPlayerSummary villainSummary) { //todo: estimate the current Range based on //position //betting history //board //hero cards switch (statusSummary.BoardStatus.BoardStage) { default: throw new NotImplementedException(); } }
public Decision MakeDecision(PostflopStatusSummary statusSummary) { var requiredEquity = CalculateRequiredEquity(statusSummary); var villain = statusSummary.Raiser; var villainRange = _rangeEstimator.EstimateRange(statusSummary, villain); var boardSpectrum = _boardSpectrumMaker.MakeSpectrum(statusSummary.BoardStatus); var villainBoardSpectrum = _boardSpectrumFilter.FilterAgainstRange(boardSpectrum, villainRange); var heroEquityAgainstVillainRange = villainBoardSpectrum.GetEquity(statusSummary.Me.Holes); return(MakeDecisionBasedOnEquityComparison(requiredEquity, heroEquityAgainstVillainRange, statusSummary)); }
public static PostflopStatusSummary GeneratePostflopStatusSummary(Round round) { var statusSummary = new PostflopStatusSummary(); statusSummary.BoardStatus = new BoardStatus(round.Flop1, round.Flop2, round.Flop3, round.Turn, round.River); var mePlayer = round.Players.First(round.IsMe); statusSummary.Me = GetPostflopPlayerSummary(round, mePlayer); statusSummary.AliveVillains = round.Players.Where(p => !round.IsMe(p)).Select(p => GetPostflopPlayerSummary(round, p)).Where(p => p.IsAlive).ToList(); statusSummary.IsRaised = round.IsRaised; if (statusSummary.IsRaised) { string raiserName; switch (round.StageEnum) { case StageEnum.Flop: raiserName = round.FlopMoves.Last(m => m.Decision.DecisionType.IsRaiseMove()).Player.Name; break; case StageEnum.Turn: raiserName = round.TurnMoves.Last(m => m.Decision.DecisionType.IsRaiseMove()).Player.Name; break; case StageEnum.River: raiserName = round.RiverMoves.Last(m => m.Decision.DecisionType.IsRaiseMove()).Player.Name; break; default: throw new InvalidOperationException($"{round.StageEnum} is not implemented"); } statusSummary.Raiser = statusSummary.AliveVillains.First(v => string.Equals(v.Name, raiserName)); } var chipsRaised = round.Players.Max(p => p.ChipsBetByStage[round.StageEnum]); statusSummary.ChipsToCall = chipsRaised - GetChipsBetByPlayerThisRound(mePlayer, round); statusSummary.PotSize = round.CurrentPotSize; statusSummary.PreflopRaiserPosition = round.PreflopRaiser.Position; statusSummary.BigBlindSize = round.BigBlindSize; return(statusSummary); }
private Decision MakeDecisionBasedOnEquityComparison(double requiredEquity, double myEquity, PostflopStatusSummary statusSummary) { if (myEquity < requiredEquity) { return(new Decision(DecisionType.Fold, 0)); } return(new Decision(DecisionType.Call, statusSummary.ChipsToCall)); //todo: implement the re-raise logic }
private Decision MakeDecisionAgainstMultipleVillains(PostflopStatusSummary statusSummary) { throw new NotImplementedException(); }