13 #define MAX_CHAT_PATTERNS 500
20 char reply
[300]; // in printf format with one param (100*winrate)
27 static char default_reply
[] = "I know all those words, but that sentence makes no sense to me";
28 static char not_playing
[] = "I'm winning big without playing";
30 /* Read the chat file, a sequence of lines of the form:
31 * minwin;maxwin;from;regex;reply
32 * Set minwin, maxwin to -1.0 2.0 for answers to chat other than winrate.
33 * Set from as one space for replies to anyone.
35 * -1.0;0.3; ;winrate;%.1f%% I'm losing
36 * -1.0;2.0;pasky;^when ;Today
38 void chat_init(char *chat_file
) {
39 if (!chat_file
) return;
40 FILE *f
= fopen(chat_file
, "r");
45 chat_table
= calloc2(MAX_CHAT_PATTERNS
, sizeof(*chat_table
));
46 struct chat
*entry
= chat_table
;
47 while (fscanf(f
, "%lf;%lf;%20[^;];%100[^;];%300[^\n]\n", &entry
->minwin
, &entry
->maxwin
,
48 entry
->from
, entry
->regex
, entry
->reply
) == 5) {
49 if (!strcmp(entry
->from
, " "))
50 entry
->from
[0] = '\0';
51 int err
= regcomp(&entry
->preg
, entry
->regex
, REG_EXTENDED
| REG_ICASE
);
54 regerror(err
, &entry
->preg
, msg
, sizeof(msg
));
55 fprintf(stderr
, "Error compiling %s: %s\n", entry
->regex
, msg
);
61 fprintf(stderr
, "syntax error around line %ld in %s\n", entry
- chat_table
, chat_file
);
64 fprintf(stderr
, "Loaded %ld chat entries from %s\n", entry
- chat_table
, chat_file
);
74 /* Reply to a chat. When not playing, color is S_NONE and all remaining parameters are undefined.
75 * If some matching entries have not yet been displayed we pick randomly among them. Otherwise
76 * we pick randomly among all matching entries. */
78 *generic_chat(struct board
*b
, bool opponent
, char *from
, char *cmd
, enum stone color
, coord_t move
,
79 int playouts
, int machines
, int threads
, double winrate
, double extra_komi
) {
81 static char reply
[1024];
83 if (strncasecmp(cmd
, "winrate", 7)) return NULL
;
84 if (color
== S_NONE
) return not_playing
;
86 snprintf(reply
, 512, "In %d playouts at %d threads, %s %s can win with %.1f%% probability",
87 playouts
, threads
, stone2str(color
), coord2sstr(move
, b
), 100*winrate
);
88 if (abs(extra_komi
) >= 0.5) {
89 snprintf(reply
+ strlen(reply
), 510, ", while self-imposing extra komi %.1f", extra_komi
);
96 for (struct chat
*entry
= chat_table
; entry
->regex
[0]; entry
++) {
98 if (color
!= S_NONE
) {
99 if (winrate
< entry
->minwin
) continue;
100 if (winrate
> entry
->maxwin
) continue;
102 if (entry
->from
[0] && strcmp(entry
->from
, from
)) continue;
103 if (regexec(&entry
->preg
, cmd
, 0, NULL
, 0)) continue;
106 if (!entry
->displayed
) undisplayed
++;
108 if (matches
== 0) return default_reply
;
109 int choices
= undisplayed
> 0 ? undisplayed
: matches
;
110 int index
= fast_random(choices
);
111 for (struct chat
*entry
= chat_table
; entry
->regex
[0]; entry
++) {
112 if (!entry
->match
) continue;
113 if (undisplayed
> 0 && entry
->displayed
) continue;
115 entry
->displayed
= true;
116 snprintf(reply
, sizeof(reply
), entry
->reply
, 100*winrate
);