C(78 + 26 * strlen)个编码
这令人惊讶地难以优化,主要是因为相邻行中可能发生颜色冲突。
字符将转换为基数12,因此每个字符都是2位数字。每条标准行包含以下内容:指针(现在在奇数行右边,在偶数行左边),重复项(堆栈上第一个数字12),推入(第一个数字),乘法,推入(第二个数字),加法,outc,push(1表示奇数行,3表示偶数行),重复项,空格,指针(现在在行尾向下)。
为避免相邻行发生颜色冲突,请记住填充空白后的状态,如果发生冲突,则将世代回退到该状态。下次尝试从下一个颜色开始。
“ Hello Piet!”的输出:
asciipiet2.c
#include "img.h"
#define WIDTH 26
#define OP(op, h, d) int op() { hue += h; dark += d; hue %= 6; dark %= 3; return setp(); }
#define CCMP(c1, c2) (((c1).r == (c2).r) && ((c1).g == (c2).g) && ((c1).b == (c2).b))
#define OPCNT(op) if(op) continue
Color piet[6][2] =
{
{{0xff, 0xc0, 0xc0}, {0xff, 0x00, 0x00}, {0xc0, 0x00, 0x00}},
{{0xff, 0xff, 0xc0}, {0xff, 0xff, 0x00}, {0xc0, 0xc0, 0x00}},
{{0xc0, 0xff, 0xc0}, {0x00, 0xff, 0x00}, {0x00, 0xc0, 0x00}},
{{0xc0, 0xff, 0xff}, {0x00, 0xff, 0xff}, {0x00, 0xc0, 0xc0}},
{{0xc0, 0xc0, 0xff}, {0x00, 0x00, 0xff}, {0x00, 0x00, 0xc0}},
{{0xff, 0xc0, 0xff}, {0xff, 0x00, 0xff}, {0xc0, 0x00, 0xc0}}
};
Color white = {0xff, 0xff, 0xff};
Image img;
int hue, dark, x, y, dx = 1;
void nextline()
{
x -= dx;
dx = -dx;
y += 1;
}
int setp()
{
if(y > 0 && CCMP(piet[hue][dark], imgGetP(img, x, y - 1)))
{
return 1;
}
imgSetP(img, x, y, piet[hue][dark]);
x += dx;
return 0;
}
void whiteto(int to)
{
if(dx == 1)
{
while(x < to) imgSetP(img, x++, y, white);
}
else
{
while(x >= WIDTH - to) imgSetP(img, x--, y, white);
}
}
OP(fill, 0, 0)
OP(pushraw, 0, 1)
OP(pop, 0, 2)
OP(add, 1, 0)
OP(sub, 1, 1)
OP(mul, 1, 2)
OP(divi, 2, 0)
OP(mod, 2, 1)
OP(not, 2, 2)
OP(gt, 3, 0)
OP(pnt, 3, 1)
OP(sw, 3, 2)
OP(dup, 4, 0)
OP(roll, 4, 1)
OP(in, 4, 2)
OP(inc, 5, 0)
OP(out, 5, 1)
OP(outc, 5, 2)
int push(int num);
int pushn(int num) { int i; for(i = 0; i < num - 1; ++i) { if(fill()) return 1; } return pushraw(); }
int push0() { return (push(1) || not()); }
int push8() { return (push(2) || dup() || dup() || mul() || mul()); }
int push9() { return (push(3) || dup() || mul()); }
int push10() { return (push(9) || push(1) || add()); }
int push11() { return (push(9) || push(2) || add()); }
int push(int num)
{
switch(num)
{
case 0: return push0();
case 8: return push8();
case 9: return push9();
case 10: return push10();
case 11: return push11();
default: return pushn(num);
}
}
int main(int argc, char* argv[])
{
char* str;
int len, i;
if(argc != 2)
{
printf("Usage: %s \"string to print\"\n", argv[0]);
return -1;
}
str = argv[1];
len = strlen(str);
imgCreate(img, WIDTH, len + 3);
fill(); push(4); push(3); mul(); push(1); dup(); whiteto(WIDTH - 2);
for(i = 0; i < len; ++i)
{
int var, sx = x, sy = y, sdx = dx, fin = 0, off = rand();
for(var = 0; var < 18 && !fin; var++)
{
x = sx; y = sy; dx = sdx;
hue = ((var + off) % 18) / 3; dark = ((var + off) % 18) % 3;
OPCNT(fill()); OPCNT(pnt());
nextline(); pnt(); dup();
OPCNT(push(str[i] / 12)); OPCNT(mul()); OPCNT(push(str[i] % 12)); OPCNT(add()); OPCNT(outc()); OPCNT(push(2 - dx)); if(i != len - 1) { OPCNT(dup()); }
whiteto(WIDTH - 2);
fin = 1;
}
if (!fin)
{
printf("collision unavoidable\n");
return -1;
}
}
x -= dx;
{
int var, sx = x, sy = y, sdx = dx, fin = 0;
for(var = 0; var < 18 && !fin; var++)
{
x = sx; y = sy; dx = sdx;
hue = var / 3; dark = var % 3;
OPCNT(fill()); OPCNT(pnt()); OPCNT(fill());
fin = 1;
}
if (!fin)
{
printf("collision unavoidable\n");
return -1;
}
}
x -= 2 * dx;
y += 1;
imgSetP(img, x, y, white);
x -= dx;
y += 1;
hue = 0; dark = 1;
fill(); fill(); fill();
imgSave(img, "piet.pnm");
return 0;
}
img.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
unsigned char r;
unsigned char g;
unsigned char b;
} Color;
typedef struct
{
Color* data;
int width;
int height;
} Image;
#define imgCreate(img, w, h) {\
int length;\
(img).width = (w);\
(img).height = (h);\
length = (img).width * (img).height * sizeof(Color);\
(img).data = malloc(length);\
memset((img).data, 0, length);\
}
#define imgDestroy(img) {\
free((img).data);\
(img).width = 0;\
(img).height = 0;\
}
#define imgGetP(img, x, y) ((img).data[(int)(x) + (int)(y) * (img).width])
#define imgSetP(img, x, y, c) {\
(img).data[(int)(x) + (int)(y) * (img).width] = c;\
}
#define imgLine(img, x, y, xx, yy, c) {\
int x0 = (x), y0 = (y), x1 = (xx), y1 = (yy);\
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;\
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;\
int err = dx + dy, e2;\
\
for(;;)\
{\
imgSetP((img), x0, y0, c);\
if (x0 == x1 && y0 == y1) break;\
e2 = 2 * err;\
if (e2 >= dy) {err += dy; x0 += sx;}\
if (e2 <= dx) {err += dx; y0 += sy;}\
}\
}
#define imgSave(img, fname) {\
FILE* f = fopen((fname), "wb");\
fprintf(f, "P6\n%d %d\n255\n", (img).width, (img).height);\
fwrite((img).data, sizeof(Color), (img).width * (img).height, f);\
fclose(f);\
}
#define imgLoad(img, fname) {\
FILE* f = fopen((fname), "rb");\
char buffer[16];\
int index = 0;\
int field = 0;\
int isP5 = 0;\
unsigned char c = ' ';\
while(field < 4)\
{\
do\
{\
if(c == '#') while(c = fgetc(f), c != '\n');\
} while(c = fgetc(f), isspace(c) || c == '#');\
index = 0;\
do\
{\
buffer[index++] = c;\
} while(c = fgetc(f), !isspace(c) && c != '#' && index < 16);\
buffer[index] = 0;\
switch(field)\
{\
case 0:\
if (strcmp(buffer, "P5") == 0) isP5 = 1;\
else if (strcmp(buffer, "P6") == 0) isP5 = 0;\
else fprintf(stderr, "image format \"%s\" unsupported (not P5 or P6)\n", buffer), exit(1);\
break;\
case 1:\
(img).width = atoi(buffer);\
break;\
case 2:\
(img).height = atoi(buffer);\
break;\
case 3:\
index = atoi(buffer);\
if (index != 255) fprintf(stderr, "image format unsupported (not 255 values per channel)\n"), exit(1);\
break;\
}\
field++;\
}\
imgCreate((img), (img).width, (img).height);\
if (isP5)\
{\
int length = (img).width * (img).height;\
for(index = 0; index < length; ++index)\
{\
(img).data[index].r = (img).data[index].g = (img).data[index].b = fgetc(f);\
}\
}\
else\
{\
fread((img).data, sizeof(Color), (img).width * (img).height, f);\
}\
fclose(f);\
}