/[cvs]/wurmi/arbiter.c
ViewVC logotype

Contents of /wurmi/arbiter.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations)
Mon Sep 10 13:00:55 2007 UTC (11 years, 1 month ago) by riso
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +196 -64 lines
File MIME type: text/plain
Running now  :-)
:

1 #include <stdio.h>
2 #include <unistd.h>
3 #include <signal.h>
4 #include <time.h>
5 #include <sys/time.h>
6 #include <sys/wait.h>
7 #include <glob.h>
8 #include <libgen.h>
9 #include "connect.h"
10 #include "board.h"
11
12 #define COMMAND_LINE_SIZE 256
13 #define HZ 100
14
15 struct player {
16 int pid;
17 char *name;
18 int in, out;
19 char ibuf[BUFFERSIZE], obuf[BUFFERSIZE];
20 int ibufptr, obufptr;
21 int ready;
22 int num;
23 int *score;
24 int act_score;
25 };
26
27 struct contestant {
28 char fn[COMMAND_LINE_SIZE];
29 char name[COMMAND_LINE_SIZE];
30 int games;
31 int score;
32 };
33
34 int ncontestants;
35 struct contestant *contestants;
36
37 int nplayers;
38 struct player *players;
39 BRD *board;
40 FILE *streamer;
41
42 static int max(int a, int b) { return (a>b)?a:b; }
43
44 void LoadPlayer(struct player *p, struct contestant *c, int i) {
45 int fdin[2], fdout[2];
46 char buf[100];
47
48 p->name = c->name;
49 p->score = &(c->score);
50 if (-1 == pipe(fdin)) { perror("Cannot create pipe"); exit(1); }
51 if (-1 == pipe(fdout)) { perror("Cannot create pipe"); exit(1); }
52 if ( ! (p->pid = fork()) ) {
53 close(fdin[1]);
54 close(fdout[0]);
55 dup2(fdin[0], 0);
56 dup2(fdout[1], 1);
57 sprintf(buf,"%d",i);
58 execl(c->fn, c->fn, buf, NULL);
59 fprintf(stderr, "Cannot execute %s\n", c->fn);
60 exit(0);
61 }
62 if (p->pid == -1) { perror("Cannot fork"); exit(1); }
63 close(fdin[0]);
64 close(fdout[1]);
65 p->in = fdin[1];
66 p->out = fdout[0];
67 p->ready = 1;
68 p->obufptr = 0;
69 p->num=i;
70 kill(p->pid, SIGSTOP);
71 }
72
73 void FreePlayer(struct player *p) {
74 kill(p->pid, SIGCONT);
75 kill(p->pid, SIGKILL);
76 waitpid(p->pid, NULL, 0);
77 close(p->in);
78 close(p->out);
79 }
80
81 unsigned long getCPUjiffies(int pid) {
82 FILE *proc;
83 char fn[1024];
84 unsigned long out;
85 sprintf(fn, "/proc/%d/stat", pid);
86 if (!(proc = fopen(fn, "r"))) return -1;
87 fscanf(proc, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu", &out);
88 fclose(proc);
89 return out;
90 }
91
92 int Sleeping(int pid) {
93 FILE *proc;
94 char fn[1024];
95 char out;
96 sprintf(fn, "/proc/%d/stat", pid);
97 if (!(proc = fopen(fn, "r"))) return -1;
98 fscanf(proc, "%*d %*s %c", &out);
99 fclose(proc);
100 return out == 'S';
101 }
102
103 int PlayerWrite(struct player *p, char *s) {
104 if (!p->ready) return 0;
105 p->ready = 0;
106 strcpy(p->ibuf, s);
107 p->ibufptr = 0;
108 return 1;
109 }
110
111 static void strcpyoverlap(char *dst, char *src) {
112 while(*src) { *dst = *src; dst++; src++; }
113 *dst = 0;
114 }
115
116 long long GetTime() {
117 struct timeval tv;
118 gettimeofday(&tv, NULL);
119 return tv.tv_sec*(long long)1000000 + tv.tv_usec;
120 }
121
122 int PlayerRead(struct player *p, long long timeout, char *out) { // timeout in miliseconds
123 fd_set rset, wset;
124 long long deadline, left;
125 struct timeval tv;
126
127 if (p->ready) return 0;
128
129 deadline = GetTime() + timeout*(long long)1000;
130
131 kill(p->pid, SIGCONT);
132
133 while ( (left = deadline - GetTime()) > 0 ) {
134 int l;
135 char *s;
136
137 tv.tv_usec = left % 1000000;
138 tv.tv_sec = left / 1000000;
139
140 FD_ZERO(&rset);
141 FD_ZERO(&wset);
142 FD_SET(p->out, &rset);
143 if (p->ibuf[p->ibufptr]) FD_SET(p->in, &wset);
144 /* fprintf(stderr, "Selecting pid=%d, left=%lld, sec=%d usec=%d\n", p->pid, left,tv.tv_sec, tv.tv_usec);*/
145 select(max(p->in, p->out)+1, &rset, &wset, NULL, &tv);
146 /*
147 if (!FD_ISSET(p->in, &wset) && !FD_ISSET(p->out, &rset)) {
148 if (Sleeping(p->pid)) {
149 fprintf(stderr, "Player pid %d in deadlock\n", p->pid);
150 kill(p->pid, SIGSTOP);
151 return 0;
152 }
153 }
154 */
155 if (FD_ISSET(p->in, &wset)) {
156 l = write(p->in, p->ibuf+p->ibufptr, strlen(p->ibuf+p->ibufptr));
157 if (l>0) p->ibufptr += l;
158 }
159 if (FD_ISSET(p->out, &rset)) {
160 l = read(p->out, p->obuf+p->obufptr, sizeof(p->obuf)-1-p->obufptr);
161 if (l>0) p->obufptr += l;
162 p->obuf[p->obufptr] = 0;
163 if ((s=strchr(p->obuf, '\n'))) {
164 *s = 0;
165 strcpy(out, p->obuf);
166 strcpyoverlap(p->obuf, s+1);
167 p->obufptr = strlen(p->obuf);
168 p->ready = 1;
169 kill(p->pid, SIGSTOP);
170 return 1;
171 }
172 }
173 }
174 fprintf(stderr, "Player %s (pid %d) timed out\n", players[p->num].name,p->pid);
175 kill(p->pid, SIGSTOP);
176 return 0;
177 }
178
179 int ParseOutput(char *response) {
180 if (response[0] == 'l' || response[0] == 'L') return 0;
181 if (response[0] == 'r' || response[0] == 'R') return 1;
182 return 2;
183 }
184
185 int cmpscore(int *a, int *b) {
186 if (board->plr[*a].length < board->plr[*b].length) return -1;
187 if (board->plr[*a].length > board->plr[*b].length) return 1;
188 return 0;
189 }
190
191 void Game(int w, int h, int f, int t, int port, int time41move) {
192 int i;
193 int *R;
194 char **player_names;
195 char buf[BUFFERSIZE], buf2[BUFFERSIZE];
196
197 while (!(streamer=Connect("localhost", port))) sleep(1);
198 printf("arbiter running on port %d\n",port);
199 player_names = (char **)malloc((nplayers+1)*sizeof(char *));
200 for (i=0; i<nplayers; i++) player_names[i] = players[i].name;
201 player_names[nplayers]=NULL;
202
203 board = NewBoard(w,h,f,nplayers, player_names, time(NULL));
204 printf("arbiter: entring event loop\n");fflush(stdout);
205 WriteBoard(board, buf);
206 fprintf(streamer, "%s\n", buf); fflush(streamer);
207 while(board->moves < t && board->live_players > 0) {
208 for (i=0; i<nplayers; i++)
209 if (board->plr[i].alive) {
210 if (!players[i].ready) PlayerRead(players+i, time41move, buf2);
211 if (players[i].ready) {
212 WriteBoard(board, buf);
213 buf[strlen(buf)+1]=0;
214 buf[strlen(buf)]='\n';
215 PlayerWrite(players+i, buf);
216 if (PlayerRead(players+i, time41move, buf2)) {
217 sprintf(buf, "1 %d %d", i, ParseOutput(buf2));
218 ApplyCommand(board, buf);
219 fprintf(streamer, "%s\n", buf); fflush(streamer);
220 }
221 }
222 }
223 CreateMaintenance(board, buf);
224 ApplyCommand(board, buf);
225 fprintf(streamer, "%s\n", buf); fflush(streamer);
226 }
227
228 printf("arbiter: %s game over.\n",(board->live_players)?"move limit exceeded,":"all players are dead,");fflush(stdout);
229 printf("Game ended after %d moves.\n\n",board->moves);
230
231 /* print results */
232 for(i=0;i<nplayers;i++) {
233 if ((board->plr)[i].alive)
234 sprintf(buf,"survived");
235 else
236 sprintf(buf,"died in move #%d",(board->plr)[i].move_of_death);
237 printf("%14s %d [%s]\n",player_names[i],(board->plr)[i].length,buf);
238 }
239
240 printf("\n");
241
242 R = (int *)malloc(nplayers*sizeof(int));
243 for (i=0; i<nplayers; i++) R[i] = i;
244 qsort(R, nplayers, sizeof(int), (int (*)(const void *, const void *))cmpscore);
245 for (i=nplayers-1; i>=0; i--) {
246 if (i<nplayers-1 && board->plr[R[i]].length==board->plr[R[i+1]].length)
247 players[R[i]].act_score = players[R[i+1]].act_score;
248 else players[R[i]].act_score = i+1;
249 (*players[R[i]].score) += players[R[i]].act_score;
250 printf("%d points - %s (total score %d)\n", players[R[i]].act_score, players[R[i]].name, *(players[R[i]].score));
251 }
252
253
254 printf("\n");
255
256 FreeBoard(board);
257 free(player_names);
258 printf("..done (wait 5sec for results)\n");
259 sleep(5);
260 fclose(streamer);
261 }
262
263 void Usage(char *s) {
264 fprintf(stderr, "Usage: %s <streamer port> <width> <height> <food> <moves> <timeout> <games each> <players> <player_dir>\n", s);
265 exit(1);
266 }
267
268 int cmpcontestant(struct contestant *a, struct contestant *b) {
269 if (a->score < b->score) return 1;
270 if (a->score > b->score) return -1;
271 return 0;
272 }
273
274 int main(int argc, char **argv) {
275 static const int offset = 9;
276 int w, h, f, t, port, i, j, k;
277 int *T;
278 char buf[BUFFERSIZE], buf2[BUFFERSIZE];
279 char player_dir[1000];
280 int time41move;
281 int GamesEach;
282 FILE *fn;
283
284 glob_t info;
285
286 signal(SIGPIPE,SIG_IGN);
287 if (argc <= offset) Usage(argv[0]);
288 if (sscanf(argv[1], "%d", &port)!=1) Usage(argv[0]);
289 if (sscanf(argv[2], "%d", &w)!=1) Usage(argv[0]);
290 if (sscanf(argv[3], "%d", &h)!=1) Usage(argv[0]);
291 if (sscanf(argv[4], "%d", &f)!=1) Usage(argv[0]);
292 if (sscanf(argv[5], "%d", &t)!=1) Usage(argv[0]);
293 if (sscanf(argv[6], "%d", &time41move)!=1) Usage(argv[0]);
294 if (sscanf(argv[7], "%d", &GamesEach)!=1) Usage(argv[0]);
295 if (sscanf(argv[8], "%d", &nplayers)!=1) Usage(argv[0]);
296
297 sprintf(player_dir,"./*.plr");
298 if (argc>=offset) sprintf(player_dir,"%s/*.plr",argv[offset]);
299
300 /* load contestants */
301 glob(player_dir,0,NULL,&info);
302 ncontestants=info.gl_pathc;
303 contestants = (struct contestant *)malloc(ncontestants*sizeof(struct contestant));
304 printf("arbiter: found %d players in %s\n",info.gl_pathc,player_dir);
305
306 for(i=0;i<(int)info.gl_pathc;i++) {
307 fprintf(stderr,"%s ", info.gl_pathv[i]);
308 contestants[i].games = contestants[i].score = 0;
309 strcpy(contestants[i].fn, info.gl_pathv[i]);
310 strcpy(buf, info.gl_pathv[i]);
311 buf[strlen(buf)-4]=0;
312 strcat(buf, ".name");
313 strcpy(buf2, basename(info.gl_pathv[i]));
314 buf2[strlen(buf2)-4]=0;
315 if ((fn=fopen(buf, "r"))) {
316 fscanf(fn, "%s", buf2);
317 fclose(fn);
318 }
319 strncpy(contestants[i].name, buf2, sizeof(contestants[i].name));
320 contestants[i].name[sizeof(contestants[i].name)-1] = 0;
321 fprintf(stderr,"%s\n", contestants[i].name);
322 }
323 globfree(&info);
324
325 T = (int *)malloc(ncontestants*sizeof(int));
326
327 if (nplayers >ncontestants) {
328 fprintf(stderr, "Not enough players!\n");
329 return 1;
330 }
331
332 players = (struct player *)malloc(nplayers * sizeof(struct player));
333
334 srand(time(NULL));
335 if (GamesEach<0) { // single game
336 for (i=0; i<ncontestants; i++) T[i] = i;
337 for (i=0; i<nplayers; i++) {
338 j = (random() % (ncontestants-i) ) + i;
339 k = T[j]; T[j] = T[i]; T[i] = k;
340 }
341
342 for (i=0; i<nplayers; i++) LoadPlayer(players+i, &contestants[T[i]], i);
343 Game(w,h,f,t,port,time41move);
344 for (i=0; i<nplayers; i++) FreePlayer(players+i);
345 } else {
346 int m,c;
347 c = 0;
348
349 while (1) {
350 for (i=0; i<ncontestants; i++) T[i] = i;
351 for (i=0; i<nplayers; i++) {
352 if (c == 0) {
353 m = GamesEach+1;
354 for (j=i; j<ncontestants; j++) {
355 if (contestants[T[j]].games == m) c++;
356 else if (contestants[T[j]].games < m) { m = contestants[T[j]].games; c = 1; }
357 }
358 for (j=0; j<ncontestants; j++) fprintf(stderr, "%d ", contestants[j].games);
359 fprintf(stderr, "Searching for %d\n", m);
360 }
361 if (m > GamesEach) break;
362 k = random() % c;
363 for (j=i; j<ncontestants; j++) {
364 if (contestants[T[j]].games == m) k--;
365 if (k<0) break;
366 }
367 k = T[j]; T[j] = T[i]; T[i] = k;
368 c--;
369 }
370
371 if (m > GamesEach) break;
372
373 for (i=0; i<nplayers; i++) contestants[T[i]].games++;
374 for (i=0; i<nplayers; i++) LoadPlayer(players+i, &contestants[T[i]], i);
375 Game(w,h,f,t,port,time41move);
376 for (i=0; i<nplayers; i++) FreePlayer(players+i);
377
378 }
379
380 printf("Total results:\n\n");
381 qsort(contestants, ncontestants, sizeof(struct contestant), (int (*)(const void *, const void *))cmpcontestant);
382 for (i=0; i<ncontestants; i++) {
383 printf("%s: score %d\n", contestants[i].name, contestants[i].score);
384 }
385 }
386
387 free(players);
388 free(T);
389
390
391 return 0;
392 }

CVS Admin">CVS Admin
ViewVC Help
Powered by ViewVC 1.1.26