mã máy x86 (IA-32), 126 byte
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
Cái này hơi dài, vì vậy để giải thích nó trước tiên tôi sẽ cung cấp mã 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);
}
Đây n
là độ dài của chuỗi đầu vào.
Kích thước của khu vực đầu ra là 2n
(chiều rộng) theo 2n-1
(chiều cao). Đầu tiên, nó lấp đầy mọi thứ bằng khoảng trắng (và thêm một byte null kết thúc). Sau đó, nó di chuyển dọc theo 11 đường thẳng trong khu vực đầu ra và điền chúng bằng văn bản:
- 2 dòng chứa đầy byte cuối dòng (= 10)
- 9 dòng chứa đầy các byte liên tiếp của chuỗi đầu vào
Mỗi dòng được đại diện bởi hai số, một bắt đầu bù và một sải chân. Tôi nhét cả hai vào mảng offsets
, để truy cập "dễ dàng".
Phần thú vị là điền vào mảng. Có rất ít tầm quan trọng đối với thứ tự của các mục trong mảng; Tôi đã cố gắng sắp xếp lại chúng để giảm thiểu số lượng xung đột đăng ký. Ngoài ra, các công thức bậc hai có một số tự do trong việc lựa chọn cách tính toán; Tôi đã cố gắng giảm thiểu số lượng phép trừ (vì việc bổ sung có thể được thực hiện bằng LEA
hướng dẫn linh hoạt ).
Nguồn hội:
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;
Tôi đã sử dụng phép nhân byte ở đây, giới hạn độ dài của chuỗi đầu vào là 127. Điều này tránh làm tắc nghẽn thanh ghi edx
- sản phẩm được tính ax
thay thế.
Một trục trặc nhỏ: khi điền vào mảng, độ dài của chuỗi bị giảm đi 1. Vì vậy, tôi đã điều chỉnh điều kiện thoát vòng lặp:
jns myout
Nó đếm ngược đến -1.