diff interps/bfjoust/egojoust.c @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/bfjoust/egojoust.c	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,438 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "buffer.h"
+
+#define MINTAPELEN 10
+#define MAXTAPELEN 30
+#define POLARITIES 4
+#define RUNCOUNT   (((MAXTAPELEN-MINTAPELEN) + 1) * POLARITIES)
+
+/* parse a BFJoust program */
+int parseFile(struct Buffer_char *progp)
+{
+    int i, end, inner, iend, llen, ilen, rlen, times, rep, loc;
+    struct Buffer_char prog = *progp;
+    struct Buffer_char temp;
+
+    /* go through looking for things to expand */
+    for (i = 0; i < prog.bufused; i++) {
+        if (prog.buf[i] == '(') {
+            /* look for the match */
+            int depth = 1;
+            inner = iend = -1;
+            for (end = i + 1; end < prog.bufused && depth; end++) {
+                if (prog.buf[end] == '(') {
+                    depth++;
+                } else if (prog.buf[end] == ')') {
+                    depth--;
+                } else if (depth == 1 && prog.buf[end] == '{') {
+                    inner = end;
+                } else if (depth == 1 && prog.buf[end] == '}') {
+                    iend = end;
+                }
+            }
+
+            /* make sure it's sensible */
+            end--;
+            if (end + 2 >= prog.bufused) return 0;
+
+            /* expand it only if it includes [ or ], or is a '%' loop (which make interpretation basically impossible if unexpanded) */
+            llen = end - i;
+            if (strcspn(prog.buf + i, "[]") >= llen && prog.buf[end+1] == '*') {
+                continue;
+            }
+
+            /* check what comes next */
+            times = atoi(prog.buf + end + 2);
+            if (times < 0 || times > 10000) times = 10000;
+            if (prog.buf[end+1] == '*') {
+                llen = end - i - 1;
+
+                /* the simple case, just repeat n times */
+                INIT_BUFFER(temp);
+                temp.bufused = times * llen;
+                while (temp.bufsz < temp.bufused) {
+                    EXPAND_BUFFER(temp);
+                }
+                for (rep = 0; rep < times; rep++) {
+                    memcpy(temp.buf + rep * llen, prog.buf + i + 1, llen);
+                }
+
+            } else if (prog.buf[end+1] == '%') {
+                /* make sure there's a {} */
+                if (inner == -1 || iend == -1) return 0;
+
+                llen = inner - i - 1;
+                ilen = iend - inner - 1;
+                rlen = end - iend - 1;
+                if (llen < 0 || ilen < 0 || rlen < 0) return 0;
+
+                /* set up the buffer */
+                INIT_BUFFER(temp);
+                temp.bufused = times * llen + ilen + times * rlen;
+                while (temp.bufsz < temp.bufused) {
+                    EXPAND_BUFFER(temp);
+                }
+                
+                /* now the left */
+                loc = 0;
+                for (rep = 0; rep < times; rep++) {
+                    memcpy(temp.buf + loc + rep * llen, prog.buf + i + 1, llen);
+                }
+                loc = times * llen;
+
+                /* the inner */
+                memcpy(temp.buf + loc, prog.buf + inner + 1, ilen);
+                loc += ilen;
+
+                /* and the right */
+                for (rep = 0; rep < times; rep++) {
+                    memcpy(temp.buf + loc + rep * rlen, prog.buf + iend + 1, rlen);
+                }
+
+            } else {
+                return 0;
+
+            }
+
+            /* now copy it back into prog */
+            while (prog.bufsz < prog.bufused + temp.bufused + 1) {
+                EXPAND_BUFFER(prog);
+            }
+            memmove(prog.buf + i + temp.bufused, prog.buf + end + 1, prog.bufused - end - 1);
+            memcpy(prog.buf + i, temp.buf, temp.bufused);
+            prog.bufused = prog.bufused - end + i - 1 + temp.bufused;
+            WRITE_BUFFER(prog, "", 1); prog.bufused--;
+
+            FREE_BUFFER(temp);
+
+            i--;
+        }
+    }
+
+    memcpy(progp, &prog, sizeof(prog));
+    return 1;
+}
+
+/* returns true if this is a BF comment */
+int isComment(char c)
+{
+    return (c != '<' && c != '>' && c != '-' && c != '+' && c != '[' && c != ']' && c != '(' && c != ')' && c != '.');
+}
+
+/* run an execution step */
+void runStep(struct Buffer_char prog, int *loops, int *pip,
+             char *tape, char *otape, int tapelen, int *tip,
+             int tapedir, int polarity,
+             struct Buffer_int *pstack, struct Buffer_int *pmax)
+{
+    int pi = *pip;
+    int ti = *tip;
+    int reps = 0;
+
+    /* find a non-comment character */
+rerun:
+    if (++reps > 16) return;
+    if (pi < 0) return;
+    for (; pi < prog.bufused && isComment(prog.buf[pi]); pi++);
+    *pip = pi;
+    if (pi >= prog.bufused) return;
+
+    /* run it */
+    switch (prog.buf[pi]) {
+        case '<':
+            ti -= tapedir;
+            break;
+
+        case '>':
+            ti += tapedir;
+            break;
+
+        case '-':
+            otape[ti] -= polarity;
+            break;
+
+        case '+':
+            otape[ti] += polarity;
+            break;
+
+        case '[':
+            if (tape[ti] == 0) {
+                /* first check the cache */
+                if (loops[pi] != -1) {
+                    pi = loops[pi];
+                } else {
+                    int depth = 1;
+                    int opi = pi;
+                    for (pi++; pi < prog.bufused && depth; pi++) {
+                        switch (prog.buf[pi]) {
+                            case '[':
+                                depth++;
+                                break;
+
+                            case ']':
+                                depth--;
+                                break;
+                        }
+                    }
+                    pi--;
+
+                    loops[opi] = pi;
+                    loops[pi] = opi;
+                }
+            }
+            break;
+
+        case ']':
+            if (tape[ti] != 0) {
+                /* check the cache */
+                if (loops[pi] != -1) {
+                    pi = loops[pi];
+                } else {
+                    int depth = 1;
+                    for (pi--; pi >= 0 && depth; pi--) {
+                        switch (prog.buf[pi]) {
+                            case ']':
+                                depth++;
+                                break;
+
+                            case '[':
+                                depth--;
+                                break;
+                        }
+                    }
+                    pi++;
+                }
+            }
+            break;
+
+        case '(':
+            /* make sure this is cached */
+            if (loops[pi] == -1) {
+                int depth = 1;
+                int ipi;
+                for (ipi = pi + 1; ipi < prog.bufused && depth; ipi++) {
+                    switch (prog.buf[ipi]) {
+                        case '(':
+                            depth++;
+                            break;
+
+                        case ')':
+                            depth--;
+                            break;
+                    }
+                }
+                ipi--;
+
+                loops[pi] = ipi;
+                loops[ipi] = pi;
+            }
+
+            /* push the counter */
+            {
+                int count = atoi(prog.buf + loops[pi] + 2);
+                if (BUFFER_SPACE(*pstack) < 1) {
+                    EXPAND_BUFFER(*pstack);
+                    EXPAND_BUFFER(*pmax);
+                }
+                pstack->buf[pstack->bufused++] = 0;
+                pmax->buf[pmax->bufused++] = count;
+            }
+
+            /* then continue immediately */
+            pi++;
+            goto rerun;
+
+        case ')':
+            /* increment the counter */
+            if (pstack->bufused > 0) {
+                pstack->buf[pstack->bufused-1]++;
+            }
+
+            /* either reloop or don't */
+            if (pstack->buf[pstack->bufused-1] < pmax->buf[pstack->bufused-1]) {
+                pi = loops[pi];
+            } else {
+                pstack->bufused = pmax->bufused = pstack->bufused - 1;
+            }
+            pi++;
+            goto rerun;
+
+        case '.':
+            /* nop */
+            break;
+    }
+    pi++;
+
+    *pip = pi;
+    *tip = ti;
+}
+
+/* simple hashing function, same as is used in sdbm */
+size_t simpleHash(size_t slen, unsigned char *str)
+{
+    size_t hash = 0;
+
+    for (; slen > 0; slen--)
+        hash = (*str++) + (hash << 6) + (hash << 16) - hash;
+
+    return hash;
+}
+
+int main(int argc, char **argv)
+{
+    struct Buffer_char lprog, rprog;
+    struct Buffer_int lloops, rloops;
+    struct Buffer_int lpstack, rpstack, lpmax, rpmax;
+    FILE *lfh, *rfh;
+    int lparse, rparse;
+    char *tape, *otape;
+    int lt, rt, tapelen;
+    int polarity, lpol, rpol;
+    int lpi, rpi;
+    int lwins, rwins;
+    int lloss, rloss;
+    int step;
+
+    if (argc < 3) {
+        fprintf(stderr, "Use: egojoust <left program> <right program>\n");
+        return 0;
+    }
+
+    /* read in the files */
+    INIT_BUFFER(lprog);
+    SF(lfh, fopen, NULL, (argv[1], "r"));
+    READ_FILE_BUFFER(lprog, lfh);
+    WRITE_BUFFER(lprog, "", 1); lprog.bufused--;
+
+    INIT_BUFFER(rprog);
+    SF(rfh, fopen, NULL, (argv[2], "r"));
+    READ_FILE_BUFFER(rprog, rfh);
+    WRITE_BUFFER(rprog, "", 1); rprog.bufused--;
+
+    /* parse them */
+    lparse = parseFile(&lprog);
+    rparse = parseFile(&rprog);
+    if (!lparse) {
+        if (!rparse) {
+            printf("Both warriors failed to parse. Tie!\n");
+            return 0;
+        } else {
+            printf("Left warrior failed to parse, right warrior wins!\n");
+            return RUNCOUNT;
+        }
+    } else if (!rparse) {
+        printf("Right warrior failed to parse, left warrior wins!\n");
+        return -RUNCOUNT;
+    }
+
+    /* allocate the tape */
+    SF(tape, malloc, NULL, (30));
+    SF(otape, malloc, NULL, (30));
+
+    /* prepare the caches */
+    INIT_BUFFER(lloops);
+    INIT_BUFFER(rloops);
+    while (lloops.bufsz < lprog.bufused) EXPAND_BUFFER(lloops);
+    memset(lloops.buf, -1, lprog.bufused * sizeof(int));
+    while (rloops.bufsz < rprog.bufused) EXPAND_BUFFER(rloops);
+    memset(rloops.buf, -1, rprog.bufused * sizeof(int));
+
+    INIT_BUFFER(lpstack);
+    INIT_BUFFER(rpstack);
+    INIT_BUFFER(lpmax);
+    INIT_BUFFER(rpmax);
+
+    /* run for each polarity, for each length from 10 to 30 */
+    lwins = 0;
+    rwins = 0;
+
+    printf("%s vs %s:\n", argv[1], argv[2]);
+
+    for (polarity = 0; polarity < POLARITIES; polarity++) {
+        /* set up the polarity */
+        if (polarity & 0x2) {
+            lpol = -1;
+        } else {
+            lpol = 1;
+        }
+
+        if (polarity & 0x1) {
+            rpol = -1;
+        } else {
+            rpol = 1;
+        }
+
+    for (tapelen = MINTAPELEN; tapelen <= MAXTAPELEN; tapelen++) {
+        /* make the tape */
+        memset(tape, 0, tapelen);
+        tape[0] = tape[tapelen-1] = (char) (unsigned char) 128;
+        lt = 0;
+        rt = tapelen - 1;
+        memcpy(otape, tape, tapelen);
+
+        /* then run */
+        lpi = rpi = lloss = rloss = 0;
+        for (step = 0; step < 100000 && lloss < 2 && rloss < 2; step++) {
+            /* run the left */
+            runStep(lprog, lloops.buf, &lpi, tape, otape, tapelen, &lt, 1, lpol, &lpstack, &lpmax);
+
+            /* and the right */
+            runStep(rprog, rloops.buf, &rpi, tape, otape, tapelen, &rt, -1, rpol, &rpstack, &rpmax);
+
+            /* commit the tape */
+            memcpy(tape, otape, tapelen);
+
+            /* check for loss conditions */
+            if (tape[0] == 0) {
+                lloss++;
+            } else {
+                lloss = 0;
+            }
+            if (lt < 0 || lt >= tapelen) {
+                fprintf(stderr, "Left ran off the tape (%d/%d)!\n", lt, tapelen);
+                lloss = 3;
+            }
+            if (tape[tapelen-1] == 0) {
+                rloss++;
+            } else {
+                rloss = 0;
+            }
+            if (rt < 0 || rt >= tapelen) {
+                fprintf(stderr, "Right ran off the tape (%d/%d)!\n", rt, tapelen);
+                rloss = 3;
+            }
+        }
+
+        /* now find the victor */
+        if (lloss > rloss) {
+            /*printf("%d/%d: %s wins!\n", polarity, tapelen, argv[2]);*/
+            printf(">");
+            rwins++;
+        } else if (rloss > lloss) {
+            /*printf("%d/%d: %s wins!\n", polarity, tapelen, argv[1]);*/
+            printf("<");
+            lwins++;
+        } else {
+            /*printf("%d/%d: Tie!\n", polarity, tapelen);*/
+            printf("X");
+        }
+    }
+
+    printf(" ");
+    }
+
+    printf("\n");
+
+    if (lwins > rwins) {
+        printf("%s wins\n\n", argv[1]);
+    } else if (rwins > lwins) {
+        printf("%s wins\n\n", argv[2]);
+    } else {
+        printf("Tie\n\n");
+    }
+    return rwins - lwins;
+}