/* b01902062 藍ĉŒşç‘‹ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "logger.h" #include "xwrap.h" #include #include #include #include #include #include #include #include #include typedef struct { pid_t pid; int read; int write; bool working; XBuf buf; } JudgeData; typedef struct { int id; long score; } PlayerData; static int player_sort_cb (const void* aa, const void* bb) { const PlayerData* a = aa; const PlayerData* b = bb; if (a->score > b->score) { return -1; } else if (a->score < b->score) { return 1; } else { if (a->id > b->id) { return 1; } else if (a->id < b->id) { return -1; } } return 0; } static bool comb4 (int players[], long player_num) { for (int i = 3; i >= 0; i--) { if (players[i] + 1 <= player_num && players[i] + 1 + (3 - i) <= player_num) { players[i]++; for (int j = i + 1; j < 4; j++) { players[j] = players[j - 1] + 1; } return true; } } return false; } static int nextjudge (JudgeData* jd, long judge_num) { for (int i = 0; i < judge_num; i++) { if (!(jd[i].working)) { return i; } } return -1; } static int nextscore (Comp135* comp, JudgeData* jd, long judge_num, PlayerData* pd, long player_num, struct pollfd* jpoll) { repoll: if (poll (jpoll, judge_num, -1) <= 0) { fprintf (stderr, "Poll fail: %s\n", strerror (errno)); return -1; } for (int i = 0; i < judge_num; i++) { if (jpoll[i].revents & POLLIN || jpoll[i].revents & POLLPRI) { comp135_log (comp, "Waiting for judge %d input", i + 1); for (int j = 0; j < 4; j++) { char* r; while ( (r = xgetline (jpoll[i].fd, &jd[i].buf, '\n')) == NULL && !(jd[i].buf.buf_error) && !(jd[i].buf.buf_eof)); if (r == NULL) { goto repoll; } long id, rank, scr; if (sscanf (r, "%ld %ld", &id, &rank) < 2) { comp135_log (comp, "Judge %d send bad input %s", i + 1, r); j--; continue; } free (r); if (id > player_num || id <= 0) { comp135_log (comp, "Bad player ID: %ld", player_num); j--; continue; } if (rank > 4 || rank < 1) { comp135_log (comp, "Bad rank: %ld", rank); j--; continue; } scr = 4 - rank; comp135_log (comp, "Player %ld gets %ld points", id, scr); pd[id - 1].score += scr; comp135_log (comp, "Player %ld has %ld points now", id, pd[id - 1].score); } comp135_log (comp, "Judge %d is available now", i + 1); jd[i].working = false; break; } } return 0; } int main (int argc, char* argv[]) { if (argc < 3) { fprintf (stderr, "Usage: %s judge_num player_num\n", argv[0]); return 1; } long judge_num, player_num; if (xatol (argv[1], &judge_num) < 0) { fprintf (stderr, "%s: `%s\' is not a number\n", argv[0], argv[1]); return 2; } if (judge_num < 0) { fprintf (stderr, "%s: judge_num must be a positive number\n", argv[0]); return 3; } if (xatol (argv[2], &player_num) < 0) { fprintf (stderr, "%s: `%s\' is not a number\n", argv[0], argv[2]); return 2; } if (player_num < 4) { fprintf (stderr, "%s: player_num must be greater than 4\n", argv[0]); return 3; } struct sigaction sa = { .sa_handler = SIG_IGN, .sa_flags = 0 }; sigemptyset (&sa.sa_mask); sigaction (SIGPIPE, &sa, NULL); Comp135 comp_struct, *comp; comp = &comp_struct; comp135_init (comp, argv[0], false); JudgeData* jd = xmalloc (sizeof (JudgeData) * judge_num); PlayerData* pd = xmalloc (sizeof (PlayerData) * player_num); struct pollfd* jpoll = xmalloc (sizeof (struct pollfd) * judge_num); for (int i = 0; i < player_num; i++) { pd[i].id = i + 1; pd[i].score = 0; } for (int i = 0; i < judge_num; i++) { int fdr[2], fdw[2]; if (pipe (fdr) < 0) { fprintf (stderr, "%s: pipe: %s\n", argv[0], strerror (errno)); return 4; } if (pipe (fdw) < 0) { fprintf (stderr, "%s: pipe: %s\n", argv[0], strerror (errno)); return 4; } jd[i].pid = fork (); if (jd[i].pid < 0) { fprintf (stderr, "%s: fork: %s\n", argv[0], strerror (errno)); return 5; } else if (jd[i].pid > 0) { close (fdr[1]); close (fdw[0]); } else { close (fdr[0]); close (fdw[1]); dup2 (fdw[0], STDIN_FILENO); close (fdw[0]); dup2 (fdr[1], STDOUT_FILENO); close (fdr[1]); char* myjudge = xgetres ("judge"); execl (myjudge, "judge", xsprintf ("%d", i + 1), (char*)NULL); fprintf (stderr, "%s: execl: %s: %s\n", argv[0], myjudge, strerror (errno)); _exit (1); } jpoll[i].fd = fdr[0]; jpoll[i].events = POLLIN | POLLPRI; jpoll[i].revents = 0; jd[i].read = fdr[0]; jd[i].write = fdw[1]; jd[i].working = false; xbufinit (&jd[i].buf); comp135_log (comp, "Judge %d created: PID = %u, read = %d, write = %d", i + 1, jd[i].pid, jd[i].read, jd[i].write); } int players[4] = {1, 2, 3, 4}; long completed_jobs = 0; long sent_jobs = 0; do { char msg[20]; int msglen; int jnext; msglen = snprintf (msg, 20, "%d %d %d %d\n", players[0], players[1], players[2], players[3]); while ((jnext = nextjudge (jd, judge_num)) < 0) { if (nextscore (comp, jd, judge_num, pd, player_num, jpoll) < 0) { continue; } completed_jobs++; } comp135_log (comp, "Sending %d %d %d %d to judge %d", players[0], players[1], players[2], players[3], jnext + 1); write (jd[jnext].write, msg, msglen); comp135_log (comp, "Judge %d is working now", jnext + 1); jd[jnext].working = true; sent_jobs++; } while (comb4 (players, player_num)); for (; completed_jobs < sent_jobs && nextscore (comp, jd, judge_num, pd, player_num, jpoll) >= 0; completed_jobs++); for (int i = 0; i < judge_num; i++) { const char msg[] = "-1 -1 -1 -1\n"; const int msglen = STATIC_STRLEN (msg); write (jd[i].write, msg, msglen); } qsort (pd, player_num, sizeof (PlayerData), player_sort_cb); printf ("%d", pd[0].id); for (int i = 1; i < player_num; i++) { printf (" %d", pd[i].id); } for (int i = 0; i < player_num; i++) { comp135_log (comp, "Rank %d = Player %d with %ld points", i + 1, pd[i].id, pd[i].score); } free (jd); free (pd); free (jpoll); comp135_destroy (comp); return 0; }