Skip to content

Commit 4b3d779

Browse files
committed
Add support for Ohtani DH rule
This adjusts the statistical tabulation for starting pitchers who DH for themselves. These players are considered to have two distinct identities within the game for lineup and substitution purposes. We adopt the convention that batting and non-pitcher fielding statistics are tabulated against the boxscore entry in the batting order, and pitching and pitcher fielding statistics against the non-batting-order identity.
1 parent 5c27426 commit 4b3d779

File tree

12 files changed

+63
-33
lines changed

12 files changed

+63
-33
lines changed

ChangeLog.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# [0.9.3] - 2022-04-08
2+
3+
## Behaviour changes
4+
- The new DH rule for the 2022 season allows a starting pitcher to DH for
5+
himself. Per the text of the rule, such a player has two identities in the
6+
lineup, one in his role as the DH in the batting order, and another as the
7+
pitcher in batting order slot zero (in DiamondWare terminology).
8+
DiamondWare files follow this convention by listing the player with two
9+
start records. This version separates the statistical tabulation for the
10+
two identities, with batting (and non-pitcher fielding) statistics for
11+
such a player appearing in his record in the batting order, and his
12+
pitching (and pitcher fielding) statistics appearing in his slot-zero entry.
13+
14+
115
# [0.9.2] - 2022-01-10
216

317
## New features

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#
2323

2424

25-
AC_INIT([chadwick],[0.9.2])
25+
AC_INIT([chadwick],[0.9.3])
2626
AC_CONFIG_SRCDIR([src/cwlib/chadwick.h])
2727
AC_CONFIG_MACRO_DIR([m4])
2828
AM_INIT_AUTOMAKE([foreign])

doc/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@
4545
# built documents.
4646
#
4747
# The short X.Y version.
48-
version = '0.9.2'
48+
version = '0.9.3'
4949
# The full version, including alpha/beta/rc tags.
50-
release = '0.9.2'
50+
release = '0.9.3'
5151

5252
# The language for content autogenerated by Sphinx. Refer to documentation
5353
# for a list of supported languages.

src/cwlib/box.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -392,18 +392,22 @@ cw_box_add_substitute(CWBoxscore *boxscore, CWGameIterator *gameiter)
392392
}
393393

