view interps/fukyorbrane/report.c @ 12500:e48c08805365 draft default tip

<b_jonas> ` learn \'The password of the month is Cthulhuquagdonic Mothraquagdonic Narwhalicorn.\' # https://logs.esolangs.org/libera-esolangs/2024-04.html#lKE Infinite craft
author HackEso <hackeso@esolangs.org>
date Wed, 01 May 2024 06:39:10 +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 4
#define RUNCOUNT   (((MAXTAPELEN-MINTAPELEN) + 1) * POLARITIES)

#define KEEP_PROGRAMS 47

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

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

void *runnerThread(void *pvp)
{
    int p = (int) (size_t) pvp;
    int row = p * programCount;
    pid_t pid;
    int i;
    int st;
    char *cacheFilename;
    FILE *cacheF;

    /* go through each program ... */
    for (i = 0; i < programCount; i++) {
        if (p == i) continue;
        
        /* 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 = getc(cacheF);
            fclose(cacheF);
            if (st == EOF)
                st = -1;
            scores[row + i] = st;

        }

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

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

            /* then get the score */
            if (WIFEXITED(st)) {
                st = WEXITSTATUS(st);
            } else {
                st = 0;
            }
            scores[row + i] = st;

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

        free(cacheFilename);
    }

    return NULL;
}

int winner(int p1, int p2)
{
    char win1, win2;

    win1 = scores[p1*programCount + p2];
    win2 = scores[p2*programCount + p1];
    if (win1 == 1 && win2 != 1)
        return p1;
    else if (win1 == 2 && win2 != 2)
        return p2;
    else if (win2 == 2 && win1 != 2)
        return p1;
    else if (win2 == 1 && win1 != 1)
        return p2;

    return -1;
}

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;
    int *plainScores;
    double *preciseScores;
    struct ProgramScore **allScores;
    char *scoreFilename;
    FILE *scoreF;

    if (argc < 4) {
        fprintf(stderr, "Use: report <fyb program> <cache dir> <fyb 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(int)));
    for (i = 0; i < programCount; i++) {
        int score = 0;
        for (j = 0; j < programCount; j++) {
            int win;

            if (i == j) continue;

            win = winner(i, j);
            if (win == i) {
                score++;
            } else if (win == j) {
                score--;
            }
        }
        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;
            int 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);
            if (win == i) {
                score += value;
            } else if (win == 0) {
                score += value/2;
            }
        }
        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   | program\n");

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

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

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

        printf("| %5.1f | %3d | %s\n", preciseScores[i], plainScores[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;
}