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}