Winning Baseball Lineup

Fiddler for 8/18/2023, by Laurent Lessard

Expected runs for a full game

This function computes the average runs for a baseball game with “sluggers” and “hitters”.​
V
o,r,b,i
is the expected runs we will score for the rest of the game if we are currently in inning i,we have o outs, r runners on base, and batter b is up to bat. Function inputs:​SLUGGERS: set of sluggers, e.g. {2,4} means sluggers are 2nd and 4th in the batting order.​INNINGS: number of innings in the baseball game​pH: hitting probability (probability a hitter will hit a single)​pS: slugging probability (probability a slugger will hit a home run)​NUMERICAL: (True/False) should Mathematica evaluate the solution numerically (faster), or analytically (slower, but exact)?
In[]:=
AvgRuns[SLUGGERS_,INNINGS_,pH_,pS_,NUMERICAL_]:=​​Module[{BATTERS,HITTERS,RUNNERS,OUTS,VARS,E1,E2,E3,E4,E5,EQNS,SOLN,V},​​(*batters,numberofbases,andnumberofouts*)​​BATTERS=Range[9];RUNNERS=3;OUTS=3;​​HITTERS=Complement[BATTERS,SLUGGERS];​​(*Listofvariables*)​​VARS=Table[
V
o,r,b,i
,{o,0,OUTS},{r,0,RUNNERS},{b,BATTERS},{i,INNINGS}]//Flatten;​​(*iftherearethreeoutsinthe9thinning,gameisover*)​​E1=Table[
V
3,r,b,INNINGS
==0,{r,0,RUNNERS},{b,BATTERS}];​​(*ifahitterisupandbasesarenotloaded,weaddarunneroranout*)​​E2=Table[
V
o,r,b,i
==pH
V
o,r+1,Mod[b,9]+1,i
+(1-pH)
V
o+1,r,Mod[b,9]+1,i
,{o,0,OUTS-1},{r,0,RUNNERS-1},{b,HITTERS},{i,INNINGS}];​​(*ifahitterisupwithbasesloaded,weaddarunoranout*)​​E3=Table[
V
o,RUNNERS,b,i
==pH(1+
V
o,RUNNERS,Mod[b,9]+1,i
)+(1-pH)
V
o+1,RUNNERS,Mod[b,9]+1,i
,{o,0,OUTS-1},{b,HITTERS},{i,INNINGS}];​​(*ifsluggerhitshomerun,clearthebasesandincrementscore*)​​E4=Table[
V
o,r,b,i
==pS(1+r+
V
o,0,Mod[b,9]+1,i
)+(1-pS)
V
o+1,r,Mod[b,9]+1,i
,{o,0,OUTS-1},{r,0,RUNNERS},{b,SLUGGERS},{i,INNINGS}];​​(*3outsinoneinningisthesameas0outsinthenextinningwithclearedbases*)​​E5=Table[
V
OUTS,r,b,i
==
V
0,0,b,i+1
,{r,0,RUNNERS},{b,BATTERS},{i,INNINGS-1}];​​(*Listofallequations*)​​EQNS={E1,E2,E3,E4,E5}//Flatten;​​SOLN=If[NUMERICAL==True,NSolve[EQNS,VARS],Solve[EQNS,VARS]];​​(*returnexpectedscorestartingfromfirstbatterinfirstinningwithnooutsorrunnersonbase*)​​
V
0,0,1,1
/.SOLN[[1]]​​];

Solving special cases

One inning, one slugger

In[]:=
v=TableAvgRuns{s},1,
1
3
,
1
10
,False,{s,9}
Out[]=

780011296399952
4236249339922935
,
892714437481427
4236249339922935
,
1014032840761142
4236249339922935
,
3051922249868633
12708748019768805
,
7729183945570084
38126244059306415
,
3573996830896157
22875746435583849
,
3850810161699482
22875746435583849
,
3986007718407239
22875746435583849
,
149930373115684
847249867984587

In[]:=
v//N
Out[]=
{0.184128,0.210732,0.23937,0.240143,0.202726,0.156235,0.168336,0.174246,0.176961}
(*makeaprettyplot*)​​Labeled[​​BarChart[v,GridLines->{None,Range[0,1,0.05]},ChartLabels->Range[9]],​​Pane["Average runs scored in one inning as a function of the slugger's position in the batting order",350,Alignment->{Center,Center}],Top,​​LabelStyle->Directive["Text",TextAlignment->Center]​​]
Out[]=
Average runs scored in one inning as a function of the slugger's position in the batting order

Nine innings, two sluggers

In[]:=
(*evaluatenumericallybecausetheexactanalyticsolutionislargeandslowtocompute!*)​​w=TableAvgRuns{s1,s2},9,
1
3
,
1
10
,True,{s1,9},{s2,s1-1};
In[]:=
w//TableForm
Out[]//TableForm=
1.93575
1.95816
1.98757
1.94247
1.97469
1.99771
1.94107
1.94284
1.96859
1.96591
1.92345
1.94693
1.94794
1.94888
1.91918
1.91631
1.96187
1.98425
1.96042
1.93426
1.90353
1.91636
1.93733
1.97991
1.9806
1.92883
1.90123
1.92556
1.89841
1.92239
1.94231
1.96654
1.93857
1.88647
1.91387
1.9179
In[]:=
(*makeaprettyplot*)​​DiscretePlot3D[w[[i,j]],{i,9},{j,9},​​PlotRange->{All,All,{1.85,2.00}},​​Ticks->{Range[9],Range[8],Automatic},​​AxesLabel->{"Second slugger","First Slugger"},​​ColorFunction->"SolarColors",ImageSize->Large,​​ExtentSize->Full,PlotStyle->Opacity[1],PlotLabel->"Average runs scored as a function of sluggers' position in the lineup"]
Out[]=