Cadena de imagen

18

Un poco de historia:

Cuando supe por primera vez sobre Brainf * ck, una de las primeras cosas que hice fue escribir una aplicación Java que tomara una cadena y creara un programa optimizado para imprimir dicha cadena.

Recientemente, he estado jugando con Piet , y he estado jugando haciendo lo mismo. Me di cuenta de que Piet es un lenguaje bastante interesante que agrega un poco a este desafío.

Entonces, quería presentar el desafío a mis amigos en SE. Veamos qué puedes hacer con este idioma.

El reto

Escriba un programa o función que tome alguna cadena no vacía de caracteres ASCII. Procese la cadena de modo que genere un programa Piet que imprima la cadena y termine.

La salida es una imagen fuente piet en cualquier formato que sea mejor para usted. Se prefiere PNG, pero no es obligatorio.

La funcionalidad de Piet se puede probar aquí .

El código Piet debe generar la cadena de salida en sí. No se permite la entrada de usuarios.

Solo se pueden usar colores aprobados por Piet, como se ve a continuación:

colores piet

Como se trata de un concurso de popularidad, los ganadores serán elegidos por votos. Los lazos se romperán por el tamaño del código fuente.

Los puntos de bonificación se otorgarán a mi criterio según la creatividad de las imágenes de salida. Estas son fotos, después de todo.

tfitzger
fuente

Respuestas:

9

C, codeles (78 + 26 * strlen)

Esto fue sorprendentemente difícil de optimizar, principalmente debido a la posibilidad de colisiones de color en líneas vecinas.

Los caracteres se convierten a la base 12, por lo que cada carácter es un número de 2 dígitos. Cada línea estándar contiene lo siguiente: puntero (ahora a la derecha para líneas impares, a la izquierda para líneas pares), duplicado (el número 12, que es el primero en la pila), empujar (1er dígito), multiplicar, empujar (2do dígito), agregar , outc, push (1 para líneas impares, 3 para líneas pares), duplicado, espacios en blanco, puntero (ahora hacia abajo al final de la línea).

Para evitar colisiones de color en líneas vecinas, se recuerda el estado después del relleno de espacios en blanco, y la generación se revierte si ocurre una colisión. El siguiente intento comienza allí con el siguiente color.

Salida para "Hello Piet!":

Hola

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);\
                                       }
Manuel Kasten
fuente
5

C, (384 + 256 * strlen) codeles, sin optimización

No hay piratería inteligente en esta solución. Cada carácter está representado por una sola línea con altura en píxeles = valor ascii. La secuencia operativa es push, outc, push, outc, ...

Salida para "Hello Piet!" (y zoom de la parte superior):

piet

asciipiet.c

#include "img.h"

Color piet[6][3] = {
    {{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};

int main(int argc, char* argv[])
{
    char* str;
    int len, i, hue, dark;
    Image out;

    if(argc != 2)
    {
        printf("Usage: %s \"string to print\"\n", argv[0]);
        return -1;
    }

    str = argv[1];
    len = strlen(str);

    imgCreate(out, len * 2 + 3, 128);

    hue = 0;
    dark = 1;
    for(i = 0; i < len; i++)
    {
        imgLine(out, i * 2, 0, i * 2, str[i] - 1, piet[hue][dark]);
        dark = (dark + 1) % 3;
        imgSetP(out, i * 2 + 1, 0, piet[hue][dark]);
        dark = (dark + 2) % 3;
        hue = (hue + 5) % 6;
    }
    imgSetP(out, len * 2, 0, piet[hue][dark]);
    imgSetP(out, len * 2 + 1, 0, white);
    imgSetP(out, len * 2 + 2, 0, white);
    imgSetP(out, len * 2 + 2, 1, white);
    imgSetP(out, len * 2 + 2, 2, white);
    imgSetP(out, len * 2 + 2, 3, white);
    imgSetP(out, len * 2 + 1, 3, white);
    imgSetP(out, len * 2, 2, piet[0][4]);
    imgSetP(out, len * 2, 3, piet[0][5]);
    imgSetP(out, len * 2, 4, piet[0][6]);

    imgSave(out, "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);\
                                       }
Manuel Kasten
fuente