🧩 Veintinueve bytes para decir hola: haciendo code golf con «Hello, World!» en SuperHack 🔗

Un análisis del reto «Super Small Hello World» de hacker.org: las soluciones que funcionaron, las que casi lo logran y el truco que finalmente alcanzó los 29 bytes.

Descripción general

📑 Tabla de Contenidos 🔗


🎯 El reto 🔗

hacker.org tiene un pequeño lenguaje esotérico llamado SuperHack. La tarea parece trivial: escribir un programa en SuperHack que imprima Hello, World!.

El truco está en la puntuación. Se te puntúa según el área del rectángulo delimitador de tu código, y cuanto más pequeño, mejor. Además, el programa tiene que terminar correctamente: ejecutando la instrucción ! (halt). Que falle con una excepción de la máquina virtual una vez impreso el texto no vale, y tampoco vale imprimir bytes sobrantes.

El número a batir era 29.


🧭 Un recorrido de dos minutos por SuperHack 🔗

SuperHack es una máquina de pila bidimensional, similar en espíritu a Befunge:

InstrucciónEfecto
0-9apila un dígito
+ - dsuma, resta, división entera (d entre cero da 0)
xduplica la cima de la pila
n ^apila una copia del elemento situado n posiciones por debajo de la cima (1^ copia el segundo)
,lee la entrada. Cuando no hay entrada, apila 0
gdesapila x, desapila y, apila el código del carácter en (x, y). Fuera de la cuadrícula apila 0
Pdesapila e imprime como carácter (solo los 7 bits inferiores)
ssalta la siguiente celda
?desapila; salta la siguiente celda si el valor era 0
@apila la posición (y dirección) actual en la pila de llamadas
$desapila una posición, salta allí y continúa dos celdas más adelante
\espejo: convierte «moverse a la derecha» en «moverse hacia abajo»
!detiene el programa (halt)
cualquier otrano-op (no hace nada)

Dos consecuencias condicionan todo lo que sigue:

  1. Los caracteres son datos. g lee el propio código del programa, de modo que la cadena Hello, World! puede simplemente residir en la cuadrícula y leerse carácter a carácter. La mayoría de sus letras (H e l o W r) son no-ops cuando se ejecutan. Tres no lo son: , apila 0, d divide y ! detiene la ejecución.
  2. @ / $ crean bucles, y el número de iteraciones depende de dónde estén los @. $ reanuda la ejecución dos celdas después del @ al que regresa. Eso aterriza sobre el siguiente @, que vuelve a apilarse a sí mismo, por lo que unos pocos @ pueden repetir el cuerpo del bucle muchas veces:
    • Los @@@@@ adyacentes producen recuentos de Fibonacci. Cinco de ellos ejecutan el cuerpo exactamente 13 veces.
    • Los @ separados de dos en dos producen potencias de dos. Cuatro de ellos permiten 16 pasadas.

Trece caracteres, trece pasadas. Quédate con ese dato.

El área es el ancho multiplicado por el alto, y 29 es primo. Por tanto, un programa de 29 celdas tiene que ser una sola fila o una sola columna.


1️⃣ Solución 1: el bucle directo (área 32) 🔗

Solución 1 comentada

Hello, World!%0@s!@@@@@ 01^gP1+$

La primera solución real coloca la carga útil (payload) al principio e inicia la ejecución después de ella:

partefunción
Hello, World!datos, nunca ejecutados, porque el PC comienza en el %
%punto de entrada
0índice i = 0
@ s !artilugio de parada (halt gadget): véase más abajo
@@@@@cinco trampolines adyacentes, por lo que el cuerpo se ejecuta 13 veces
relleno (explicado más abajo)
0 1^ gapila la fila 0, copia i y obtiene el carácter de la columna i
Plo imprime
1+i += 1
$repite el bucle

El artilugio de parada. El primer @ coloca su propia posición en el fondo de la pila de llamadas, y s salta por encima del !. A continuación, la cadena de Fibonacci realiza sus 13 pasadas. Cuando la pila de llamadas finalmente se desenrolla hasta ese primer @, $ reanuda la ejecución dos celdas después, que es exactamente donde está el !. El programa se detiene limpiamente y no hay ninguna comprobación de final de cadena en ninguna parte.

El relleno. Con @ adyacentes, al regresar del último @ la ejecución se reanuda dos celdas más adelante, lo que salta la primera celda posterior a la cadena. Por tanto, esa celda debe ser algo inofensivo, así que es un espacio.

Resultado: Hello, World!, parada limpia, área 32. Es correcto pero holgado: el texto es peso muerto, y el %, el espacio de relleno y el 0 cuestan en conjunto tres celdas.


2️⃣ Solución 2: intercalado (área 28, pero no válida) 🔗

