summaryrefslogblamecommitdiffstats
path: root/hw2/judge.c
blob: 02b513a8ea808ef544555f4c65d4dbcbfdae87c5 (plain) (tree)
1
2
3
4
5
6
7
8
9







                         
                  
                  
                  
                   
                   
                    
                  
                   

                     
                     
                      
                 

                   



                         


                     
                          

                   

        














                                           






















                                                               






                                                                  
                        




                                                                                   

          



                                                                                       

                                 





















                                                                                   
                                      

         

                                        




                                            

                                                       





                                                

                                       
 


                                  






                                  
                                                                         

                                                                           
                         







                                                                                            
 









                                                            
                                                        
                                              





                                                                                        
                                                                                    
                                                                


                                                                                            
















                                                                            
                                                                             
                                                                                    



                                                                          









                                                                            








































                                                                                                                
                                                 


                                                                                                        

                                                                 
 
                                                                           
 



                                                                                                         
                                                                 













                                                                                                           


                                         










































                                                                                        

                                 











                                                          

                                                                     
                                                                     
                 
                                
 



                               

                                                                                  
         
 
                       

                               




                                                          



                 
/* 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;
}