Der Nano-Kernkrieg

21

Dies ist eine Adaption von Core War , einem Programm von KOTH aus dem 20. Jahrhundert. Genauer gesagt wird ein unglaublich vereinfachter Befehlssatz verwendet, der hauptsächlich auf dem ursprünglichen Vorschlag basiert .

Hintergrund

In Core War kämpfen zwei Programme um die Kontrolle über den Computer. Das Ziel jedes Programms ist es, durch Auffinden und Beenden des gegnerischen Programms zu gewinnen.

Der Kampf findet im Hauptspeicher des Computers statt. Dieser Speicher wird als Core bezeichnet und enthält 8192 Adressen. Wenn der Kampf beginnt, wird der Code für jeden Konkurrenten (als Krieger bezeichnet) in einem zufälligen Speicherblock abgelegt. Die Programmausführung wechselt zwischen Kriegern und führt jeweils eine Anweisung aus. Jeder Befehl ist in der Lage, einen Teil des Kerns zu ändern, was zur Möglichkeit führt, Programme selbst zu ändern.

Ziel ist es, das gegnerische Programm zu beenden. Ein Programm wird beendet, wenn versucht wird, einen ungültigen Befehl auszuführen, bei dem es sich um einen beliebigen DATBefehl handelt.

Der Befehlssatz

Jedes Programm besteht aus einer Reihe von Anweisungen auf niedriger Ebene, die jeweils zwei Felder enthalten, die als A- und B-Felder bezeichnet werden.

Dieser Befehlssatz lehnt sich stark an die ursprüngliche Spezifikation an. Die wichtigsten Änderungen sind 1) Erläuterungen zum Hinzufügen / Entfernen von Befehlen und 2) eine Änderung des #Adressierungsmodus, damit er überall verwendet werden kann. Die meisten Vollversionen von Core Wars haben über 20 Opcodes, 8 Adressierungsmodi und eine Reihe von "Anweisungsmodifikatoren".

Opcodes

Jeder Befehl muss einen von sieben verschiedenen Operationscodes haben.

  • DAT A B- (Daten) - Hier stehen einfach die Zahlen Aund B. Wichtig ist, dass ein Prozess abstürzt, wenn er versucht, einen DAT-Befehl auszuführen.
  • MOV A B- (Verschieben) - Verschiebt den Inhalt des Speicherorts Azum Speicherort B. Hier ist eine Demonstration von Vorher und Nachher:

    MOV 2 1
    ADD @4 #5
    JMP #1 -1
    
    MOV 2 1
    JMP #1 -1
    JMP #1 -1
    
  • ADD A B- (Hinzufügen) - Fügt den Inhalt des Speicherorts Azum Speicherort hinzu B. Die beiden ersten Felder von beiden werden hinzugefügt, und die zweiten Felder werden hinzugefügt.

    ADD 2 1
    MOV @4 #5
    JMP #1 -1
    
    ADD 2 1
    MOV @5 #4
    JMP #1 -1
    
  • SUB A B- (subtrahieren) - Hiermit wird der Inhalt des Speicherorts vom Speicherort subtrahiert A(und das Ergebnis dort gespeichert) B.

    SUB 2 1
    MOV @4 #5
    JMP #1 -1
    
    SUB 2 1
    MOV @3 #6
    JMP #1 -1
    
  • JMP A B- (Sprung) - Sprung zur Position A, die im nächsten Zyklus ausgeführt wird. Bmuss eine Zahl sein, tut aber nichts (Sie können sie jedoch zum Speichern von Informationen verwenden).

    JMP 2 1337
    ADD 1 2
    ADD 2 3
    

    Der Sprung bedeutet, ADD 2 3dass der nächste Zyklus ausgeführt wird.

  • JMZ A B- (Sprung bei Null) - Wenn beide Zeilenfelder B0 sind, springt das Programm zur Position A.

    JMZ 2 1
    SUB 0 @0
    DAT 23 45
    

    Da die beiden Felder der Anweisung 1 0 sind, wird der DAT-Befehl in der nächsten Runde ausgeführt, was zum unmittelbar bevorstehenden Tod führt.

  • CMP A B- (vergleichen und überspringt , wenn nicht gleich) - Wenn die Felder in Anweisungen Aund Bnicht gleich sind, lassen Sie die nächste Anweisung.

    CMP #1 2
    ADD 2 #3
    SUB @2 3
    

    Da die beiden Felder von Befehl 1 und 2 den gleichen Wert haben, wird der Befehl ADD nicht übersprungen und in der nächsten Runde ausgeführt.

Wenn zwei Befehle addiert / subtrahiert werden, werden die beiden Felder (A und B) paarweise addiert / subtrahiert. Der Adressierungsmodus und der Opcode werden nicht geändert.

Adressierungsmodi

Es gibt drei Arten von Adressierungsmodi. Jedes der beiden Felder eines Befehls hat einen dieser drei Adressierungsmodi.

  • Sofort#X - Xist die Zeile, die direkt bei der Berechnung verwendet werden soll. Zum Beispiel #0ist die erste Zeile des Programms. Negative Zeilen beziehen sich auf Zeilen im Kern vor dem Start des Programms.

    ... //just a space-filler
    ...
    ADD #3 #4
    DAT 0 1
    DAT 2 4
    

    Dadurch wird die erste der beiden DAT-Zeilen zur zweiten hinzugefügt, da sich diese in den Zeilen 3 bzw. 4 befinden. Sie möchten diesen Code jedoch nicht verwenden, da der DAT Ihren Bot im nächsten Zyklus tötet.

  • RelativX - Die Zahl gibt Xdie Position einer Zielspeicheradresse relativ zur aktuellen Adresse an. Die Nummer an dieser Stelle wird für die Berechnung verwendet. Wenn line #35ausgeführt wird und enthält -5, wird line #30verwendet.

    ... //just a space-filler
    ...
    ADD 2 1
    DAT 0 1
    DAT 2 4
    

    Dadurch wird die zweite DAT-Zeile zur ersten hinzugefügt.

  • Indirekt@X - Die Nummer Xrepräsentiert eine relative Adresse. Der Inhalt an dieser Stelle wird vorübergehend zur Nummer X hinzugefügt, um eine neue relative Adresse zu bilden, von der die Nummer abgerufen wird. Wenn die Zeile #35ausgeführt wird @4und das zweite Feld #39die Nummer enthält -7, wird die Zeile #32verwendet.

    ... //just a space-filler
    ...
    ADD @1 @1
    DAT 0 1
    DAT 2 4
    

    Dadurch wird das erste DAT zum zweiten DAT hinzugefügt, jedoch auf eine komplexere Weise. Das erste Feld ist @ 1, das die Daten von dieser relativen Adresse abruft. Dies ist das erste Feld des ersten DAT, eine 0. Dies wird als zweite relative Adresse von dieser Position interpretiert, sodass 1 + 0 = 1 die Summe ergibt Versatz von der ursprünglichen Anweisung. Für das zweite Feld erhält @ 1 den Wert von dieser relativen Adresse (die 1 im zweiten Feld des ersten DAT) und fügt ihn auf die gleiche Weise zu sich selbst hinzu. Der Gesamtversatz beträgt dann 1 + 1 = 2. Diese Anweisung wird also ähnlich wie folgt ausgeführt ADD 1 2.