Solución 2 comentada

1H@e@l@l@o ,1 ^WgoPr2lsds!+$

La siguiente idea consiste en dejar de gastar celdas en un bloque de datos separado y entrelazar la cadena con el código. Los caracteres de Hello, World! ocupan las columnas impares (1, 3, …, 25), y el código rellena las columnas pares intermedias:

El problema es que 16 pasadas son más que 13. Después de imprimir la cadena, el bucle sigue leyendo más allá del final e imprime $ y dos bytes NUL. Entonces $ encuentra vacía la pila de llamadas y la máquina virtual muere:

output:  "Hello, World!$\0\0"
message: call stack underflow

Es pequeño, pero no es una solución válida. Sin embargo, introduce la idea clave: los caracteres de datos que resultan ser instrucciones útiles (,) cumplen una doble función como datos y como código.


3️⃣ Solución 3: en vertical (área 27, pero no válida) 🔗

Solución 3 comentada

\
2
H
@
e
@
l
@
l
@
o
x
,
g

P
W
2
o
+
r
$
l

d

!

(Un carácter por línea. Las líneas en blanco son espacios individuales, que forman parte de los datos).

Poner el programa en vertical tiene una ventaja inesperada. En una sola columna, g necesita que la coordenada x sea 0 y que la fila sea i. La , de los datos proporciona ese 0 gratis, por lo que la lectura se reduce a x , g: duplicar i, apilar 0 y obtener el carácter. El coste es un único \ en la parte superior para dirigir el PC hacia abajo.

No obstante, tiene el mismo defecto que la solución 2. El bucle se pasa de largo, imprime bytes NUL y termina con call stack underflow. Con un área de 27, es el programa más pequeño de este artículo, pero no cuenta.

La lección de las soluciones 2 y 3 es que detenerse limpiamente cuesta celdas. El intercalado abarata el bucle, pero te da 16 pasadas cuando necesitas exactamente 13.


4️⃣ Solución 4: pagar por la salida (área 30) 🔗

Solución 4 comentada

\
2
H
@
e
@
l
@
l
@
o
x
,
g
 
P
W
x
o
5
r
d
l
5
d
?
!
2
+
$

La solución 4 conserva el intercalado vertical de la solución 3 y añade una comprobación de fin de cadena en toda regla:

fila(s)celdasfunción
0\girar hacia abajo
12i = 2
3, 5, 7, 9@cuatro trampolines, hasta 16 pasadas
11-13x , gleer la fila i (la , es parte de los datos)
15Pimprimir
17-24x 5 d 5 dvalor de prueba floor(floor(i/5)/5) = floor(i/25) (la última d es dato)
25?si el valor es 0, saltar la siguiente celda…
26!…que es el propio ! de los datos
27-282 +i += 2
29$repetir el bucle

El índice recorre 2, 4, …, 26. floor(i/25) se mantiene en 0 hasta el último carácter (i = 26), por lo que ? salta la parada en todas las pasadas salvo en la última. En la última pasada, la ejecución cae sobre el ! de los datos, que es simultáneamente el último carácter impreso y la instrucción que detiene el programa.

Es una reutilización magnífica: la ,, la d y el ! del texto sirven todos como código. Pero la comprobación cuesta cinco celdas y el total asciende a 30.

🧱 Por qué bajar a 29 parecía imposible 🔗

Llegados a este punto, mi compañero de IA intentó demostrar que 30 era el óptimo. Todos los enfoques parecían chocar contra el mismo muro:

Las búsquedas exhaustivas por ordenador en áreas más pequeñas no encontraron nada, y las búsquedas alrededor de la disposición de la solución 4 con área 29 tampoco arrojaron resultados. «30 es el límite inferior» empezaba a parecer un teorema.

No lo era.


🏆 Solución 5: veintinueve (área 29) 🔗

Solución 5 comentada

9@s!@@@@@Hello, Worlä¡1^gP1+$

El avance llegó al releer el código fuente del juez. Hay dos líneas clave:

case 'P':
  $output .= chr($this->Pop() & 0x7F); break;
...
default:
  break;   // every unknown character is a no-op

Por consiguiente, cada carácter de los datos tiene dos codificaciones. La normal puede hacer algo al ejecutarse. La codificación c | 0x80 es garantizadamente inerte. Esa es la «fórmula para los datos»: almacenar los caracteres peligrosos como c + 128, y dejar que P elimine el bit alto gratis.

Solo dos caracteres del texto son peligrosos: d se convierte en ä (0xE4) y ! se convierte en ¡ (0xA1). Con esos dos cambios, toda la cadena de datos puede ejecutarse. Eso elimina el obstáculo del tercer punto anterior.

Ahora tomamos la solución 1 y movemos los datos dentro del bucle:

colsceldasfunción
09i = 9 (la columna de la H)
1-3@ s !artilugio de parada, igual que en la solución 1
4-8@@@@@cinco trampolines adyacentes, el cuerpo se ejecuta 13 veces
9-21Hello, Worlä¡los datos, ejecutados en cada pasada
22-271 ^ g P 1 +copiar i, obtener carácter, imprimir, incrementar
28$repetir el bucle

Recorramos una pasada:

  1. El PC aterriza en algún punto de la cadena de @ y atraviesa los datos. H e l l o, el espacio y W o r l no hacen nada. La , de los datos apila el 0 que g necesita como fila. ä y ¡ no hacen nada.
  2. 1^ copia i encima de ese 0, y g lee la columna i.
  3. P la imprime. Para los dos últimos caracteres imprime 0xE4 & 0x7F = 'd' y 0xA1 & 0x7F = '!'.
  4. 1+ incrementa i, y $ regresa a la cadena de @.

En comparación con la solución 1, desaparecen tres celdas:

32 − 3 = 29. Tras la 13.ª pasada, la pila de llamadas se desenrolla hasta el artilugio inicial y el programa se detiene en el ! de la columna 3.

Salida Hello, World!, sin mensaje de error de la VM, 271 ciclos, área 29.

🌐 El último obstáculo: hacer llegar los bytes al juez 🔗

El primer envío devolvió got: 'Hello, WorlC$' y una puntuación de 31. El formulario web había enviado los datos en UTF-8, convirtiendo cada carácter especial en dos bytes (ä → C3 A4, ¡ → C2 A1). Al aplicar la máscara de 7 bits, 0xC3 se imprime como C y 0xA4 como $.

La solución consiste en hacer que el navegador envíe Latin-1, donde cada uno de esos caracteres ocupa un solo byte. En la página del reto, tuve que abrir la consola de DevTools y ejecutar:

document.querySelectorAll('form').forEach(
  f => f.acceptCharset = 'ISO-8859-1');
document.querySelector('textarea').value =
  "9@s!@@@@@Hello, Worl\u00e4\u00a11^gP1+$";

Y luego pulsar el botón de envío normal. El juez imprime Hello, World!, y la puntuación máxima es 29.


📊 Tabla de resultados 🔗

#programaárea¿termina limpiamente?
1Hello, World!%0@s!@@@@@ 01^gP1+$32✅
21H@e@l@l@o ,1 ^WgoPr2lsds!+$28❌ bytes sobrantes y desbordamiento inferior de la pila
3\2H@e@l@l@ox,g PW2o+r$ld!27❌ bytes sobrantes y desbordamiento inferior de la pila
4\2H@e@l@l@ox,g PWxo5rdl5d?!2+$30✅
59@s!@@@@@Hello, Worlä¡1^gP1+$29✅

💡 Conclusiones 🔗


📚 Descarga Mi Ebook Gratuito 🔗

Obtén la edición sin conexión de El Estilo de Vida de Kaue—una guía práctica para optimizar 🍏 Salud, 💰 Riqueza, ❤️ Amor y 🧘 Sentido.

El Estilo de Vida de Kaue

El Estilo de Vida de Kaue

📬 Suscríbete a Mi Boletín 🔗

Recibe notificaciones cuando publique nuevos ensayos, resúmenes de libros y guías prácticas sobre cómo vivir bien. Sin spam—cancela cuando quieras.


💬 Comentarios y Debate 🔗

¿Tienes alguna pregunta, perspectiva o sugerencia? Comparte tus ideas abajo. Los comentarios funcionan con GitHub Discussions (sin anuncios y sin spam)—haz clic en Iniciar sesión con GitHub abajo para comentar o reaccionar (crear una cuenta gratuita en GitHub toma menos de un minuto).



Actualizado el 2 oct 2026.

AVISO LEGAL: El contenido de este sitio tiene fines exclusivamente informativos y educativos y no constituye asesoramiento médico, psicológico, financiero, de inversión, fiscal ni legal. Las ideas, la selección y las opiniones aquí presentadas son exclusivamente mías y no representan las de mi empleador. Los resúmenes de libros, conferencias y artículos son comentarios educativos independientes y siguen siendo propiedad intelectual de sus respectivos autores. Se pueden utilizar herramientas de IA para ayudar en la edición, el formato y la síntesis; aunque se hace todo lo posible por garantizar la precisión, pueden producirse errores. PRIVACIDAD: Este sitio utiliza servicios de terceros para la suscripción opcional al boletín (follow.it), los comentarios (giscus / GitHub Discussions) y el contenido multimedia incrustado (YouTube), que pueden procesar las direcciones IP y las cookies de los visitantes de acuerdo con sus respectivas políticas de privacidad.