Uma análise do desafio “Super Small Hello World” do hacker.org: as soluções que funcionaram, as que quase chegaram lá e o truque que finalmente alcançou 29.
O hacker.org tem uma pequena linguagem esotérica chamada
SuperHack. A tarefa parece trivial: escrever um programa em SuperHack que imprima
Hello, World!.
O detalhe está na pontuação. Você é avaliado pela área do retângulo delimitador
do seu código, e quanto menor, melhor. O programa também precisa terminar corretamente:
executando a instrução ! (halt). Travar com uma exceção da VM depois que o
texto já saiu não conta, nem imprimir bytes extras indesejados.
O número a ser batido era 29.
SuperHack é uma máquina de pilha 2D, com espírito semelhante ao Befunge:
%) e se move para a direita.| Instrução | Efeito |
|---|---|
0-9 | empilha um dígito |
+ - d | soma, subtrai, faz divisão inteira (d por zero resulta em 0) |
x | duplica o topo da pilha |
n ^ | empilha uma cópia do item n posições abaixo do topo (1^ copia o segundo) |
, | lê a entrada. Quando não há entrada, empilha 0 |
g | desempilha x, desempilha y, empilha o código do caractere em (x, y). Fora da grade, empilha 0 |
P | desempilha e imprime como caractere (apenas os 7 bits menos significativos) |
s | pula a próxima célula |
? | desempilha; pula a próxima célula se o valor for 0 |
@ | empilha a posição (e direção) atual na pilha de chamadas |
$ | desempilha uma posição, salta para lá e continua duas células adiante |
\ | espelho: transforma “movendo para a direita” em “movendo para baixo” |
! | encerra a execução (halt) |
| qualquer outro | nenhuma operação (no-op) |
Duas consequências moldam tudo o que vem a seguir.
g lê o próprio código do programa, então a string
Hello, World! pode simplesmente ficar na grade e ser lida um caractere por
vez. A maioria de suas letras (H e l o W r) são no-ops quando executadas. Três
não são: , empilha 0, d divide e ! encerra o programa.@ / $ criam loops, e a contagem de iterações depende de onde os @s estão.
$ retoma a execução duas células após o @ para o qual retorna. Isso cai no próximo
@, que se empilha novamente, de modo que alguns @s podem repetir o corpo do loop muitas
vezes:@@@@@ adjacentes geram contagens de Fibonacci. Cinco deles executam o corpo
exatamente 13 vezes.@s espaçados de dois em dois geram potências de dois. Quatro deles permitem 16
passagens.Treze caracteres, treze passagens. Guarde essa informação.
A área é a largura multiplicada pela altura, e 29 é primo. Portanto, um programa de 29 células precisa ser uma única linha ou uma única coluna.
Hello, World!%0@s!@@@@@ 01^gP1+$
A primeira solução funcional coloca o payload no início e começa a execução depois dele:
| parte | função |
|---|---|
Hello, World! | dados, nunca executados, pois o PC começa no % |
% | ponto de entrada |
0 | índice i = 0 |
@ s ! | gadget de parada (halt): veja abaixo |
@@@@@ | cinco trampolins adjacentes, fazendo o corpo rodar 13 vezes |
| preenchimento / padding (explicado abaixo) |
0 1^ g | empilha a linha 0, copia i e busca o caractere na coluna i |
P | imprime o caractere |
1+ | i += 1 |
$ | faz o loop |
O gadget de parada. O primeiro @ coloca sua própria posição no fundo da
pilha de chamadas, e s salta sobre o !. A cadeia de Fibonacci faz então suas 13
passagens. Quando a pilha de chamadas finalmente se desenrola até aquele primeiro @, $ retoma
duas células após ele, que é exatamente o !. O programa para de forma limpa, e
não há nenhum teste de fim de string em lugar algum.
O preenchimento (padding). Com @s adjacentes, retornar do último @ retoma duas
células depois, o que pula a primeira célula após a cadeia. Essa célula deve,
portanto, ser algo inofensivo, razão pela qual é um espaço.
Resultado: Hello, World!, parada limpa, área 32. Está correto, mas espaçoso: o
payload é peso morto, e o %, o espaço de preenchimento e o 0 custam, juntos, três
células.
1H@e@l@l@o ,1 ^WgoPr2lsds!+$
A próxima ideia é parar de gastar células com um payload separado e entrelaçar a
string no código. Os caracteres de Hello, World! ficam nas colunas ímpares
(1, 3, …, 25), e o código preenche as colunas pares entre eles:
1 inicia o índice na coluna 1 (o H).@s espaçados de dois em dois (colunas 2, 4, 6, 8) permitem até 16 passagens., do payload (coluna 11) empilha o 0 de que g precisa como linha.2+ avança o índice para a próxima coluna ímpar.s saltam sobre o d e o ! do payload, para que não rodem como código.O problema é que 16 passagens são mais do que 13. Depois de imprimir a string, o
loop continua buscando além do fim e imprime $ e dois bytes NUL. Em seguida, $
encontra a pilha de chamadas vazia e a VM morre:
output: "Hello, World!$\0\0"
message: call stack underflow
É pequeno, mas não é uma solução válida. Ainda assim, introduz a ideia-chave:
caracteres do payload que por acaso são instruções úteis (,) cumprem dupla função como
dados e código.
\
2
H
@
e
@
l
@
l
@
o
x
,
g
P
W
2
o
+
r
$
l
d
!
(Um caractere por linha. As linhas em branco são espaços simples, que fazem parte dos dados.)
Colocar o programa na vertical traz um benefício inesperado. Em uma única coluna,
g precisa que a coordenada x seja 0 e a linha seja i. A , do payload
fornece esse 0 de graça, então a busca encolhe para x , g: duplicar i, empilhar
0, buscar. O custo é um \ no topo para virar o PC para baixo.
Contudo, ele tem a mesma falha da solução 2. O loop passa do ponto, imprime bytes NUL
e termina em call stack underflow. Com área 27, é o menor programa
deste post, mas não vale.
A lição das soluções 2 e 3 é que parar de forma limpa custa células. A intercalação torna o loop barato, mas entrega 16 passagens quando você precisa de exatamente 13.
\
2
H
@
e
@
l
@
l
@
o
x
,
g
P
W
x
o
5
r
d
l
5
d
?
!
2
+
$
A solução 4 mantém a intercalação vertical da solução 3 e adiciona um teste de fim de string de verdade:
| linha(s) | células | função |
|---|---|---|
| 0 | \ | vira para baixo |
| 1 | 2 | i = 2 |
| 3, 5, 7, 9 | @ | quatro trampolins, até 16 passagens |
| 11-13 | x , g | busca a linha i (a , faz parte do payload) |
| 15 | P | imprime |
| 17-24 | x 5 d 5 d | testa o valor floor(floor(i/5)/5) = floor(i/25) (o último d é payload) |
| 25 | ? | se o teste for 0, pula a próxima célula… |
| 26 | ! | …que é o próprio ! do payload |
| 27-28 | 2 + | i += 2 |
| 29 | $ | faz o loop |
O índice percorre 2, 4, …, 26. floor(i/25) permanece 0 até o último
caractere (i = 26), de modo que o ? pula a parada em todas as passagens, exceto na última.
Na última passagem, a execução cai sobre o ! do payload, que é simultaneamente
o último caractere impresso e a instrução que encerra o programa.
É um belo exemplo de reaproveitamento: ,, d e ! do payload servem todos como código.
Mas o teste custa cinco células, e o total vai para 30.
Nesse ponto, meu assistente de IA tentou provar que 30 era o limite ótimo. Todas as abordagens pareciam esbarrar na mesma parede:
@s adjacentes, e uma intercalação não tem células de código adjacentes. Assim, você fica
preso a 16 passagens e a um teste pago com células.? nunca pode ficar
diretamente na frente de $. A célula entre eles é sempre uma célula de payload.% ou um índice inicial grande), porque
executar ...d! como código trava ou encerra o programa prematuramente.Buscas exaustivas por computador em áreas menores não encontraram nada, e buscas em torno do layout da solução 4 com área 29 também não deram resultado. “30 é o piso” começou a parecer um teorema.
Não era.
9@s!@@@@@Hello, Worlä¡1^gP1+$
A virada veio ao reler o código-fonte do juiz. Duas linhas importam:
case 'P':
$output .= chr($this->Pop() & 0x7F); break;
...
default:
break; // every unknown character is a no-op
P imprime apenas os 7 bits menos significativos. Um byte com o bit mais significativo ativado, c + 128,
é impresso exatamente como c.Cada caractere do payload tem, portanto, duas codificações. A normal pode fazer
alguma coisa quando executada. Já a versão c | 0x80 é garantidamente inerte. Essa é a
“fórmula para os dados”: armazene os caracteres perigosos como c + 128 e deixe que P
remova o bit alto de graça.
Apenas dois caracteres do payload são perigosos: d vira ä (0xE4) e !
vira ¡ (0xA1). Com esses dois alterados, todo o payload pode ser
executado. Isso remove o obstáculo do terceiro item acima.
Agora pegue a solução 1 e mova o payload para dentro do loop:
| colunas | células | função |
|---|---|---|
| 0 | 9 | i = 9 (a coluna do H) |
| 1-3 | @ s ! | gadget de parada, como na solução 1 |
| 4-8 | @@@@@ | cinco trampolins adjacentes, fazendo o corpo rodar 13 vezes |
| 9-21 | Hello, Worlä¡ | o payload, executado em cada passagem |
| 22-27 | 1 ^ g P 1 + | copia i, busca, imprime, incrementa |
| 28 | $ | faz o loop |
Acompanhe uma passagem:
@ e percorre o payload. H e l l o, o espaço e W o r l não fazem nada. A , do payload empilha o 0
de que g precisa como linha. ä e ¡ não fazem nada.1^ copia i acima desse 0, e g busca a coluna i.P imprime o caractere. Para os dois últimos caracteres, ele imprime 0xE4 & 0x7F = 'd' e
0xA1 & 0x7F = '!'.1+ avança i, e $ retorna para a cadeia.Em comparação com a solução 1, três células desaparecem:
%: o payload não precisa mais ser protegido da execução.H do payload, um no-op.0 antes de 1^g: a , do payload o fornece em todas as passagens.32 − 3 = 29. Após a 13ª passagem, a pilha de chamadas se desenrola até o gadget e
o programa para no ! da coluna 3.
Saída Hello, World!, nenhuma mensagem da VM, 271 ciclos, área 29.
O primeiro envio retornou got: 'Hello, WorlC$' e uma pontuação de 31.
O formulário web havia enviado UTF-8, o que transformou cada caractere especial em dois
bytes (ä → C3 A4, ¡ → C2 A1). Mascarados para 7 bits, 0xC3 é impresso como C e
0xA4 como $.
A correção consiste em fazer o navegador enviar em Latin-1, codificação na qual cada um desses caracteres ocupa um único byte. Na página do desafio, precisei abrir o console do DevTools e executar:
document.querySelectorAll('form').forEach(
f => f.acceptCharset = 'ISO-8859-1');
document.querySelector('textarea').value =
"9@s!@@@@@Hello, Worl\u00e4\u00a11^gP1+$";
Depois, bastou pressionar o botão normal de envio. O juiz imprime Hello, World!, e a
pontuação no King of the Hill crava 29.
| # | programa | área | termina de forma limpa? |
|---|---|---|---|
| 1 | Hello, World!%0@s!@@@@@ 01^gP1+$ | 32 | ✅ |
| 2 | 1H@e@l@l@o ,1 ^WgoPr2lsds!+$ | 28 | ❌ bytes extras e call stack underflow |
| 3 | \2H@e@l@l@ox,g PW2o+r$ld! | 27 | ❌ bytes extras e call stack underflow |
| 4 | \2H@e@l@l@ox,g PWxo5rdl5d?!2+$ | 30 | ✅ |
| 5 | 9@s!@@@@@Hello, Worlä¡1^gP1+$ | 29 | ✅ |
, do payload como um push 0 gratuito, seu ! como a parada,
e, finalmente, todo o payload como parte do corpo do loop.& 0x7F e default: break) fizeram o que horas de busca automatizada não conseguiram.Baixe a edição offline selecionada de O Estilo de Vida do Kaue—um guia prático para otimizar 🍏 Saúde, 💰 Riqueza, ❤️ Amor e 🧘 Sentido.
Receba notificações quando eu publicar novos ensaios, resumos de livros e guias práticos sobre como viver bem. Sem spam—cancele quando quiser.
Tem alguma pergunta, perspectiva ou sugestão? Compartilhe suas ideias abaixo. Os comentários usam o GitHub Discussions (sem anúncios e sem spam)—clique em Entrar com o GitHub abaixo para comentar ou reagir (criar uma conta gratuita no GitHub leva menos de um minuto).
Atualizado em 2 de out. de 2026.
AVISO LEGAL: O conteúdo deste site tem finalidade exclusivamente informativa e educacional e não constitui aconselhamento médico, psicológico, financeiro, de investimentos, tributário ou jurídico. As ideias, a curadoria e as opiniões aqui apresentadas são exclusivamente minhas e não representam as do meu empregador. Os resumos de livros, palestras e artigos são comentários educacionais independentes e permanecem propriedade intelectual de seus respectivos autores. Ferramentas de IA podem ser utilizadas para auxiliar na edição, formatação e síntese; embora todos os esforços sejam feitos para garantir a precisão, erros podem ocorrer. PRIVACIDADE: Este site utiliza serviços de terceiros para inscrição opcional em newsletter (follow.it), comentários (giscus / GitHub Discussions) e mídia incorporada (YouTube), que podem processar endereços IP e cookies dos visitantes de acordo com suas respectivas políticas de privacidade.