Jedes Programm kann bis zu 64 Anweisungen enthalten.

Wenn eine Runde beginnt, werden die beiden Programme zufällig in einer Speicherbank mit 8192 Speicherplätzen abgelegt. Der Befehlszeiger für jedes Programm beginnt am Anfang des Programms und wird nach jedem Ausführungszyklus inkrementiert. Das Programm stirbt, sobald der Befehlszeiger versucht, einen DATBefehl auszuführen .

Parameter des Kerns

Die Kerngröße beträgt 8192 mit einem Timeout von 8192 * 8 = 65536 Ticks. Der Kern ist zyklisch, sodass das Schreiben an Adresse 8195 dem Schreiben an Adresse 3 entspricht. Alle nicht verwendeten Adressen werden mit initialisiert DAT #0 #0.

Jeder Teilnehmer darf nicht länger als 64 Linien sein. Ganzzahlen werden als 32-Bit-Ganzzahlen mit Vorzeichen gespeichert.

Parsing

Um den Wettbewerbern das Programmieren zu erleichtern, werde ich dem Parser eine Zeilenbeschriftung hinzufügen. Alle Wörter, die in einer Zeile vor einem Opcode vorkommen, werden als Zeilenbezeichnungen interpretiert. Hat zum Beispiel tree mov 4 6die Zeilenbezeichnung tree. Wenn sich irgendwo im Programm ein Feld befindet, das tree #treeoder enthält @tree, wird eine Zahl ersetzt. Auch die Großschreibung wird ignoriert.

Hier ist ein Beispiel, wie Zeilenbeschriftungen ersetzt werden:

labelA add labelB @labelC
labelB add #labelC labelC
labelC sub labelA @labelB

Hier stehen die Bezeichnungen A, B und C in den Zeilen 0, 1 und 2. Die Instanzen von #labelwerden durch die Zeilennummer der Bezeichnung ersetzt. Instanzen von labeloder @labelwerden durch die relative Position des Etiketts ersetzt. Adressierungsarten bleiben erhalten.

ADD 1 @2
ADD #2 1
SUB -2 @-1

Wertung

Für jedes Teilnehmerpaar wird jede mögliche Schlacht durchgeführt. Da das Ergebnis eines Kampfes von den relativen Offsets der beiden Programme abhängt, wird jeder mögliche Offset (etwa 8000 davon) ausprobiert. Darüber hinaus hat jedes Programm die Möglichkeit, sich bei jedem Versatz zuerst zu bewegen. Das Programm, das die Mehrheit dieser Offsets gewinnt, ist der Gewinner des Paares.

Für jedes Paar, das ein Krieger gewinnt, erhält er 2 Punkte. Für jedes Unentschieden erhält ein Krieger 1 Punkt.

Du darfst mehr als einen Krieger einreichen. Es gelten die typischen Regeln für mehrere Einreichungen, wie kein Tag-Teaming, keine Zusammenarbeit, keine Königswerdung usw. In Core War gibt es dafür sowieso keinen Platz, daher sollte es keine große Sache sein.

Der Controller

Der Code für den Controller sowie zwei einfache Beispiel-Bots befinden sich hier . Da dieser Wettbewerb (bei Verwendung der offiziellen Einstellungen) vollständig deterministisch ist, entspricht die von Ihnen erstellte Rangliste genau der offiziellen Rangliste.

Beispiel Bot

Hier ist ein Beispiel-Bot, der einige Funktionen der Sprache demonstriert.

main mov bomb #-1
     add @main main
     jmp #main 0
bomb dat 0 -1

Dieser Bot löscht langsam den gesamten Speicher im Kern, indem er ihn durch eine "Bombe" ersetzt. Da die Bombe eine DATAnweisung ist, wird jedes Programm, das eine Bombe erreicht, zerstört.

Es gibt zwei Zeilenbezeichnungen, "main" und "bomb", die dazu dienen, Zahlen zu ersetzen. Nach der Vorverarbeitung sieht das Programm folgendermaßen aus:

MOV 3 #-1
ADD @-1 -1
JMP #0 0
DAT 0 -1

Die erste Zeile kopiert die Bombe in die Zeile unmittelbar über dem Programm. In der nächsten Zeile wird der Wert von bomb ( 0 -1) zum Befehl move hinzugefügt und die Verwendung des @Adressierungsmodus demonstriert . Dieser Zusatz bewirkt, dass der Befehl move auf ein neues Ziel zeigt. Der nächste Befehl springt bedingungslos zum Programmstart zurück.


Aktuelle Rangliste

24 - Turbo
22 - DwarvenEngineer
20 - HanShotFirst
18 - Dwarf
14 - ScanBomber
10 - Paranoid
10 - FirstTimer
10 - Janitor
10 - Evolved
6 - EasterBunny
6 - CopyPasta
4 - Imp
2 - Slug

Paarweise Ergebnisse:

Dwarf > Imp
CopyPasta > Imp
Evolved > Imp
FirstTimer > Imp
Imp > Janitor
Imp > ScanBomber
Slug > Imp
DwarvenEngineer > Imp
HanShotFirst > Imp
Turbo > Imp
EasterBunny > Imp
Paranoid > Imp
Dwarf > CopyPasta
Dwarf > Evolved
Dwarf > FirstTimer
Dwarf > Janitor
Dwarf > ScanBomber
Dwarf > Slug
DwarvenEngineer > Dwarf
HanShotFirst > Dwarf
Turbo > Dwarf
Dwarf > EasterBunny
Dwarf > Paranoid
Evolved > CopyPasta
FirstTimer > CopyPasta
Janitor > CopyPasta
ScanBomber > CopyPasta
CopyPasta > Slug
DwarvenEngineer > CopyPasta
HanShotFirst > CopyPasta
Turbo > CopyPasta
CopyPasta > EasterBunny
Paranoid > CopyPasta
Evolved > FirstTimer
Evolved > Janitor
ScanBomber > Evolved
Evolved > Slug
DwarvenEngineer > Evolved
HanShotFirst > Evolved
Turbo > Evolved
EasterBunny > Evolved
Paranoid > Evolved
Janitor > FirstTimer
ScanBomber > FirstTimer
FirstTimer > Slug
DwarvenEngineer > FirstTimer
HanShotFirst > FirstTimer
Turbo > FirstTimer
FirstTimer > EasterBunny
FirstTimer > Paranoid
ScanBomber > Janitor
Janitor > Slug
DwarvenEngineer > Janitor
HanShotFirst > Janitor
Turbo > Janitor
Janitor > EasterBunny
Janitor > Paranoid
ScanBomber > Slug
DwarvenEngineer > ScanBomber
HanShotFirst > ScanBomber
Turbo > ScanBomber
ScanBomber > EasterBunny
ScanBomber > Paranoid
DwarvenEngineer > Slug
HanShotFirst > Slug
Turbo > Slug
EasterBunny > Slug
Paranoid > Slug
DwarvenEngineer > HanShotFirst
Turbo > DwarvenEngineer
DwarvenEngineer > EasterBunny
DwarvenEngineer > Paranoid
Turbo > HanShotFirst
HanShotFirst > EasterBunny
HanShotFirst > Paranoid
Turbo > EasterBunny
Turbo > Paranoid
Paranoid > EasterBunny

