x86 (IA-32) 머신 코드, 126 바이트
16 진 덤프 :
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 코드를 줄 것입니다.
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);
}
n
입력 문자열의 길이는 다음과 같습니다 .
출력 영역의 크기는 2n
(너비) x 2n-1
(높이)입니다. 먼저, 공백으로 모든 것을 채우고 종료 널 바이트를 추가합니다. 그런 다음 출력 영역에서 11 개의 직선을 따라 이동하고 텍스트로 채 웁니다.
- 2 줄은 줄 끝 바이트 (= 10)로 채워집니다.
- 9 줄은 입력 문자열의 연속 바이트로 채워집니다.
각 줄은 시작 오프셋과 보폭의 두 숫자로 표시됩니다. offsets
액세스를 "쉽게"만들기 위해 둘 다 배열에 넣었습니다 .
흥미로운 부분은 배열을 채우는 것입니다. 배열의 항목 순서는 중요하지 않습니다. 레지스터 충돌 수를 최소화하기 위해 다시 정렬하려고했습니다. 또한 이차 방정식은 계산 방법을 선택할 때 약간의 자유가 있습니다. 나는 뺄셈의 수를 최소화하려고 노력했다.LEA
명령 ).
조립 소스 :
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;
여기에서는 바이트 곱셈을 사용하여 입력 문자열의 길이를 127로 제한했습니다. 이렇게하면 레지스터가 방해받지 않습니다. 대신 edx
제품이 계산 ax
됩니다.
사소한 결함 : 배열을 채울 때 문자열의 길이가 1 씩 줄어 듭니다. 그래서 루프 종료 조건을 조정했습니다.
jns myout
-1로 카운트 다운됩니다.