/* b01902062 藍ĉŒşç‘‹ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "logger.h" #include "xwrap.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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++) { struct stat st; if (stat (ffd[i].fname, &st) >= 0 && S_ISFIFO (st.st_mode)) { unlink (ffd[i].fname); } 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; } xfaddfd (fdr, FD_CLOEXEC); 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; } xfaddfd (fdw, FD_CLOEXEC); 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; 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; } char trash_buf[512]; xfaddfl (ffd[0].fd, O_NONBLOCK); while (read (ffd[0].fd, trash_buf, 512) > 0); xfdelfl (ffd[0].fd, O_NONBLOCK); 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); } else { while (read (ffd[i].fd, trash_buf, 512) > 0); fdata_clear (&ffd[i]); ffd[i].key = random (); for (int j = 1; j < i; j++) { if (ffd[i].key == ffd[j].key) { ffd[i].key = random (); j = 0; } } ffd[i].pid = fork (); if (ffd[i].pid < 0) { fprintf (stderr, "Cannot fork: %s\n", strerror (errno)); for (int j = 1; j < i; j++) { kill (ffd[i].pid, SIGKILL); waitpid (ffd[i].pid, NULL, 0); } goto new_loop_end; } 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' }; close (STDIN_FILENO); close (STDOUT_FILENO); execl (plthis, plname, judgename, plid, plkey, (char*)NULL); fprintf (stderr, "Cannot execl `%s\': %s\n", plthis, strerror (errno)); _exit (127); } comp135_log (comp, "Player %c has PID %u", c, ffd[i].pid); } 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[rank[j] - 1], ffd[rank[j]].rank); printf ("%s %d\n", pl[rank[j] - 1], ffd[rank[j]].rank); } fflush (stdout); /* clean up all child process */ for (i = 1; i <= 4; i++) { comp135_log (comp, "Waiting for PID %u to exit ...", ffd[i].pid); kill (ffd[i].pid, SIGKILL); waitpid (ffd[i].pid, NULL, 0); } comp135_log (comp, "Waiting for the next request from big_judge"); new_loop_end: free (linestr); linestr = NULL; linelen = 0; } 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; }