纳米核心战争


21

这是对《核心战争》的改编,《核心战争》可追溯到20世纪。更具体地说,它使用的是一种非常简化的指令集,主要是基于原始提案

背景

在《核心战争》中,有两个程序争夺对计算机的控制权。每个程序的目标是通过定位和终止相反的程序来取胜。

战斗发生在计算机的主内存中。该内存称为核心,它包含8192个地址。当战斗开始时,每个竞争对手(称为战士)的代码都会放在随机的内存块中。程序执行在战士之间交替,每个战士执行一条指令。每条指令都可以修改Core的一部分,从而有可能自行修改程序。

目的是终止相反的程序。程序在尝试执行无效指令(即任何DAT指令)时会终止。

指令集

每个程序由一系列低级指令组成,每个指令都有两个字段,称为A和B字段。

该指令集极大地借鉴了原始规范。主要的更改是1)澄清了添加/减去命令的问题,以及2)更改了#寻址模式以使其可以在任何地方使用。Core Wars的大多数完整版本都有20多个操作码,8种寻址模式和一组“指令修饰符”。

操作码

每个指令必须具有七个不同的操作码之一。

  • DAT A B-(数据)-仅保存数字AB。重要的是,进程在尝试执行DAT指令时会死掉。
  • MOV A B-(移动)-将存储位置的内容移动A到存储位置B。这是前后的演示:

    MOV 2 1
    ADD @4 #5
    JMP #1 -1
    
    MOV 2 1
    JMP #1 -1
    JMP #1 -1
    
  • ADD A B-(添加)-将存储位置的内容添加A到存储位置B。两者的前两个​​字段被添加,第二个字段被添加。

    ADD 2 1
    MOV @4 #5
    JMP #1 -1
    
    ADD 2 1
    MOV @5 #4
    JMP #1 -1
    
  • SUB A B-(减)-从存储位置中减去存储位置的内容A(并将结果存储到其中)B

    SUB 2 1
    MOV @4 #5
    JMP #1 -1
    
    SUB 2 1
    MOV @3 #6
    JMP #1 -1
    
  • JMP A B-(跳转)-跳转到location A,它将在下一个周期执行。 B必须为数字,但不执行任何操作(不过,您可以使用它来存储信息)。

    JMP 2 1337
    ADD 1 2
    ADD 2 3
    

    跳转意味着ADD 2 3将在下一个周期执行。

  • JMZ A B-(如果为零则跳转)-如果line的两个字段B均为0,则程序跳转到location A

    JMZ 2 1
    SUB 0 @0
    DAT 23 45
    

    由于指令1的两个字段均为0,因此DAT命令将在下一轮执行,从而导致死亡。

  • CMP A B- (比较和跳过,如果不相等) -如果指令的领域AB不相等,则跳过下一条指令。

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

    由于指令1和2的两个字段的值相等,因此ADD命令不会被跳过,而是在下一回合执行。

当两个指令相加/相减时,两个字段(A和B)成对相加/相减。寻址模式和操作码不变。

寻址方式

有三种寻址方式。一条指令的两个字段中的每个字段都具有这三种寻址模式之一。

  • 立即#X - X是直接在计算中使用的行。例如,#0是程序的第一行。负行是指程序开始之前内核中的行。

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

    这会将两个DAT行中的第一个添加到第二行,因为它们分别在第3行和第4行中。但是,您不希望使用此代码,因为DAT将在下一个周期杀死您的机器人。

  • 相对X -该数字X表示目标内存地址相对于当前地址的位置。此位置上的数字用于计算。如果line #35正在执行并包含-5,则使用line #30

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

    这会将第二条DAT行添加到第一条。

  • 间接的@X -数字X代表相对地址。该位置的内容被临时添加到数字X中,以形成一个新的相对地址,从该地址中检索该数字。如果#35正在执行line ,并且它的第二个字段是@4,并且line的第二个字段#39包含number -7,那么#32将使用line 。

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

    这会将第一个DAT添加到第二个DAT中,但是会更加复杂。第一个字段是@ 1,它从该相对地址获取数据,该相对地址是第一个DAT的第一个字段,即0。这被解释为该位置的第二个相对地址,因此1 + 0 = 1得出总数与原始指令的偏移量。对于第二个字段,@ 1从该相对地址(第一个DAT的第二个字段中的1)获取值并将其添加到自身中。则总偏移为1 + 1 = 2。因此,该指令的执行方式与相似ADD 1 2

