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