Das neueste Update (neue Versionen von Turbo und Paranoid) benötigte ungefähr 5 Minuten, um auf einem alten Laptop ausgeführt zu werden. Ich möchte Ilmari Karonen für seine Verbesserungen am Controller danken . Wenn Sie eine lokale Kopie des Controllers haben, sollten Sie Ihre Dateien aktualisieren.

PhiNotPi
quelle
Was passiert, wenn zwei konkurrierende Bots versuchen, dasselbe Label zu verwenden?
mbomb007
1
@ mbomb007 Labels sind eine Vorverarbeitungssache und werden berechnet, während die Quelldatei des Bots analysiert wird. Ihre Labels interagieren nicht mit Konkurrenz-Labels.
PhiNotPi
1
@ mbomb007 Damit sich die Programme nicht überschneiden. Außerdem habe ich nicht vor, dieser Version weitere Funktionen hinzuzufügen, außer denen für Micro Core War.
PhiNotPi
1
@ mbomb007 Indirekte Adressierung verweist auf dasselbe Feld, das die Referenz erstellt (1. oder 2.). Es gibt keine Anweisungsmodifikatoren. Ich stütze diese Herausforderung nicht auf den 94er Standard.
PhiNotPi
2
@Thrax Ich werde nein sagen, dass Sie nicht auf einen Beitrag beschränkt sind. Es gelten die typischen Regeln für Mehrfacheinreichungen (kein Tag-Teaming usw.), obwohl in Kernkriegen sowieso nicht viel Raum für eine Zusammenarbeit besteht.
PhiNotPi

Antworten:

9

Zwergeningenieur

Ein neuer und verbesserter Zwerg. Gewinne gegen alles andere, was bisher eingereicht wurde. Die ausgefallene Corestep- optimierte Schrittweite ist hier wohl übertrieben.

        MOV bomb    @aim
aim     MOV bomb    @-6326
        SUB step    aim
step    JMZ #0      6328
        MOV 0       1
bomb    DAT 0       3164

Bemerkenswerte Features sind die schnelle Bombardierung Schleife , die zwei Bomben in vier Zyklen, für eine durchschnittliche Bombardierung Geschwindigkeit von 0.5c in alten Core Sind Jargon wirft, und die Verwendung JMZzu erkennen , wenn die Bombardierung abgeschlossen ist und es Zeit zum Schalter auf Plan B ( hier ein Kobold).


Ich habe Core War in den 90er Jahren gespielt (einige von Ihnen haben vielleicht den grundlegenden Leitfaden gesehen, den ich 1997 geschrieben habe), und ich dachte, es wäre interessant zu sehen, welche alten Strategien aus der RedCode '88 / '94-Welt das könnten in dieser Variante nützlich sein.

Meine ersten Gedanken waren:

  • Es gibt keine SPL, also keine Replikatoren (und keine Koboldringe / Spiralen). Dies sollte Bomber stark machen. (Auch all diese ausgefallenen Bombenstrategien, die darauf ausgelegt sind, mit Replikatoren und Koboldspiralen umzugehen? Völlig unnötig und nutzlos hier. Einfach mit irgendwelchen Bomben bombardieren DAT.)

  • Dann wieder, CMPScannen ist immer noch potenziell schneller als Bombardierung, so dass ein schneller Scanner könnte eine Chance haben.

  • Das Fehlen von In / Dekrementen macht das Löschen des Kerns sehr langsam. Tatsächlich ist ein Core Clear in dieser Variante so ziemlich nur ein Bomber mit einer (suboptimalen) Schrittweite von ± 1. Auch dies schadet den Scannern. Eine One-Shot-Scanner-Bomber-Strategie könnte jedoch funktionieren.

  • Schnellscanner / Schnellbomber (eine Strategie für das frühe Spiel, bei der eine ungerollte Scan- / Bomben-Schleife verwendet wird, für diejenigen, die nicht mit Core War-Jargon vertraut sind) sind immer noch potenziell nützlich, aber nur gegen lange Programme (die sie selbst sind), also gibt es eine Art Feedback hier bewirken). Schwer zu sagen, ob es sich wirklich lohnt.

  • Das Punktesystem ist interessant. Krawatten erzielen halb so viele Punkte wie ein Sieg (statt 1/3 wie im traditionellen Kernkrieg), wodurch sie attraktiver werden. Andererseits ist das einzige Programm, das nach diesen Regeln wahrscheinlich viele Gleichstände erzielt, ein Kobold. (Auch das Fehlen von De- / Inkrementen erschwert Imp-Gates, so dass selbst einfache Imps tatsächlich die Chance haben, ein Unentschieden zu erzielen, wenn sie ihren Gegner lebend erreichen.)

  • Da die endgültigen Platzierungen nur davon abhängen, welche Programme Sie schlagen, und nicht davon, um wie viel Sie sie schlagen, werden Einträge von Generalisten bevorzugt. Es ist besser, nur alle Gegner zu besiegen, als die Hälfte zu vernichten und nur knapp gegen die anderen zu verlieren.

  • Da der Code öffentlich ist, ist es immer möglich, ein Programm zu finden, das eine bestimmte frühere Einreichung - möglicherweise sogar mehrere - übertreffen kann, egal wie gut sie im Allgemeinen sind. Solche Tricks (wie das Abstimmen der Schrittgröße, um den Gegner kurz vor dem Treffer zu treffen) können jedoch leicht billig erscheinen. Und natürlich könnte der Zielspieler immer nur eine neue Version mit anderen Konstanten einreichen.