每个程序最多可包含64条指令。

一轮开始时,这两个程序被随机放置在具有8192个位置的存储库中。每个程序的指令指针从程序的开头开始,并在每个执行周期后递增。一旦程序的指令指针尝试执行DAT指令。

核心参数

核心大小为8192,超时值为8192 * 8 = 65536个ticks。内核是循环的,因此写入地址8195与写入地址3相同。所有未使用的地址均初始化为DAT #0 #0

每个参赛者不得超过64行。整数将存储为32位带符号整数。

解析中

为了使竞争对手更容易编程,我将向解析器添加行标签功能。操作码之前一行上出现的任何单词都将被解释为行标签。例如,tree mov 4 6具有线标签tree。如果程序中的任何地方都有一个包含tree #tree或的字段,@tree则将替换一个数字。同样,大写也被忽略。

这是如何替换行标签的示例:

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

在这里,标签A,B和C位于第0、1和2行。的实例#label将替换为标签的行号。实例label或被@label标签的相对位置代替。寻址模式被保留。

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

计分

对于每对参赛者,将进行所有可能的战斗。由于战斗的结果取决于两个程序的相对偏移量,因此会尝试每个可能的偏移量(其中大约8000个)。此外,每个程序都有机会在每个偏移量中首先移动。赢得大部分补偿的程序是该对的赢家。

勇士每赢得一对配对,将获得2分。对于每条领带,战士都会获得1分。

您可以提交多个战士。适用多个提交的典型规则,例如不进行标签团队合作,不进行合作,不做国王等。反正在《核心战争》中实际上没有任何空间可以这样做,因此这没什么大不了的。

控制器

控制器的代码以及两个简单的示例bot 都位于此处。由于此竞赛(使用正式设置进行比赛)是完全确定性的,因此您创建的页首横幅将与官方排行榜完全相同。

机器人例子

这是一个示例bot,演示了该语言的某些功能。

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

该机器人通过用“炸弹”代替它来缓慢擦除内核中的所有其他内存,从而进行操作。由于炸弹是DAT指令,因此到达炸弹的任何程序都将被销毁。

有两个线标签,“ main”和“ bomb”,用于替换数字。经过预处理后,程序如下所示:

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

第一行将炸弹复制到程序上方的行。下一行将炸弹(0 -1)的值添加到move命令中,并且还演示了@寻址模式的用法。此添加使move命令指向新目标。下一条命令无条件地跳回到程序的开始。


现任排行榜

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

成对结果:

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

最新更新(新版本的Turbo和Paranoid)在旧笔记本电脑上运行大约需要5分钟。我要感谢Ilmari Karonen对控制器的改进。如果您有控制器的本地副本,则应更新文件。


如果两个相互竞争的机器人试图使用相同的标签会怎样?
mbomb007'3

1
@ mbomb007标签是预处理对象,在解析bot的源文件时进行计算。您的标签不会与任何竞争对手的标签互动。
PhiNotPi 2015年

1
@ mbomb007,以便程序不重叠。另外,我不打算在此版本中添加任何其他功能,除非Micro Core War可用。
PhiNotPi 2015年

1
@ mbomb007间接寻址引用的是与引用相同的字段(第一个或第二个)。没有指令修饰符。我并没有根据'94标准提出这一挑战。
PhiNotPi 2015年

