🧩 Neunundzwanzig Bytes für ein Hallo: Code-Golfing von „Hello, World!" in SuperHack 🔗

Ein Erfahrungsbericht zur „Super Small Hello World"-Challenge auf hacker.org: die Lösungen, die funktionierten, die, die fast funktionierten, und der Trick, der schließlich die 29 knackte.

Überblick

📑 Inhaltsverzeichnis 🔗


🎯 Die Herausforderung 🔗

Auf hacker.org gibt es eine kleine esoterische Programmiersprache namens SuperHack. Die Aufgabe klingt zunächst trivial: Schreibe ein SuperHack-Programm, das Hello, World! ausgibt.

Der Haken ist die Bewertung. Bewertet wird die Fläche des umschließenden Rechtecks deines Codes – je kleiner, desto besser. Außerdem muss sich das Programm sauber beenden, nämlich durch Ausführen der Anweisung ! (Halt). Ein Absturz mit einer VM-Exception nach der Textausgabe zählt ebenso wenig wie das Ausgeben überflüssiger Bytes.

Die zu schlagende Bestmarke lag bei 29.


🧭 Eine Zwei-Minuten-Tour durch SuperHack 🔗

SuperHack ist eine zweidimensionale Stack-Maschine, im Geiste ähnlich wie Befunge:

AnweisungWirkung
0-9legt eine Ziffer auf den Stack (Push)
+ - daddieren, subtrahieren, ganzzahlig dividieren (d durch null ergibt 0)
xdupliziert das oberste Element des Stacks
n ^legt eine Kopie des Elements n unterhalb der Spitze auf den Stack (1^ kopiert das zweitoberste)
,liest Eingabe. Wenn keine Eingabe vorhanden ist, legt es 0 auf den Stack
gnimmt x und y vom Stack und legt den Zeichencode an Position (x, y) ab (außerhalb des Gitters 0)
Pnimmt den obersten Wert vom Stack und gibt ihn als Zeichen aus (nur die unteren 7 Bits)
süberspringt die nächste Zelle
?nimmt den obersten Wert vom Stack; überspringt die nächste Zelle, falls der Wert 0 war
@legt die aktuelle Position (und Richtung) auf den Call-Stack
$nimmt eine Position vom Call-Stack, springt dorthin und fährt zwei Zellen weiter fort
\Spiegel: macht aus „nach rechts bewegen" ein „nach unten bewegen"
!Programm anhalten (Halt)
alles anderekeine Operation (No-Op)

Zwei Konsequenzen prägen alles Folgende:

  1. Zeichen sind Daten. g liest den eigenen Programmcode, sodass die Zeichenkette Hello, World! einfach im Gitter liegen und Zeichen für Zeichen ausgelesen werden kann. Die meisten Buchstaben darin (H e l o W r) sind bei der Ausführung No-Ops. Drei jedoch nicht: , legt 0 auf den Stack, d dividiert und ! hält das Programm an.
  2. @ / $ bilden Schleifen, und die Anzahl der Durchläufe hängt davon ab, wo die @-Zeichen stehen. $ setzt die Ausführung zwei Zellen nach dem @ fort, zu dem es zurückkehrt. Dort landet es auf dem nächsten @, das sich wiederum selbst auf den Call-Stack legt, sodass wenige @-Zeichen den Schleifenrumpf viele Male wiederholen können:
    • Nebeneinanderliegende @@@@@ liefern Fibonacci-Anzahlen. Fünf davon führen den Rumpf genau 13-mal aus.
    • @-Zeichen im Abstand von zwei Zellen liefern Zweierpotenzen. Vier davon ermöglichen 16 Durchläufe.

Dreizehn Zeichen, dreizehn Durchläufe. Behalten wir das im Hinterkopf.

Die Fläche ist Breite mal Höhe, und 29 ist eine Primzahl. Ein Programm mit 29 Zellen muss also zwingend eine einzelne Zeile oder eine einzelne Spalte sein.


1️⃣ Lösung 1: Die geradlinige Schleife (Fläche 32) 🔗

Lösung 1 mit Anmerkungen

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

Die erste funktionierende Lösung platziert den Text (die Payload) ganz vorne und startet die Ausführung dahinter:

TeilRolle
Hello, World!Daten, werden nie ausgeführt, da der PC beim % startet
%Einstiegspunkt
0Index i = 0
@ s !Halt-Gadget: siehe unten
@@@@@fünf benachbarte Trampoline, sodass der Rumpf 13-mal läuft
Füllzeichen (Padding, wird unten erklärt)
0 1^ glege Zeile 0 auf den Stack, kopiere i, hole das Zeichen in Spalte i
Pgib es aus
1+i += 1
$Schleifenrücksprung

Das Halt-Gadget. Das erste @ legt seine eigene Position ganz unten auf dem Call-Stack ab, und s springt über das ! hinweg. Die Fibonacci-Kette absolviert dann ihre 13 Durchläufe. Wenn der Call-Stack schließlich bis zu diesem allerersten @ abgearbeitet ist, setzt $ die Ausführung zwei Zellen dahinter fort – und das ist genau das !. Das Programm hält sauber an, ganz ohne Prüfung auf das Ende der Zeichenkette.

Das Füllzeichen (Padding). Bei direkt benachbarten @-Zeichen setzt die Rückkehr vom letzten @ zwei Zellen weiter wieder an, wodurch die erste Zelle nach der Kette übersprungen wird. In dieser Zelle muss daher etwas Harmloses stehen – also ein Leerzeichen.

Ergebnis: Hello, World!, sauberer Halt, Fläche 32. Das Programm ist korrekt, aber verschwenderisch: Die Payload liegt als totes Gewicht herum, und das %, das Leerzeichen sowie die 0 kosten zusammen drei Zellen.


2️⃣ Lösung 2: Verschränkung (Fläche 28, aber ungültig) 🔗

Lösung 2 mit Anmerkungen

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

Die nächste Idee besteht darin, keine eigenen Zellen mehr für eine separate Payload zu verschwenden, sondern die Zeichenkette direkt mit dem Code zu verweben. Die Zeichen von Hello, World! sitzen in den ungeraden Spalten (1, 3, …, 25), und der Code füllt die geraden Spalten dazwischen:

Das Problem: 16 Durchläufe sind mehr als 13. Nachdem die Zeichenkette ausgegeben wurde, liest die Schleife hinter dem Ende weiter und gibt $ sowie zwei NUL-Bytes aus. Danach findet $ einen leeren Call-Stack vor und die VM stürzt ab:

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

Es ist zwar klein, aber keine gültige Lösung. Allerdings führt es die Schlüsselidee ein: Payload-Zeichen, die zufällig nützliche Anweisungen sind (,), übernehmen eine Doppelrolle als Daten und Code.


3️⃣ Lösung 3: Ab in die Vertikale (Fläche 27, aber ungültig) 🔗

Lösung 3 mit Anmerkungen

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

P
W
2
o
+
r
$
l

d

!

(Ein Zeichen pro Zeile. Die Leerzeilen enthalten jeweils ein einzelnes Leerzeichen, das als Datum dient.)

Das Programm auf die Seite zu kippen, bringt einen unerwarteten Vorteil. In einer einzelnen Spalte benötigt g als x-Koordinate eine 0 und als Zeile den Index i. Das , der Payload liefert diese 0 kostenlos, sodass das Auslesen auf x , g schrumpft: i duplizieren, 0 auf den Stack legen, Zeichen holen. Die Kosten dafür betragen lediglich ein \ ganz oben, um den PC nach unten zu lenken.

Allerdings leidet dieser Ansatz unter demselben Fehler wie Lösung 2: Die Schleife schießt über das Ziel hinaus, gibt NUL-Bytes aus und endet mit einem call stack underflow. Mit Fläche 27 ist es das kleinste Programm in diesem Artikel – aber es zählt nicht.

Die Lektion aus den Lösungen 2 und 3 lautet: Sauberes Anhalten kostet Zellen. Das Verschränken macht die Schleife billig, liefert aber 16 Durchläufe, obwohl wir genau 13 brauchen.


4️⃣ Lösung 4: Den Preis für den Ausstieg zahlen (Fläche 30) 🔗

Lösung 4 mit Anmerkungen

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