Das Ergebnis ist jedenfalls, dass ich beschlossen habe, entweder einen schnellen Bomber oder einen sehr schnellen Scanner zu schreiben und vielleicht einen Quickscanner / Bomber daran anzuheften. Von diesen Optionen schien ein schneller Bomber am einfachsten und am wahrscheinlichsten zu funktionieren.

Zu diesem Zeitpunkt habe ich viel zu viel Zeit damit verbracht, den Interpreter-Code von PhiNotPi zu optimieren, weil ich dachte, ich würde wahrscheinlich viele Brute-Force-Tests durchführen, um die Konstanten zu optimieren. Zufälligerweise musste ich das nie tun - der obige Code ist so ziemlich die erste Version, die tatsächlich funktioniert hat (nach ein paar fehlgeschlagenen Versuchen, die aufgrund alberner Fehler Selbstmord begangen haben).


Der Trick, der meinen Bomber schnell macht, ist die indirekte Adressierung, um zwei Bomben für jede zu werfen ADD. So funktioniert es:

  1. Im ersten Zyklus führen wir aus MOV bomb @aim. Dadurch wird die bombAnweisung an die Stelle im Kern kopiert, an der sich das B-Feld mit den aimPunkten befindet (anfangs genau 6326 Anweisungen zuvor aimoder 6328 Anweisungen zuvor step; Sie werden später sehen, warum diese Zahlen von Bedeutung sind).

  2. Im nächsten Schritt führen wir die aimAnweisung selbst aus! Beim ersten Durchgang, sieht es wie folgt aus : MOV bomb @-6326. So kopiert esbomb an die Stelle auf die das B-Feld des Befehls bei 6326 Zeilen vor sich selbst zeigt.

    Also, was gibt es bei 6326 Zeilen vor aim? Es ist die Kopie, die bombwir gerade einen Zyklus früher dort abgelegt haben! Und wir haben die Dinge einfach so angeordnet, dass das B-Feld von bombeinen Wert ungleich Null hat, sodass die neue Bombe nicht über die alte kopiert wird, sondern in einiger Entfernung (in der Tat beträgt die Entfernung 3164, das ist die Hälfte unserer nominellen Schrittgröße 6328, aber andere Offsets könnten funktionieren, vielleicht sogar besser).

  3. Im nächsten Zyklus passen wir unser Ziel mit SUB step aim, die die Werte der subtrahiert stepAnweisung (was auch der Sprung wir als nächstes ausführen werden sein geschieht, obwohl es haben könnte nur ein einfacher gewesen DATirgendwo) aus aim.

    (Ein Detail hier beachten ist , dass wir Art von dem A-Wert sollen von stepNull sein, so dass wir immer noch die gleichen Bomben auf der nächsten Iteration werfen würden sogar , dass nicht unbedingt erforderlich ist, obwohl,. Nur die Bomben geworfen Nach dem ersten Befehl muss das B-Feld 3164 sein, der Rest kann alles sein.)

  4. Als nächstes wird JMZüberprüft, ob der Befehl 6328 immer noch null ist, und in diesem Fall wird zum Anfang des Codes zurückgesprungen. 6328 ist die Schrittgröße unseres Bombers und durch 8 teilbar (aber nicht durch 16). Wenn wir also alle 6328 Schritte Bomben werfen würden, würden wir irgendwann dahin zurückkehren, wo wir angefangen haben, nachdem wir jede achte Anweisung im Kern bombardiert haben (und mit den zusätzlichen Bomben, die um 3163 = 6328/2 mod 4 versetzt sind (Mod 8) , wir hätten jede vierte Anweisung getroffen).

    Aber wir haben unseren Bombardierungslauf mit 6328 Anweisungen vor dem begonnen JMZund sind bei jeder Iteration um -6328 zurückgegangen, also werden wir die Position 6328 Schritte nach der JMZeinzigen Iteration bombardieren, bevor wir die JMZselbst treffen würden . Wenn die JMZBombe 6328 Anweisungen später entdeckt, ist dies ein Zeichen dafür, dass wir so viel wie möglich vom Kern abgedeckt haben, ohne uns selbst zu treffen, und dass wir zu einer Sicherungsstrategie wechseln sollten, bevor wir uns selbst töten.

  5. Was die Backup-Strategie angeht, ist es nur ein alter MOV 0 1Kobold, da mir momentan nichts Besseres einfällt. So wie ich es sehe, wenn wir jeden vierten Ort des Kerns bombardiert haben und immer noch nicht gewonnen haben, kämpfen wir wahrscheinlich gegen etwas sehr Kleines oder sehr Defensives und könnten genauso gut versuchen zu überleben und uns mit einem Unentschieden zufrieden zu geben. Es ist in Ordnung, weil solche kleinen oder defensiven Programme im Allgemeinen nicht sehr gut darin sind, irgendetwas anderes zu töten. Selbst wenn wir also nur ein paar Kämpfe zufällig gewinnen, werden wir wahrscheinlich immer noch die Nase vorn haben.


Ps. Für den Fall, dass es jemand anderes möchte, hier ist meine leicht verbesserte Version des PhiNotPi-Turniercodes . Es ist ungefähr doppelt so schnell, speichert alte Kampfergebnisse, sodass Sie sie nicht erneut ausführen müssen, und behebt einen meiner Meinung nach geringfügigen Fehler bei der Berechnung der Kampfergebnisse. Die Änderungen wurden von PhiNotPi in die Hauptversion übernommen. Vielen Dank!

Ilmari Karonen
quelle
1
Nur damit Sie wissen, testet die Wertung JEDE mögliche Kombination von Programmstartpositionen, und das Programm, das die meisten Punkte erzielt, gewinnt Punkte. Dies macht Unentschieden unmöglich oder völlig ungünstig, da ein Programm, solange es sich nicht selbst umbringt und mindestens eine Adresse einmal bombardiert, einen Kobold besiegt, einen Sieg erzielt und die restlichen Unentschieden besiegt.
mbomb007
9

Diagrammansicht

Dies kann als Debugging-Tool verwendet werden. Es zeigt den Kern und die Position des Players an. Um es zu benutzen, müssen Sie es aus dem Code aufrufen. Ich habe auch ein modifiziertes bereitgestellt, das das GraphView Game.javaautomatisch anzeigt.

PhiNotPi und Ilmari Karonen haben kürzlich den Controller gewechselt. Ilmari Karonen hat freundlicherweise ein aktualisiertes GameView an dieser Stelle zur Verfügung gestellt .

import javax.swing.*;
import java.awt.*;

public class GameView extends JComponent{

    final static Color[] commandColors = new Color[]{
            Color.black, //DAT
            Color.blue,  //MOV
            Color.blue,  //ADD
            Color.blue,  //SUB
            Color.blue,  //JMP
            Color.blue,  //JMZ
            Color.blue,  //CMP
    };

