Die Bezeichnung „Spiel“ ist etwas verwirrend: Weder benötigt man einen Joystick, noch gibt es Gewehrsalven oder UFOs, die über den flackernden Bildschirm sausen. Freilich kann man den „Krieg der Kerne“ auch kaum als Anwenderprogramm bezeichnen, denn die spielerische Komponente ist unübersehbar: Ein Kampf, aus dem Sieger und Unterlegene hervorgehen.
Das Schlachtfeld, auf dem es zu siegen gilt, ist das Innere des Computers. Genauer gesagt: Ein vorher festzulegender Speicherbereich von zum Beispiel 8000 Bytes Länge.
Zwei Computerprogramme sind die Gegner, die sich in dieser Arena den Garaus zu machen versuchen. Sie sind in einer künstlichen, assemblerähnlichen Sprache geschrieben. Die gegnerische Position und Strategie ist völlig unbekannt. Fest steht nur, daß der Feind alles daransetzt, seinen Gegner durch Einpflanzen eines ungültigen Befehls zum Absturz zu bringen.
Die Rolle des Spielers beim „Krieg der Kerne“ besteht allein darin, ein möglichst raffiniertes Programm in der bereits erwähnten Sprache zu erstellen, die von ihrem Erfinder REDCODE genannt wurde. Dieses Programm muß in der Lage sein, ein gegnerisches Programm aufzuspüren und es durch „Beschießen“ mit ungültigen Befehlen außer Gefecht zu setzen. Natürlich kann es auch einen anderen Weg einschlagen, indem es eine starke Verteidigung gegen gegnerischen Beschluß aufbaut und eigene Wunden, also Treffer, gegebenenfalls sogar selbst repariert. Der Phantasie des Programmierers sind hierbei kaum Grenzen gesetzt. Denkbar sind auch Programme, die sich todbringenden Treffern entziehen, indem sie sich ziellos im Speicher hin-und herkopieren und dabei womöglich selbst den Gegner ins Visier nehmen oder ihn gar überrollen. Hat so ein Programm noch heute viele Kämpfe überstanden, so kann es morgen schon von einem stärkeren Gegner in seine Schranken verwiesen werden.
Hat man also das Programm erstellt und für tauglich befunden, so gibt es nur noch eines zu tun: Es muß zusammen mit dem gegnerischen Programm in die Arena geschickt werden, um sich zu bewähren. Der weitere Ablauf entzieht sich jeglicher Einflußnahme durch den Programmierer: Der Kampf findet in aller Stille statt. Kein Gewehrdonner, kein Schlachtengetümmel läßt merken, daß im Inneren des Computers ein mitunter recht heftiges Gefecht tobt. Erst die trockene Textzeile „Sieger ist Programm X“ verkündet nach oft überraschend kurzer Zeit Ende und Ergebnis des Kampfes.
Bevor wir uns jedoch den Details widmen, muß erwähnt werden, daß die Idee zum „Krieg der Kerne“ von A. K. Dewdney stammt, der sie bereits vor einigen Jahren in zwei Artikeln der Zeitschrift „Spektrum der Wissenschaft“ (Hefte 8/84 und 5/85) publizierte. Dort findet man zwar viele Einzelheiten, Tips und Anregungen, jedoch keine Inplementierung für einen bestimmten Computertyp.
Weil nun das „Spektrum der Wissenschaft“ nicht gerade jedermanns Frühstückslektüre ist, doch die Idee von A. K. Dewdney insgesamt sehr interessant erscheint, haben wir uns zu zweit sofort daran gemacht, eine Version für den Atari ST zu schreiben. Das Ergebnis dieser Bemühungen liegt nun als Public-Domain-Programm vor, das auf Diskette 57 enthalten ist.
Der Leser wird sich hier wohl fragen, wie es denn möglich sei, zwei Programme gleichzeitig ablaufen zu lassen. Selbst der smarteste Computer kann doch gewöhnlich nur einen Befehl auf einmal abarbeiten. Die Lösung lautet „Time sharing“. Dies bedeutet lediglich, daß sich beide Programme die Computer-Zeit „teilen“. In der Praxis sorgt ein übergeordnetes Programm namens MARS (Memory Ar-ray Redcode Simulator) dafür, daß erst ein Befehl des einen Kampfprogramms abgearbeitet wird, dann ein Befehl des anderen Programms und abwechselnd immer so weiter. Dieser Vorgang endet, wenn MARS auf einen ungültigen Befehl stößt. Das betreffende Programm wird von MARS zum Verlierer erklärt, und das war’s dann schon.
Zur Erläuterung sei hier das absolut kürzeste REDCODE-Programm vorgestellt. Es nennt sich KNIRPS und ist trotz seiner Winzigkeit ein durchaus ernstzunehmender Gegner im „Krieg der Kerne“:
MOV 0 1
KNIRPS tut nichts anderes, als sich bei jedem Aufruf um genau eine Speicherstelle weiterzubewegen. Das Mnemonik MOV bewirkt, daß der Inhalt, der durch die erste Zahl bezeichneten Speicherstelle an die, durch die zweite Zahl bestimmte, kopiert wird (MOVE: engl, „bewegen“). Die Zahlen geben dabei eine relative Adresse an, d. h. der Inhalt von (augenblickliche Adresse + 0) - es handelt sich um den Befehl selbst - wird nach (augenblickliche Adresse +1) kopiert. Freunde der Assemblersprache haben es hier leichter, aber mit etwas Gewöhnung wird dies auch für Hochsprachenprogrammierer zu durchschauen sein.
KNIRPS bewegt sich also mit einer Geschwindigkeit von einer Speicherstelle pro MARS-Zyklus im Speicher vorwärts. Ohne ausreichende Gegenmaßnahmen würde er früher oder später in das gegnerische Programm hineinrennen und es einfach überrollen. Dies würde zwar nicht dazu führen, daß MARS beim Gegner auf einen ungültigen Befehl träfe - es fände lediglich eine Kopie von KNIRPS vor. Der Gegner ist jedoch „umgedreht“ worden, d. h. von nun an rennen zwei KNIRPSE durch den Speicher, ohne sich jemals zu kriegen oder sich Schaden zuzufügen. Das Spiel wird unentschieden enden.
Sollte einer unserer KNIRPSE dabei das obere Ende des Speicherplatzes erreichen, so läuft er einfach an dessen Anfang weiter, was uns zu einem besonderen Merkmal des „Schlachtfeldes“ führt: Dieser Speicherbereich ist als Ring zu verstehen. An seine höchste Adresse schließt die niedrigste Adresse unmittelbar an. Hat das Schlachtfeld zum Beispiel eine Größe von 8000 Bytes und würde ein Befehl, der sich auf Adresse 7900 befindet, die Adresse 200 ansprechen, so würde dies von MARS in die Adresse 100 übersetzt.
augenblickliche Adresse:
7900
z. B. MOV 0 200:
7900 + 200 = 8100
wird zu:
8100 mod 8000 = 100
Die „Computerviren“, über die ja in letzter Zeit häufiger berichtet wurde, sind den beim „Krieg der Kerne“ erstellten Programmen nicht unähnlich, denn ihre Funktion besteht ja auch meist darin, andere Programme zu zerstören oder unbrauchbar zu machen. Beim „Krieg der Kerne“ bleiben jedoch, durch die geschlossene Struktur der „Arena“, die Tierchen im Stall und können keinen Unfug mit dem Betriebssystem oder mit anderen Programmen anstellen.
Weitere Feinheiten der REDCODE-Programmierung seien anhand eines zweiten kurzen Kampfprogrammes namens GNOM erklärt (siehe Tabelle 1).
Adresse | 1. Zyklus | 2. Zyklus | 9. Zyklus |
---|---|---|---|
0 | ------ | ----- | ------ |
1 | ADD #5 3 | ADD #5 3 | ADD #5 3 |
2 | MOV #0 @2 | MOV #0 @2 | MOV #0 ©2 |
3 | JMP -2 | JMP -2 | JMP -2 |
4 | DAT -4 | DAT 1 | DAT 11 |
5 | ------ | ----- | ------ |
6 | ------ | ----- | ------ |
7 | ------ | ----- | ------ |
8 | ------ | ----- | ------ |
9 | ------ | ----- | ------ |
10 | ------ | ----- | -- o - |
11 | ------ | ----- | ------ |
12 | ------ | ----- | ------ |
13 | ------ | ----- | ------ |
14 | ------ | ----- | ------ |
15 | ------ | ----- | -- o - |
Tabelle 1: klein aber aggressiv: der GNOM
Um es gleich vorwegzunehmen: Der GNOM tut nichts anderes, als jede fünfte Speicherstelle mit einer 0 zu belegen. Die 0 stellt in REDCODE einen ungültigen Befehl dar. Sollte sich an ihrer Stelle vorher das feindliche Programm befunden haben, so wird es bei Abarbeitung dieser „Bombe“ unweigerlich abstürzen. Die Gefährlichkeit des GNOMS ist also offensichtlich. Jedes stationäre Programm, sofern es länger als vier Zeilen ist, wird früher oder später von GNOM erwischt werden.
Sein erster Befehl - ADD #5 3 - besagt, daß zum Inhalt der dritten Speicherstelle die Zahl 5 addiert werden soll. Das ’#’ Zeichen bedeutet, daß die 5 keine Adresse bezeichnet, sondern diesmal unmittelbar als Zahl gemeint ist; man nennt dies daher auch „unmittelbare Adressierung“.
Nach Ausführung dieses Befehles steht in der Zeile DAT -4 nunmehr statt -4 der Wert 1 (-4 + 5=1).
In dem zweiten Befehl - MOV #0 @2 - lernen wir eine weitere Adressierungsart kennen: die indirekte Adressierung. Der Befehl bedeutet: Schreibe die Zahl 0 (unmittelbar!) an DIE ADRESSE, DIE IN DER, DURCH DIE INDIREKTE ADRESSE 2 BEZEICHNTEN SPEICHERSTELLE steht. MARS schaut also zuerst nach, welche Speicherstelle mit @ 2 gemeint ist: Es ist wiederum unser DAT-Befehl zwei Zeilen tiefer. Welche Zahl steht nun dort? Es ist noch von vorhin -die 1. Da der DAT-Befehl selbst auf Speicherstelle 4 steht, ist durch MOV =#=0 '© 2 die Speicherstelle 4+1 = 5 gemeint, also direkt hinter dem DAT-Befehl. Der MOV-Befehl soll demnach eine „Bombe“ an die durch den DAT-Befehl bestimmte Speicherstelle legen.
Der dritte Befehl - JMP -2 - ist schnell erklärt: Er weist MARS an, zur Bearbeitung des nächsten Befehls zwei Schritte zurückzugehen, also wieder zum ADD-Befehl (JUMP: engl, „springe“).
Um es zusammenzufassen: Der GNOM besteht aus einer Endlosschleife, in der erst der Inhalt einer bestimmten Speicherstelle um 5 erhöht wird, um dann an den, durch diese Speicherstelle be-zeichneten Ort eine Bombe in Form eines ungültigen Befehles - der NULL - zu legen.
Wir haben nun alle drei Adressierungsarten, und zwar (s. Tabelle 3)
Das Argument gibt an, wieviele Speicherstellen ausgehend von der Position des gerade bearbeiteten Befehls -weiter gezählt werden muß, um die gewünschte Speicherstelle zu erhalten. DIREKTE Argumente haben kein Vorzeichen.
TABELLE 2: REDCODE komplett
Anweisung | Kürzel | Argumente | Erk1ärung |
---|---|---|---|
Übertrage | MOV | A B | Übertrage Inhalt von Adresse A auf Adresse B |
Addiere | ADD | A B | Addiere Inhalt von Adresse A zu Adresse B |
Subtrahiere | SUB | A B | Subtrahiere Inhalt von Adresse A von dem von Adresse B |
Springe | JMP | A | Übergib die Ausführung an Adresse A |
Springe, wenn null | JMZ | A B | Übergib die Ausführung an Adresse A, falls Inhalt von Adresse B null ist |
Springe, wenn größer | JMG | A B | Springe nach A, falls Inghalt von B größer als null ist. |
Vermindere; springe, wenn null | DJZ | A B | Ziehe vom Inhalt der Adresse B 1 ab; Springe nach A, wenn B dann null ist |
Vergleiche | CMF | A B | Vergleiche Inhalt der Adressen A und bei Ungleichheit überspringe nächste Anweisung |
Data-Anweisung | DAT | B | Nichtausführbare Anweisung B ist der Datenwert |
Tabelle 2: REDCODE komplett
Das Argument bezeichnet keine Speicherstelle, sondern einen Wert, der unmittelbar als Zahl zu benutzen ist.
UNMITTELBARE Argumente sind durch ein gekennzeichnet.
Das Argument verweist - nach Art der direkten Adressierung - auf eine andere Speicherstelle. Der Inhalt dieser Speicherstelle wiederum kann nun als direkte Adresse aufgefaßt werden, d. h. es wird um den Betrag der dort stehenden Zahl weiter gezählt, um die durch das Indirekt-Argument bestimmte Speicherstelle zu erhalten.
INDIREKTE Argumente sind durch ein gekennzeichnet.
Im übrigen gilt für alle Argumente, daß sie auch mit einem negativen Vorzeichen versehen werden können. Solche negativen Zahlen werden vom MARS sofort in ihr positives Komplement umgewandelt, denn in einem ringförmigen Speicher läuft die Subtraktion von z. B. 1 auf dasselbe hinaus wie die Addition von 8000-1, also 7999.
Noch ein Wort zum DAT-Befehl: Er hat eine ähnliche Funktion wie z. B. der DATA-Befehl in BASIC. Man kann mit ihm Daten oder Zahlen speichern. Man sollte sich jedoch merken, daß der DAT-Befehl keine ausführbare Anweisung darstellt: Falls MARS bei der Abarbeitung eines Programms auf einen solchen Befehl trifft, bedeutet dies für das betreffende Programm den Todesstoß.
Außerdem ist noch zu erwähnen, daß GNOMs „Bombardement“ ebenfalls den Gesetzen des zirkulären Speichers unterliegt. Wenn seine Bomben nämlich das obere Ende des Speichers erreicht haben, beginnen sie wieder im unteren Ende. Dies hat interessanterweise zur Folge, daß - wenn die Zahl der Speicherstellen der „Arena“ nicht durch 5 teilbar ist - der GNOM sich früher oder später „von vorn in den Rücken schießt“. Das muß ihm erst mal jemand nachmachen...
Ist die Länge des Speichers jedoch genau durch 5 teilbar, dann schießt er stets haargenau an sich selbst vorbei.
Wir sind nun schon mit einigen Befehlen von REDCODE vertraut. Den Rest finden wir in Tabelle 2. Es sind insgesamt zehn Befehle, und wenn man unsere bisherigen Erklärungen erst einmal verdaut hat, dürfte sich die Bedeutung der restlichen Befehle fast von selbst erklären.
KNIRPS und GNOM stehen für eine Klasse von Programmen, die zwar nicht so wahnsinnig intelligent sind, dafür jedoch ausgesprochen aggressiv (so etwas soll es ja geben). Die nächste Klasse von Programmen könnte vielleicht so aussehen, daß sie zwar nicht ganz so aggressiv wären, dafür jedoch schlau genug, um unseren kleinen Nervensägen, den KNIRPSEN und GNOMEN, auszuweichen, indem sie sich aus deren Reichweite herauskopieren.
Wie auch immer, alle Kampfprogramme unterliegen denselben Gesetzen: Sie bestehen aus einer Folge von REDCODE-Befehlen, die durch den MARS sequentiell abgearbeitet werden. Ein Befehl wiederum setzt sich aus einem Befehlskürzel (MOV, ADD etc.) sowie einem oder zwei Argumenten zusammen, denen ggf. ein Vorzeichen zur Bestimmung der Adressierungsart vorangeht. Dabei kann es sich um direkte, indirekte oder unmittelbare Adressierung handeln.
Da allgemein das Prinzip der relativen Adressierung Verwendung findet, hat kein Programm die Möglichkeit, seine Absolutposition in dem ringförmigen Speicher festzustellen. Es kann sozusagen niemals über den Rand seines eigenen Universums hinausblicken.
Dies soll als Einführung in den „Krieg der Kerne“ genügen. Als Ergänzung können die beiden bereits erwähnten Artikel im „Spektrum der Wissenschaft“ empfohlen werden.
Das von uns erstellte Programm übernimmt die Übersetzung der mit einem Editor geschriebenen Programme, läßt sie gegeneinander kämpfen und zeigt das Ergebnis an. Es handelt sich um ein GEM-Programm; seine Drop-Down-Menüs ermöglichen die Einstellung einiger Parameter und Optionen. Auf der Public-Domain-Diskette befindet sich der „Krieg der Kerne“ sowie die Bedienungsanleitung zum Programm.
Da wir zu zweit auf die Idee zum „Krieg der Kerne“ gestoßen sind, haben wir auch die Programmierung gemeinsam durchgeführt. Dies war eine gute Erfahrung, und wir können es jedem ans Eierz legen, einmal mit einem
Partner ein Programmierprojekt durchzuführen. Man wird dadurch gezwungen, seinem Programm ein deutliches Konzept zu geben. Es erfordert auch erhebliche Disziplin, sich mit dem Partner über modularen Aufbau, Schnittstellen zwischen einzelnen Programmteilen usw. zu einigen, und es kommt nach unserer Erfahrung auch dem Programmierstil zugute. Sogenannter „Spaghetti-Code“ rächt sich hier sehr schnell, so daß man besser von Anfang an übersichtlich programmiert.
Die relativ lange Programmierdauer von rund vier Monaten war nicht nur darin begründet, daß wir von Natur aus faul sind, sondern auch durch die Tatsache, daß die Programmierung von GEM-Programmen - trotz vieler Bücher und Kurse zu diesem Thema -für den gewöhnlichen Amateurprogrammierer noch immer ein ausgesprochenes Abenteuer darstellt. Will man neben den relativ einfach zu handhabenden VDI-Funktionen noch mehrere Windows mit ihren verschiedenen Möglichkeiten der Manipulation einsetzen, dann nimmt der erforderliche Mehraufwand in der Programmierphase — sowohl den Umfang als auch die Komplexität betreffend - schnell Formen an, die einen in einer schwachen Minute wehmutsvoll auf die guten alten BASIC-Zeiten zurückblicken lassen, als sich fast jeder Benutzerdialog durch die Befehle PRINT, GET und INPUT abwickeln ließ.
Trotzdem sollte niemand dieses Abenteuer scheuen. Mit etwas Mut und -wie gesagt - vielleicht mit einem Partner zusammen kann man es schon schaffen. Der Benutzer eines so erstellten Programms wird es später danken.
(Christian Hoofe / Ralf Flauke)