2
@Thrax我要说不,您不仅限于一次提交。尽管无论如何在核心战争中没有太多合作空间,但仍适用典型的多次提交规则(无需标签合作等)。
PhiNotPi 2015年

Answers:


9

矮人工程师

一个新的和改进的矮人。赢得到目前为止提交的所有其他内容。花哨的核心步骤-优化的步长可能在这里是过大的。

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

值得注意的功能包括快速轰炸循环,该炸弹循环可在四个周期内投掷两枚炸弹,以旧式Core War行话的平均轰炸速度为0.5c,并使用JMZ来检测轰炸的完成时间以及何时切换至计划B(在这里,一个小鬼)。


我曾经在90年代玩过《核心战争》(有些人可能看过我写于'97 的基本指南),所以我认为看看RedCode '88 / '94世界中哪些旧策略可能会很有趣在此变体中很有用。

我最初的想法是:

  • 没有SPL,因此没有复制器(也没有imp环/螺旋)。这应该使轰炸机更坚固。(此外,所有那些旨在应对复制者和小恶魔般螺旋桨的奇特的轰炸策略?在这里完全没有必要,也没有用。只需用任何炸弹轰炸DAT。)

  • 再说一次,CMP扫描仍可能比轰炸更快,因此快速扫描仪可能会有机会。

  • 缺少in / decrements使核心清除非常缓慢。实际上,此变体中的核心清除器几乎只是一个轰炸机,步长为(次优)±1。同样,这也伤害了扫描仪。不过,一键式扫描仪→轰炸机策略可能会起作用。

  • 快速扫描仪/快速轰炸机(对于那些不熟悉Core War术语的人来说,使用展开式扫描/轰炸循环的早期游戏策略)仍然可能有用,但仅适用于长程序(它们本身就是这样,因此会有一种反馈)效果在这里)。很难说这是否真的值得麻烦。

  • 计分系统很有趣。领带的得分只有胜利的一半(而不是传统的《核心战争》的1/3),因此更具吸引力。再说一次,在这些规则下唯一可能获得很多平局的程序就是一个小鬼。(此外,缺少de / increments会使imp gates变得困难,因此,即使简单的imps实际上有机会在对手还活着的情况下得分并列。)

  • 同时,由于最终排名仅取决于你打,而不是怎么哪些程序多少您可以通过击败他们,这往往有利于通才条目。仅仅勉强击败所有对手,而不是完全消灭一半对手,而仅仅输给其余对手,比总好一些。

  • 因为该代码是公开的,所以总的来说,无论它们的质量如何,总是有可能找到一个可以击败任何给定的早期提交程序(甚至可能是其中的几个)的程序。但是,这些技巧(例如调整步长以在对手击中对手之前就将其击中)看起来很便宜。而且,当然,目标玩家总是可以提交具有不同常量的新版本。

无论如何,所有这些的结果是我决定我应该尝试编写一个快速轰炸机或一个非常快速的扫描仪,也许在上面安装 /轰炸机。在这些选择中,快速轰炸机似乎是最简单且最可能起作用的。

那时,我花了太多时间来调整和优化PhiNotPi的解释器代码,因为我认为我可能会进行大量的蛮力试验来优化常量。碰巧的是,我不需要这样做-上面的代码几乎是第一个实际起作用的版本(在几次由于愚蠢的错误导致自杀而失败的尝试之后)。


