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