fast_frandom() always returns float, not floating_t
[pachi/t.git] / chat.c
blob16a7bec1f460ae56d16735b10527b119606d1e3b
1 #include <assert.h>
2 #include <math.h>
3 #include <stdio.h>
4 #include <sys/types.h>
5 #include <regex.h>
7 #define DEBUG
9 #include "debug.h"
10 #include "chat.h"
11 #include "random.h"
13 #define MAX_CHAT_PATTERNS 500
15 static struct chat {
16 double minwin;
17 double maxwin;
18 char from[20];
19 char regex[100];
20 char reply[300]; // in printf format with one param (100*winrate)
22 regex_t preg;
23 bool displayed;
24 bool match;
25 } *chat_table;
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.
34 * Examples:
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");
41 if (!f) {
42 perror(chat_file);
43 return;
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);
52 if (err) {
53 char msg[200];
54 regerror(err, &entry->preg, msg, sizeof(msg));
55 fprintf(stderr, "Error compiling %s: %s\n", entry->regex, msg);
56 } else {
57 entry++;
60 if (!feof(f))
61 fprintf(stderr, "syntax error around line %ld in %s\n", entry - chat_table, chat_file);
62 fclose(f);
63 if (DEBUGL(1))
64 fprintf(stderr, "Loaded %ld chat entries from %s\n", entry - chat_table, chat_file);
67 void chat_done() {
68 if (chat_table) {
69 free(chat_table);
70 chat_table = NULL;
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. */
77 char
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];
82 if (!chat_table) {
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);
91 strcat(reply, ".");
92 return reply;
94 int matches = 0;
95 int undisplayed = 0;
96 for (struct chat *entry = chat_table; entry->regex[0]; entry++) {
97 entry->match = false;
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;
104 entry->match = true;
105 matches++;
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;
114 if (--index < 0) {
115 entry->displayed = true;
116 snprintf(reply, sizeof(reply), entry->reply, 100*winrate);
117 return reply;
120 assert(0);
121 return NULL;