-
Notifications
You must be signed in to change notification settings - Fork 116
/
Copy pathchat.c
143 lines (126 loc) · 4 KB
/
chat.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdint.h>
#include "board.h"
#include "chat.h"
#ifndef HAVE_NO_REGEX_SUPPORT
#include <regex.h>
#define DEBUG
#include "debug.h"
#include "random.h"
#define MAX_CHAT_PATTERNS 500
typedef struct {
double minwin;
double maxwin;
char from[20];
char regex[100];
char reply[300]; // in printf format with one param (100*winrate)
regex_t preg;
bool displayed;
bool match;
} chat_t;
static chat_t *chat_table;
static char default_reply[] = "I know all those words, but that sentence makes no sense to me";
static char not_playing[] = "I'm winning big without playing";
/* Read the chat file, a sequence of lines of the form:
* minwin;maxwin;from;regex;reply
* Set minwin, maxwin to -1.0 2.0 for answers to chat other than winrate.
* Set from as one space for replies to anyone.
* Examples:
* -1.0;0.3; ;winrate;%.1f%% I'm losing
* -1.0;2.0;pasky;^when ;Today
*/
void chat_init(char *chat_file) {
if (!chat_file) return;
FILE *f = fopen(chat_file, "r");
if (!f) {
perror(chat_file);
return;
}
chat_table = calloc2(MAX_CHAT_PATTERNS, chat_t);
chat_t *entry = chat_table;
while (fscanf(f, "%lf;%lf;%20[^;];%100[^;];%300[^\n]\n", &entry->minwin, &entry->maxwin,
entry->from, entry->regex, entry->reply ) == 5) {
if (!strcmp(entry->from, " "))
entry->from[0] = '\0';
int err = regcomp(&entry->preg, entry->regex, REG_EXTENDED | REG_ICASE);
if (err) {
char msg[200];
regerror(err, &entry->preg, msg, sizeof(msg));
fprintf(stderr, "Error compiling %s: %s\n", entry->regex, msg);
} else {
entry++;
}
}
if (!feof(f))
fprintf(stderr, "syntax error around line %u in %s\n", (unsigned)(entry - chat_table), chat_file);
fclose(f);
if (DEBUGL(1))
fprintf(stderr, "Loaded %u chat entries from %s\n", (unsigned)(entry - chat_table), chat_file);
}
void chat_done(void) {
if (chat_table) {
free(chat_table);
chat_table = NULL;
}
}
/* Reply to a chat. When not playing, color is S_NONE and all remaining parameters are undefined.
* If some matching entries have not yet been displayed we pick randomly among them. Otherwise
* we pick randomly among all matching entries. */
char *
generic_chat(board_t *b, bool opponent, char *from, char *cmd, enum stone color, coord_t move,
int playouts, int machines, int threads, double winrate, double extra_komi, char *score_est)
{
static_strbuf(buf, 1024);
if (!chat_table) {
if (strncasecmp(cmd, "winrate", 7)) return NULL;
if (color == S_NONE) return not_playing;
sbprintf(buf, "In %d playouts, %s %s can win with %.1f%% probability",
playouts, stone2str(color), coord2sstr(move), 100*winrate);
if (fabs(extra_komi) >= 0.5) {
sbprintf(buf, ", while self-imposing extra komi %.1f", extra_komi);
}
sbprintf(buf, ". Score Est: %s", score_est);
return buf->str;
}
int matches = 0;
int undisplayed = 0;
for (chat_t *entry = chat_table; entry->regex[0]; entry++) {
entry->match = false;
if (color != S_NONE) {
if (winrate < entry->minwin) continue;
if (winrate > entry->maxwin) continue;
}
if (entry->from[0] && strcmp(entry->from, from)) continue;
if (regexec(&entry->preg, cmd, 0, NULL, 0)) continue;
entry->match = true;
matches++;
if (!entry->displayed) undisplayed++;
}
if (matches == 0) return default_reply;
int choices = undisplayed > 0 ? undisplayed : matches;
int index = fast_random(choices);
for (chat_t *entry = chat_table; entry->regex[0]; entry++) {
if (!entry->match) continue;
if (undisplayed > 0 && entry->displayed) continue;
if (--index < 0) {
entry->displayed = true;
sbprintf(buf, entry->reply, 100*winrate);
return buf->str;
}
}
assert(0);
return NULL;
}
#else
void chat_init(char *chat_file) {}
void chat_done(void) {}
char
*generic_chat(board_t *b, bool opponent, char *from, char *cmd, enum stone color, coord_t move,
int playouts, int machines, int threads, double winrate, double extra_komi, char *score_est) {
static char reply[1024] = { '.', '\0' };
return reply;
}
#endif