    final static Color[] specialColors = new Color[]{
            new Color(0,0,0),
            new Color(190, 255, 152),
            Color.yellow,
            new Color(0, 93, 14),
            new Color(96, 92, 4),
            new Color(0, 93, 14),
            new Color(96, 92, 4),
            new Color(0, 93, 14),
            new Color(96, 92, 4)
    };

    final static Color playerOneColor = Color.green;
    final static Color playerTwoColor = Color.white;

    final Game game;

    int playerOneLocation;
    int playerTwoLocation;

    final static int width = 128;
    final static int height = 64;

    public GameView(Game game) {
        this.game = game;
    }

    @Override
    public void paint(Graphics g) {
        int pixelWidth = getSize().width;
        int pixelHeight = getSize().height;
        if (width > pixelWidth){
            pixelWidth = width;
            setSize(width, pixelHeight);
        }
        if (height > pixelHeight){
            pixelHeight = height;
            setSize(pixelWidth, height);
        }
        int squareWidth = Math.min(pixelWidth / width, pixelHeight / height);
        for (int x = 0; x < squareWidth * width; x += squareWidth){
            for (int y = 0; y < squareWidth * height; y += squareWidth){
                int index = (y / squareWidth) * width + (x / squareWidth);
                Color color = commandColors[game.core[index][0]];
                if (game.coreData[index] != 0){
                    color = specialColors[game.coreData[index]];
                }
                if (index == playerOneLocation){
                    color = playerOneColor;
                }
                if (index == playerTwoLocation){
                    color = playerTwoColor;
                }
                g.setColor(color);
                g.fillRect(x, y, squareWidth, squareWidth);
            }
        }
    }

    public void setLocations(int p1loc, int p2loc){
        this.playerOneLocation = p1loc;
        this.playerTwoLocation = p2loc;
    }
}

Geändertes Game.java:

import javax.swing.*;
import java.util.Random;
import java.util.ArrayList;
import java.util.Arrays;
/**
 * This runs a game of Core Wars between two players.  It can be called mutiple times.
 * 
 * @author PhiNotPi 
 * @version 3/10/15
 */
public class Game
{
    final Player p1;
    final Player p2;
    final int coreSize;
    final int coreSizeM1;
    final int maxTime;
    final int debug;
    public int[][] core;
    public int[] coreData; //Used in debugging.
    int offset1;
    int offset2;
    Random rand;
    ArrayList<int[]> p1code;
    ArrayList<int[]> p2code;
    int p1size;
    int p2size;
    GameView gameView;
    int time = 1000000; //Time in nanoseconds between frames
    public Game(Player A, Player B, int coreSize, int maxTime, int debug)
    {
        p1 = A;
        p2 = B;

        coreSize--;
        coreSize |= coreSize >> 1;
        coreSize |= coreSize >> 2;
        coreSize |= coreSize >> 4;
        coreSize |= coreSize >> 8;
        coreSize |= coreSize >> 16;
        coreSize++;

        this.coreSize = coreSize;
        this.coreSizeM1 = coreSize - 1;
        this.maxTime = maxTime / 2;
        this.debug = debug;
        core = new int[coreSize][5];
        rand = new Random();
        p1code =  p1.getCode();
        p1size = p1code.size();
        p2code =  p2.getCode();
        p2size = p2code.size();
        if (debug == 1){
            gameView = new GameView(this);
            JFrame frame = new JFrame("Game");
            frame.add(gameView);
            frame.setVisible(true);
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            frame.setSize(128, 64);
            coreData = new int[coreSize];
        }
    }

    public int runAll()
    {
        int sum = 0;
        for(int i = 0; i < coreSize - p1size - p2size; i++)
        {
            sum += run(i) - 1;
        }
        if(sum > 0)
        {
            return 1;
        }
        if(sum < 0)
        {
            return -1;
        }
        return 0;
    }

    public int run()
    {
        return run(rand.nextInt(coreSize - p1size - p2size + 1));
    }

