pietp

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

pietp.c (4469B)


      1#include <stdlib.h>
      2#include <stdio.h>
      3#include <stdbool.h>
      4#include <err.h>
      5
      6#define STB_IMAGE_IMPLEMENTATION
      7#include "stb_image.h"
      8#define STB_IMAGE_WRITE_IMPLEMENTATION
      9#include "stb_image_write.h"
     10
     11#define ARRLEN(x) (sizeof(x)/sizeof((x)[0]))
     12
     13enum {
     14	PUSH,
     15	POP,
     16	ADD,
     17	SUB,
     18	MUL,
     19	DIV,
     20	MOD,
     21	NOT,
     22	GTR,
     23	DPI,
     24	CCI,
     25	DUP,
     26	ROLL,
     27	INN,
     28	INC,
     29	OUTN,
     30	OUTC,
     31	NONE
     32};
     33
     34static const char *inst_names[] = {
     35	"PUSH",
     36	"POP",
     37	"ADD",
     38	"SUB",
     39	"MUL",
     40	"DIV",
     41	"MOD",
     42	"NOT",
     43	"GTR",
     44	"DPI",
     45	"CCI",
     46	"DUP",
     47	"ROLL",
     48	"INN",
     49	"INC",
     50	"OUTN",
     51	"OUTC",
     52	""
     53};
     54
     55static const uint32_t colors[] = {
     56	0xffc0c0, 0xffffc0, 0xc0ffc0, 0xc0ffff, 0xc0c0ff, 0xffc0ff,
     57	0xff0000, 0xffff00, 0x00ff00, 0x00ffff, 0x0000ff, 0xff00ff,
     58	0xc00000, 0xc0c000, 0x00c000, 0x00c0c0, 0x0000c0, 0xc000c0,
     59	0x000000, 0xffffff
     60};
     61
     62static const int instructions[][2] = {
     63	[PUSH] = { 0, 1 },
     64	[POP]  = { 0, 2 },
     65	[ADD]  = { 1, 0 },
     66	[SUB]  = { 1, 1 },
     67	[MUL]  = { 1, 2 },
     68	[DIV]  = { 2, 0 },
     69	[MOD]  = { 2, 1 },
     70	[NOT]  = { 2, 2 },
     71	[GTR]  = { 3, 0 },
     72	[DPI]  = { 3, 1 },
     73	[CCI]  = { 3, 2 },
     74	[DUP]  = { 4, 0 },
     75	[ROLL] = { 4, 1 },
     76	[INN]  = { 4, 2 },
     77	[INC]  = { 5, 0 },
     78	[OUTN] = { 5, 1 },
     79	[OUTC] = { 5, 2 },
     80};
     81
     82static const int piet_code[] = {
     83	PUSH, PUSH, ADD, DUP, MUL, DUP, DUP, DUP, MUL, // 4 4 16
     84	DUP, DUP, ADD, DUP, DUP, ADD, ADD, ADD, // 4 4 112
     85	DUP, DUP, PUSH, PUSH, ADD, PUSH, ADD, ADD, // 4 4 112 112 115
     86	OUTC,
     87	PUSH, PUSH, ADD, SUB, // 4 4 112 110
     88	OUTC,
     89	ADD, ADD, // 120
     90	OUTC
     91};
     92
     93static int debug = 0;
     94
     95const char *
     96dirstr(int dx, int dy)
     97{
     98	if (dx > 0)
     99		return "+X";
    100	else if (dx < 0)
    101		return "-X";
    102	else if (dy > 0)
    103		return "+Y";
    104	else if (dy < 0)
    105		return "-Y";
    106	else
    107		return "O";
    108}
    109
    110int
    111nextcolor(int prev, int insti)
    112{
    113	int x, y;
    114
    115	x = ((prev % 6) + 6 + instructions[insti][0]) % 6;
    116	y = ((prev / 6) + 3 + instructions[insti][1]) % 3;
    117	return y * 6 + x;
    118}
    119
    120void
    121setrgb(uint8_t *pix, int stride, int x, int y, int color)
    122{
    123	pix[y * stride + x * 3 + 0] = (colors[color] & 0xff0000) >> 16;
    124	pix[y * stride + x * 3 + 1] = (colors[color] & 0x00ff00) >> 8;
    125	pix[y * stride + x * 3 + 2] = (colors[color] & 0x0000ff) >> 0;
    126}
    127
    128int
    129main(int argc, const char **argv)
    130{
    131	uint8_t *map, *vis;
    132	uint8_t *pix;
    133	const char *mappath;
    134	int width, height;
    135	int insti, nexti;
    136	int x, y, dx, dy;
    137	int color, nextc;
    138	int rotonce;
    139	int i;
    140
    141	color = 0;
    142	mappath = NULL;
    143	for (i = 1; i < argc; i++) {
    144		if (!strcmp(argv[i], "-d"))
    145			debug = 1;
    146		else if (!strcmp(argv[i], "-s") && i + 1 < argc)
    147			color = atoi(argv[++i]);
    148		else if (!strcmp(argv[i], "-h"))
    149			errx(0, "pietp [-h] [-d] [-s COLOR] [MAP-IMAGE]");
    150		else if (mappath)
    151			errx(1, "More than one map specified\n");
    152		else
    153			mappath = argv[i];
    154	}
    155
    156	if (mappath) {
    157		map = stbi_load(mappath, &width, &height, NULL, STBI_grey);
    158		if (!map) errx(1, "Failed to read image");
    159	} else {
    160		map = calloc(width * height, 1);
    161		if (!map) err(1, "calloc");
    162	}
    163
    164	vis = calloc(width * height, 1);
    165	pix = calloc(width * height, 3);
    166	if (!pix || !vis) err(1, "malloc");
    167
    168	dx = 1;
    169	dy = 0;
    170
    171	x = y = 0;
    172	setrgb(pix, width * 3, x++, y, color);
    173
    174	insti = 0;
    175	while (1) {
    176		if (vis[y * width + x]) {
    177			if (insti >= ARRLEN(piet_code))
    178				break;
    179			fprintf(stderr, "Overlap! Code remaining: %i/%li\n",
    180				insti, ARRLEN(piet_code));
    181			exit(1);
    182		}
    183
    184		/* write color to image */
    185		if (map[y * width + x] == 0xC0) {
    186			nexti = PUSH;
    187			nextc = nextcolor(color, nexti);
    188		} else if (map[y * width + x] == 0x80) {
    189			nexti = DPI;
    190			nextc = nextcolor(color, nexti);
    191		} else if (map[y * width + x] == 0x40) {
    192			nexti = NONE;
    193			nextc = color;
    194		} else if (insti < ARRLEN(piet_code)) {
    195			nexti = piet_code[insti++];
    196			nextc = nextcolor(color, nexti);
    197		} else {
    198			nexti = NONE;
    199			nextc = color;
    200		}
    201		setrgb(pix, width * 3, x, y, nextc);
    202		vis[y * width + x] = 1;
    203		if (debug) printf("[%3i,%3i]: %06X -> %06X  | %4s\n", x, y,
    204			colors[color], colors[nextc], inst_names[nexti]);
    205		color = nextc;
    206
    207		/* rotate until free */
    208		rotonce = 0;
    209		while (x + dx < 0 || x + dx >= width
    210			|| y + dy < 0 || y + dy >= height
    211			|| map[y * width + x] == 0x80 && !rotonce
    212			|| map[(y + dy) * width + x + dx] == 0)
    213		{
    214			if (debug) printf("ROTATE %s ->", dirstr(dx, dy));
    215			if (dx != 0) {
    216				dy = dx;
    217				dx = 0;
    218			} else {
    219				dx = -dy;
    220				dy = 0;
    221			}
    222			if (debug) printf(" %s\n", dirstr(dx, dy));
    223			rotonce = 1;
    224		}
    225
    226		x += dx;
    227		y += dy;
    228	}
    229
    230	stbi_write_png("piet.png", width, height, STBI_rgb, pix, 3 * width);
    231
    232	free(pix);
    233	free(vis);
    234	STBI_FREE(map);
    235}