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}