Mercurial > repo
view interps/bfjoust/egojoust.c @ 12518:2d8fe55c6e65 draft default tip
<int-e> learn The password of the month is release incident pilot.
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Sun, 03 Nov 2024 00:31:02 +0000 |
parents | 859f9b4339e6 |
children |
line wrap: on
line source
#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, <, 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; }