-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.html
More file actions
150 lines (150 loc) · 17.7 KB
/
index.html
File metadata and controls
150 lines (150 loc) · 17.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<!doctype html><meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding"><html><head><title>Softball.app Lineup Optimizer Gallery</title><link rel="stylesheet" href="css/main.css"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css"><link rel="icon" href="https://softball.app/server/assets/icons/favicon.ico"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.min.css"><script type="text/javascript" defer src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.8.4/mermaid.min.js"></script><script type="text/javascript" defer onload="renderKatex()" src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js"></script></head><body><main id="main" class="content"><div id="header" class="gallery-header-wrapper"><div class="gallery-header inner"><h1>Softball.app Lineup Optimizer Gallery</h1></div></div><div id="gallery" class="inner"><div class="gallery-tile" onClick="optimizerClick("0","optimizer-name-0","optimizer-img-0","optimizer-description-0")"><div class="img-container"><img src="https://i.imgur.com/35aPFzD.jpg" width="600" height="400"></div><div class="text-container"><div id="optimizer-img-0" class="gallery-tile-img hidden">https://i.imgur.com/35aPFzD.jpg</div><div id="optimizer-name-0" class="gallery-tile-name">Monte Carlo Exhaustive</div><div id="optimizer-description-0" class="gallery-tile-body"><p>Runs Monte Carlo simulations of games for all possible lineups. The optimizer then averages the runs scored acrosss all possible lineups and returns the lineup with the highest average runs scored.</p>
<h3>Overview</h3>
<p>Simulation flow. This flowchart refers to the parameter <em>g</em> which is a configurable value indicating the number of games to simulate. The stages with thick black outlines have sections w/ additional details below.</p>
<div class="mermaid">
flowchart TD;
A[Select a lineup from<br> the lineup pool.]:::addtDoc-->B;
B[Simulate a game,<br>remember the number<br> of runs scored.]:::addtDoc-->D
D{Have we simulated<br>more than *g* games?}--yes-->E
D--no-->B
E[Compute the mean <br>score of all simulated<br> games using this lineup.]-->F
F{Is this lineup's <br>mean game score better <br>than all the others we<br> have simulated?}--yes-->G
F--no-->I
G[Remember this lineup<br> as bestLineup and its<br> mean score as bestScore.]-->I
I{Is the lineup pool<br> depleted?}--yes-->J
I--no-->A
J[Done! Print the bestLineup <br>and bestScore that we<br> remembered earlier.]
classDef addtDoc stroke:#333,stroke-width:4px;
</div>
<h3>The Lineup Pool</h3>
<p>This optimizer simulates games for all possible lineups. The number of possible lineups for each lineup type is given by these equations where 'm' is the number of male batters and 'f' is the number of female batters:</p>
<h4>Normal/Ordinary/No Restrictions</h4>
<div class="katex">
numberOfLineups = (m+f)!
</div>
<h4>Alternating Gender</h4>
<div class="katex">
numberOfLineups = (m! + f!) * 2
</div>
<h4>No Consecutive Females</h4>
<div class="katex">
numberOfLineups = m! * f! * (\\binom{m}{f} + \\binom{m-1}{f-1})
</div>
<h4>Performance</h4>
<p>Because of the factorial nature of these equations, adding even one more player to the lineup can make the optimizer take significantly longer to run.</p>
<p>Example simulation (7 innings, 10000 games)</p>
<table><thead><tr><th># players in lineup</th><th>possible lineups</th><th>runtime (ms)</th><th>~runtime (human)</th></tr></thead><tbody><tr><td>6</td><td>720</td><td>1958</td><td>2 seconds</td></tr><tr><td>7</td><td>5,040</td><td>15982</td><td>16 seconds</td></tr><tr><td>8</td><td>40,320</td><td>135255</td><td>2 minutes</td></tr><tr><td>9</td><td>362,880</td><td>832902</td><td>14 minutes</td></tr><tr><td>10</td><td>3,628,800</td><td>6613484</td><td>2 hours</td></tr></tbody></table>
<h3>Simulating a game</h3>
<p>This flowchart refers to the parameter <em>i</em> which is a configurable value indicating the number of innings to simulate (typically 9 for baseball, 7 for softball, but can be anything). Same as before, the stage with the thick black outline has a section w/ additional details below.
Simulate a game</p>
<div class="mermaid">
flowchart TD;
B[Set active batter to<br>the first player <br>in the lineup.]-->C
C{Simulate a <br> plate appearance <br> for the active batter.}:::addtDoc--Result: 0-->D
C--Result: 1,2,3,4-->E
D[Increment the<br> number of outs <br>by one]-->F
E["Advance the runners. <br> Increase score if the<br>plate appearance <br>drove home (a) run(s)."]-->G
F[> 3 outs?]--no--> G
F--yes-->I
G[Set active batter to<br>the next batter <br>in the lineup.]
G-->C
I{Have we <br>simulated more <br>than *i* innings?}--yes-->J
I--no--> K
J[Done! Return the score<br> for this simulated game.]
K[Increment the <br>number of innings<br> simulated by one. <br> Clear the bases. <br> Clear the outs.]-->G
classDef addtDoc stroke:#333,stroke-width:4px;
</div>
<h3>Simulate a Plate Appearance</h3>
<p>Each plate appearance result (Out, SAC, E, BB, 1B, 2B, 3B, HRi, HRo) is mapped to a number indicating the number of bases awarded for that plate appearance. The mapping is illustrated in this table:</p>
<table><thead><tr><th>Result</th><th>Bases</th></tr></thead><tbody><tr><td>Out, SAC*, E, K</td><td>0</td></tr><tr><td>1B, BB*</td><td>1</td></tr><tr><td>2B</td><td>2</td></tr><tr><td>3B</td><td>3</td></tr><tr><td>HRi, HRo</td><td>4</td></tr></tbody></table>
<p>We can then use the frequency of each type of hit to build a distribution that reflects the way any given player is likely perform when they get a plate appearance. Whenever we need to simulate a hit for that player, we draw a random sample from that player's distribution.</p>
<h4>An Example</h4>
<p>Tim's historical at bats are as follows:
Out,1B,2B,SAC,E,HRo,3B,1B,1B,Out,Out,2B,1B,Out,Out</p>
<p>First we translate those hits to number of bases using our mapping from the table above:
0,1,2,0,0,4,3,1,1,0,0,2,1,0,0</p>
<p>Then we determine the histogram and chance of each hit:</p>
<table><thead><tr><th># of bases</th><th># of times</th><th>% of plate appearances</th></tr></thead><tbody><tr><td>0</td><td>7</td><td>47</td></tr><tr><td>1</td><td>4</td><td>27</td></tr><tr><td>2</td><td>2</td><td>13</td></tr><tr><td>3</td><td>1</td><td>7</td></tr><tr><td>4</td><td>1</td><td>7</td></tr></tbody></table>
<p>And every time we simulate a plate appearance for Tim, we'll draw a random hit with that distribution. That is to say, for every simulated plate appearance, Tim has a 47% of getting out, 27% chance of getting a single, a 13% chance of getting a double, a 7% chance of getting a triple, and a 7% chance of getting a home run. Of course, other players will have their own distribution of hits to draw from based of their historical performance.</p>
<h3>Other Notes</h3>
<p>Things that are not accounted for in the simulation:</p>
<ul><li>Double/triple plays</li><li>Stolen bases</li><li>Players who were on base advancing more bases than the hitter</li><li>Any pitching data</li></ul>
<p><em>*We can debate about how walks or sacrifices should be counted. It probably depends on what flavor of the sport you are playing. IMHO sacrifices should be counted as outs in slowpitch softball and kickball, but not baseball or fastpitch. In any event, these mapping are configurable (or will be configurable soon). So you are welcome to impose your own philosophy.</em></p>
</div><div class="gallery-fade"></div><div id="button- 0" class="gallery-tile-add-button add-button hidden" onClick="selectToggleClick("0",event)">+ Add</div></div></div><div class="gallery-tile" onClick="optimizerClick("1","optimizer-name-1","optimizer-img-1","optimizer-description-1")"><div class="img-container"><img src="https://cdn.pixabay.com/photo/2019/09/24/16/32/chameleon-4501712_1280.jpg" width="600" height="400"></div><div class="text-container"><div id="optimizer-img-1" class="gallery-tile-img hidden">https://cdn.pixabay.com/photo/2019/09/24/16/32/chameleon-4501712_1280.jpg</div><div id="optimizer-name-1" class="gallery-tile-name">Monte Carlo Adaptive</div><div id="optimizer-description-1" class="gallery-tile-body"><p>Employs the same approach as the Monte Carlo Exhaustive optimizer but instead of simulating a fixed number of games for each lineup, performs a variable number of simulated games. The exact number of games simulated for each lineup is determined by continuing to do simulations on a lineup until a statistical t-test determines that the expected run totals for two lineups are significantly different (by some configurable alpha value). The lineup with the lower mean is then rejected and the larger one remembered as the best so far.</p>
</div><div class="gallery-fade"></div><div id="button- 1" class="gallery-tile-add-button add-button hidden" onClick="selectToggleClick("1",event)">+ Add</div></div></div><div class="gallery-tile" onClick="optimizerClick("2","optimizer-name-2","optimizer-img-2","optimizer-description-2")"><div class="img-container"><img src="https://upload.wikimedia.org/wikipedia/commons/f/f8/Fotothek_df_n-08_0000320.jpg" width="600" height="400"></div><div class="text-container"><div id="optimizer-img-2" class="gallery-tile-img hidden">https://upload.wikimedia.org/wikipedia/commons/f/f8/Fotothek_df_n-08_0000320.jpg</div><div id="optimizer-name-2" class="gallery-tile-name">Monte Carlo Annealing</div><div id="optimizer-description-2" class="gallery-tile-body"><p>A faster (time constrained), less accurate optimizer that doesn't test the entire search space of possible lineups.
Instead, it employs <a href="https://en.wikipedia.org/wiki/Simulated_annealing">simulated annealing</a> to seaerch only a subset of possible lineups.
Like the Monte Carlo Adaptive optimizer, this optimizer uses statistical t-tests to determine when a particular lineup is better or worse than another.</p>
</div><div class="gallery-fade"></div><div id="button- 2" class="gallery-tile-add-button add-button hidden" onClick="selectToggleClick("2",event)">+ Add</div></div></div><div class="gallery-tile" onClick="optimizerClick("3","optimizer-name-3","optimizer-img-3","optimizer-description-3")"><div class="img-container"><img src="https://cdn.pixabay.com/photo/2020/03/07/19/16/swiss-francs-4910665_1280.jpg" width="600" height="400"></div><div class="text-container"><div id="optimizer-img-3" class="gallery-tile-img hidden">https://cdn.pixabay.com/photo/2020/03/07/19/16/swiss-francs-4910665_1280.jpg</div><div id="optimizer-name-3" class="gallery-tile-name">Expected Value</div><div id="optimizer-description-3" class="gallery-tile-body"><p>Runs Monte Carlo simulations of games for all possible lineups. The optimizer then averages the runs scored acrosss all possible lineups and returns the lineup with the highest average runs scored.</p>
<h3>Overview</h3>
<p>Simulation flow. This flowchart refers to the parameter <em>g</em> which is a configurable value indicating the number of games to simulate. The stages with thick black outlines have sections w/ additional details below.</p>
<div class="mermaid">
flowchart TD;
A[Select a lineup from<br> the lineup pool.]:::addtDoc-->B;
B[Simulate a game,<br>remember the number<br> of runs scored.]:::addtDoc-->D
D{Have we simulated<br>more than *g* games?}--yes-->E
D--no-->B
E[Compute the mean <br>score of all simulated<br> games using this lineup.]-->F
F{Is this lineup's <br>mean game score better <br>than all the others we<br> have simulated?}--yes-->G
F--no-->I
G[Remember this lineup<br> as bestLineup and its<br> mean score as bestScore.]-->I
I{Is the lineup pool<br> depleted?}--yes-->J
I--no-->A
J[Done! Print the bestLineup <br>and bestScore that we<br> remembered earlier.]
classDef addtDoc stroke:#333,stroke-width:4px;
</div>
<h3>The Lineup Pool</h3>
<p>This optimizer simulates games for all possible lineups. The number of possible lineups for each lineup type is given by these equations where 'm' is the number of male batters and 'f' is the number of female batters:</p>
<h4>Normal/Ordinary/No Restrictions</h4>
<div class="katex">
numberOfLineups = (m+f)!
</div>
<h4>Alternating Gender</h4>
<div class="katex">
numberOfLineups = (m! + f!) * 2
</div>
<h4>No Consecutive Females</h4>
<div class="katex">
numberOfLineups = m! * f! * (\\binom{m}{f} + \\binom{m-1}{f-1})
</div>
<h4>Performance</h4>
<p>Because of the factorial nature of these equations, adding even one more player to the lineup can make the optimizer take significantly longer to run.</p>
<p>Example simulation (7 innings, 10000 games)</p>
<table><thead><tr><th># players in lineup</th><th>possible lineups</th><th>runtime (ms)</th><th>~runtime (human)</th></tr></thead><tbody><tr><td>6</td><td>720</td><td>1958</td><td>2 seconds</td></tr><tr><td>7</td><td>5,040</td><td>15982</td><td>16 seconds</td></tr><tr><td>8</td><td>40,320</td><td>135255</td><td>2 minutes</td></tr><tr><td>9</td><td>362,880</td><td>832902</td><td>14 minutes</td></tr><tr><td>10</td><td>3,628,800</td><td>6613484</td><td>2 hours</td></tr></tbody></table>
<h3>Simulating a game</h3>
<p>This flowchart refers to the parameter <em>i</em> which is a configurable value indicating the number of innings to simulate (typically 9 for baseball, 7 for softball, but can be anything). Same as before, the stage with the thick black outline has a section w/ additional details below.
Simulate a game</p>
<div class="mermaid">
flowchart TD;
B[Set active batter to<br>the first player <br>in the lineup.]-->C
C{Simulate a <br> plate appearance <br> for the active batter.}:::addtDoc--Result: 0-->D
C--Result: 1,2,3,4-->E
D[Increment the<br> number of outs <br>by one]-->F
E["Advance the runners. <br> Increase score if the<br>plate appearance <br>drove home (a) run(s)."]-->G
F[> 3 outs?]--no--> G
F--yes-->I
G[Set active batter to<br>the next batter <br>in the lineup.]
G-->C
I{Have we <br>simulated more <br>than *i* innings?}--yes-->J
I--no--> K
J[Done! Return the score<br> for this simulated game.]
K[Increment the <br>number of innings<br> simulated by one. <br> Clear the bases. <br> Clear the outs.]-->G
classDef addtDoc stroke:#333,stroke-width:4px;
</div>
<h3>Simulate a Plate Appearance</h3>
<p>Each plate appearance result (Out, SAC, E, BB, 1B, 2B, 3B, HRi, HRo) is mapped to a number indicating the number of bases awarded for that plate appearance. The mapping is illustrated in this table:</p>
<table><thead><tr><th>Result</th><th>Bases</th></tr></thead><tbody><tr><td>Out, SAC*, E, K</td><td>0</td></tr><tr><td>1B, BB*</td><td>1</td></tr><tr><td>2B</td><td>2</td></tr><tr><td>3B</td><td>3</td></tr><tr><td>HRi, HRo</td><td>4</td></tr></tbody></table>
<p>We can then use the frequency of each type of hit to build a distribution that reflects the way any given player is likely perform when they get a plate appearance. Whenever we need to simulate a hit for that player, we draw a random sample from that player's distribution.</p>
<h4>An Example</h4>
<p>Tim's historical at bats are as follows:
Out,1B,2B,SAC,E,HRo,3B,1B,1B,Out,Out,2B,1B,Out,Out</p>
<p>First we translate those hits to number of bases using our mapping from the table above:
0,1,2,0,0,4,3,1,1,0,0,2,1,0,0</p>
<p>Then we determine the histogram and chance of each hit:</p>
<table><thead><tr><th># of bases</th><th># of times</th><th>% of plate appearances</th></tr></thead><tbody><tr><td>0</td><td>7</td><td>47</td></tr><tr><td>1</td><td>4</td><td>27</td></tr><tr><td>2</td><td>2</td><td>13</td></tr><tr><td>3</td><td>1</td><td>7</td></tr><tr><td>4</td><td>1</td><td>7</td></tr></tbody></table>
<p>And every time we simulate a plate appearance for Tim, we'll draw a random hit with that distribution. That is to say, for every simulated plate appearance, Tim has a 47% of getting out, 27% chance of getting a single, a 13% chance of getting a double, a 7% chance of getting a triple, and a 7% chance of getting a home run. Of course, other players will have their own distribution of hits to draw from based of their historical performance.</p>
<h3>Other Notes</h3>
<p>Things that are not accounted for in the simulation:</p>
<ul><li>Double/triple plays</li><li>Stolen bases</li><li>Players who were on base advancing more bases than the hitter</li><li>Any pitching data</li></ul>
<p><em>*We can debate about how walks or sacrifices should be counted. It probably depends on what flavor of the sport you are playing. IMHO sacrifices should be counted as outs in slowpitch softball and kickball, but not baseball or fastpitch. In any event, these mapping are configurable (or will be configurable soon). So you are welcome to impose your own philosophy.</em></p>
</div><div class="gallery-fade"></div><div id="button- 3" class="gallery-tile-add-button add-button hidden" onClick="selectToggleClick("3",event)">+ Add</div></div></div></div><div id="optimizer-modal" class="modal"><div class="modal-content"><span class="close">×</span><div id="modal-body"><div class="loader"></div></div></div></div></main></body><script type="text/javascript" src="js/script.js"></script></html>