pietr

Piet code runner
git clone https://git.sinitax.com/sinitax/pietr
Log | Files | Refs | LICENSE | sfeed.txt

pietr.c (7062B)


      1#include <stdlib.h>
      2#include <stdio.h>
      3#include <stdbool.h>
      4#include <stdarg.h>
      5#include <err.h>
      6
      7#define STB_IMAGE_IMPLEMENTATION
      8#include "stb_image.h"
      9#define STB_IMAGE_WRITE_IMPLEMENTATION
     10#include "stb_image_write.h"
     11
     12#define ARRLEN(x) (sizeof(x)/sizeof((x)[0]))
     13#define ABS(x) ((x) >= 0 ? (x) : -(x))
     14
     15#define ASSERT(x) do { \
     16	if (!(x)) errx(1, "Assertion failed: '%s'", #x); } while (0)
     17#define ASSERTI(i, x) do { \
     18	if (!(x)) errx(1, "Assertion failed: '%s' in %s", #x, #i); } while (0)
     19
     20#define BLACK 18
     21#define WHITE 19
     22
     23enum {
     24	PUSH,
     25	POP,
     26	ADD,
     27	SUB,
     28	MUL,
     29	DIV,
     30	MOD,
     31	NOT,
     32	GTR,
     33	DPI,
     34	CCI,
     35	DUP,
     36	ROLL,
     37	INN,
     38	INC,
     39	OUTN,
     40	OUTC,
     41	NONE
     42};
     43
     44static const char *inst_names[] = {
     45	"PUSH",
     46	"POP",
     47	"ADD",
     48	"SUB",
     49	"MUL",
     50	"DIV",
     51	"MOD",
     52	"NOT",
     53	"GTR",
     54	"DPI",
     55	"CCI",
     56	"DUP",
     57	"ROLL",
     58	"INN",
     59	"INC",
     60	"OUTN",
     61	"OUTC",
     62	""
     63};
     64
     65static const int inst_lut[18] = {
     66	[0 * 3 + 0] = NONE,
     67	[0 * 3 + 1] = PUSH,
     68	[0 * 3 + 2] = POP,
     69	[1 * 3 + 0] = ADD,
     70	[1 * 3 + 1] = SUB,
     71	[1 * 3 + 2] = MUL,
     72	[2 * 3 + 0] = DIV,
     73	[2 * 3 + 1] = MOD,
     74	[2 * 3 + 2] = NOT,
     75	[3 * 3 + 0] = GTR,
     76	[3 * 3 + 1] = DPI,
     77	[3 * 3 + 2] = CCI,
     78	[4 * 3 + 0] = DUP,
     79	[4 * 3 + 1] = ROLL,
     80	[4 * 3 + 2] = INN,
     81	[5 * 3 + 0] = INC,
     82	[5 * 3 + 1] = OUTN,
     83	[5 * 3 + 2] = OUTC,
     84};
     85
     86static const uint32_t colors[20] = {
     87	0xffc0c0, 0xffffc0, 0xc0ffc0, 0xc0ffff, 0xc0c0ff, 0xffc0ff,
     88	0xff0000, 0xffff00, 0x00ff00, 0x00ffff, 0x0000ff, 0xff00ff,
     89	0xc00000, 0xc0c000, 0x00c000, 0x00c0c0, 0x0000c0, 0xc000c0,
     90	0x000000, 0xffffff,
     91};
     92
     93static const size_t stacksize = 2048;
     94static int debug = 0;
     95
     96int
     97getcolor(uint8_t *pix, int stride, int x, int y)
     98{
     99	uint32_t rgb;
    100	int i;
    101
    102	rgb = pix[y * stride + x * 3 + 0] << 16
    103		| pix[y * stride + x * 3 + 1] << 8
    104		| pix[y * stride + x * 3 + 2] << 0;
    105	for (i = 0; i < ARRLEN(colors); i++)
    106		if (colors[i] == rgb)
    107			return i;
    108
    109	errx(1, "Encountered invalid color: #%06X", rgb);
    110	return -1;
    111}
    112
    113int
    114getinst(int prev, int next)
    115{
    116	int dx, dy;
    117
    118	if (prev == WHITE || next == WHITE)
    119		return NONE;
    120	dx = ((next % 6) - (prev % 6) + 6) % 6;
    121	dy = ((next / 6) - (prev / 6) + 3) % 3;
    122	return inst_lut[dx * 3 + dy];
    123}
    124
    125const char *
    126dirstr(int dx, int dy)
    127{
    128	if (dx > 0)
    129		return "+X";
    130	else if (dx < 0)
    131		return "-X";
    132	else if (dy > 0)
    133		return "+Y";
    134	else if (dy < 0)
    135		return "-Y";
    136	else
    137		return "O";
    138}
    139
    140void
    141rotate(int *dx, int *dy)
    142{
    143	if (debug) printf("ROTATE %s ->", dirstr(*dx, *dy));
    144	if (*dx != 0) {
    145		*dy = *dx;
    146		*dx = 0;
    147	} else {
    148		*dx = -*dy;
    149		*dy = 0;
    150	}
    151	if (debug) printf(" %s\n", dirstr(*dx, *dy));
    152}
    153
    154void
    155roll(int *top, int depth)
    156{
    157	int tmp, i;
    158
    159	tmp = top[-1];
    160	for (i = -1; i > -depth; i++)
    161		top[i] = top[i-1];
    162	top[-depth] = tmp;
    163}
    164
    165void
    166unroll(int *top, int depth)
    167{
    168	int tmp, i;
    169
    170	tmp = top[-depth];
    171	for (i = -depth; i < -1; i++)
    172		top[i] = top[i+1];
    173	top[-1] = tmp;
    174}
    175
    176void
    177debuginst(int *stack, int stacktop, int prevc, int nextc,
    178	int x, int y, const char *name)
    179{
    180	int i;
    181
    182	printf("[%3i,%3i]: %06X -> %06X | %4s | ", x, y,
    183		colors[prevc], colors[nextc], name);
    184	for (i = 0; i < stacktop; i++)
    185		printf("%i ", stack[i]);
    186	printf("\n");
    187}
    188
    189int
    190main(int argc, const char **argv)
    191{
    192	uint8_t *pix, *vismap;
    193	const char *inpath;
    194	int *stack;
    195	int width, height;
    196	int inst, x, y;
    197	int dx, dy;
    198	int prevc, nextc;
    199	int rotcount;
    200	int stacktop;
    201	int edgedir;
    202	int i, tmp;
    203
    204	inpath = NULL;
    205	for (i = 1; i < argc; i++) {
    206		if (!strcmp(argv[i], "-d"))
    207			debug = 1;
    208		else if (!strcmp(argv[i], "-h"))
    209			errx(0, "pietr [-h] [-d] IMAGE");
    210		else if (inpath)
    211			errx(1, "Multiple image specified");
    212		else
    213			inpath = argv[i];
    214	}
    215	if (!inpath)
    216		errx(1, "No image specified");
    217
    218	pix = stbi_load(inpath, &width, &height, NULL, STBI_rgb);
    219	if (!pix) errx(1, "Image load failed");
    220
    221	stack = calloc(stacksize, sizeof(int));
    222	if (!stack) err(1, "calloc");
    223	stacktop = 0;
    224
    225	vismap = calloc(width * height, 1);
    226	if (!vismap) err(1, "calloc");
    227
    228	dx = 1;
    229	dy = 0;
    230
    231	x = y = 0;
    232	while (1) {
    233		prevc = getcolor(pix, width * 3, x, y);
    234
    235		/* rotate until free */
    236		rotcount = 0;
    237		while (x + dx < 0 || x + dx >= width
    238			|| y + dy < 0 || y + dy >= height
    239			|| getcolor(pix, width * 3, x + dx, y + dy) == BLACK)
    240		{
    241			rotate(&dx, &dy);
    242			rotcount += 1;
    243			ASSERT(rotcount < 4);
    244		}
    245
    246		x += dx;
    247		y += dy;
    248
    249		if (vismap[y * width + x] == (dy + 1) * 2 + (dx + 1)) {
    250			if (debug) printf("Loop detected. Stopping..\n");
    251			break;
    252		}
    253		vismap[y * width + x] = (dy + 1) * 2 + (dx + 1);
    254
    255		nextc = getcolor(pix, width * 3, x, y);
    256		ASSERT(nextc != BLACK);
    257
    258		inst = getinst(prevc, nextc);
    259
    260		if (debug) {
    261			printf("[%3i,%3i]: %06X -> %06X  | %4s | ", x, y,
    262				colors[prevc], colors[nextc], inst_names[inst]);
    263			for (i = 0; i < stacktop; i++)
    264				printf("%i ", stack[i]);
    265			printf("\n");
    266		}
    267
    268		switch (inst) {
    269		case PUSH:
    270			ASSERTI(PUSH, stacktop != stacksize);
    271			stack[stacktop++] = 1;
    272			break;
    273		case POP:
    274			ASSERTI(POP, stacktop >= 1);
    275			stacktop--;
    276			break;
    277		case ADD:
    278			ASSERTI(ADD, stacktop >= 2);
    279			stack[stacktop-2] += stack[stacktop-1];
    280			stacktop--;
    281			break;
    282		case SUB:
    283			ASSERTI(SUB, stacktop >= 2);
    284			stack[stacktop-2] -= stack[stacktop-1];
    285			stacktop--;
    286			break;
    287		case MUL:
    288			ASSERTI(DIV, stacktop >= 2);
    289			stack[stacktop-2] *= stack[stacktop-1];
    290			stacktop--;
    291			break;
    292		case DIV:
    293			ASSERTI(DIV, stacktop >= 2);
    294			stack[stacktop-2] /= stack[stacktop-1];
    295			stacktop--;
    296			break;
    297		case MOD:
    298			ASSERTI(MOD, stacktop >= 2);
    299			stack[stacktop-2] %= stack[stacktop-1];
    300			stacktop--;
    301			break;
    302		case NOT:
    303			ASSERTI(NOT, stacktop >= 1);
    304			stack[stacktop-1] = stack[stacktop-1] == 0;
    305			stacktop--;
    306			break;
    307		case GTR:
    308			ASSERTI(GTR, stacktop >= 2);
    309			stack[stacktop-2] = stack[stacktop-2] > stack[stacktop-1];
    310			stacktop--;
    311			break;
    312		case DPI:
    313			ASSERTI(DPI, stacktop >= 1);
    314			for (i = 0; i < stack[stacktop-1]; i++)
    315				rotate(&dx, &dy);
    316			stacktop--;
    317			break;
    318		case CCI:
    319			ASSERTI(CCI, stacktop >= 1);
    320			if (ABS(stack[stacktop-1]) % 2 == 1)
    321				edgedir ^= 1;
    322			stacktop--;
    323			break;
    324		case DUP:
    325			ASSERTI(DUP, stacktop >= 1);
    326			stack[stacktop] = stack[stacktop-1];
    327			stacktop++;
    328			break;
    329		case ROLL:
    330			ASSERTI(ROLL, stacktop >= 2);
    331			stacktop -= 2;
    332			ASSERTI(ROLL, stacktop >= stack[stacktop]);
    333			if (stack[stacktop+1] < 0) {
    334				for (i = 0; i < -stack[stacktop+1]; i++)
    335					unroll(stack, stack[stacktop]);
    336			} else {
    337				for (i = 0; i < stack[stacktop+1]; i++)
    338					roll(stack, stack[stacktop]);
    339			}
    340			break;
    341		case INN:
    342			ASSERTI(INN, stacktop < stacksize);
    343			ASSERTI(INN, scanf("%i", &tmp) == 1);
    344			stack[stacktop++] = tmp;
    345			break;
    346		case INC:
    347			ASSERTI(INC, stacktop < stacksize);
    348			stack[stacktop++] = getchar();
    349			break;
    350		case OUTN:
    351			ASSERTI(OUTN, stacktop >= 1);
    352			if (debug) {
    353				printf("OUTNUM %i\n", stack[stacktop-1]);
    354			} else {
    355				putchar(stack[stacktop-1]);
    356			}
    357			stacktop--;
    358			break;
    359		case OUTC:
    360			ASSERTI(OUTC, stacktop >= 1);
    361			if (debug) {
    362				printf("OUTCHAR %c\n", stack[stacktop-1]);
    363			} else {
    364				putchar(stack[stacktop-1]);
    365			}
    366			stacktop--;
    367			break;
    368		case NONE:
    369			break;
    370		default:
    371			errx(1, "Invalid instruction %i", inst);
    372		}
    373	}
    374
    375	STBI_FREE(pix);
    376}