/* b01902062 藍挺瑋 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "logger.h"
#include "xwrap.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
typedef struct {
int fd;
int fd_unused;
char* fname;
long last;
long score;
int rank;
int ignore : 1;
pid_t pid;
long key;
} FData;
static volatile sig_atomic_t player_tle;
static void player_tle_setter (int signo) {
player_tle = 1;
}
static void fdata_clear (FData* d) {
d->last = 0;
d->score = 0;
d->rank = 0;
d->ignore = 0;
d->pid = 0;
d->key = 0;
}
static int str2list (char* str, char* result[], int maxlen) {
int complen = 0;
char* now = str;
while (complen < maxlen) {
for (; isspace (*now) && *now != '\0'; now++);
if (*now == '\0') {
break;
}
result[complen++] = now;
for (; !isspace (*now) && *now != '\0'; now++);
if (*now == '\0') {
break;
}
*now = '\0';
now++;
}
return complen;
}
int main (int argc, char* argv[]) {
if (argc < 2) {
fprintf (stderr, "Usage: %s judge_id\n", argv[0]);
return 1;
}
const char* judgename = argv[1];
FData ffd[5] = {
{ .fname = xstrcat ("judge", judgename, ".FIFO", (char*)NULL) }, // read
{ .fname = xstrcat ("judge", judgename, "_A.FIFO", (char*)NULL) }, // write
{ .fname = xstrcat ("judge", judgename, "_B.FIFO", (char*)NULL) }, // write
{ .fname = xstrcat ("judge", judgename, "_C.FIFO", (char*)NULL) }, // write
{ .fname = xstrcat ("judge", judgename, "_D.FIFO", (char*)NULL) } // write
};
for (int i = 0; i < ARRAY_LEN (ffd, FData); i++) {
if (mkfifo (ffd[i].fname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
fprintf (stderr, "%s: cannot create FIFO `%s\': %s\n",
argv[0], ffd[i].fname, strerror (errno));
return 2;
}
int fdr = open (ffd[i].fname, O_RDONLY | O_NONBLOCK);
if (fdr < 0) {
fprintf (stderr, "%s: cannot open `%s\' for reading: %s\n",
argv[0], ffd[i].fname, strerror (errno));
return 3;
}
int fdw = open (ffd[i].fname, O_WRONLY | O_NONBLOCK);
if (fdw < 0) {
fprintf (stderr, "%s: cannot open `%s\' for writing: %s\n",
argv[0], ffd[i].fname, strerror (errno));
return 3;
}
if (i) {
ffd[i].fd = fdw;
ffd[i].fd_unused = fdr;
} else {
ffd[i].fd = fdr;
ffd[i].fd_unused = fdw;
}
fdata_clear (&ffd[i]);
}
xfdelfl (ffd[0].fd, O_NONBLOCK);
Comp135 comp_struct, *comp;
comp = &comp_struct;
comp135_init (comp, argv[0], false);
srandom (time (NULL) + getpid () + argv[0][0]);
struct sigaction sa = {
.sa_handler = player_tle_setter,
.sa_flags = 0
};
sigemptyset (&sa.sa_mask);
sigaction (SIGALRM, &sa, NULL);
sa.sa_handler = SIG_IGN;
sigaction (SIGPIPE, &sa, NULL);
char *linestr = NULL;
size_t linelen = 0;
bool request_exit = false;
fd_set rset;
int nfds;
FD_ZERO (&rset);
FD_SET (ffd[0].fd, &rset);
nfds = ffd[0].fd + 1;
comp135_log (comp, "Waiting for initial request from big_judge");
while (!request_exit && getline (&linestr, &linelen, stdin) >= 0) {
char* pl[4];
int i, c;
int p = str2list (linestr, pl, 4);
if (p < 4) {
fprintf (stderr, "Too few arguments: %d provided, 4 required\n", p);
goto new_loop_end;
}
comp135_log (comp, "Request: player list: %s %s %s %s",
pl[0], pl[1], pl[2], pl[3]);
if (strcmp (pl[0], "-1") == 0 &&
strcmp (pl[1], "-1") == 0 &&
strcmp (pl[2], "-1") == 0 &&
strcmp (pl[3], "-1") == 0)
{
comp135_log (comp, "Request: exit");
request_exit = true;
goto new_loop_end;
}
for (i = 1, c = 'A'; i <= 4; i++, c++) {
fdata_clear (&ffd[i]);
ffd[i].key = random ();
ffd[i].pid = fork ();
if (ffd[i].pid < 0) {
fprintf (stderr, "Cannot fork: %s\n", strerror (errno));
break;
} else if (ffd[i].pid == 0) {
char* plname = xstrcat ("player_", pl[i - 1], NULL);
char* plthis = xgetres (plname);
char* plkey = xsprintf ("%ld", ffd[i].key);
char plid[2] = { c, '\0' };
execl (plthis, plname, judgename, plid, plkey, (char*)NULL);
fprintf (stderr, "Cannot execl `%s\': %s\n",
plthis, strerror (errno));
_exit (127);
}
}
if (i <= 4 && ffd[i].pid) {
for (int j = 1; j < i; j++) {
kill (ffd[i].pid, SIGKILL);
}
goto new_loop_end;
}
for (int t = 0; t < 20; t++) {
char lastmsg[20];
int lastlen;
lastlen = snprintf (lastmsg, 20, "%ld %ld %ld %ld\n",
ffd[1].last, ffd[2].last, ffd[3].last, ffd[4].last);
lastmsg[lastlen - 1] = '\0';
comp135_log (comp, "Previous round: %s", lastmsg);
lastmsg[lastlen - 1] = '\n';
comp135_log (comp, "This is round %d", t + 1);
for (i = 1, c = 'A'; i <= 4; i++, c++) {
if (t) {
write (ffd[i].fd, lastmsg, lastlen);
}
if (ffd[i].ignore) {
continue;
}
XBuf rbuf;
char* rline;
xbufinit (&rbuf);
player_tle = 0;
setitimer (ITIMER_REAL, &(struct itimerval) {
.it_interval = (struct timeval) { 0, 0 },
.it_value = (struct timeval) { 3, 0 }
}, NULL);
rline = NULL;
while (!player_tle) {
comp135_log (comp, "Waiting for player %c input ...", c);
while (
(rline = xgetline (ffd[0].fd, &rbuf, '\n')) == NULL &&
!(rbuf.buf_error) && !(rbuf.buf_eof) && !player_tle);
if (rbuf.buf_error) {
fprintf (stderr, "Read error: %s\n", strerror (errno));
}
if (rbuf.buf_eof) {
fputs ("Unexpected EOF!!!\n", stderr);
}
if (rline != NULL) {
comp135_log (comp, "Read: %s", rline);
char* p[3];
int pnum = str2list (rline, p, 3);
if (pnum < 3) {
comp135_log (comp,
"Too few arguments (3 required, %d got)", pnum);
free (rline), rline = NULL;
continue;
}
char plfrom = p[0][0];
long checknum, ans;
if (xatol (p[1], &checknum) < 0) {
comp135_log (comp, "Invalid checknum (%s)", p[1]);
free (rline), rline = NULL;
continue;
}
if (xatol (p[2], &ans) < 0) {
comp135_log (comp, "Invalid choose (%s)", p[2]);
free (rline), rline = NULL;
continue;
}
free (rline), rline = NULL;
if (checknum != ffd[i].key) {
comp135_log (comp,
"Incorrect checknum %ld (should be %ld)",
ffd[i].key, checknum);
continue;
}
if (ans != 1 && ans != 3 && ans != 5) {
comp135_log (comp,
"Incorrect choose %ld (should be 1, 3, 5)",
ans);
continue;
}
comp135_log (comp, "Player %c (checknum %ld) says %ld",
plfrom, checknum, ans);
ffd[i].last = ans;
break;
}
}
setitimer (ITIMER_REAL, &(struct itimerval) {
.it_interval = (struct timeval) { 0, 0 },
.it_value = (struct timeval) { 0, 0 }
}, NULL);
if (player_tle) {
comp135_log (comp, "Player %c TLE!!!", c);
ffd[i].last = 0;
ffd[i].ignore = true;
}
}
int c1 = 0, c3 = 0, c5 = 0;
for (i = 1; i <= 4; i++) {
switch (ffd[i].last) {
case 1: c1++; break;
case 3: c3++; break;
case 5: c5++; break;
}
}
for (i = 1; i <= 4; i++) {
if (ffd[i].last == 1 && c1 == 1) {
ffd[i].score += 1;
} else if (ffd[i].last == 3 && c3 == 1) {
ffd[i].score += 3;
} else if (ffd[i].last == 5 && c5 == 1) {
ffd[i].score += 5;
}
}
comp135_log (comp, "Player score: %ld %ld %ld %ld",
ffd[1].score, ffd[2].score, ffd[3].score, ffd[4].score);
}
int rank[4];
long lastmin = LONG_MAX;
int lastrank = 4;
for (int j = 4; j > 0; j--) {
long vmin = LONG_MAX;
int pmin = 0;
for (i = 1; i <= 4; i++) {
if (!ffd[i].rank && ffd[i].score < vmin) {
vmin = ffd[i].score;
pmin = i;
}
}
if (vmin == lastmin) {
ffd[pmin].rank = lastrank;
rank[j - 1] = pmin;
} else {
ffd[pmin].rank = j;
rank[j - 1] = pmin;
lastrank = j;
}
lastmin = vmin;
}
for (int j = 0; j < 4; j++) {
comp135_log (comp, "Send %s %d to big_judge",
pl[j], ffd[rank[j]].rank);
printf ("%s %d\n", pl[j], ffd[rank[j]].rank);
}
fflush (stdout);
new_loop_end:
free (linestr);
linestr = NULL;
linelen = 0;
comp135_log (comp, "Waiting for the next request from big_judge");
}
free (linestr);
comp135_destroy (comp);
for (int i = 0; i < ARRAY_LEN (ffd, FData); i++) {
close (ffd[i].fd);
close (ffd[i].fd_unused);
unlink (ffd[i].fname);
free (ffd[i].fname);
}
return 0;
}