    public int run(int deltaOffset)
    {
        core = new int[coreSize][5];
        //offset1 = rand.nextInt(coreSize);
        offset1 = 0;
        for(int i = 0; i != p1size; i++)
        {
            //System.arraycopy(p1.getCode().get(i), 0, core[(offset1 + i) % coreSize], 0, 5 );
            int[] line = p1code.get(i);
            int loc = (offset1 + i) & coreSizeM1;
            core[loc][0] = line[0];
            core[loc][1] = line[1];
            core[loc][2] = line[2];
            core[loc][3] = line[3];
            core[loc][4] = line[4];
            if (debug != 0){
                coreData[loc] = 1;
            }
        }
        offset2 = offset1 + p1size + deltaOffset;
        for(int i = 0; i != p2size; i++)
        {
            //System.arraycopy(p2.getCode().get(i), 0, core[(offset2 + i) % coreSize], 0, 5 );
            int[] line = p2code.get(i);
            int loc = (offset2 + i) & coreSizeM1;
            core[loc][0] = line[0];
            core[loc][1] = line[1];
            core[loc][2] = line[2];
            core[loc][3] = line[3];
            core[loc][4] = line[4];
            if (debug != 0){
                coreData[loc] = 2;
            }
        }

        int p1loc = offset1 & coreSizeM1;
        int p2loc = offset2 & coreSizeM1;
        for(int time = 0; time != maxTime; time++)
        {
            if(debug != 0)
            {
                //printCore(p1loc,p2loc);
                //System.out.println("p1loc " + p1loc);
                //System.out.println("offset " + offset1);
                gameView.setLocations(p1loc, p2loc);
                gameView.repaint();
                try {
                    Thread.sleep(time / 1000000, time % 1000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            if(core[p1loc][0] == 0)
            {
                return 0;
            }
            p1loc = execute(p1loc, offset1, 1);

            if(debug != 0)
            {
                //printCore(p1loc,p2loc);
                //System.out.println("p2loc " + p2loc);
                //System.out.println("offset " + offset2);
                gameView.setLocations(p1loc, p2loc);
                gameView.repaint();
                /*try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
            }
            if(core[p2loc][0] == 0)
            {
                return 2;
            }
            p2loc = execute(p2loc, offset2, 2);

        }
        return 1;
    }
    public int execute(int ploc, int offset, int player)
    {
        int line1 = offset + core[ploc][3];
        if(core[ploc][1] != 0)
        {
            line1 += ploc - offset;
        }
        if(core[ploc][1] == 2)
        {
            line1 += core[line1 & coreSizeM1][3];
        }
        int line2 = offset + core[ploc][4];
        if(core[ploc][2] != 0)
        {
            line2 += ploc - offset;
        }
        if(core[ploc][2] == 2)
        {
            line2 += core[line2 & coreSizeM1][4];
        }
        line1 = line1 & coreSizeM1;
        line2 = line2 & coreSizeM1;
        int opcode = core[ploc][0];
        ploc = (ploc + 1) & coreSizeM1;
        //String opDescription = "";
        if(opcode == 1)
        {
            core[line2][0] = core[line1][0];
            core[line2][1] = core[line1][1];
            core[line2][2] = core[line1][2];
            core[line2][3] = core[line1][3];
            core[line2][4] = core[line1][4];
            if (debug != 0) {
                coreData[line2] = player + 2;
            }
            return ploc;
            //opDescription = "Moved from " + line1 + " to " + line2;
        }
        if(opcode == 2)
        {
            core[line2][3] += core[line1][3];
            core[line2][4] += core[line1][4];
            if (debug != 0) {
                coreData[line2] = player + 4;
            }
            return ploc;
            //opDescription = "Added " + line1 + " to " + line2;
        }
        if(opcode == 3)
        {
            core[line2][3] -= core[line1][3];
            core[line2][4] -= core[line1][4];
            if (debug != 0) {
                coreData[line2] = player + 6;
            }
            return ploc;
                //opDescription = "Subtracted " + line1 + " to " + line2;
        }
        if(opcode == 4)
        {
            ploc = line1;
            return ploc;
                //opDescription = "Jumped to " + line1;
        }
        if(opcode == 5)
        {
                if(core[line2][3] == 0 && core[line2][4] == 0)
                {
                    ploc = line1;
                    //opDescription = "Jumped to " + line1;
                }
                else
                {
                    //opDescription = "Did not jump to " + line1;
                }
                return ploc;
        }
        if(opcode == 6)
        {
            if(core[line1][3] == core[line2][3] && core[line1][4] == core[line2][4])
            {
                //opDescription = "Did not skip because " + line1 + " and " + line2 + " were equal.";
            }
            else
            {
                ploc = (ploc + 1) & coreSizeM1;
                //opDescription = "Skipped because " + line1 + " and " + line2 + " were not equal.";
            }
            return ploc;
        }
        if(debug != 0)
        {
            //System.out.println(opDescription);
        }
        return ploc;
    }
    /*public void printCore(int p1loc, int p2loc)
    {
        int dupCount = 0;
        int[] dupLine = new int[]{0,0,0,0,0};
        for(int i = 0; i < core.length; i++)
        {
            int[] line = core[i];
            if(Arrays.equals(line, dupLine) && i != p1loc && i != p2loc)
            {
                if(dupCount == 0)
                {
                    System.out.println(Player.toString(line));
                }
                dupCount++;
            }
            else
            {
                if(dupCount == 2)
                {
                    System.out.println(Player.toString(dupLine));
                }
                else if(dupCount > 2)
                {
                    System.out.println("    " + (dupCount - 1) + " lines skipped.");
                }
                System.out.println(Player.toString(line));
                if(i == p1loc)
                {
                    System.out.print(" <- 1");
                }
                if(i == p2loc)
                {
                    System.out.print(" <- 2");
                }
                dupLine = line;
                dupCount = 1;
            }
        }
        if(dupCount == 2)
        {
            System.out.println(Player.toString(dupLine));
        }
        else if(dupCount > 2)
        {
            System.out.println("    " + (dupCount - 1) + " lines skipped.");
        }
    }*/
}
Die Nummer eins
quelle
Sie haben anscheinend auch eine Änderung an Player vorgenommen. Ich bekomme./Game.java:275: error: method toString in class Object cannot be applied to given types; System.out.println(Player.toString(line)); ^ required: no arguments found: int[]
AShelly
@AShelly Entschuldigung. Ich hätte die printCore()Methode auskommentieren sollen.
TheNumberOne
9

Turbo

main   add three target
test   jmz -1 @target
bomb   mov three @target
       sub j1 target 
       mov jump @target
       sub j1 target 
       mov copy @target
       sub j1 target
two    mov decr @target
j1     jmp @target 1
target dat -8 -8   
decr   sub #two 3
copy   mov 2 @2
jump   jmp -2 0
three dat -9 -9

Mein zweiter CoreWar-Versuch. Entwarf, Zwerg zu schlagen. Scannt alle 2 Sekunden um 3 Sekunden nach Daten und legt dann eine Bombe ab. Jede Stufe besteht aus nur 3 Anweisungen, in der Hoffnung, dass die Bomben der Zwerge diese verfehlen.

NEUER Turbo ++ : Jetzt erweitert. Es scannt rückwärts, bis es Daten findet, bewegt sich dann dorthin und bombardiert dann rückwärts. Die Hoffnung ist, dass der Zug entweder den Gegner überfordert oder an einen bereits bombardierten und damit sicheren Ort geht.

... und eine Bearbeitung, die das Scannen sparsamer macht, lässt es alle schlagen!

Ahelly
quelle
Scheint viel mehr als nur einen Zwerg zu schlagen. Herzliche Glückwünsche! Ich denke, Sie könnten den dritten Platz erreichen, wenn Sie nur Imp schlagen könnten.
Ilmari Karonen
Ich habe dieses Update aktualisiert, aber es ist tatsächlich eine ziemlich große Entwicklung gegenüber dem vorherigen. Sollte ich stattdessen einen neuen Eintrag machen?
AShelly
Ich nehme nicht an, für PhiNotPi zu sprechen, aber ich denke, es liegt an Ihnen. Wenn Sie ein In-Place-Update durchführen, bedeutet dies im Grunde, dass Sie Ihren alten Eintrag zurückziehen. Wie auch immer, noch mehr Glückwünsche für die erfolgreiche Flucht vor dem dritten Platz! Ich denke, du bist der einzige Spieler, der DwarvenEngineer bisher paarweise besiegt hat.
Ilmari Karonen
Gut gemacht ;). Du bist derjenige, den es jetzt zu schlagen gilt!
Hit
8

Zwerg

Ein allgemeines und einfaches Programm, das einen Zwerg darstellt, der Steine ​​wirft. Es gibt DATalle vier Adressen eine Anweisung aus.

add 2 3
mov 2 @2
jmp -2 #4
dat #0 #4

EDIT: Korrigiert die Adressierung. Anscheinend unterscheiden sich die Adressierungsmodi von der Spezifikation, mit der das OP verknüpft ist.

mbomb007
quelle
Ich denke, es ist "add # 3 3" für die erste Zeile, nicht wahr?
Hit
@Hit Nope. Ich möchte jede 4. Adresse treffen. Ich könnte es verwenden add 3 3, aber dann würde es jede Schleife verdoppeln, anstatt sie hinzuzufügen, und das wäre nicht nützlich. #4Ist ein sofortiger 4Wert, wird die Nummer zum zweiten Wert in der Adresse hinzugefügt, die 3nach der aktuellen Adresse liegt.
mbomb007
Ich denke, dass Sie den #Adressierungsmodus in der Herausforderung falsch interpretieren . Wie in der Spezifikation angegeben, habe ich den #Adressierungsmodus geändert .
PhiNotPi
Sie sollten wie folgt vorgehen: "addiere 2 3 mov 2 @ 2 jmp -2 4 dat 0 4"
Hit
Bei richtigem Verhalten entwickelten sich sogar Niederlagen
Hit
7

Entwickelt

Ich verstehe ehrlich gesagt nicht, wie es funktioniert. Es scheint seinen Quellcode zu konstruieren, bevor etwas unternommen wird. Ich würde es lieben, wenn mir jemand erklären würde, wie es funktioniert.

Nachdem ich es studiert hatte, stellte ich fest, dass es einfach ein modifizierter Zwerg mit einem Koboldschutz ist. Anstatt die Feinde mit DATAnweisungen zu bombardieren , wird der Code der Feinde gemischt. Es bombardiert auch alle zwei Register anstatt alle vier Register. Bei genügend Zeit würde es sich zweifellos selbst zerstören.

MOV -2 #-1
MOV #4 -9
SUB -5 #6
MOV #1 1
MOV #-6 #4
SUB @8 @7
JMP -3 @4
DAT #-4 8
JMP -1 9
JMP 5 #-10
CMP @-1 #0
SUB 3 #-10
JMP @10 #-9
JMZ #1 10
MOV #3 2
ADD @9 @-3
CMP #-3 @7
DAT @0 @-2
JMP @-7 #6
DAT @-8 -6
MOV @0 #9
MOV #2 1
DAT @6882 #-10
JMP @3 4
CMP @8 2
ADD -7 @11
ADD @1 #-9
JMZ @-5 7
CMP 11 5526
MOV @8 6
SUB -6 @0
JMP 1 11
ADD @-3 #-8
JMZ @-14 @-5
ADD 0 @-8
SUB #3 @9
JMP #-1 5
JMP #9 @1
CMP -9 @0
SUB #4 #-2
JMP #-8 5
DAT -1 @-10
MOV 6 #2
CMP @-11 #-14
ADD @4 @-3
MOV @5 #-6
SUB -3 -2
DAT @-10 #-1
MOV #-13 #-6
MOV #1 5
ADD 5 #-5
MOV -8 @-1
DAT 0 10
DAT #5 #7
JMZ 6 -5
JMZ -12 -11
JMP 5 @-7
MOV #7 -3
SUB #-7 @-3
JMP -4 @-11
CMP @-5 #-2
JMZ @-1 #0
ADD #3 #2
MOV #5 @-6
Die Nummer eins
quelle
1
Wo hast du es dann bekommen?
PyRulez
4
@ PyRulez Es ist computergeneriert über genetischen Algorithmus.
TheNumberOne
1
Es sieht so aus, als ob die Ausführung nicht weiter fortschreitet als Zeile 6, da sie dort im Programm zurückspringt. Ich glaube, der Grund für den Erfolg ist, dass es mehr Moves / Loops gibt als die Konkurrenz.
PhiNotPi
6

FirstTimer

Wenn es funktioniert, sollte es versuchen, am Anfang des Kerns eine Position einzunehmen und eine Abwehr zu schaffen

main MOV 5 #0
     ADD #data #main
     CMP #main #max
     JMP #0 0
     JMP #main 0
     MOV #data #100
     ADD #data -1
     JMP -2 0
data DAT 1 1
max  DAT 8 3
Thrax
quelle
Es funktioniert nicht ganz so, wie Sie es angenommen haben: #0Bezieht sich auf den Start Ihres Programms (dh auf das Gleiche wie #main), nicht auf den Start des Kerns (was ohnehin kein wirklich aussagekräftiges Konzept ist - der Kern ist es) Rundschreiben, Ihr Code kann nicht sagen, wo es beginnt oder endet). Was passiert ist, dass Ihr erster Befehl ( main) sich mit dem überschreibt MOV #data #100, wonach Ihr Code effektiv in einen 0.25c (= ein Befehl pro vier Zyklen) Forward Core Clear verwandelt.
Ilmari Karonen
@IlmariKaronen Oh, danke für die Erklärung. Ich habe mich #0für den Anfang des Kerns gehalten. Die 5 ersten Anweisungen sind dann völlig unbrauchbar.
Thrax
6

CopyPasta

Nie an einem CoreWar teilgenommen, versucht dieses einfache Programm nur, sich selbst einzufügen und die Kopie dann auszuführen. Möglicherweise hat es nicht das richtige Verhalten. Sagen Sie mir bitte, ob dies der Fall ist.

Es ist zu pazifistisch und kann in der Tat nicht gewinnen.

MOV 6 0
MOV @-1 @-1
CMP @-2 3
JMP 4242 0
SUB -3 -4
JMP -4 0
DAT 0 4244
Schlagen
quelle
Diese aktuelle Änderung wird wahrscheinlich nicht im nächsten Leaderboard-Update enthalten sein (ich führe das Turnier gerade durch). Die alte Version gewann jedoch die vorläufigen Ergebnisse (kleine Kerngröße).
PhiNotPi
Okay :) Die ältere Version geht nicht aus der Schleife heraus1, es ist nicht wirklich das gewünschte Verhalten, ich versuche das zu korrigieren.
Hit
Die aktuelle Version scheint kaputt zu sein. Ich weiß noch nicht warum.
PhiNotPi
1
Ich habe die Debugging-Tools überarbeitet, damit ich das Problem jetzt diagnostizieren kann. Was passiert ist, dass das Programm nur die zweite Hälfte von sich selbst kopiert (beginnend mit JMP loop 0). Wenn es dann dorthin springt, wo der Anfang der Kopie sein soll, ist es nur ein leerer Raum und es verliert.
PhiNotPi
2
Bitte ignoriere meinen früheren (jetzt gelöschten) Kommentar; Ich hatte eine falsche Version Ihres Codes getestet (ironischerweise wegen eines Kopierfehlers), weshalb es für mich so schlecht funktionierte.
Ilmari Karonen
6

Hausmeister

Es sollte überprüfen, ob die folgenden Adressen leer sind und falls nicht, sie bereinigen (also hoffentlich den gegnerischen Bot löschen).

Bearbeiten: Diese neue Version sollte schneller sein (jetzt, da ich den JMZBefehl und die @Referenz richtig verstanden habe).

JMZ 2 6
MOV 4 @-1
ADD 2 -2
JMP -3 0
DAT 0 1
DAT 0 0
Plannapus
quelle
Begeht der Hausmeister mit der ersten JMZ nicht Selbstmord? Es sollte mindestens JMZ 2 8 sein. Übrigens könnten Sie mit @ die beiden add zu nur einem reduzieren. Etwas wie: "JMZ 2 @ 5 MOV 5 @ 4 ADD 2 3 JMP -3 0 DAT 0 1 DAT 0 2 DAT 0 0" (ungetestet)
Hit
@Hit Es springt nicht, weil die Adresse 2 von dort ist ADD 3 -2, aber du hast recht, dass er es ändern sollte, denke ich.
mbomb007
Ja, ich habe die Anweisung für falsch gelesen JMZund dachte, ich würde JMZ A Bprüfen Aund auf B0 springen, wenn es anscheinend das Gegenteil ist. Danke, dass
du es
5

ScanBomber

Entfernen Sie meine Kommentare vor dem Kompilieren. Sucht eine Weile und bombardiert dann, wenn ein Programm gefunden wird. Es wird aber wahrscheinlich immer noch gegen meinen Zwerg verlieren.

scan add #eight #range  ; scan
jmz #scan @range
sub #six #range
fire mov #zero @range   ; bombs away! (-6)
add #two #range
mov #zero @range
add #two #range
mov #zero @range
add #two #range
mov #zero @range        ; (+0)
add #two #range
mov #zero @range
add #two #range
mov #zero @range
add #two #range
mov #zero @range
add #two #range
mov #zero @range        ; (+8)
range jmp #scan 6
two dat 0 2
six dat 0 6
zero dat 0 0
eight dat 0 8
mbomb007
quelle
Das OP definiert sich #völlig anders als die Spezifikation (lies den Link, mit dem er verlinkt ist), ich muss dieses Programm noch dafür reparieren.
mbomb007
@TheBestOne Ich glaube, ich habe es behoben. Sieht es so aus, als ob es jetzt Sinn macht? Oder muss ich #vor jedem Verweis darauf setzenzero ? Ja, ich denke ich muss ...
mbomb007
Es funktioniert jetzt gut. Es schlägt jeden Bot außer Dwarf und Imp.
TheNumberOne
@TheBestOne Dwarf ist zu klein und wird nur in 50% der möglichen Programmplatzierung erkannt. Es verliert wahrscheinlich nur gegen Imp, weil es sich selbst bombardiert, nachdem es die gesamte Erinnerung durchgegangen ist.
mbomb007
5

Han zuerst erschossen (v2)

Ich dachte, die Konkurrenz könnte etwas mehr Abwechslung gebrauchen, und hier ist mein zweiter Beitrag: ein One-Shot- CMPScanner.

Dies ist Version 2 mit verbesserter Anti-Imp-Abwehr - sie kann nun Imp schlagen, wenn auch nur um einen Punkt. Es verliert immer noch gegen den Zwergeningenieur, schlägt aber alles andere bisher und belegt damit derzeit den ersten Platz.

scan    ADD bomb    aim
aim     CMP 17      12
        JMZ scan    #-3
loop    MOV bomb    @aim
        ADD step    aim
step    JMP loop    #2
bomb    DAT 10      10

Dabei werden benachbarte Kernpositionen in Abständen von 10 Schritten in einem Abstand von 5 Schritten verglichen, bis ein Unterschied festgestellt wird. Wenn es dies tut, wirft es in Abständen von 2 Schritten Bomben, bis es seinen Gegner tötet oder sich um den gesamten Kern schlingt, um sich selbst zu erreichen.

Wenn der Scan nicht nicht irgendetwas anderes finden, wird es schließlich um Schleife und seinen eigenen Code finden und sie angreifen. Das wäre Selbstmord, aber der glückliche Zufall, dass die erste Bombe direkt auf der Erde landetaim Linie , wodurch die nächste Bombe 12 Positionen (anstatt der üblichen 2) in den Kern geworfen und der Code übersprungen wird. (Dies geschieht auch mit einer Wahrscheinlichkeit von 50%, wenn der Scan etwas findet, den Gegner jedoch nicht tötet.) Da die Kerngröße ein Vielfaches von zwei ist, geschieht dies auch dann, wenn der Bombenangriff eine Schleife durchläuft, wodurch die Notwendigkeit für a entfällt weitere Backup-Strategie.

(Dieser Selbstbombardierungstrick war ursprünglich ein reiner Zufall - ich hatte mir eine völlig andere Art des Wechsels vom Scan- zum Bombenmodus vorgenommen, wenn nichts gefunden wurde, aber als ich den Code zum ersten Mal testete, waren die Konstanten einfach richtig, um ihn zu erstellen arbeite auf diese Weise, und ich habe mich entschlossen, dabei zu bleiben.)

Ilmari Karonen
quelle
4

Imp

MOV 0 1

Einfach Zoll durch das Programm.

Die Nummer eins
quelle
4

Schnecke

     mov    ones    @-1024
     mov    from    -3
     mov    here    -3
loop mov    @-5 @-4
     add    ones  -5
     jmz    -17 -6
     add    ones  -8    
     jmp    loop    42
ones dat    1   1
from dat    2   2
here dat    -11 -11

Kriecht rückwärts durch den Speicherplatz. Wirft gelegentlich eine Bombe weit weg.

Ahelly
quelle
3

Osterhase

Er hüpft gerne rückwärts :)

loop mov 0 -10
     add data loop
     cmp -7 data
     jmp -13 0
     jmp loop 0
data dat 1 1
Die Nummer eins
quelle
3

Paranoid

Eine Art Kopiernudel, prüft aber, ob der Code durch Bombenangriffe geändert wurde. Wenn ja, kopiert es an einem Zwerg vorbei und führt ihn aus. Wenn ich es schaffe, das GameView erneut zu erstellen, werde ich versuchen, einige der Konstanten zu ändern.

copy    MOV data copy
loop    MOV @-1 @-1
    CMP @copy end
out JMP check 0
    SUB loop copy
    JMP loop 0
data    DAT 0 4109
check   MOV data copy
loop2   CMP @copy @copy
    JMP ok 0
    MOV aah 2
ok  CMP @copy end
    JMP 4098 0
    SUB loop copy
    JMP loop2 0
panic   MOV end copy
    MOV jump out
    JMP loop 0
jump    JMP 4124 0
dwarf   ADD 2 bomb
    MOV bomb @bomb
    JMP dwarf 4
bomb    DAT 0 4
aah JMP 3 0
end DAT 19 4127
Schlagen
quelle
Okay, in der Tat funktioniert es und ich war gerade in der Nähe, danke für den neuen Lauf;)
Hit