File Coverage

blib/lib/Baseball/Simulation.pm
Criterion Covered Total %
statement 195 205 95.1
branch 80 92 86.9
condition 21 29 72.4
subroutine 11 12 91.6
pod 0 9 0.0
total 307 347 88.4


line stmt bran cond sub pod time code
1             package Baseball::Simulation;
2              
3 1     1   656 use 5.008;
  1         4  
  1         38  
4 1     1   6 use strict;
  1         1  
  1         29  
5 1     1   4 use warnings;
  1         4  
  1         2411  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             our @EXPORT_OK = ( );
12              
13             our @EXPORT = (
14             );
15              
16             our $VERSION = '0.10';
17              
18             #The Global Parameters that are the arguments
19             my %arg;
20             my $TeamBattingFile = "";
21             my $TeamPitchingFile = "";
22             my $NumOfSeasons = 1;
23              
24             #Global variables used by various arguments
25             my @Lineup;
26             my @PitchingLineup;
27              
28             ##################################################
29             # new
30             #
31             # Parameters: An argument list containing:
32             # BattingFile - The batters file stats
33             # PitchingFile - The batters file stats
34             # Seasons - the number of seasons to simulate
35             # (default 1)
36             #
37             # Description: Creates an object and checks if the parameters are
38             # correct..
39             #
40             # Returns: Return itself unless there is a parameter error, in which
41             # it dies
42             #
43             ##################################################
44             sub new {
45 1     1 0 91690 my $class = shift;
46 1         13 %arg = @_;
47              
48 1         6 $TeamBattingFile = $arg{'BattingFile'};
49 1         3 $TeamPitchingFile = $arg{'PitchingFile'};
50 1   50     10 $NumOfSeasons = $arg{'Seasons'} || 1;
51              
52 1 50       24 unless (-e $TeamBattingFile) {
53 0         0 die "Cannot open the batting file: $TeamBattingFile";
54             }
55              
56 1 50       17 unless (-e $TeamPitchingFile) {
57 0         0 die "Cannot open the pitching file: $TeamPitchingFile";
58             }
59              
60 1         5 @Lineup = CreateBatterArray(CreateNewLineup($TeamBattingFile));
61            
62 1         3 @PitchingLineup= CreateBatterArray(CreateNewLineup($TeamPitchingFile));
63              
64 1         8 return bless{}, $class;
65             }
66              
67             ##################################################
68             # Round
69             #
70             # Parameters: un unrounded number
71             #
72             # Description: Rounds a number
73             #
74             # Returns: The rounded number
75             #
76             ##################################################
77             sub Round($) {
78 0     0 0 0 my $Float = $_[0];
79 0         0 $Float += 0.5;
80 0         0 return int($Float);
81             }
82              
83             ##################################################
84             # StripLine
85             #
86             # Parameters: A line with white surrounding white space and comments
87             #
88             # Description: Removes surrounding white space and comments
89             #
90             # Returns: A cleaned up line
91             #
92             ##################################################
93             sub StripLine($) {
94 16     16 0 26 my $LineToBeParsed = $_[0]; # The text to be stripped
95 16         25 chomp $LineToBeParsed; # Get rid of line feed
96            
97             # Delete leading spaces;
98 16 50       57 if ( $LineToBeParsed =~ /^\s+/ ) {
99 0         0 $LineToBeParsed = $'; #'
100             }
101            
102             # Check for comment characters
103 16 100       51 if ( $LineToBeParsed =~ /#/ ) {
104 6         16 $LineToBeParsed = $`;
105             }
106             # Delete the ending spaces
107 16 50       44 if ( $LineToBeParsed =~ /\s+$/ ) {
108 0         0 $LineToBeParsed = $`;
109             }
110            
111 16         37 return $LineToBeParsed;
112             }
113              
114             ##################################################
115             # CreateBatter
116             #
117             # Paramenters: The array consisting the cumalitve totals for:
118             # At-Bats
119             # Walks
120             # Singles
121             # Doubles
122             # Triples
123             # Homers
124             # StolenBases
125             #
126             # Description: Calculates the averages for the batting statistics
127             #
128             # Returns: The array consisting the cumalitve averages for:
129             # WalkChance - The percentage for a walk
130             # SingleChance - The percentage that a single can be hit
131             # DoubleChance - The percentage that a single can be hit
132             # TripleChance - The percentage that a single can be hit
133             # HomerChance - The percentage that a single can be hit
134             # SacChance - The percentage that a sacrifice occurs
135             # StolenBaseChance - The percentage that a stolen base occurs
136             #
137             ##################################################
138             sub CreateBatterArray(@) {
139 2     2 0 6 my ($AtBats, $Hits, $Doubles, $Triples, $Homers, $Walks, $Steals) = @_;
140 2         3 my $TotalAtBats = $AtBats + $Walks;
141 2         4 my $Singles = $Hits - $Doubles - $Triples - $Homers;
142 2         8 my $WalkChance = int (($Walks / $TotalAtBats) * 1000);
143 2         11 my $SinglesChance = int (($Singles / $TotalAtBats) * 1000);
144 2         4 my $DoublesChance = int (($Doubles / $TotalAtBats) * 1000);
145 2         5 my $TriplesChance = int (($Triples / $TotalAtBats) * 1000);
146 2         3 my $HomersChance = int (($Homers / $TotalAtBats) * 1000);
147 2         3 my $StealsChance = int ($Steals / ($Walks + $Singles));
148 2         3 my $SacrificeChance = 0;
149              
150 2         8 return ($WalkChance, $SinglesChance, $DoublesChance, $TriplesChance, $HomersChance, $SacrificeChance, $StealsChance);
151             }
152              
153             ##################################################
154             # CreateNewLineup
155             #
156             # Parameters: The file of user list
157             #
158             # Description: Reads the stats from a file, adding the additions
159             # and subtracting the subtractions
160             #
161             # Returns: The array consisting the cumalitve totals for:
162             # At-Bats
163             # Walks
164             # Singles
165             # Doubles
166             # Triples
167             # Homers
168             # StolenBases
169             #
170             ##################################################
171             sub CreateNewLineup($) {
172 2     2 0 6 my $File = $_[0];
173 2         7 my @TotalStats = (0,0,0,0,0,0,0);;
174 2         5 my @PlayerStats = (0,0,0,0,0,0,0);
175 2         7 my $Line;
176              
177 2 50       75 open(INFILE, "$File") || die "Cannot open $File";
178 2         59 my @FileLines = ;
179 2         23 close(INFILE);
180            
181 2         3 my $i = 0;
182 2         5 my $MaxLine = @FileLines;
183 2   33     22 while (($Line = $FileLines[$i++]) && ($i <= $MaxLine)){
184 2         7 $Line = StripLine($Line);
185 2 50       6 next unless ($Line);
186 2         14 @TotalStats = split /\:/, $Line;
187 2 50       10 if ($#TotalStats + 1 != 7) {
188 0         0 die "The following line does not contain 7 double colon seperated values: $Line";
189             }
190 2         6 last;
191             }
192              
193 2   66     13 while (($Line = $FileLines[$i++]) && ($i <= $MaxLine)){
194 1         7 $Line = StripLine($Line);
195 1 50       22 last if ($Line =~ /additions/i);
196             }
197              
198 2         4 my $l = 0;
199 2   66     24 while (($Line = $FileLines[$i++]) && ($i <= $MaxLine)){
200 5         11 $Line = StripLine($Line);
201 5 100       16 last if ($Line =~ /sub/i);
202 4 100       18 if ($Line) {
203 2         4 my $j = 0;
204 2         12 @PlayerStats = split /\:/, $Line;
205 2 50       7 if ($#PlayerStats + 1 != 7) {
206 0         0 die "The following line does not contain 7 double colon seperated values: $Line";
207             }
208 2         7 for ($l = 0; $l < 7; $l++) {
209 14         47 $TotalStats[$l] += $PlayerStats[$l];
210             }
211             }
212             }
213              
214 2   66     23 while (($Line = $FileLines[$i++]) && ($i <= $MaxLine)){
215 8         13 $Line = StripLine($Line);
216 8 100       37 if ($Line) {
217 4         21 @PlayerStats = split /\:/, $Line;
218 4 50       15 if ($#PlayerStats + 1 != 7) {
219 0         0 die "The following line does not contain 7 double colon seperated values: $Line";
220             }
221 4         13 for ($l = 0; $l < 7; $l++) {
222 28         81 $TotalStats[$l] -= $PlayerStats[$l];
223             }
224             }
225             }
226              
227 2         41 return @TotalStats;
228             }
229              
230             ##################################################
231             # AtBat
232             #
233             # Parameters: WalkChance - The percentage for a walk
234             # SingleChance - The percentage that a single can be hit
235             # DoubleChance - The percentage that a single can be hit
236             # TripleChance - The percentage that a single can be hit
237             # HomerChance - The percentage that a single can be hit
238             # SacChance - The percentage that a single can be hit
239             # StolenBaseChance - The percentage that a single can be hit
240             #
241             # Description: Simulates an at-bat
242             #
243             # Returns: The result - -1 = walk
244             # 0 = out
245             # 1 = single
246             # 2 = double
247             # 3 = triple
248             # 4 = home run
249             #
250             ##################################################
251             #ignore double plays and sacrifices for now
252             sub AtBat(@) {
253 264948     264948 0 343633 my $WalkChance = 0;
254 264948         326861 my $SingleChance = 0;
255 264948         370140 my $DoubleChance = 0;
256 264948         314583 my $TripleChance = 0;
257 264948         292434 my $HomerChance = 0;
258 264948         298669 my $SacChance = 0;
259 264948         300778 my $StolenBaseChance = 0;
260 264948         267679 my $Random2 = 0;
261 264948         516967 ($WalkChance, $SingleChance, $DoubleChance, $TripleChance, $HomerChance, $SacChance, $StolenBaseChance) = @_;
262            
263 264948         567086 $Random2 = (((int (rand(10000))) + (int (rand(2000))))
264             % 1000);
265              
266 264948 100       1353396 if ($Random2 < $WalkChance) {
    100          
    100          
    100          
    100          
267 20954         48889 return -1;
268             } elsif ($Random2 < ($SingleChance + $WalkChance)) {
269 42153         90519 return 1;
270             } elsif ($Random2 < ($SingleChance + $WalkChance + $DoubleChance)) {
271 12774         22610 return 2;
272             } elsif ($Random2 < ($SingleChance + $WalkChance + $DoubleChance + $TripleChance)) {
273 1467         2732 return 3;
274             } elsif ($Random2 < ($SingleChance + $WalkChance + $DoubleChance + $TripleChance + $HomerChance)) {
275 8446         27271 return 4;
276             }
277              
278 179154         357657 return 0;
279             }
280              
281             ##################################################
282             # AdvanceRunner
283             #
284             # Parameters: Result - the result of the at bat
285             # PlayerStealChance - the player's chance of stealing
286             # FirstBase - whether someone is on first
287             # FirstBaseStealChance - the guys on first's chance of stealing
288             # SecondBase - whether someone is on second
289             # SecondBaseStealChance - the guys on third's chance of stealing
290             # ThirdBase - whether someone is on third
291             # Score - The score so far
292             #
293             # Description: Advances runners after an at-bat
294             #
295             # Returns: Updated values for: $FirstBase, $FirstBaseStealChance, $
296             # SecondBase, $SecondBaseStealChance, $ThirdBase, $Score
297             #
298             ##################################################
299             sub AdvanceRunner($$$$$$$$) {
300 205230     205230 0 362758 my ($Result, $PlayerStealChance, $FirstBase, $FirstBaseStealChance, $SecondBase, $SecondBaseStealChance, $ThirdBase, $Score) = @_;
301              
302 205230 100       923619 if ($Result == -1) {
    100          
    100          
    100          
    100          
    50          
303 20954 100 100     218320 if ($FirstBase && $SecondBase && $ThirdBase) {
    100 100        
    100 100        
304             #Advance all one
305 235         253 $Score++;
306 235         303 $SecondBaseStealChance = $FirstBaseStealChance;
307             } elsif ($FirstBase && $SecondBase) {
308             #Advance the first two one
309 1138         5217 $SecondBaseStealChance = $FirstBaseStealChance;
310 1138         1348 $ThirdBase = 1;
311             } elsif ($FirstBase) {
312             #Advance the first base
313 5828         7061 $SecondBaseStealChance = $FirstBaseStealChance;
314 5828         7633 $SecondBase = 1;
315             }
316 20954         29699 $FirstBase = 1;
317 20954         24402 $FirstBaseStealChance = $PlayerStealChance;
318             } elsif ($Result == 1) {
319             #ThirdBase always scores
320 42153 100       95596 if ($ThirdBase) {
321 3603         3584 $Score++;
322 3603         4273 $ThirdBase = 0;
323             }
324 42153 100       131777 if ($SecondBase) {
    100          
325 7221         8356 $SecondBase = 0;
326             #There is a 70% chance the guy from second score
327 7221 100       13388 if (rand (10) < 7) {
328 5036         5956 $Score++;
329             } else {
330 2185         2834 $ThirdBase = 0;
331             }
332              
333             } elsif ($FirstBase) {
334             #There is a 70% chance the guy from second score
335 11740 100       21742 if (rand (10) < 7) {
336 8158         11520 $ThirdBase = 1;
337             } else {
338 3582         3841 $SecondBase = 1;
339 3582         4080 $SecondBaseStealChance = $FirstBaseStealChance;
340             }
341             }
342 42153         62632 $FirstBaseStealChance = $PlayerStealChance;
343 42153         54801 $FirstBase = 1;
344             } elsif ($Result == 2) {
345 12774         18425 $Score = $Score + $SecondBase + $ThirdBase;
346 12774         12483 $ThirdBase = 0;
347 12774         14211 $SecondBase = 1;
348             #There is a 70% chance the guy from first scores
349 12774 100       27593 if ($FirstBase) {
350 4457 100       30500 if (rand (10) < 7) {
351 3108         3751 $Score += $FirstBase;
352 3108         3663 $ThirdBase = 0;
353             } else {
354 1349         1865 $ThirdBase = 1;
355             }
356             }
357 12774         15697 $FirstBase = 0;
358 12774         14933 $SecondBaseStealChance = $PlayerStealChance;
359             } elsif ($Result == 3) {
360 1467         8130 $Score = $Score + $FirstBase + $SecondBase + $ThirdBase;
361 1467         1602 $FirstBase = 0;
362 1467         1485 $SecondBase = 0;
363 1467         2190 $ThirdBase = 1;
364             } elsif ($Result == 4) {
365 8446         25281 $Score = $Score + $FirstBase + $SecondBase + $ThirdBase + 1;
366 8446         10463 $FirstBase = 0;
367 8446         14007 $SecondBase = 0;
368 8446         11322 $ThirdBase = 0;
369             } elsif ($Result == 0) {
370 119436 100 66     700027 if ($ThirdBase) {
    100 66        
    100          
371             #Sacrifice for third
372 7213 100       15927 if (rand (10) < 4) {
373 2849         3190 $Score++;
374 2849         3725 $ThirdBase = 0;
375             }
376             } elsif($SecondBase && !$ThirdBase) {
377 13779 100       38413 if (rand (10) < 3) {
378 4119         5219 $ThirdBase = 1;
379 4119         5015 $SecondBase = 0;
380             }
381             } elsif($FirstBase && !$SecondBase) {
382 25590 100       78436 if (rand (10) < 3) {
383 7724         8561 $SecondBase = 1;
384 7724         7587 $FirstBase = 0;
385 7724         9793 $SecondBaseStealChance = $FirstBaseStealChance;
386             }
387             }
388             }
389              
390 205230         964267 return ($FirstBase, $FirstBaseStealChance, $SecondBase, $SecondBaseStealChance, $ThirdBase, $Score);
391             }
392              
393             ##################################################
394             # Inning
395             #
396             # Parameters: Who is batting - 1 if the team is batting
397             # - 0 if the other team is batting
398             #
399             # Description: Simulates an inning
400             #
401             # Returns: Returns the score from that inning
402             #
403             ##################################################
404             sub Inning($) {
405 59718     59718 0 100691 my $Who = $_[0];
406 59718         79366 my $Outs = 0;
407 59718         91587 my $FirstBase = 0;
408 59718         62508 my $FirstBaseStealChance = 0;
409 59718         63304 my $SecondBase = 0;
410 59718         63160 my $SecondBaseStealChance = 0;
411 59718         60989 my $ThirdBase = 0;
412 59718         112043 my $Score = 0;
413 59718         61439 my $Result = 0;
414 59718         130790 my @Player = "";
415              
416 59718 100       113985 if ($Who) {
417 29859         80873 @Player = @Lineup;
418             } else {
419 29859         88873 @Player = @PitchingLineup;
420             }
421              
422 59718         165054 while ($Outs < 3) {
423 264948         550046 $Result = AtBat(@Player);
424 264948 100       715346 if (!$Result) {
425 179154         242619 $Outs++;
426 264948 100       726257 } if ($Outs < 3) {
427 205230         525962 ($FirstBase, $FirstBaseStealChance, $SecondBase, $SecondBaseStealChance, $ThirdBase, $Score) = AdvanceRunner($Result, $Player[6], $FirstBase, $FirstBaseStealChance, $SecondBase, $SecondBaseStealChance, $ThirdBase, $Score);
428             }
429             }
430              
431 59718         279534 return $Score;
432             }
433              
434             ##################################################
435             # Simulate
436             #
437             # Parameters: None
438             #
439             # Description: Simulates the season
440             #
441             # Returns: Average victories per season
442             # Average defeats per season
443             # Average runs scored per season
444             # Average runs allowed per season
445             #
446             ##################################################
447             sub Simulate() {
448 1     1 0 7 my $TotalVictories = 0;
449 1         2 my $TotalDefeats = 0;
450 1         2 my $SingleOtherScore = 0;
451 1         2 my $TotalScore = 0;
452 1         2 my $TotalOtherScore = 0;
453            
454 1         1 my $i = 0;
455 1         2 my $k = 0;
456              
457 1         5 for ($k = 0; $k < $NumOfSeasons; $k++) {
458 20         24 my $Victories = 0;
459 20         24 my $Defeats = 0;
460 20         21 my $SingleScore = 0;
461 20         18 my $j = 0;
462              
463 20         43 for ($j = 0; $j < 162; $j++) {
464 3240         3290 $SingleScore = 0;
465 3240         7494 for ($i = 1; $i <= 9; $i++) {
466 29160         51771 $SingleScore += Inning(1);
467             }
468              
469             #The opposing team
470 3240         3664 $SingleOtherScore = 0;
471 3240         6859 for ($i = 1; $i <= 9; $i++) {
472 29160         61953 $SingleOtherScore += Inning(0);
473             }
474              
475              
476 3240         8531 while ($SingleScore == $SingleOtherScore) {
477 699         1359 $SingleScore +=Inning(1);
478 699         1411 $SingleOtherScore +=Inning(0);
479             }
480              
481 3240 100       14365 if ($SingleScore > $SingleOtherScore) {
    50          
482 1419         1707 $Victories++;
483             } elsif ($SingleScore < $SingleOtherScore) {
484 1821         2113 $Defeats++;
485             }
486            
487            
488 3240         3680 $TotalScore +=$SingleScore;
489            
490 3240         10286 $TotalOtherScore +=$SingleOtherScore;
491             }
492              
493 20         37 $TotalVictories += $Victories;
494 20         65 $TotalDefeats += $Defeats;
495              
496             }
497              
498 1         13 return ($TotalVictories/$NumOfSeasons, $TotalDefeats/$NumOfSeasons, $TotalScore/$NumOfSeasons, $TotalOtherScore/$NumOfSeasons);
499             }
500              
501             1;
502             __END__