使我的轰炸机快速运转的诀窍是使用间接寻址为每个炸弹投掷两枚炸弹ADD。运作方式如下:

  1. 在第一个循环中,我们执行MOV bomb @aim。这会将指令复制bombaim指向B字段核心的任何位置(最初,确切地说是6326之前的指令aim,或者6328之前的指令step;您将稍后了解为什么这些数字很重要)。

  2. 下一步,我们执行aim指令本身!在第一遍中,它看起来像这样:MOV bomb @-6326。因此,它将其bomb自身之前的6326行处的指令的B字段复制到该位置。

    那么,之前6326行处有什么aim?为什么呢,这是bomb我们刚放置一个周期的副本!而且我们只是碰巧将东西的B场安排bomb为非零值,所以新炸弹不会被复制到旧炸弹的顶部,而是被复制了一段距离(实际上,距离是3164,这是我们标称步长6328的一半;但其他偏移量也可能有效,甚至更好)。

  3. 在下一个循环中,我们用调整目标SUB step aim,该目标从中减去step指令的值(这也恰好是我们接下来要执行的跳转,尽管可能只是一个简单的DAT地方)aim

    (这里要注意的一个细节是,我们有点希望A的值step是零,以便我们在下一次迭代时仍会投掷相同的炸弹。尽管如此,这并不是绝对必要的;只投掷了炸弹根据第一个指令,其B字段必须等于3164,其余的可以是任何值。)

  4. 接下来,JMZ检查指令6328离开它是否仍然为零,如果是,则跳回到代码的顶部。现在,6328是轰炸机的步距,可被8整除(但不能除以16);因此,如果我们仅每6328步就投掷一次炸弹,我们最终会回到开始的位置,炸毁了内核中的每条第八条指令(多余的炸弹抵消了3163 = 6328/2≡4(mod 8) ,我们将每隔四条命中一次)。

    但是,我们开始轰炸在6328个指令之前JMZ,并且在每次迭代由-6328向后踩,所以我们要轰炸位置6328个步骤JMZ只是一个迭代之前,我们会打的JMZ本身。因此,当JMZ在6328指令之后检测到炸弹时,这表明我们已经覆盖了尽可能多的核心而不会撞上自己,并且应该在杀死自己之前切换到备用策略。

  5. 至于备份策略,这只是一个简单的旧MOV 0 1印象,因为我暂时无法想到更好的方法。我的看法是,如果我们轰炸了核心的第四个位置而仍未获胜,那么我们可能是在战斗很小的东西或非常防御的东西,还不妨尝试生存并安顿下来。没关系,因为这样的小型或防御性程序通常不太擅长杀死其他任何东西,因此即使我们只是偶然赢得了几次战斗,我们也可能会领先。


附言 万一其他人想要它,这是我对PhiNotPi锦标赛代码的稍加改进。它的速度大约是以前的两倍,可以保存旧的战斗结果,因此您无需重新运行它们,并修复了我认为是战斗结果计算中的小错误的问题。更改已被PhiNotPi 合并到主线版本中。谢谢!


1
众所周知,计分会测试程序开始位置的所有可能组合,并且计分最多的是获胜点。只要一个程序从不杀死自己并轰炸至少一个地址,这将使联系变得不可能或完全不利,它将击败一个小鬼,赢得一次胜利,而其余的则保持联系。
mbomb007

9

图表视图

可以用作调试工具。它显示核心并显示播放器的位置。要使用它,您必须从代码中调用它。我还提供了Game.java自动显示GraphView的功能。

PhiNotPi和Ilmari Karonen最近更改了控制器。Ilmari Karonen非常友善,可以在此位置提供更新的GameView 。

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;
    }
}

修改的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.");
        }
    }*/
}

看来您也对Player进行了修改。我得到./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抱歉。我应该注释掉该printCore()方法。
TheNumberOne

9

涡轮

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

我第二次尝试CoreWar。设计用来击败矮人。按3扫描以获取数据,然后每2放一枚炸弹。每个阶段仅执行3条指令,希望矮人的炸弹会错过它。

新Turbo ++:现已增强。它向后扫描,直到找到数据,然后将其移动到那里,然后向后炸弹。希望这一举动要么扼杀对手,要么到已经轰炸的地方,因此很安全。

...并且进行更稀疏的扫描使其击败所有人!


