Merge pull request #50 from lemonsqueeze/can_countercap
[pachi.git] / chat.c
blob5bcea80a39b7a5977d7f3e33541d65df01b1cc6d
1 #include <assert.h>
2 #include <math.h>
3 #include <stdio.h>
4 #include <sys/types.h>
5 #include <stdint.h>
6 #include "chat.h"
8 #ifndef HAVE_NO_REGEX_SUPPORT
9 #include <regex.h>
11 #define DEBUG
13 #include "debug.h"
14 #include "random.h"
16 #define MAX_CHAT_PATTERNS 500
18 static struct chat {
19 double minwin;
20 double maxwin;
21 char from[20];
22 char regex[100];
23 char reply[300]; // in printf format with one param (100*winrate)
25 regex_t preg;
26 bool displayed;
27 bool match;
28 } *chat_table;
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.
37 * Examples:
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");
44 if (!f) {
45 perror(chat_file);
46 return;
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);
55 if (err) {
56 char msg[200];
57 regerror(err, &entry->preg, msg, sizeof(msg));
58 fprintf(stderr, "Error compiling %s: %s\n", entry->regex, msg);
59 } else {
60 entry++;
63 if (!feof(f))
64 fprintf(stderr, "syntax error around line %u in %s\n", (unsigned)(entry - chat_table), chat_file);
65 fclose(f);
66 if (DEBUGL(1))
67 fprintf(stderr, "Loaded %u chat entries from %s\n", (unsigned)(entry - chat_table), chat_file);
70 void chat_done() {
71 if (chat_table) {
72 free(chat_table);
73 chat_table = NULL;
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. */
80 char
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];
85 if (!chat_table) {
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);
94 strcat(reply, ".");
95 return reply;
97 int matches = 0;
98 int undisplayed = 0;
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;
107 entry->match = true;
108 matches++;
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;
117 if (--index < 0) {
118 entry->displayed = true;
119 snprintf(reply, sizeof(reply), entry->reply, 100*winrate);
120 return reply;
123 assert(0);
124 return NULL;
126 #else
127 void chat_init(char *chat_file) {}
129 void chat_done() {}
131 char
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' };
135 return reply;
137 #endif