view interps/bfjoust/report.c @ 3418:d0d4a6a6ad9b

<boily> learn ph\xe1\xbb\x9f l\xc3\xa0 m\xe1\xbb\x99t m\xc3\xb3n \xc4\x83n truy\xe1\xbb\x81n th\xe1\xbb\x91ng c\xe1\xbb\xa7a Vi\xe1\xbb\x87t Nam, c\xc5\xa9ng c\xc3\xb3 th\xe1\xbb\x83 xem l\xc3\xa0 m\xe1\xbb\x99t trong nh\xe1\xbb\xafng m\xc3\xb3n \xc4\x83n \xc4\x91\xe1\xba\xb7c tr\xc6\xb0ng nh\xe1\xba\xa5t cho \xe1\xba\xa9m th\xe1\xbb\xb1c Vi\xe1\xbb\x87t Nam.
author HackBot
date Thu, 15 Aug 2013 19:52:26 +0000
parents 859f9b4339e6
children
line wrap: on
line source

/*
 * Copyright (c) 2009, 2011 Gregor Richards
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/* NOTE: I am aware of how ugly this code is. It was quick hack. */

#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif

#include <pthread.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "helpers.h"

#define MINTAPELEN 10
#define MAXTAPELEN 30
#define POLARITIES 2
#define RUNCOUNT   (((MAXTAPELEN-MINTAPELEN) + 1) * POLARITIES)

#define KEEP_PROGRAMS 47

char *fyb, *cachedir;
int programCount;
char **programs;
signed char *scores;
int breakdown;

struct ProgramScore {
    int id;
    double pts;
    double prc;
};

void *runnerThread(void *pvp)
{
    int p = (int) (size_t) pvp;
    int row = p * programCount;
    pid_t pid;
    int i, tmpi;
    int st;
    int scorepipe[2];
    char scorepipes[128];
    char *cacheFilename;
    FILE *cacheF;

    /* go through each program ... */
    for (i = p + 1; i < programCount; i++) {
        /* check the cache */
        SF(cacheFilename, malloc, NULL, (strlen(cachedir) + strlen(programs[p]) + strlen(programs[i]) + 5));
        sprintf(cacheFilename, "%s/:%s:%s:", cachedir, programs[p], programs[i]);
        cacheF = fopen(cacheFilename, "r");

        st = -1;
        if (cacheF != NULL) {
            /* get the result out of the cache */
            st = (signed char) getc(cacheF);
            fclose(cacheF);
            if (st == EOF)
                st = -1;
            scores[row + i] = st;

        }

        if (st == -1) {
            /* and run p vs i */
            SF(tmpi, pipe, -1, (scorepipe));
            sprintf(scorepipes, "%d", scorepipe[1]);
            SF(pid, fork, -1, ());
            if (pid == 0) {
                close(0);
                close(1);
                close(2);
                dup2(breakdown, 1);
                execlp(fyb, fyb, programs[p], programs[i], scorepipes, NULL);
                exit(0);
            }
            close(scorepipe[1]);

            /* wait for it */
            waitpid(pid, &st, 0);

            if (WEXITSTATUS(st) != 0) {
                st = 0;
            } else {
                /* read in the score */
                st = 0;
                SF(tmpi, read, -1, (scorepipe[0], &st, sizeof(int)));
                scores[row + i] = st;
            }
            close(scorepipe[0]);

            /* and cache it */
            cacheF = fopen(cacheFilename, "w");
            if (cacheF != NULL) {
                putc(st, cacheF);
                fclose(cacheF);
            }
        }

        free(cacheFilename);
    }

    return NULL;
}

/* returns points won by p1 against p2 */
int winner(int p1, int p2)
{
    signed char win;

    if (p1 < p2) {
        win = scores[p1*programCount + p2] * -1;
    } else {
        win = scores[p2*programCount + p1];
    }

    return win;
}

int ptscompar(const void *lv, const void *rv)
{
    const struct ProgramScore *l = *((const struct ProgramScore **) lv);
    const struct ProgramScore *r = *((const struct ProgramScore **) rv);

    if (l->pts < r->pts) {
        return -1;
    } else if (l->pts > r->pts) {
        return 1;
    } else {
        return 0;
    }
}

int prccompar(const void *lv, const void *rv)
{
    const struct ProgramScore *l = *((const struct ProgramScore **) lv);
    const struct ProgramScore *r = *((const struct ProgramScore **) rv);

    if (l->prc < r->prc) {
        return -1;
    } else if (l->prc > r->prc) {
        return 1;
    } else {
        return 0;
    }
}