似乎击败的不仅仅是侏儒。恭喜你!我认为如果您也可以击败Imp,那么您可以排名第三。
Ilmari Karonen 2015年

我更新了此版本,但实际上是前一个版本的相当大的改进。我应该重新输入吗?
AShelly

我不代表PhiNotPi发言,但我想这取决于您。进行就地更新基本上只是意味着撤回您的旧条目。无论如何,更恭喜您成功地将炸弹推向了第三位!我认为您是迄今为止唯一击败DwarvenEngineer的人。
Ilmari Karonen 2015年

做得好 ;)。你是现在打败的人!

8

侏儒

一个普通而简单的程序,代表矮人扔石头。它DAT每四个地址放置一条指令。

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

编辑:修复寻址。显然,寻址方式与OP链接的规范不同。


我认为第一行是“添加#3 3”,不是吗?
2015年

@Hit Nope。我想打第四个地址。我可以使用add 3 3,但是它将使每个循环加倍而不是添加,这将没有用。#4是立即数,因此会将数字4加到3当前地址之后的地址的第二个值中。
mbomb007'3

我认为您#在挑战中误解了寻址方式。如规范中所述,我对#寻址模式进行了更改。
PhiNotPi 2015年

您应该像:“添加2 3 mov 2 @ 2 jmp -2 4 dat 0 4”
点击

凭借正确的行为,它甚至会失败,并不断演变
击中2015年

7

进化的

老实说,我不知道它是如何工作的。似乎在做任何事情之前都要先构造其源代码。如果有人给我解释它的工作原理,我将非常乐意。

在研究了它之后,我发现它只是一个带有防撞罩的改良矮人。DAT它没有用指令轰炸敌人,而是改编了敌人的代码。它还会炸弹每两个寄存器,而不是每四个寄存器。如果有足够的时间,它无疑会毁灭自己。

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

1
那你从哪儿得到的呢?
PyRulez'3

4
@PyRulez这是通过遗传算法生成的计算机。
TheNumberOne

1
看起来执行实际上并没有比第6行前进的多,因为它在那里跳回了程序。我相信它成功的原因是比竞争对手有更多的动作/循环。
PhiNotPi 2015年

6

第一时间

如果确实可行,它应该尝试在核心的开始位置取得位置并建立防御

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

它与我认为的假设并不完全一样:#0指的是程序的开始(即与相同#main),而不是核心的开始(无论如何,这实际上不是一个有意义的概念,核心是循环,您的代码无法分辨它的开始或结束位置。发生的情况是您的第一条指令(main)用覆盖了自己MOV #data #100,然后代码有效地变成了0.25c(=每四个周期一条指令)正向内核清除。
Ilmari Karonen

@IlmariKaronen哦,谢谢您的解释。#0对于核心的开始,我确实犯了错误。然后,前5条指令完全没有用。
Thrax

6

复制面

从来没有参加过CoreWar,这个简单的程序只是尝试复制粘贴自己然后执行复制。它可能没有正确的行为,如果是这种情况,请告诉我。

它太和平了,实际上不能赢。

MOV 6 0
MOV @-1 @-1
CMP @-2 3
JMP 4242 0
SUB -3 -4
JMP -4 0
DAT 0 4244

当前的编辑可能不会在下一个排行榜更新中出现(我现在正在运行锦标赛)。但是,旧版本赢得了(较小的内核尺寸)初步结果。
PhiNotPi 2015年

好的:)较旧的版本不会退出loop1,这不是真正想要的行为,我正在尝试纠正它。

当前版本似乎已损坏。我还不知道为什么。
PhiNotPi

1
我已经修改了调试工具,所以现在我可以诊断问题了。发生的情况是该程序仅复制其后半部分(从开始JMP loop 0)。然后,当它跳到副本的起始位置时,它只是空白空间而丢失。
PhiNotPi

