diff interps/adjust/adjust.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/adjust/adjust.c	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,498 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+typedef unsigned char cell;
+
+cell *read_arbitrary_length_string(FILE *fp);
+void run(cell **code, int lines, int maxline);
+
+int main(int argc, char *argv[])
+{
+	cell **code;
+	FILE *src;
+	int codespace, codelines = 0, maxline = 0;
+
+	if (argc != 2)
+	{
+		fprintf(stderr, "Incorrect invocation\n");
+		return 1;
+	}
+
+	src = fopen(argv[1], "r");
+	if (src == NULL)
+	{
+		fprintf(stderr, "Unreadable file\n");
+		return 2;
+	}
+
+	codespace = 10;
+	code = malloc(codespace * sizeof(cell*));
+	if (!code)
+		return 3;
+
+	for (;;)
+	{
+		int len;
+		if (codelines == codespace)
+		{
+			codespace *= 2;
+			code = realloc(code, codespace * sizeof(cell*));
+			if (!code)
+				return 4;
+		}
+		code[codelines] = read_arbitrary_length_string(src);
+		if (code[codelines] == NULL)
+			break;
+		len = strlen(code[codelines]);
+		if (len > maxline)
+			maxline = len;
+		codelines++;
+	}
+	fclose(src);
+
+	run(code, codelines, maxline);
+	free(code);
+	return 0;
+}
+
+cell *addmem(cell *mem, int cursize, int newsize)
+{
+	mem = realloc(mem, newsize);
+	if (!mem)
+	{
+		fprintf(stderr, "Out of memory\n");
+		exit(-1);
+	}
+	memset(&mem[cursize], 0, newsize - cursize);
+	return mem;
+}
+
+/* For 2 <= n <= 126, next[n] = n / gpf[n]. */
+cell next[127] =
+{
+	 0,  0,  1,  1,  2,  1,  2,  1,
+	 4,  3,  2,  1,  4,  1,  2,  3,
+	 8,  1,  6,  1,  4,  3,  2,  1,
+	 8,  5,  2,  9,  4,  1,  6,  1,
+	16,  3,  2,  5, 12,  1,  2,  3,
+	 8,  1,  6,  1,  4,  9,  2,  1,
+	16,  7, 10,  3,  4,  1, 18,  5,
+	 8,  3,  2,  1, 12,  1,  2,  9,
+	32,  5,  6,  1,  4,  3, 10,  1,
+	24,  1,  2, 15,  4,  7,  6,  1,
+	16, 27,  2,  1, 12,  5,  2,  3,
+	 8,  1, 18,  7,  4,  3,  2,  5,
+	32,  1, 14,  9, 20,  1,  6,  1,
+	 8, 15,  2,  1, 36,  1, 10,  3,
+	16,  1,  6,  5,  4,  9,  2,  7,
+	24, 11,  2,  3,  4, 25, 18
+};
+
+/* For 2 <= n <= 126, gpf[n] is n's greatest prime factor. */
+cell gpf[127] =
+{
+	  0,   0,   2,   3,   2,   5,   3,   7,
+	  2,   3,   5,  11,   3,  13,   7,   5,
+	  2,  17,   3,  19,   5,   7,  11,  23,
+	  3,   5,  13,   3,   7,  29,   5,  31,
+	  2,  11,  17,   7,   3,  37,  19,  13,
+	  5,  41,   7,  43,  11,   5,  23,  47,
+	  3,   7,   5,  17,  13,  53,   3,  11,
+	  7,  19,  29,  59,   5,  61,  31,   7,
+	  2,  13,  11,  67,  17,  23,   7,  71,
+	  3,  73,  37,   5,  19,  11,  13,  79,
+	  5,   3,  41,  83,   7,  17,  43,  29,
+	 11,  89,   5,  13,  23,  31,  47,  19,
+	  3,  97,   7,  11,   5, 101,  17, 103,
+	 13,   7,  53, 107,   3, 109,  11,  37,
+	  7, 113,  19,  23,  29,  13,  59,  17,
+	  5,  11,  61,  41,  31,   5,   7
+};
+
+cell bitsset[256] =
+{
+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+#define       LEFT     0
+#define    UP_LEFT     1
+#define         UP     2
+#define   UP_RIGHT     3
+#define      RIGHT     4
+#define DOWN_RIGHT     5
+#define       DOWN     6
+#define  DOWN_LEFT     7
+
+#define RIGHT135(d) ((d) = right135((d)))
+#define  RIGHT90(d) ((d) =  right90((d)))
+#define  RIGHT45(d) ((d) =  right45((d)))
+#define   LEFT45(d) ((d) =   left45((d)))
+#define   LEFT90(d) ((d) =   left90((d)))
+static inline int right135(int dir) { return (dir+3)%8; }
+static inline int  right90(int dir) { return (dir+2)%8; }
+static inline int  right45(int dir) { return (dir+1)%8; }
+static inline int   left45(int dir) { return (dir-1)%8; }
+static inline int   left90(int dir) { return (dir-2)%8; }
+static inline void movefwd(int *x, int *y, int dir, int steps)
+{
+	if (dir == LEFT || dir == UP_LEFT || dir == DOWN_LEFT)
+		*x -= steps;
+	else if (dir == RIGHT || dir == UP_RIGHT || dir == DOWN_RIGHT)
+		*x += steps;
+	if (dir == UP || dir == UP_LEFT || dir == UP_RIGHT)
+		*y -= steps;
+	else if (dir == DOWN || dir == DOWN_LEFT || dir == DOWN_RIGHT)
+		*y += steps;
+}
+#ifdef UNSAFE
+static inline void checkmove(int x, int y, int w, int h) {}
+#else
+static inline void checkmove(int x, int y, int w, int h)
+{
+	if (x < 0 || y < 0 || x >= w || y >= h)
+	{
+		fprintf(stderr, "Out of bounds\n");
+		exit(-1);
+	}
+}
+#endif
+static inline void push(cell val, cell **pstack, int *items, int *space)
+{
+	if (*items == *space)
+	{
+		*pstack = addmem(*pstack, *space, 2**space);
+		*space *= 2;
+	}
+	(*pstack)[(*items)++] = val;
+}
+static inline int pop(cell *stack, int *items)
+{
+	if (*items == 0)
+		return -1;
+	return stack[--(*items)];
+}
+static inline int peek(cell *stack, int items)
+{
+	if (items == 0)
+		return -1;
+	return stack[items - 1];
+}
+
+void run(cell **code, int lines, int maxline)
+{
+	cell acc, *stack1 = NULL, *stack2 = NULL;
+	int stack1size = 10, stack2size = 10;
+	int stack1pos = 0, stack2pos = 0;
+	int dir = UP_RIGHT, codex, codey;
+	int i, *lengths;
+
+	stack1 = addmem(stack1, 0, stack1size);
+	stack2 = addmem(stack2, 0, stack2size);
+	acc = 0;
+	codex = 0;
+	codey = lines - 1;
+
+	lengths = malloc(sizeof(int) * lines);
+	for (i = 0; i < lines; i++)
+		lengths[i] = strlen(code[i]);
+
+	for (;;)
+	{
+		cell c;
+		if (codex >= lengths[codey])
+			c = '!'; /* lines are padded with ! */
+		else
+		{
+			c = code[codey][codex];
+#ifndef UNSAFE
+			if (c < 32 || c > 126)
+			{
+				fprintf(stderr, "Invalid character\n");
+				exit(-1);
+			}
+#endif
+		}
+
+		/* run the commands */
+		for (; c > 1; c = next[(size_t) c]) switch(gpf[(size_t) c])
+		{
+			case 2:
+			{
+				cell tmp;
+				tmp = (acc & 7) << 5;
+				acc >>= 3;
+				acc |= tmp;
+				break;
+			}
+			case 3:
+			{
+				int s1, s2;
+				s1 = peek(stack1, stack1pos);
+				s2 = peek(stack2, stack2pos);
+				if (s2 < s1)
+				{
+					push(acc, &stack2,
+						&stack2pos, &stack2size);
+					LEFT45(dir);
+					movefwd(&codex, &codey, dir, 1);
+					break;
+				}
+				push(acc, &stack1, &stack1pos, &stack1size);
+				if (s2 == s1)
+				{
+					RIGHT45(dir);
+					movefwd(&codex, &codey, dir, 1);
+					break;
+				}
+				if (acc)
+					LEFT90(dir);
+				else
+					RIGHT135(dir);
+				movefwd(&codex, &codey, dir, 1);
+				break;
+			}
+			case 5:
+			{
+				if (acc & 1)
+					acc--;
+				else
+					acc++;
+				break;
+			}
+			case 7:
+			{
+				movefwd(&codex, &codey, dir,
+					bitsset[(size_t) acc]);
+				break;
+			}
+			case 11:
+			{
+				int s1, s2;
+				s1 = peek(stack1, stack1pos);
+				s2 = peek(stack2, stack2pos);
+				if (s1 > s2)
+					acc = pop(stack1, &stack1pos);
+				else if (s2 == -1)
+					acc = 0;
+				else
+					acc = pop(stack2, &stack2pos);
+				break;
+			}
+			case 13:
+			{
+				int s2;
+				s2 = pop(stack2, &stack2pos);
+				if (s2 != -1)
+					putchar(s2);
+				break;
+			}
+			case 17:
+			case 19:
+			{
+				int ch;
+				if (gpf[(size_t) c] == 17)
+					ch = getchar();
+				else
+					ch = pop(stack2, &stack2pos);
+				if (ch < 0 || ch > 255) /* empty stack/EOF */
+				{
+					int steps = 0;
+					if (acc & (1<<2))
+						RIGHT90(dir);
+					steps += (acc & (1<<3));
+					steps += (acc & (1<<4));
+					steps += (acc & (1<<7));
+					movefwd(&codex, &codey, dir, steps);
+					break;
+				}
+				push(ch, &stack1, &stack1pos, &stack1size);
+				break;
+			}
+			case 23:
+			{
+				acc <<= 5;
+				break;
+			}
+			case 29:
+			{
+				int s1, s2, steps = 2;
+				if (acc != 0)
+					break;
+				LEFT45(dir);
+				s1 = peek(stack1, stack1pos);
+				s2 = peek(stack2, stack2pos);
+				if (s2 < s1)
+					steps++;
+				movefwd(&codex, &codey, dir, steps);
+				RIGHT45(dir);
+				break;
+			}
+			case 31:
+			{
+				movefwd(&codex, &codey, dir, 1);
+				break;
+			}
+			case 37:
+			{
+				int s1, s2;
+				s1 = peek(stack1, stack1pos);
+				s2 = peek(stack2, stack2pos);
+				if (s1 == s2)
+					break;
+				if (s1 < s2)
+					push(s1, &stack2, &stack2pos,
+						&stack2size);
+				else
+					push(s2, &stack1, &stack1pos,
+						&stack1size);
+				break;
+			}
+			case 41:
+			{
+				int s1, s2;
+				s1 = peek(stack1, stack1pos);
+				s2 = peek(stack2, stack2pos);
+				if (s1 == s2)
+					break;
+				if (s1 > s2)
+					pop(stack1, &stack1pos);
+				else
+					pop(stack2, &stack2pos);
+				break;
+			}
+			case 43:
+			{
+				acc >>= 1;
+				if (!acc)
+				{
+					movefwd(&codex, &codey, dir, 1);
+					LEFT90(dir);
+				}
+				break;
+			}
+			case 47:
+			{
+				int s1, s2;
+				s1 = peek(stack1, stack1pos);
+				s2 = peek(stack2, stack2pos);
+				if (s1 == s2)
+					break;
+				if (s1 < s2)
+					acc = pop(stack1, &stack1pos);
+				else
+					acc = pop(stack2, &stack2pos);
+				break;
+			}
+			case 53:
+			{
+				int s1, s2;
+				s1 = peek(stack1, stack1pos);
+				s2 = peek(stack2, stack2pos);
+				if (s1 < s2)
+				{
+					cell tmp;
+					tmp = acc & 0xf0;
+					if (acc & 1)
+						tmp |= 8;
+					if (acc & 2)
+						tmp |= 4;
+					if (acc & 4)
+						tmp |= 2;
+					if (acc & 8)
+						tmp |= 1;
+					acc = tmp;
+				}
+				else
+				{
+					cell tmp;
+					tmp = acc & 0x0f;
+					if (acc & 16)
+						tmp |= 128;
+					if (acc & 32)
+						tmp |= 64;
+					if (acc & 64)
+						tmp |= 32;
+					if (acc & 128)
+						tmp |= 16;
+					acc = tmp;
+				}
+				break;
+			}
+			case 59:
+			{
+				int n;
+				n = bitsset[(size_t) acc] % 8;
+				while(n--)
+					RIGHT45(dir);
+				break;
+			}
+			case 61:
+			{
+				cell *tmps;
+				int tmp;
+				tmps = stack1;
+				stack1 = stack2;
+				stack2 = tmps;
+				tmp = stack1size;
+				stack1size = stack2size;
+				stack2size = tmp;
+				tmp = stack1pos;
+				stack1pos = stack2pos;
+				stack2pos = tmp;
+				break;
+			}
+			case 67:
+				goto quit;
+			default:
+				acc = gpf[(size_t) c];
+		}
+
+		movefwd(&codex, &codey, dir, 1);
+		checkmove(codex, codey, maxline, lines);
+	}
+
+quit:
+	free(lengths);
+	free(stack1);
+	free(stack2);
+}
+
+cell *read_arbitrary_length_string(FILE *fp)
+{
+	cell *p = NULL, *q;
+	int size = 50;
+
+	if ((p = malloc(size)) == NULL)
+		return NULL;
+	if (fgets(p, size, fp) == NULL)
+		return NULL;
+
+	while ((q = strchr(p, '\n')) == NULL)
+	{
+		size *= 2;
+		if ((p = realloc(p, size)) == NULL)
+			return NULL;
+		if (fgets(&p[size/2-1], size/2+1, fp) == NULL)
+			return NULL; /* invalid; file must end with newline */
+	}
+
+	*q = '\0';
+	return p;
+}