código de máquina x86, 70 bytes
60 89 d7 31 db 43 88 ce b2 fe 49 d1 e1 87 da 0f
c7 f0 24 7f 3c 22 72 f7 48 3c 79 74 f2 3c 59 74
ee aa 49 7c 1c 00 df 79 06 86 f7 42 43 eb f6 f6
c3 01 74 03 b0 0a aa 51 88 f9 b0 20 f3 aa 59 eb
cc c6 07 00 61 c3
Meu código executável, desmontado:
0000003d <myheh>:
3d: 60 pusha
3e: 89 d7 mov %edx,%edi
40: 31 db xor %ebx,%ebx
42: 43 inc %ebx
43: 88 ce mov %cl,%dh
45: b2 fe mov $0xfe,%dl
47: 49 dec %ecx
48: d1 e1 shl %ecx
0000004a <myloop>:
4a: 87 da xchg %ebx,%edx
0000004c <myrand>:
4c: 0f c7 f0 rdrand %eax
4f: 24 7f and $0x7f,%al
51: 3c 22 cmp $0x22,%al
53: 72 f7 jb 4c <myrand>
55: 48 dec %eax
56: 3c 79 cmp $0x79,%al
58: 74 f2 je 4c <myrand>
5a: 3c 59 cmp $0x59,%al
5c: 74 ee je 4c <myrand>
5e: aa stos %al,%es:(%edi)
5f: 49 dec %ecx
60: 7c 1c jl 7e <mydone>
00000062 <mylab>:
62: 00 df add %bl,%bh
64: 79 06 jns 6c <myprint>
66: 86 f7 xchg %dh,%bh
68: 42 inc %edx
69: 43 inc %ebx
6a: eb f6 jmp 62 <mylab>
0000006c <myprint>:
6c: f6 c3 01 test $0x1,%bl
6f: 74 03 je 74 <myprint1>
71: b0 0a mov $0xa,%al
73: aa stos %al,%es:(%edi)
00000074 <myprint1>:
74: 51 push %ecx
75: 88 f9 mov %bh,%cl
77: b0 20 mov $0x20,%al
79: f3 aa rep stos %al,%es:(%edi)
7b: 59 pop %ecx
7c: eb cc jmp 4a <myloop>
0000007e <mydone>:
7e: c6 07 00 movb $0x0,(%edi)
81: 61 popa
82: c3 ret
É uma função que recebe o tamanho do X em ecx e um ponteiro para o buffer de saída em edx.
Ele preenche o buffer de saída sequencialmente com bytes. Existem 2 * n - 1
iterações (iguais ao número de caracteres não espaciais para saída). Em cada iteração, ele faz o seguinte:
- Gere um número aleatório
- Brinque com o número para ajustá-lo ao alcance; se estiver ruim, volte e gere novamente
- Imprimir o caractere aleatório
- Imprimir uma nova linha (todas as outras iterações)
- Imprimir o número adequado de espaços
A conversão de um número aleatório para um caractere aleatório não é notável:
myrand:
rdrand eax;
and al, 7fh;
cmp al, 22h;
jb myrand;
dec eax;
cmp al, 'y';
je myrand;
cmp al, 'Y';
je myrand;
A parte interessante é o cálculo do número de espaços. Ele deve gerar os seguintes números (exemplo para N = 9):
7 1
5 2
3 3
1 4
3
1 2
3 1
5 0
7
Os números são obtidos alternadamente de duas progressões aritméticas. O primeiro desce com o passo -2 e o segundo com o passo 1. Quando a primeira progressão chega a -1 (no meio do X), há uma falha (-1 é removida) e depois as progressões mudam de direção.
As progressões são armazenadas em registradores ebx
e edx
- as partes altas bh
e dh
armazenam o número atual, e as partes baixas bl
e dl
armazenam a etapa. Para alternar entre as progressões, o código troca os registros com xchg
.
Quando a progressão chega a -1 (ao redor do mylab
rótulo), aumenta os dois registros, alternando as etapas de -2, 1
para -1, 2
. Isso também muda as funções dos registros, e então troca as partes altas dos registros.
No final da função, ele armazena um byte zero para indicar o final da string.