2
请忽略我之前的评论(现已删除);我测试了您的代码的错误版本(具有讽刺意味的是,由于复制粘贴错误),这就是为什么它对我而言如此糟糕的原因。
Ilmari Karonen

6

看门人

它应该检查以下地址是否为空,如果不清除,则将其清除(因此,有希望清除对手的机器人)。

编辑:此新版本应该更快(现在,我正确理解了JMZ命令和@参考)。

JMZ 2 6
MOV 4 @-1
ADD 2 -2
JMP -3 0
DAT 0 1
DAT 0 0

看门人不是和第一个JMZ自杀了吗?它至少应为JMZ 28。通过使用@可以将两个加法减少为一个。像这样的东西:“ JMZ 2 @ 5 MOV 5 @ 4 ADD 2 3 JMP -3 0 DAT 0 1 DAT 0 2 DAT 0 0”(未经测试)
击中

@Hit它不会跳转,因为那里的地址2是ADD 3 -2,但是我认为他应该更改它是正确的。
mbomb007'3

是的,我误读了说明JMZ,以为JMZ A B正在检查A并跳至B是否为0(显然相反)。感谢您的注意,因为我没有:)
plannapus

5

扫描轰炸机

删除我的评论,然后再编译。扫描一会儿,然后在找到程序时炸弹。不过,它可能仍然会输给我的矮人。

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

OP的定义#与规范完全不同(请阅读他链接到的链接),我尚未为其修复此程序。
mbomb007'3

@TheBestOne我想我已经解决了。看起来现在有意义吗?还是我需要#在每次引用之前都写上zero?是的,我想我需要...
mbomb007'3

现在效果很好。它击败了除矮人和小鬼以外的所有机器人。
TheNumberOne 2015年

@TheBestOne Dwarf太小,只能在可能的程序放置的50%中检测到。它可能只会输给Imp,因为它在遍历整个内存后会自行爆炸。
mbomb007

5

Han Shot First(v2)

我认为比赛可以使用更多的多样性,所以这是我的第二篇文章:一口气CMP扫描仪。

这是 第2版,具有改进的抗Imp防御功能-现在仅差一分就可以击败Imp。它仍然输给了Dwarven Engineer,但到目前为止击败了其他所有游戏,目前排名并列第一。

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

它通过比较相邻的磁芯位置(以10步为间隔,以5步为间隔)进行比较,直到发现差异为止。当它这样做时,它将开始以两步为间隔投掷炸弹,直到杀死对手或在核心周围一直循环直至到达自己为止。

如果扫描确实 没有找到其他任何东西,它将最终循环并找到自己的代码并对其进行攻击。这很容易自杀,但幸运的是,第一个炸弹正好落在aim生产线上,导致下一个炸弹被抛到核心下方12个位置(而不是通常的2个位置),很方便地跳过了代码。(如果扫描确实找到了东西,但也未能杀死对手,则也有50%的概率发生。)由于核心大小是2的倍数,所以如果轰炸循环不断,这种情况也将继续发生,从而消除了对进一步的备份策略。

(这种自我轰炸的技巧本来是纯粹的巧合-我计划采用一种完全不同的方式,如果什么也没发现,则从扫描模式切换到轰炸模式,但是当我第一次测试代码时,常量恰巧是正确的这样工作,我决定坚持下去。)


4

小鬼

MOV 0 1

只需在程序中进行操作即可。


4

ug

     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

向后爬过内存空间。有时会在远处扔炸弹。


3

复活节兔子

他喜欢向后跳:)

loop mov 0 -10
     add data loop
     cmp -7 data
     jmp -13 0
     jmp loop 0
data dat 1 1

3

偏执狂

复制粘贴的种类,但是它将检查轰炸是否已修改代码。如果是这样,它将复制通过一个小矮人并执行它。如果我设法再次制作GameView,我将尝试更改一些常量。

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

好的,实际上它正在工作,我只是在附近打乱,感谢新的尝试;)
命中
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.