private BattingResult GetBatterBattingResult(BattingStint batter, Random random)
        {
            if (batter == null)
            {
                batter = BattingStintHelperFunctions.CreateBattingStintForNonBatter();
            }

            var randomResult = random.Next(0, 1001);

            var totalOutcomes    = batter.AtBats + batter.HitByPitch + batter.Walks;
            var successThreshold = ((double)batter.Doubles / totalOutcomes) * 1000;

            if (randomResult <= successThreshold)
            {
                randomResult = random.Next(0, 3);
                if (randomResult == 0)
                {
                    return(BattingResult.Double3Bases);
                }
                return(BattingResult.Double);
            }
            successThreshold += (((double)batter.HitByPitch) / totalOutcomes) * 1000;
            if (randomResult <= successThreshold)
            {
                return(BattingResult.HitByPitch);
            }
            successThreshold += (((double)batter.HomeRuns) / totalOutcomes) * 1000;
            if (randomResult <= successThreshold)
            {
                return(BattingResult.HomeRun);
            }
            successThreshold += (((double)batter.Strikeouts) / totalOutcomes) * 1000;
            if (randomResult <= successThreshold)
            {
                return(BattingResult.Strikeout);
            }
            successThreshold += (((double)batter.Triples) / totalOutcomes) * 1000;
            if (randomResult <= successThreshold)
            {
                return(BattingResult.Triple);
            }
            successThreshold += (((double)batter.Walks) / totalOutcomes) * 1000;
            if (randomResult <= successThreshold)
            {
                return(BattingResult.Walk);
            }
            successThreshold += (((double)batter.Hits - (batter.Doubles + batter.Triples + batter.HomeRuns)) / totalOutcomes) * 1000;
            if (randomResult <= successThreshold)
            {
                randomResult = random.Next(0, 1);
                if (randomResult == 0)
                {
                    return(BattingResult.Single2Bases);
                }
                return(BattingResult.Single);
            }
            return(GetFieldedByRandomPositionResult(random));
        }
        public FieldingResult GetBuntForAHitResult(BattingStint batter)
        {
            if (batter == null)
            {
                batter = BattingStintHelperFunctions.CreateBattingStintForNonBatter();
            }

            var random       = new Random();
            var randomResult = random.Next(0, 100);

            var successThreshold = 20;

            if (batter.SacrificeHits > 0)
            {
                successThreshold += 5;
            }
            if (batter.SacrificeHits >= 10)
            {
                successThreshold += 5;
            }
            if (batter.StolenBases >= 10)
            {
                successThreshold += 5;
            }
            if (batter.StolenBases >= 25)
            {
                successThreshold += 10;
            }

            if (randomResult <= successThreshold)
            {
                return(FieldingResult.Single);
            }
            randomResult = random.Next(0, 100);
            if (randomResult < 3)
            {
                return(FieldingResult.GroundoutDoublePlay);
            }
            if (randomResult < 10)
            {
                return(FieldingResult.GroundoutFieldersChoice);
            }
            if (randomResult < 40)
            {
                return(FieldingResult.Groundout);
            }
            if (randomResult < 60)
            {
                return(FieldingResult.Popout);
            }
            if (randomResult < 80)
            {
                return(FieldingResult.Strikeout);
            }
            return(FieldingResult.GroundoutAllAdvance);
        }
        public bool GetHitAndRunResult(BattingStint batter)
        {
            if (batter == null)
            {
                batter = BattingStintHelperFunctions.CreateBattingStintForNonBatter();
            }

            var random       = new Random();
            var randomResult = random.Next(0, 100);

            var successThreshold = 35 + ((double)batter.Hits / batter.AtBats) * 100;

            return(randomResult < successThreshold);
        }
        public FieldingResult GetSacrificeBuntResult(BattingStint batter)
        {
            if (batter == null)
            {
                batter = BattingStintHelperFunctions.CreateBattingStintForNonBatter();
            }

            var random       = new Random();
            var randomResult = random.Next(0, 101);

            var successThreshold = 60;

            if (batter.SacrificeHits > 0)
            {
                successThreshold += 12;
            }
            if (batter.SacrificeHits > 10)
            {
                successThreshold += 8;
            }

            if (randomResult <= successThreshold)
            {
                randomResult = random.Next(0, 100);
                if (randomResult < 8)
                {
                    return(FieldingResult.Single);
                }
                return(FieldingResult.GroundoutAllAdvance);
            }
            randomResult = random.Next(0, 100);
            if (randomResult < 8)
            {
                return(FieldingResult.GroundoutDoublePlay);
            }
            if (randomResult < 18)
            {
                return(FieldingResult.GroundoutFieldersChoice);
            }
            if (randomResult < 50)
            {
                return(FieldingResult.Groundout);
            }
            if (randomResult < 70)
            {
                return(FieldingResult.Popout);
            }
            return(FieldingResult.Strikeout);
        }
        public bool GetStealResult(BattingStint runner, FieldingStint catcher, BaseballBase baseballBase)
        {
            // only handles lead runner steals
            // todo add complex steals/errors/balks/rundowns2
            var random       = new Random();
            var randomResult = random.Next(0, 1001);

            if (catcher == null)
            {
                catcher = FieldingStintHelperFunctions.CreateFieldingStintForPlayerOutOfPosition(PositionType.Catcher);
            }

            if (runner == null)
            {
                runner = BattingStintHelperFunctions.CreateBattingStintForNonBatter();
            }

            double baseFactor = 1;

            if (baseballBase == BaseballBase.Third)
            {
                baseFactor = .75;
            }
            else if (baseballBase == BaseballBase.Home)
            {
                baseFactor = .5;
            }

            double catcherArmFactor = 1;

            if (catcher.StolenBases < 20 || runner.StolenBases < 20)
            {
                catcherArmFactor = .9;
            }
            else
            {
                var csRatio = (double)catcher.CaughtStealing / (catcher.CaughtStealing + catcher.StolenBases);
                if (csRatio >= .6)
                {
                    catcherArmFactor = .6;
                }
                else if (csRatio >= .5)
                {
                    catcherArmFactor = .7;
                }

                else if (catcher.StolenBases >= .4)
                {
                    catcherArmFactor = .8;
                }
                else if (catcher.StolenBases >= .3)
                {
                    catcherArmFactor = .9;
                }
                else if (catcher.StolenBases >= .2)
                {
                    catcherArmFactor = .95;
                }
            }

            double stealingFrequencyFactor = 1;

            if (runner.StolenBases >= 100)
            {
                stealingFrequencyFactor = .97;
            }
            else if (runner.StolenBases >= 70)
            {
                stealingFrequencyFactor = .92;
            }
            else if (runner.StolenBases >= 50)
            {
                stealingFrequencyFactor = .87;
            }
            else if (runner.StolenBases >= 40)
            {
                stealingFrequencyFactor = .82;
            }
            else if (runner.StolenBases >= 30)
            {
                stealingFrequencyFactor = .75;
            }
            else if (runner.StolenBases >= 20)
            {
                stealingFrequencyFactor = .7;
            }
            else if (runner.StolenBases >= 10)
            {
                stealingFrequencyFactor = .6;
            }
            else
            {
                stealingFrequencyFactor = .5;
            }

            var successThreshold = stealingFrequencyFactor * catcherArmFactor * baseFactor * 1000;

            return(randomResult <= successThreshold);
        }