/* Program to do baseball career projections by Bill James's Brock2 system Copyright 1992, David Grabiner. This program may be used, copied, and modified freely, provided that this copyright notice is included in all copies. The Brock2 algorithm itself was placed in the public domain by Bill James. Version 1.1, June 4, 1995: adjusts for shortened seasons. Version 1.1.1, July 28, 1997: corrects typos in calculating AB for older players. */ #include /* Column numbers in the array of statistics */ #define GAMES 0 #define AB 1 #define RUNS 2 #define HITS 3 #define DOUBLES 4 #define TRIPLES 5 #define HOMERS 6 #define RBI 7 #define WALKS 8 #define NUMSTATS 9 /* number of stats to read from file */ #define AVERAGE 9 #define TOTALBASES 10 #define RC 11 #define RC25 12 #define SUSTENANCE 13 #define OKREGULAR 14 #define OKBENCH 15 #define PLAYFACTOR 16 #define PROJGAMES 17 #define LASTCOLUMN 17 #define MINAGE 20 /* youngest and lowest ages */ #define MAXAGE 41 /* to which method applies */ #define FIRST162 1962 /* Assumes NL; change 1962 to 1961 for AL */ #define TOTALS (MAXAGE-MINAGE+1) /* row for keeping career totals */ #define EPSILON .000001 /* used as denominator to avoid division by zero */ double stats[TOTALS+1][LASTCOLUMN+1]; int year, cumage, firstage, currage; double sustlevel; int age; int row, col; double a, tempavg; /* Round to nearest integer */ double round(value) double value; { int tempval; tempval = (int)(value + .5); return((double)tempval); } /* Read a line of stats from the input */ void readstatline(age) int age; { int row, col; { row = (age ? (age-MINAGE) : TOTALS); if (scanf ("%lf %lf %lf %lf %lf %lf %lf %lf %lf", &stats[row][0], &stats[row][1], &stats[row][2], &stats[row][3], &stats[row][4], &stats[row][5], &stats[row][6], &stats[row][7], &stats[row][8]) != 9) { (void)printf ("Invalid stat line format \n"); exit(1); } if (age > cumage) /* Must add to cumulative stats */ for (col = 0; col < NUMSTATS; col++) stats[TOTALS][col] += stats[row][col]; stats[row][AVERAGE] = stats[row][HITS] / (stats[row][AB] + EPSILON); } return; } /* Calculate auxilliary stats (runs created, etc.) */ void calcauxstats(row) int row; { stats[row][TOTALBASES] = stats[row][HITS] + stats[row][DOUBLES] + 2*stats[row][TRIPLES] + 3*stats[row][HOMERS]; /* protect against division by zero */ stats[row][RC] = stats[row][TOTALBASES] * (stats[row][HITS] + stats[row][WALKS]) / (stats[row][AB] + stats[row][WALKS] + EPSILON); stats[row][RC25] = stats[row][RC] * 25 / (stats[row][AB] - stats[row][HITS] + EPSILON); if (row >= (firstage-MINAGE)) { stats[row][OKREGULAR] = (stats[row][RC25] > stats[row][SUSTENANCE]); stats[row][OKBENCH] = (stats[row][RC25] > stats[row][SUSTENANCE] - (row > 12 ? .6 : 1)); } else /* Assume player was good enough to play before rookie year */ stats[row][OKREGULAR] = stats[row][OKBENCH] = 1; if (row < 1) stats[row][PLAYFACTOR] = 0; else if (row < 5) stats[row][PLAYFACTOR] = (stats[row][OKREGULAR] + stats[row-1][OKBENCH] + stats[row][OKBENCH]) / 3; else if (row < 11) stats[row][PLAYFACTOR] = (stats[row-1][OKREGULAR] + stats[row][OKREGULAR] + stats[row-1][OKBENCH] + stats[row][OKBENCH]) / 4; else stats[row][PLAYFACTOR] = (stats[row-2][OKREGULAR] + stats[row-1][OKREGULAR] + stats[row][OKREGULAR] + stats[row-1][OKBENCH] + stats[row][OKBENCH]) / 5; } main() { if (scanf("%d %d %d %d", &year, &cumage, &firstage, &currage) != 4) { (void)printf("Invalid age line format\n"); exit(1); } if ((cumage < firstage-1) || (cumage > currage) || (firstage > currage) || (firstage < MINAGE) || (currage > MAXAGE) || (currage <= MINAGE)) { (void)printf("Invalid ages on age line\n"); exit(1); } if (scanf("%lf", &sustlevel) != 1) { (void)printf("Sustenance level must be on second line\n"); exit(1); } /* Ignore line with stat column headings */ (void)getchar(); /* first ignore newline */ while (getchar() != '\n'); readstatline(0); /* Cumulative stats */ for (age = firstage; age <= currage; age++) { int seasonlength; readstatline(age); switch(year+age-cumage) /* project games to 162-game season */ { case 1972: /* Strike seasons */ seasonlength = 154; break; case 1981: seasonlength = 108; break; case 1994: seasonlength = 114; break; case 1995: seasonlength = 144; break; default: seasonlength = ((year+age-firstage)= 0) break; /* If negative denominator above, fall through and use another formula to increase walks */ case 7: case 13: stats[row][WALKS] = stats[row][AB] * ((stats[row-2][WALKS] + stats[row-1][WALKS] + 20) / (stats[row-2][AB] + stats[row-1][AB] + 100)); break; case 14: stats[row][WALKS] = stats[row][AB] * ((stats[row-2][WALKS] + stats[row-1][WALKS]) / (stats[row-2][AB] + stats[row-1][AB] + 100)); break; default: stats[row][WALKS] = stats[row][AB] * ((stats[row-2][WALKS] + stats[row-1][WALKS] + 10) / (stats[row-2][AB] + stats[row-1][AB] + 100)); break; } stats[row][AVERAGE] = round(stats[row][HITS]) / (EPSILON + round(stats[row][AB])); calcauxstats(row); /* Now we can calculate runs and RBI */ stats[row][RUNS] = stats[row-1][RUNS] * (stats[row][RC]/stats[row-1][RC]); stats[row][RBI] = stats[row][HOMERS] + .235 * stats[row][TOTALBASES]; for (col = 0; col < NUMSTATS; col++) stats[TOTALS][col] += round(stats[row][col]); } stats[TOTALS][AVERAGE] = stats[TOTALS][HITS] / stats[TOTALS][AB]; /* And now print out the career, including past years if we have data */ (void)printf(" YEAR G AB R H 2B 3B HR RBI BB AVG\n"); for (row = 0; row < TOTALS; row++) if (stats[row][GAMES] != 0) (void)printf("%6d %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.3f \n", year-cumage+MINAGE+row, stats[row][0], stats[row][1], stats[row][2], stats[row][3], stats[row][4], stats[row][5], stats[row][6], stats[row][7], stats[row][8], stats[row][9]); (void)printf("TOTALS %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.3f \n", stats[TOTALS][0], stats[TOTALS][1], stats[TOTALS][2], stats[TOTALS][3], stats[TOTALS][4], stats[TOTALS][5], stats[TOTALS][6], stats[TOTALS][7], stats[TOTALS][8], stats[TOTALS][9]); exit(0); }