394394
/*
395-
* Find the boxscore entry for player with ID player_id
395+
* Find the boxscore entry for player with ID player_id.
396+
* If batter is nonzero, search only for batting entries; this implements
397+
* the 'Ohtani rule' for DHes, in which a player who DHes for himself
398+
* has two identities within the game, one in the batting order and
399+
* one as the DHed-for pitcher.
396400
*/
397401
CWBoxPlayer *
398-
cw_box_find_player(CWBoxscore *boxscore, char *player_id)
402+
cw_box_find_player(CWBoxscore *boxscore, char *player_id, int batter)
399403
{
400404
int i, t;
401405

402406
if (player_id == NULL) {
403407
return NULL;
404408
}
405409
for (t = 0; t <= 1; t++) {
406-
for (i = 0; i <= 9; i++) {
410+
for (i = (batter) ? 1 : 0; i <= 9; i++) {
407411
CWBoxPlayer *player = boxscore->slots[i][t];
408412
while (player != NULL) {
409413
if (!strcmp(player->player_id, player_id)) {
@@ -616,7 +620,8 @@ cw_box_batter_stats(CWBoxscore *boxscore, CWGameIterator *gameiter)
616620
player = cw_box_find_player(boxscore,
617621
cw_gamestate_charged_batter(gameiter->state,
618622
gameiter->event->batter,
619-
event_data));
623+
event_data),
624+
1);
620625
if (cw_event_is_batter(event_data) && player == NULL) {
621626
/* If not a batter event, we will be tolerant if the player ID
622627
* in the batter field is bogus.
@@ -1319,7 +1324,8 @@ cw_box_process_boxscore_file(CWBoxscore *boxscore, CWGame *game)
13191324
team = cw_data_get_item_int(stat, 2);
13201325
seq = cw_data_get_item_int(stat, 3);
13211326
pos = cw_data_get_item_int(stat, 4);
1322-
player = cw_box_find_player(boxscore, stat->data[1]);
1327+
player = cw_box_find_player(boxscore, stat->data[1],
1328+
(pos != 1) ? 1 : 0);
13231329
if (player == NULL) {
13241330
fprintf(stderr,
13251331
"ERROR: In %s, cannot find entry for player '%s' listed in dline.\n",
@@ -1348,7 +1354,7 @@ cw_box_process_boxscore_file(CWBoxscore *boxscore, CWGame *game)
13481354
}
13491355
else if (!strcmp(stat->data[0], "phline")) {
13501356
team = cw_data_get_item_int(stat, 3);
1351-
player = cw_box_find_player(boxscore, stat->data[1]);
1357+
player = cw_box_find_player(boxscore, stat->data[1], 1);
13521358
if (player == NULL) {
13531359
fprintf(stderr,
13541360
"ERROR: In %s, cannot find entry for player '%s' listed in phline.\n",
@@ -1359,7 +1365,7 @@ cw_box_process_boxscore_file(CWBoxscore *boxscore, CWGame *game)
13591365
}
13601366
else if (!strcmp(stat->data[0], "prline")) {
13611367
team = cw_data_get_item_int(stat, 3);
1362-
player = cw_box_find_player(boxscore, stat->data[1]);
1368+
player = cw_box_find_player(boxscore, stat->data[1], 1);
13631369
if (player == NULL) {
13641370
fprintf(stderr,
13651371
"ERROR: In %s, cannot find entry for player '%s' listed in prline.\n",
@@ -1487,7 +1493,7 @@ cw_box_create(CWGame *game)
14871493
if (pitcher != NULL) pitcher->pitching->sv = 1;
14881494
}
14891495
if (cw_game_info_lookup(game, "gwrbi") != NULL) {
1490-
batter = cw_box_find_player(boxscore, cw_game_info_lookup(game, "gwrbi"));
1496+
batter = cw_box_find_player(boxscore, cw_game_info_lookup(game, "gwrbi"), 1);
14911497
if (batter != NULL) batter->batting->gw = 1;
14921498
}
14931499
return boxscore;

src/cwlib/box.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ CWBoxPitcher *cw_box_get_starting_pitcher(CWBoxscore *boxscore, int team);
149149
/*
150150
* Find the player entry for player with ID player_id
151151
*/
152-
CWBoxPlayer *cw_box_find_player(CWBoxscore *boxscore, char *player_id);
152+
CWBoxPlayer *cw_box_find_player(CWBoxscore *boxscore, char *player_id,
153+
int batter);
153154

154155
/*
155156
* Find the pitching entry for player with ID player_id

src/cwlib/file.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,19 @@ char *cw_strtok(char *strToken)
134134
* for invalid values.
135135
*/
136136
int
137-
cw_atoi(char *s)
137+
cw_atoi(char *s, char *msg)
138138
{
139139
char *end = NULL;
140140
long temp = strtol(s, &end, 10);
141141
if (end != s && errno != ERANGE && temp >= INT_MIN && temp <= INT_MAX) {
142142
return (int) temp;
143143
}
144-
fprintf(stderr, "Warning: Invalid integer value '%s'\n", s);
144+
if (msg != NULL) {
145+
fprintf(stderr, msg, s);
146+
}
147+
else {
148+
fprintf(stderr, "Warning: Invalid integer value '%s'\n", s);
149+
}
145150
return -1;
146151
}
147152

src/cwlib/file.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ char *cw_strtok(char *strToken);
3333
/*
3434
* A replacement for C atoi(), which does validity checking and returns
3535
* -1 as the "null" value for invalid inputs.
36+
* If 'msg' is specified and not null, it is used as the format string
37+
* to print a warning message.
3638
*/
37-
int cw_atoi(char *s);
39+
int cw_atoi(char *s, char *msg);
3840

3941
/*
4042
* Searches for the game 'game_id' in 'file'; sets the file pointer to

src/cwlib/game.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ int cw_data_get_item_int(CWData *data, unsigned int index)
3535
if (index >= data->num_data) {
3636
return -1;
3737
}
38-
return cw_atoi(data->data[index]);
38+
return cw_atoi(data->data[index], NULL);
3939
}
4040

4141
CWGame *cw_game_create(char *game_id)
@@ -726,8 +726,8 @@ cw_game_read(FILE *file)
726726
pos = cw_strtok(NULL);
727727
if (player_id && name && team && slot && pos) {
728728
cw_game_starter_append(game, player_id, name,
729-
cw_atoi(team), cw_atoi(slot),
730-
cw_atoi(pos));
729+
cw_atoi(team, NULL), cw_atoi(slot, NULL),
730+
cw_atoi(pos, NULL));
731731
}
732732
}
733733
else if (!strcmp(tok, "play")) {
@@ -739,7 +739,9 @@ cw_game_read(FILE *file)
739739
pitches = cw_strtok(NULL);
740740
play = cw_strtok(NULL);
741741
if (inning && batting_team && batter && count && pitches && play) {
742-
cw_game_event_append(game, cw_atoi(inning), cw_atoi(batting_team),
742+
cw_game_event_append(game,
743+
cw_atoi(inning, NULL),
744+
cw_atoi(batting_team, NULL),
743745
batter, count, pitches, play);
744746
}
745747
if (batHand != ' ' && !strcmp(batHandBatter, batter)) {
@@ -781,8 +783,8 @@ cw_game_read(FILE *file)
781783
pos = cw_strtok(NULL);
782784
if (player_id && name && team && slot && pos) {
783785
cw_game_substitute_append(game, player_id, name,
784-
cw_atoi(team), cw_atoi(slot),
785-
cw_atoi(pos));
786+
cw_atoi(team, NULL), cw_atoi(slot, NULL),
787+
cw_atoi(pos, NULL));
786788
}
787789
}
788790
else if (!strcmp(tok, "com")) {
@@ -863,8 +865,8 @@ cw_game_read(FILE *file)
863865
align = cw_strtok(NULL);
864866
slot = cw_strtok(NULL);
865867
if (align && slot) {
866-
ladjAlign = cw_atoi(align);
867-
ladjSlot = cw_atoi(slot);
868+
ladjAlign = cw_atoi(align, NULL);
869+
ladjSlot = cw_atoi(slot, NULL);
868870
}
869871
}
870872
else if (!strcmp(tok, "cw:itb") | !strcmp(tok, "radj")) {
@@ -878,7 +880,7 @@ cw_game_read(FILE *file)
878880
base = cw_strtok(NULL);
879881
if (runner && base) {
880882
strncpy(autoRunner, runner, 255);
881-
autoBase = cw_atoi(base);
883+
autoBase = cw_atoi(base, NULL);
882884
}
883885
}
884886
}

src/cwtools/cwboxsml.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,8 +1402,8 @@ cwbox_event_metadata(XMLNode *parent, CWGame *game)
14021402
}
14031403

14041404
xml_node_attribute_int(node, "game-of-day",
1405-
(cw_atoi(cw_game_info_lookup(game, "number")) == 0) ? 1 :
1406-
cw_atoi(cw_game_info_lookup(game, "number")));
1405+
(cw_atoi(cw_game_info_lookup(game, "number"), NULL) == 0) ? 1 :
1406+
cw_atoi(cw_game_info_lookup(game, "number"), NULL));
14071407

14081408
if (cw_game_info_lookup(game, "htbf") &&
14091409
!strcmp(cw_game_info_lookup(game, "htbf"), "true")) {

src/cwtools/cwdaily.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ DECLARE_FIELDFUNC(cwdaily_number)
122122
char *tmp;
123123
return sprintf(buffer, (ascii) ? "%d" : "%5d",
124124
(tmp = cw_game_info_lookup(gameiter->game, "number")) ?
125-
cw_atoi(tmp) : 0);
125+
cw_atoi(tmp, NULL) : 0);
126126
}
127127

128128
/* Field 3 */

0 commit comments

Comments
 (0)