Lösung 4 behält die vertikale Verschränkung aus Lösung 3 bei und ergänzt eine reguläre Prüfung auf das Ende der Zeichenkette:

Zeile(n)ZellenRolle
0\Richtung nach unten ändern
12i = 2
3, 5, 7, 9@vier Trampoline, bis zu 16 Durchläufe
11-13x , ghole Zeile i (das , gehört zur Payload)
15Pausgeben
17-24x 5 d 5 dPrüfwert floor(floor(i/5)/5) = floor(i/25) (das letzte d ist Payload)
25?falls der Prüfwert 0 ist, überspringe die nächste Zelle…
26!…welche das ! der Payload selbst ist
27-282 +i += 2
29$Schleifenrücksprung

Der Index durchläuft die Werte 2, 4, …, 26. floor(i/25) bleibt 0 bis zum allerletzten Zeichen (i = 26), sodass ? den Halt bei jedem Durchlauf außer dem letzten überspringt. Beim letzten Durchlauf fällt die Ausführung direkt auf das ! der Payload, das damit gleichzeitig das letzte ausgegebene Zeichen und der Befehl zum Anhalten des Programms ist.

Eine wunderbare Mehrfachnutzung: ,, d und ! aus der Payload dienen alle zugleich als Code. Doch der Test kostet fünf Zellen, womit wir insgesamt bei 30 landen.

🧱 Warum 29 unmöglich erschien 🔗

An diesem Punkt versuchte mein KI-Begleiter zu beweisen, dass 30 das theoretische Optimum sei. Jeder Ansatz schien gegen dieselbe Wand zu laufen:

Erschöpfende Maschinensuchen über kleinere Flächen ergaben nichts, und auch Suchen rund um das Layout von Lösung 4 mit Fläche 29 blieben erfolglos. „30 ist die Untergrenze" sah immer mehr wie ein mathematischer Satz aus.

War es aber nicht.


🏆 Lösung 5: Neunundzwanzig (Fläche 29) 🔗

Lösung 5 mit Anmerkungen

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

Der Durchbruch kam beim erneuten Lesen des Quellcodes des Bewertungsservers (Judge). Zwei Zeilen sind entscheidend:

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

Jedes Payload-Zeichen besitzt somit zwei Kodierungen: Die normale Variante tut möglicherweise etwas, wenn sie ausgeführt wird. Die Variante c | 0x80 ist garantiert wirkungslos. Das ist die „Formel für die Daten": Speichere die gefährlichen Zeichen als c + 128 und lass P das höchste Bit kostenlos wieder abschneiden.

Nur zwei Zeichen in der Payload sind gefährlich: Aus d wird ä (0xE4) und aus ! wird ¡ (0xA1). Mit diesen beiden Änderungen kann die gesamte Payload problemlos durchlaufen werden. Damit löst sich das Hindernis aus dem dritten Punkt oben in Luft auf.

Jetzt nehmen wir Lösung 1 und verschieben die Payload mitten in die Schleife:

SpaltenZellenRolle
09i = 9 (die Spalte von H)
1-3@ s !Halt-Gadget, genau wie in Lösung 1
4-8@@@@@fünf benachbarte Trampoline, sodass der Rumpf genau 13-mal läuft
9-21Hello, Worlä¡die Payload, wird bei jedem Durchlauf durchlaufen
22-271 ^ g P 1 +i kopieren, Zeichen holen, ausgeben, inkrementieren
28$Schleifenrücksprung

Gehen wir einen Durchlauf Schritt für Schritt durch:

  1. Der PC landet irgendwo in der @-Kette und läuft mitten durch die Payload. H e l l o, das Leerzeichen und W o r l tun nichts. Das , der Payload legt die 0 auf den Stack, die g als Zeilennummer braucht. ä und ¡ tun nichts.
  2. 1^ kopiert i über diese 0, und g liest Spalte i aus.
  3. P gibt das Zeichen aus. Für die letzten beiden Zeichen berechnet es 0xE4 & 0x7F = 'd' und 0xA1 & 0x7F = '!'.
  4. 1+ erhöht i, und $ springt zurück in die Kette.

Im Vergleich zu Lösung 1 verschwinden gleich drei Zellen:

32 − 3 = 29. Nach dem 13. Durchlauf wird der Call-Stack bis zum Halt-Gadget abgebaut, und das Programm stoppt sauber auf dem ! in Spalte 3.

Ausgabe Hello, World!, keine VM-Fehlermeldung, 271 Zyklen, Fläche 29.

🌐 Die letzte Hürde: Die Bytes unbeschadet zum Judge bringen 🔗

Der erste Einreichungsversuch kam mit got: 'Hello, WorlC$' und einer Punktzahl von 31 zurück. Das Webformular hatte die Daten als UTF-8 gesendet, wodurch jedes Sonderzeichen in zwei Bytes umgewandelt wurde (ä → C3 A4, ¡ → C2 A1). Auf 7 Bit maskiert wird 0xC3 als C und 0xA4 als $ ausgegeben.

Die Lösung besteht darin, den Browser anzuweisen, Latin-1 zu senden, wo jedes dieser Zeichen genau ein Byte lang ist. Auf der Challenge-Seite musste ich dazu die DevTools-Konsole öffnen und Folgendes ausführen:

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

Danach genügte ein Klick auf den normalen Absende-Button. Der Judge gibt Hello, World! aus, und der Bestwert liegt bei 29.


📊 Ergebnisübersicht 🔗

#ProgrammFlächeBeendet sauber?
1Hello, World!%0@s!@@@@@ 01^gP1+$32✅
21H@e@l@l@o ,1 ^WgoPr2lsds!+$28❌ zusätzliche Bytes und Call-Stack-Underflow
3\2H@e@l@l@ox,g PW2o+r$ld!27❌ zusätzliche Bytes und Call-Stack-Underflow
4\2H@e@l@l@ox,g PWxo5rdl5d?!2+$30✅
59@s!@@@@@Hello, Worlä¡1^gP1+$29✅

💡 Erkenntnisse 🔗


📚 Mein Kostenloses E-Book Herunterladen 🔗

Lade die kuratierte Offline-Ausgabe von Kaues Lebensweise herunter – ein praktischer Leitfaden zur Optimierung von 🍏 Gesundheit, 💰 Wohlstand, ❤️ Liebe und 🧘 Sinn.

Kaues Lebensweise

Kaues Lebensweise

📬 Meinen Newsletter Abonnieren 🔗

Erhalte eine Benachrichtigung, wenn ich neue Essays, Buchzusammenfassungen und praktische Leitfäden für ein gutes Leben veröffentliche. Kein Spam – jederzeit abbestellbar.


💬 Kommentare & Diskussion 🔗

Hast du eine Frage, eine Perspektive oder einen Vorschlag? Teile deine Gedanken unten mit. Die Kommentare werden über GitHub Discussions bereitgestellt (werbefrei und spamfrei) – klicke unten auf Mit GitHub anmelden, um zu kommentieren oder zu reagieren (ein kostenloses GitHub-Konto ist in weniger als einer Minute erstellt).



Aktualisiert am 02.10.2026.

HAFTUNGSAUSSCHLUSS: Die Inhalte auf dieser Website dienen ausschließlich Informations- und Bildungszwecken und stellen keine medizinische, psychologische, finanzielle, steuerliche oder rechtliche Beratung sowie keine Anlageberatung dar. Die hier präsentierten Ideen, Zusammenstellungen und Meinungen sind meine eigenen und spiegeln nicht die meines Arbeitgebers wider. Zusammenfassungen von Büchern, Vorträgen und Artikeln sind unabhängige Bildungskommentare und bleiben geistiges Eigentum der jeweiligen Autoren. KI-Tools können zur Unterstützung bei der Bearbeitung, Formatierung und Synthese eingesetzt werden; obwohl größte Sorgfalt auf Richtigkeit gelegt wird, können Fehler auftreten. DATENSCHUTZ: Diese Website nutzt Dienste von Drittanbietern für optionale Newsletter-Abonnements (follow.it), Kommentare (giscus / GitHub Discussions) und eingebettete Medien (YouTube), die IP-Adressen und Cookies der Besucher gemäß ihren jeweiligen Datenschutzrichtlinien verarbeiten können.