int main(int argc, char **argv)
{
    pthread_t *threads;
    int i, j;
    double *plainScores;
    double *preciseScores;
    struct ProgramScore **allScores;
    char *scoreFilename;
    FILE *scoreF;

    if (argc < 4) {
        fprintf(stderr, "Use: report <bfjoust program> <cache dir> <bfjoust files>\n");
        return 1;
    }

    fyb = argv[1];
    cachedir = argv[2];
    programCount = argc - 3;
    programs = argv + 3;

    signal(SIGCHLD, SIG_DFL);

    /* allocate space for the scores */
    SF(scores, malloc, NULL, (programCount * programCount));

    /* now run them in threads */
    breakdown = open("breakdown.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
    SF(threads, malloc, NULL, (programCount * sizeof(pthread_t)));
    for (i = 0; i < programCount; i++) {
        /*pthread_create(&threads[i], NULL, runnerThread, (void *) (size_t) i);*/
        runnerThread((void *) (size_t) i);
    }
    close(breakdown);

    /* wait for the threads to finish * /
       for (i = 0; i < programCount; i++) {
       pthread_join(threads[i], NULL);
       } */

    /* allocate the score buffers */
    SF(allScores, malloc, NULL, (programCount * sizeof(struct ProgramScore *)));
    for (i = 0; i < programCount; i++) {
        SF(allScores[i], malloc, NULL, (sizeof(struct ProgramScore)));
        allScores[i]->id = i;
    }

    /* now calculate the plain score for each */
    SF(plainScores, malloc, NULL, (programCount * sizeof(double)));
    for (i = 0; i < programCount; i++) {
        double score = 0;
        for (j = 0; j < programCount; j++) {
            if (i == j) continue;

            score += winner(i, j) / (double) RUNCOUNT;
        }
        allScores[i]->pts = plainScores[i] = score;
    }

    /* and the precise scores for each */
    SF(preciseScores, malloc, NULL, (programCount * sizeof(double)));
    for (i = 0; i < programCount; i++) {
        double score = 0;
        for (j = 0; j < programCount; j++) {
            double value;
            double win;

            if (i == j) continue;

            /* get the value of j */
            value = (double) (plainScores[j] + programCount) / (double) (2*programCount-2);

            /* and add the value if correct */
            win = winner(i, j) / (double) RUNCOUNT;
            if (win > 0) {
                score += value * win;
            }
        }
        allScores[i]->prc = preciseScores[i] = score * 200 / (programCount-1);

        /* save it to the cache */
        SF(scoreFilename, malloc, NULL, (strlen(cachedir) + strlen(programs[i]) + 8));
        sprintf(scoreFilename, "%s/%s.score", cachedir, programs[i]);
        scoreF = fopen(scoreFilename, "w");
        if (scoreF != NULL) {
            fprintf(scoreF, "%.1f", preciseScores[i]);
            fclose(scoreF);
        }
        free(scoreFilename);
    }

    /* now print out the scores */
    qsort(allScores, programCount, sizeof(struct ProgramScore *), prccompar);
    printf("Pos  ID   Score  Points  Program\n");
    for (i = programCount - 1; i >= 0; i--) {
        struct ProgramScore *sc = allScores[i];
        printf(" %2d  %2d  %6.2f  %6.2f  %s\n",
                programCount - i, (int) sc->id, sc->prc, sc->pts, programs[sc->id]);
    }
    printf("\n");

    /* and the full scoreboard */

    /* header */
    printf("   | ");
    for (i = 0; i < programCount; i++) {
        if (i < 10) printf("  ");
        else        printf("%1d ", (int) (i/10%10));
    }
    printf("|\n   | ");
    for (i = 0; i < programCount; i++) {
        printf("%1d ", (int) (i%10));
    }
    printf("| score | pts   | id | program\n");

    /* scores */
    for (i = 0; i < programCount; i++) {
        printf("%2d | ", (int) i);
        for (j = 0; j < programCount; j++) {
            double win;

            if (i == j) {
                printf("  ");
                continue;
            }

            win = winner(i, j);
            if (win > 0) {
                printf("+ ");
            } else if (win < 0) {
                printf("- ");
            } else {
                printf("0 ");
            }
        }

        printf("| %5.1f | %5.1f | %2d | %s\n", preciseScores[i], plainScores[i], (int) i, programs[i]);
    }

    /* kill any poorly-performing programs */
    if (programCount > KEEP_PROGRAMS) {
        for (i = 0; i < programCount - KEEP_PROGRAMS; i++) {
            char buf[1024];
            snprintf(buf, 1024, "hg rm -f %s", programs[allScores[i]->id]);
            system(buf);
            system(buf + 3);
        }
        system("hg commit -m Trimming.");
    }

    return 0;
}