Código de máquina x86 (IA-32), 126 bytes
Hexdump:
60 8b f9 57 33 c0 f2 ae 5e 2b fe 4f 87 fa 8d 1c
12 8b c3 48 f6 e3 c6 04 07 00 48 c6 04 07 20 75
f9 8b ea 4d 53 8d 04 2a 50 53 8b c5 f6 e3 8d 44
68 01 50 53 2b c2 8b c8 50 4b 53 55 53 03 c5 50
f7 d3 53 50 53 95 f6 e2 6b c0 04 50 43 53 51 6a
01 4a 52 6a 01 50 6a ff 51 b0 0a 6a 0b 8b dc 59
8b 6c cb fc 88 04 2f 03 2c cb 89 6c cb fc 83 f9
0a 75 01 ac e2 ea 4a 79 e0 83 c4 58 61 c3
Esto es un poco largo, así que para explicarlo, primero le daré el código C:
void doit(const char* s, char out[])
{
int n = strlen(s);
int w = 2 * n;
int h = w - 1;
int m = n - 1;
memset(out, ' ', h * w);
out[h * w] = 0;
int offset1 = n + m;
int offset2 = w * m + 2 * m + 1; // 2 * n * n - 1
int offset3 = offset2 - n; // 2 * n * n - n - 1
int offset4 = 4 * n * m; // 4 * n * n - 4 * n
int offsets[] = {
offset3, -1,
offset4, 1,
m, 1,
offset3, 1 - w,
offset4, -w,
offset2 - 1, -w,
offset2 - 1, w - 1,
m, w - 1,
offset3, w,
offset2, w,
offset1, w,
};
do
{
char c = *s++;
for (int i = 0; i < 11; ++i)
{
if (i == 9)
c = '\n';
int offset = offsets[i * 2];
assert(offset > 0 && offset < w * h);
out[offset] = c;
offsets[i * 2] += offsets[i * 2 + 1];
}
} while (--n);
}
Aquí n
está la longitud de la cadena de entrada.
Las dimensiones del área de salida son 2n
(ancho) por 2n-1
(alto). Primero, llena todo con espacios (y agrega un byte nulo de terminación). Luego, viaja a lo largo de 11 líneas rectas en el área de salida y las llena de texto:
- 2 líneas se llenan con bytes de fin de línea (= 10)
- 9 líneas se llenan con los bytes consecutivos de la cadena de entrada
Cada línea está representada por dos números, un desplazamiento inicial y una zancada. Los metí en la matriz offsets
, para que el acceso sea "fácil".
La parte interesante es llenar la matriz. Hay poca importancia para el orden de las entradas en la matriz; Traté de reorganizarlos para minimizar el número de conflictos de registro. Además, las fórmulas cuadráticas tienen cierta libertad para elegir la forma de cálculo; Traté de minimizar el número de restas (porque las LEA
instrucciones flexibles pueden implementar adiciones ).
Fuente de montaje:
pushad;
; // Calculate the length of the input string
mov edi, ecx;
push edi;
xor eax, eax;
repne scasb;
pop esi; // esi = input string
sub edi, esi;
dec edi;
; // Calculate the size of the output area
xchg edi, edx; // edx = n
// edi = output string
lea ebx, [edx + edx]; // ebx = w
mov eax, ebx;
dec eax; // eax = h
mul bl; // eax = w * h
; // Fill the output string with spaces and zero terminate it
mov byte ptr [edi + eax], 0;
myfill:
dec eax;
mov byte ptr [edi + eax], ' ';
jnz myfill;
mov ebp, edx;
dec ebp; // ebp = m
; // Fill the array of offsets
push ebx; // w
lea eax, [edx + ebp];
push eax; // offset1
push ebx; // w
mov eax, ebp;
mul bl;
lea eax, [eax + 2 * ebp + 1];
push eax; // offset2
push ebx; // w
sub eax, edx;
mov ecx, eax; // ecx = offset3
push eax; // offset3
dec ebx;
push ebx; // w - 1
push ebp; // m
push ebx; // w - 1
add eax, ebp;
push eax; // offset2 - 1
not ebx;
push ebx; // -w
push eax; // offset2 - 1
push ebx; // -w
xchg eax, ebp; // eax = m
mul dl;
imul eax, eax, 4;
push eax; // offset4
inc ebx;
push ebx; // 1 - w
push ecx; // offset3
push 1;
dec edx; // edx = n - 1
push edx;
push 1;
push eax;
push -1;
push ecx;
; // Use the array of offsets to write stuff to output
myout:
mov al, '\n';
push 11;
mov ebx, esp;
pop ecx;
myloop:
mov ebp, [ebx + ecx * 8 - 4];
mov [edi + ebp], al;
add ebp, [ebx + ecx * 8];
mov [ebx + ecx * 8 - 4], ebp;
cmp ecx, 10;
jne skip_read;
lodsb;
skip_read:
loop myloop;
dec edx;
jns myout;
add esp, 11 * 8;
popad;
ret;
Utilicé multiplicaciones de bytes aquí, limitando la longitud de la cadena de entrada a 127. Esto evita golpear el registro edx
; el producto se calcula en su ax
lugar.
Una falla menor: al llenar la matriz, la longitud de la cadena se reduce en 1. Así que ajusté la condición de salida del bucle:
jns myout
Cuenta atrás hasta -1.