不对称KOTH:抓住猫(捕手的线)


17

不对称的KOTH:捉住猫

更新由于Controller.java没有捕获到异常(仅错误),因此更新了主要文件(包括新的次要任务)。现在,它确实可以捕获错误和异常并打印它们。

这个挑战包括两个线程,这是捕手线程,猫线程可以在这里找到。

控制器可在此处下载。

这是不对称的KOTH:每个提交物都是还是捕手。每对猫和捕手之间都有游戏。猫和捕手的排名各不相同。

捕手

六角形网格上有一只猫。您的任务是尽快捕获它。每转一圈,您都可以在一个网格单元上放置一个水桶,以防止猫能够去那里。但是猫不是(也许)那么笨,每当您放置一个桶时,猫就会移动到另一个网格。由于网格是六角形的,因此猫可以向6个不同的方向移动。您的目标是用水桶包围猫,速度越快越好。

您知道捕手想通过在您周围放水桶来接住您。当然,您会尝试逃避,但是由于您是一只懒惰的猫(就像猫一样),您当时确实迈出了一步。这意味着您不能待在同一个地方,而是必须移至周围的六个景点之一。每当您看到捕手放了一个新的水桶时,您就会转到另一个牢房。当然,您会尽力逃避。

格网

网格是六边形的,但是由于我们没有六边形的数据结构,因此我们采用一个11 x 11二维二维数组,并模仿该六边形的“行为”,即猫只能在6个方向上移动:

在此处输入图片说明

拓扑是环形的,这意味着如果您踩到阵列“外部”的单元格,您将被转移到阵列另一侧的相应单元格。

游戏

猫从网格中的给定位置开始。捕手可以先走,然后猫及其捕手交替走动,直到猫被抓到为止。步骤数是该游戏的分数。猫试图获得尽可能高的分数,捕手试图获得尽可能低的分数。您参与的所有游戏的平均总和就是您提交的分数。有两个单独的等级,一个用于猫,一个用于捕手。

控制者

给定的控制器是用Java编写的。作为捕手或猫,您每个人都必须完成一个Java类(已经有一些原始示例)并将其放在players包中(并更新Controller类中的猫/捕手列表),但是您也可以编写该类中的其他功能。控制器附带了简单的cat / catcher类的每两个工作示例。

该字段是一个11 x 11二维int数组,用于存储单元格当前状态的值。如果一个单元格为空,则它具有值0;如果有一只猫,则它具有值-1;如果有一个存储桶,则有一个值1

您可以使用一些给定的功能:isValidMove()/ isValidPosition()用于检查您的移动(类别)/位置(类别)是否有效。

每次轮到您时,takeTurn()都会调用您的函数。参数包含当前网格的副本,并具有类似于read(i,j)读取处的单元格的方法(i,j),以及isValidMove()/ isValidPosition()检查答案是否正确的方法。这也可以管理环形拓扑的环绕,这意味着即使网格只有11 x 11,您仍然可以访问单元格(-5,13)。

该方法应返回一个int包含两个元素的数组,这些元素代表可能的移动。对于猫来说,{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}它们代表了猫想去的位置的相对位置,而捕手则返回了他们想要放水桶的位置的绝对坐标{i,j}

如果您的方法产生无效举动,则您的提交将被取消资格。如果在您的目的地已经是一个铲斗或不允许该举动/目的地已被占用(作为猫),或者如果已经有一个铲斗/猫(作为捕手),则该举动被视为无效。您可以使用给定的功能事先检查一下。

您的提交应该工作得相当快。如果您的方法每个步骤花费的时间超过200毫秒,则也将被取消比赛资格。(最好少得多...)

程序可以在步骤之间存储信息。

意见书

  • 您可以根据需要进行任意数量的提交。
  • 请不要显着改变您已经提交的提交。
  • 请每个提交一个新的答案。
  • 每个提交最好都具有唯一的名称。
  • 提交内容应包括您班级的代码以及可以告诉我们您提交内容如何工作的描述。
  • 您可以在<!-- language: lang-java -->源代码前写一行,以自动突出显示语法。

计分

所有都将与所有捕手竞争相同的次数。我将尝试经常更新当前分数,当活动减少时将确定获胜者。

这项古老的Flash游戏启发了这一挑战

感谢@PhiNotPi进行测试并提供一些建设性的反馈。

当前分数(每对100场比赛)

Name              Score      Rank   Author

RandCatcher       191674     8      flawr   
StupidFill        214246     9      flawr
Achilles          76820      6      The E
Agamemnon         74844      5      The E
CloseCatcher      54920      4      randomra
ForwordCatcher    94246      7      MegaTom  
Dijkstra          46500      2      TheNumberOne
HexCatcher        48832      3      randomra
ChoiceCatcher     43828      1      randomra

RandCat           77928      7      flawr
StupidRightCat    81794      6      flawr
SpiralCat         93868      5      CoolGuy
StraightCat       82452      9      CoolGuy
FreeCat           106304     3      randomra
RabidCat          77770      8      cain
Dijkstra's Cat    114670     1      TheNumberOne
MaxCat            97768      4      Manu
ChoiceCat         113356     2      randomra

什么程序制作动画?
MegaTom 2015年

动画只是GUI(启动控制器时,您必须设置PRINT_STEPS = true,文件中有更详细的设置MyFrame.java)。然后我用LICEcap记录了下来,并用GIMP对其进行了编辑。如果您还有其他问题,请提问!
瑕疵的

如果将用户输入添加到控制器,则可以使用GUI和已编写的机器人来制作一款不错的软件。看看人类能破解/滥用特定的机器人策略多少也很有趣。
randomra 2015年

另外,我的机器人可以保留上一次比赛的信息,以尝试找到针对同一机器人的更好的移动顺序吗?我想不是因为你做的越多越好。它还必须猜测它是否正在与新的bot对抗,因此运行顺序也很重要。
randomra 2015年

1
为什么猫的分数无序?
Spikatrix

Answers:


6

阿喀琉斯

阿喀琉斯不是太聪明,但他效率极高。首先,他阻止猫使用木板缠绕,然后将木板分成两部分。然后他继续将猫的木板部分分成两半,直到被困住为止。

示威RandCat vs阿喀琉斯

randcat vs achilles

package players;
/**
 * @author The E
 */
import main.*;



public class Achilles implements Catcher
{
    public Achilles() {

    }
    @Override
    public String getName() {

        return "Achilles";
    }

    @Override
    public int[] takeTurn(Field f) {
        try{
        if(f.read(0, f.SIZE-1)!=Field.BUCKET)
        {
            //Make the first line

            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(0, j) == Field.EMPTY)
                {
                    return new int[]{0,j};
                }
            }
            return WasteGo(f);

        }
        else if (f.read(f.SIZE-1, 0)!=Field.BUCKET)
        {
            //Make the second line
            for(int i = 0; i<f.SIZE; i++)
            {
                if(f.read(i, 0) == Field.EMPTY)
                {
                    return new int[]{i,0};
                }
            }
            //The cat got in the way
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(1, j) == Field.EMPTY)
                {
                    return new int[]{1,j};
                }
            }
            return WasteGo(f);
        }
        else
        {
            return TrapCat(1,1,f.SIZE-1, f.SIZE-1, false, f);

        }
        }
        catch (Exception e)
        {
            return WasteGo(f);
        }
    }
    private int[] TrapCat(int i1, int j1, int i2, int j2, Boolean direction, Field f) {
        for(int a = 0; a<f.SIZE+10; a++)
        {
            if(direction)
            {

                int height = j2-j1+1;
                int row = j1 + height/2;
                for(int i = i1; i<=i2; i++)
                {
                    if(f.read(i, row)==Field.EMPTY)
                    {
                        return new int[]{i,row};
                    }
                }

                    //Done that Row
                    //Find cat
                    if(f.findCat()[1]>row)
                    {
                        //he's above the line
                        j1 = row+1;
                        direction = !direction;
                        //return TrapCat(i1, row+1, i2, j2, !direction, f);
                    }
                    else
                    {
                        //he's below the line
                        j2 = row - 1;
                        direction = !direction;
                        //return TrapCat(i1, j1, i2, row-1, !direction, f);
                    }


            }
            else
            {
                int bredth = i2-i1+1;
                int column = i1 + bredth/2;
                //Continue making the line
                for(int j = j1; j<=j2; j++)
                {
                    if(f.read(column,j)==Field.EMPTY)
                    {
                        return new int[]{column,j};
                    }
                }

                    //Done that Column
                    //Find cat
                    if(f.findCat()[0]>column)
                    {
                        //he's right of the line
                        i1 = column + 1;
                        direction = !direction;
                        //return TrapCat(column+1, j1, i2, j2, !direction, f);
                    }
                    else
                    {
                        //he's left of the line
                        i2 = column -1;
                        direction = !direction;
                        //return TrapCat(i1, j1, column-1, j2, !direction, f);
                    }

            }
        }
        return WasteGo(f);
    }
    private int[] WasteGo(Field f) {
        for (int i = 0; i<f.SIZE;i++)
        {
            for(int j=0;j<f.SIZE;j++)
            {
                if(f.read(i,j)==Field.EMPTY)
                {
                    return new int[]{i,j};
                }
            }
        }
        //Something drastic happened
        return new int[]{0,0};
    }



}

那么现在是阿喀琉斯还是赫克托尔呢?(或患有分离性身份障碍的人?=)
虚假的2015年

@flawr阿喀琉斯,大声笑我在中途更改了名称(更容易命名捕手阿喀琉斯和猫赫克托),但忘了更改
Java-

但是赫克托宁愿成为狗的名字=)感谢您的投稿工作很棒。希望您不要介意我在您的代码中也包含了“序言”。
flawr

是的,没问题。赫克托听起来确实像狗的名字……
euanjt 2015年

我只是进行了一次模拟(每个配对10000场比赛),由于重复的StackOverflowError,阿喀琉斯被取消资格。我认为递归并未结束:pastebin.com/9n6SQQnd
漏洞

5

阿伽门农

阿伽门农用垂直线将猫的区域分成两半,直到猫只有一条可移动的宽度为2的条带,这时他将猫困住了。

阿伽门农vs兰德猫:

在此处输入图片说明

package players;
/**
 * @author The E
 */
import main.*;



    public class Agamemnon implements Catcher {
        boolean up = true;
        @Override
        public String getName() {
            return "Agamemnon";
        }

        @Override
        public int[] takeTurn(Field f) {
            //First Make Line in column 1
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(0, j)==Field.EMPTY)
                {
                    return new int[]{0,j};
                }
            }
            //Then in column SIZE/2
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(f.SIZE/2, j)==Field.EMPTY)
                {
                    return new int[]{f.SIZE/2,j};
                }
            }
            //Then work out where the cat is
            int left, right;
            int cati = f.findCat()[0];
            if(cati<f.SIZE/2)
            {
                left = 1;
                right = f.SIZE/2-1;
            }
            else
            {
                left = f.SIZE/2+1;
                right = f.SIZE-1;
            }
            while(right-left>1)
            {
                //If the cat is not in a two width column
                //Split the area the cat is in in half
                int middleColumn = (left+right)/2;
                for(int j = 0; j<f.SIZE; j++)
                {
                    if(f.read(middleColumn, j)==Field.EMPTY)
                    {
                        return new int[]{middleColumn,j};
                    }
                }
                //If we got here we had finished that column
                //So update left and/or right
                if(cati<middleColumn)
                {
                    //he's left of the middle Column
                    right = middleColumn - 1;
                }
                else
                {
                    //he's right of the middle Column
                    left = middleColumn+1;
                }
                //Repeat
            }
            //Otherwise try to trap the cat
            //Make a line up and down on the opposite side of the cat
            int catj = f.findCat()[1];
            if(left!=right){
                if(cati==left)
                {
                    if(f.read(right, catj)==Field.EMPTY)
                    {
                        return new int[]{right, catj};
                    }
                    if(f.read(right, catj-1)==Field.EMPTY)
                    {
                        return new int[]{right, catj-1};
                    }
                    if(f.read(right, catj+1)==Field.EMPTY)
                    {
                        return new int[]{right, catj+1};
                    }


                }
                else
                {
                    if(f.read(left, catj)==Field.EMPTY)
                    {
                        return new int[]{left, catj};
                    }
                    if(f.read(left, catj-1)==Field.EMPTY)
                    {
                        return new int[]{left, catj-1};
                    }
                    if(f.read(left, catj+1)==Field.EMPTY)
                    {
                        return new int[]{left, catj+1};
                    }

                }
            }
            //Alternate between above and below
            if(up)
            {
                up = !up;
                if(f.read(cati, catj+1)==Field.EMPTY)
                {

                    return new int[]{cati, catj+1};
                }
            }
            up = !up;
            if(f.read(cati, catj-1)==Field.EMPTY)
            {

                return new int[]{cati, catj-1};
            }
            return WasteGo(f);
        }

        private int[] WasteGo(Field f) {
            for (int i = 0; i<f.SIZE;i++)
            {
                for(int j=0;j<f.SIZE;j++)
                {
                    if(f.read(i,j)==Field.EMPTY)
                    {
                        return new int[]{i,j};
                    }
                }
            }
            //Something drastic happened
            return new int[]{0,0};
        }
    }

这位捕手的表现始终优于阿喀琉斯,而且我认为他的与众不同足以保证有新的答案。


很好的解决方案,我确定阿喀琉斯已接近最佳状态,但现在我认为甚至阿伽门农也可以略有改善=)
更加模糊的2015年

是的,阿伽门农有比阿喀琉斯更好的最终游戏诱捕算法,但我敢肯定有一些调整...现在,我将尝试研究一只猫:)
euanjt 2015年

@flawr添加了非常小的调整以加快捕获速度,在某些特殊情况下,这不会影响此处的动画(尽管我认为这可能会影响SpiralCat的动画)
euanjt 2015年

题!如果您要关闭一条直线但猫咪站在最后一个位置,会发生什么?
骆马先生2015年

@Llama先生,它开始制作下一行,就好像该行已被填满(即,猫实际上是一个水桶)-不是最有效的转弯方式,但很少发生,但这并不重要-猫必须在下一个转弯处走开,这样我才能将水桶放在那里
euanjt 2015年

5

六角捕手

如果捕手可以将猫抓到一个大的六边形内侧,该大六边形的边已被水桶占据,而六边形的边已被水桶占据,则捕手可以将猫留在该区域并抓住它。六角形看起来像这样:

在此处输入图片说明

这是HexCatcher试图实现的目标。它在思维上用这些大六边形平铺该字段,以使每个角落单元格成为3个大六边形的一部分。

如果有机会通过将猫的两个角连接起来将猫保持在当前区域中,则机器人将执行此操作。(例如,在图像中,如果猫的身高为7.5,即使只占据了6,6和8,5个单元格,我们也会选择7.6。)

如果没有上一个选项,我们选择打一个角,该角是猫所在区域的一部分。如果已经选择了所有这些角(如图中所示),我们将在猫旁边选择一个单元格。

可能会进行多项小改进,例如更好地处理环绕效果(在其中平铺),或者使最后几对移动达到最佳状态。我可能会做一些。如果不允许,我将(出于竞争目的)附加给感兴趣的人。

DijkstrasCat vs HexCatcher:

在此处输入图片说明

package players;
/**
 * @author randomra
 */
import main.Field;

public class HexCatcher implements Catcher {
    public String getName() {
        return "HexCatcher";
    }

    final int[][] o = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 }, { 0, -1 },
            { 1, -1 } };// all valid moves
    final int[][] t = { { -2, 2 }, { 0, 2 }, { -2, 0 }, { 2, 0 }, { 0, -2 },
            { 2, -2 } };// all valid double moves in one direction
    final int[][] h = { { -1, 2 }, { -2, 1 }, { -1, -1 }, { 1, -2 }, { 2, -1 },
            { 1, 1 } };// all valid moves in not one direction
    int opp = 0;

    public int[] takeTurn(Field f) {
        int[] p = f.findCat();
        // center of the hexagon the cat is in
        int[] c = { ((int) p[0] / 3) * 3 + 1, ((int) p[1] / 3) * 3 + 1 };
        // change priority of catching direction at every turn
        opp = 1 - opp;

        // check missing corner piece next to cat
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            boolean close = false;
            for (int k = 0; k < 6; k++) {
                if (c[0] + h[ind][0] == p[0] + o[k][0]
                        && c[1] + h[ind][1] == p[1] + o[k][1]) {
                    close = true;
                }
            }
            if (f.read(c[0] + h[ind][0], c[1] + h[ind][1]) == 0 && close) {
                return new int[] { c[0] + h[ind][0], c[1] + h[ind][1] };
            }
        }
        // cut off escape route if needed
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(c[0] + o[ind][0], c[1] + o[ind][1]) == -1
                    && f.read(c[0] + t[ind][0], c[1] + t[ind][1]) == 0) {
                return new int[] { c[0] + t[ind][0], c[1] + t[ind][1] };
            }
        }
        // check any missing corner piece in the area
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(c[0] + h[ind][0], c[1] + h[ind][1]) == 0) {
                return new int[] { c[0] + h[ind][0], c[1] + h[ind][1] };
            }
        }
        // choose an empty cell next to the cat
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(p[0] + o[ind][0], p[1] + o[ind][1]) == 0) {
                return new int[] { p[0] + o[ind][0], p[1] + o[ind][1] };
            }
        }
        return null;
    }
}

3

关闭捕手

选择猫可以在下一步中踩到的位置之一。如果它移动到那只猫并且视野不会改变,它会选择3个步骤后将为猫提供最多可能路径的那只猫。

代码与我的Cat条目FreeCat几乎相同,后者以非常相似的方式选择方向。

SpiralCat与CloseCatcher:

SpiralCat和CloseCatcher

package players;
/**
 * @author randomra
 */

import main.Field;
import java.util.Arrays;

public class CloseCatcher implements Catcher {
    public String getName() {
        return "CloseCatcher";
    }

    final int[][] turns = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 },
            { 0, -1 }, { 1, -1 } };// all valid moves
    final int turnCheck = 3;

    public int[] takeTurn(Field f) {

        int[] pos = f.findCat();
        int[] bestMove = { 0, 1 };
        int bestMoveCount = -1;
        for (int[] t : turns) {
            int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
            int moveCount = free_count(currPos, turnCheck, f);
            if (moveCount > bestMoveCount) {
                bestMoveCount = moveCount;
                bestMove = t;
            }
        }
        int[] bestPos = { pos[0] + bestMove[0], pos[1] + bestMove[1] };
        return bestPos;
    }

    private int free_count(int[] pos, int turnsLeft, Field f) {
        if (f.isValidPosition(pos) || Arrays.equals(pos, f.findCat())) {
            if (turnsLeft == 0) {
                return 1;
            }
            int routeCount = 0;
            for (int[] t : turns) {
                int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
                int moveCount = free_count(currPos, turnsLeft - 1, f);
                routeCount += moveCount;
            }
            return routeCount;
        }
        return 0;
    }

}

不错+1。CloseCatcher可以轻松捕获StraightCat
Spikatrix

3

迪克斯特拉

他不太喜欢猫(:v{ >

FreeCat vs Dijkstra (需要更新)

在此处输入图片说明

package players;

import main.Controller;
import main.Field;

import java.util.*;

/**
 * @author TheNumberOne
 *
 * Catches the cat.
 */

public class Dijkstra implements Catcher{

    private static final int[][][] CACHE;

    static {
        CACHE = new int[Controller.FIELD_SIZE][Controller.FIELD_SIZE][2];
        for (int x = 0; x < Controller.FIELD_SIZE; x++){
            for (int y = 0; y < Controller.FIELD_SIZE; y++){
                CACHE[x][y] = new int[]{x,y};
            }
        }
    }

    private static final int[][] possibleMoves = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};
    @Override
    public String getName() {
        return "Dijkstra";
    }

    @Override
    public int[] takeTurn(Field f) {
        long startTime = System.nanoTime();

        final int[] theCat = f.findCat();
        int[] bestMove = {-1,1};
        int[] bestOpenness = {Integer.MAX_VALUE, 0};
        List<int[]> possiblePositions = new ArrayList<>();
        for (int x = 0; x < 11; x++){
            for (int y = 0; y < 11; y++){
                int[] pos = {x,y};
                if (f.isValidPosition(pos)){
                    possiblePositions.add(pos);
                }
            }
        }
        Collections.sort(possiblePositions, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return distance(o1, theCat) - distance(o2, theCat);
            }
        });
        for (int i = 0; i < possiblePositions.size() && System.nanoTime() - startTime < Controller.MAX_TURN_TIME/2; i++){
            int[] pos = possiblePositions.get(i);
            int before = f.field[pos[0]][pos[1]];
            f.placeBucket(pos);
            int[] openness = openness(theCat, f, true);
            if (openness[0] < bestOpenness[0] ||
                    (openness[0] == bestOpenness[0] &&
                            (openness[1] > bestOpenness[1])
                    )
                    ){
                bestOpenness = openness;
                bestMove = pos;
            }
            f.field[pos[0]][pos[1]] = before;
        }
        return bestMove;
    }


    /**
     *
     * @param pos The pos to calculate the openness of.
     * @param f The field to use.
     * @return Two integers. The first integer represents the number of reachable hexagons.
     * The second integer represents how strung out the squares are relative to the pos.
     */
    public static int[] openness(int[] pos, Field f, boolean catZeroWeight){
        Map<int[], Integer> lengths = new HashMap<>();
        PriorityQueue<int[]> open = new PriorityQueue<>(10,new Comparator<int[]>() {
            Map<int[], Integer> lengths;
            @Override
            public int compare(int[] o1, int[] o2) {
                return lengths.get(o1) - lengths.get(o2);
            }
            public Comparator<int[]> init(Map<int[], Integer> lengths){
                this.lengths = lengths;
                return this;
            }
        }.init(lengths));
        Set<int[]> closed = new HashSet<>();
        lengths.put(pos, catZeroWeight ? 0 : 6 - pointsAround(pos, f).size());
        open.add(pos);
        while (open.size() > 0){
            int[] top = open.remove();
            if (closed.contains(top)){
                continue;
            }
            closed.add(top);
            int l = lengths.get(top);
            List<int[]> pointsAround = pointsAround(top, f);

            for (ListIterator<int[]> iter = pointsAround.listIterator(); iter.hasNext();){
                int[] point = iter.next();
                if (closed.contains(point)){
                    iter.remove();
                }
            }

            for (int[] p : pointsAround){
                int length = l + 7 - pointsAround(p, f).size();
                if (lengths.containsKey(p)){
                    length = Math.min(length, lengths.get(p));
                }
                lengths.put(p, length);
                open.add(p);
            }
        }
        int sum = 0;
        for (int integer : lengths.values()){
            sum += integer;
        }
        return new int[]{lengths.size(),sum};
    }

    public static int distance(int[] p1, int[] p2){
        p2 = Arrays.copyOf(p2, 2);
        while (p2[0] < p1[0]){
            p2[0] += 11;
        }
        while (p2[1] < p2[0]){
            p2[1] += 11;
        }
        int lowestDistance = 0;
        for (int dx = 0; dx == 0; dx -= 11){
            for (int dy = 0; dy == 0; dy -= 11){
                lowestDistance = Math.min(lowestDistance,Math.min(Math.abs(p1[0]-p2[0]-dx),Math.min(Math.abs(p1[1]-p2[1]-dy),Math.abs(p1[0]+p1[1]-p2[0]-dx-p2[1]-dy))));
            }
        }
        return Math.min(Math.abs(p1[0]-p2[0]),Math.min(Math.abs(p1[1]-p2[1]),Math.abs(p1[0]+p1[1]-p2[0]-p2[1])));
    }

    public static int[] normalize(int[] p){
        return CACHE[(p[0]%11+11)%11][(p[1]%11+11)%11];
    }

    public static List<int[]> pointsAround(int[] p, Field f){
        int[] cat = f.findCat();
        List<int[]> locations = new ArrayList<>();
        for (int[] move : possibleMoves){
            int[] location = normalize(new int[]{p[0]+move[0], p[1] + move[1]});
            if (f.isValidPosition(location) || Arrays.equals(cat, location)){
                locations.add(location);
            }
        }
        return locations;
    }
}

他如何捉住猫:

他分析了板子的所有正方形,并试图找到使板子的开度最小化并最大化板子拉出的正方形。关于猫。电路板的开放性和严格性是通过对他著名算法的修改来计算的

开放性:

相对于某个位置的木板开度是从该位置可到达的位置数。

严谨度:

板相对于位置的拉紧度是可到达位置与该位置之间的距离之和。

最后更新:

现在,他在赶上FreeCat和他自己的所有猫时要好得多。不幸的是,他在抓狂不合作的猫方面也更糟。通过检测猫是否是疯猫之一,然后充当CloseCatcher,可以使他得到改善。

错误修复。


可以确认它到目前为止是否有效,但是我认为到目前为止最慢,但最好的之一。在对RandCat的100场比赛中,需要134秒,而总共仅执行4406步!我想我将不得不在接下来的几天中让我的PC过夜运行...您能告诉我们一些工作原理吗?
瑕疵的

@flawr添加了描述。
TheNumberOne

仍然对我不起作用。给我一个错误:error: cannot infer type arguments for PriorityQueue<>在这一行上PriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {
Spikatrix

@CoolGuy您正在使用Java 6吗?我认为您需要更新您的JDK。
TheNumberOne 2015年

@CoolGuy您还可以int[]在之后的两个空钻石之间放置一个PriorityQueue
TheNumberOne 2015年

2

ForwordCatcher

将水桶放在猫的前面,或者将水桶放在猫的后面。

RabidCat vs ForwordCatcher:

RabidCat vs ForwordCatcher:

package players;

import main.Field;
import java.util.Arrays;

public class ForwordCatcher implements Catcher {
    public String getName() {
        return "ForwordCatcher";
    }

    private int[] lastPos = {0,0};

    public int[] takeTurn(Field f) {
        int[] temp = lastPos;
        int[] pos = f.findCat();
        lastPos = pos;
        int[] Move = {pos[0]*2-temp[0], pos[1]*2-temp[1]};
        if(f.isValidPosition(Move)){return Move;}
        if(f.isValidPosition(temp)){return temp;}
        Move[0] = pos[0];Move[1] = pos[1]+1;
        return Move;
    }
}

1
有很多错误,这使我想到您没有测试程序的假设。请修复这些问题
更加糟糕的

@flawr已修复。对不起,错误。我没有测试它,而我的Java也不太好。
MegaTom 2015年

很好,到目前为止,一切都进行得很顺利,但我仍然不确定它是否总是会产生有效的动作=)
更加虚假的

1
@flawr对于捕手来说,猫后面的空间将永远是空的:)
TheNumberOne

2

选择捕手

使用与我的ChoiceCat条目相同的计分机制。有一点修改,可以帮助您在开始的几个步骤中选择相关的单元格,因为ChoiceCat并不关心前几个存储桶,因为它不认为它们是威胁。

ChoiceCatcher的得分似乎比当前的catchers好得多。

ChoiceCat与ChoiceCatcher:

ChoiceCat与ChoiceCatcher

package players;
/**
 * @author randomra
 */
import java.util.Arrays;

import main.Field;

public class ChoiceCatcher implements Catcher {

    private class Values {
        public final int size;
        private double[][] f;

        Values(int size) {
            this.size = size;
            f = new double[size][size];
        }

        public double read(int[] p) {
            int i = p[0];
            int j = p[1];
            i = (i % size + size) % size;
            j = (j % size + size) % size;
            return f[i][j];
        }

        private double write(int[] p, double v) {
            int i = p[0];
            int j = p[1];
            i = (i % size + size) % size;
            j = (j % size + size) % size;
            return f[i][j] = v;
        }
    }

    final int[][] turns = { { -1, 1 }, { 0, 1 }, { 1, 0 }, { 1, -1 },
            { 0, -1 }, { -1, 0 } };// all valid moves CW order
    final int stepCheck = 5;

    public String getName() {
        return "ChoiceCatcher";
    }

    @Override
    public int[] takeTurn(Field f) {
        int[] bestPos = null;
        double bestPosValue = Double.MAX_VALUE;
        for (int i = 0; i < f.SIZE; i++) {
            for (int j = 0; j < f.SIZE; j++) {
                if (f.read(i, j) == Field.EMPTY) {
                    Field myField = new Field(f);
                    myField.placeBucket(new int[] { i, j });
                    double posValue = catTurnValue(myField);
                    if (posValue < bestPosValue) {
                        bestPosValue = posValue;
                        bestPos = new int[] { i, j };
                    }
                }
            }
        }
        return bestPos;
    }

    private double catTurnValue(Field f) {

        int[] pos = f.findCat();
        double[] values = new double[6];
        int count=0;
        for (int[] t : turns) {
            int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
            double moveValue = movePosValue(currPos, f);
            values[count++]=moveValue;
        }
        Arrays.sort(values);
        return values[5];
    }

    private double movePosValue(int[] pos, Field f) {

        Values v = new Values(f.SIZE);

        for (int ring = stepCheck; ring >= 0; ring--) {
            for (int phase = 0; phase < 2; phase++) {
                for (int sidepos = 0; sidepos < Math.max(1, ring); sidepos++) {
                    for (int side = 0; side < 6; side++) {
                        int[] evalPos = new int[2];
                        for (int coord = 0; coord < 2; coord++) {
                            evalPos[coord] = pos[coord] + turns[side][coord]
                                    * sidepos + turns[(side + 1) % 6][coord]
                                    * (ring - sidepos);
                        }
                        if (phase == 0) {
                            if (ring == stepCheck) {
                                // on outmost ring, init value
                                v.write(evalPos, -1);
                            } else {
                                v.write(evalPos, posValue(evalPos, v, f));
                            }
                        } else {
                            // finalize position value for next turn
                            v.write(evalPos, -v.read(evalPos));
                        }
                    }
                }
            }
        }

        return -v.read(pos);
    }

    private double posValue(int[] pos, Values v, Field f) {
        if (f.read(pos[0], pos[1]) == Field.BUCKET) {
            return 0;
        }
        int count = 0;
        int maxRoutes = 2;
        double[] product = new double[6];
        for (int[] t : turns) {
            int[] tPos = new int[] { pos[0] + t[0], pos[1] + t[1] };
            if (v.read(tPos) > 0) {
                product[count] = 1 - 1 / (v.read(tPos) + 1);
                count++;
            }
        }
        Arrays.sort(product);
        double fp = 1;
        for (int i = 0; i < Math.min(count, maxRoutes); i++) {
            fp *= product[5 - i];
        }
        double fp2 = 1;
        for (int i = 0; i < Math.min(count, 6); i++) {
            fp2 *= product[5 - i];
        }
        double retValue = Math.min(count, maxRoutes) + fp;
        double retValue2 = Math.min(count, 6) + fp2;
        return -retValue - retValue2 / 1000000;
    }

}

1

RandCatcher

这只是为了测试控制器而做的,只是随机地放置了存储桶(效率很低)。

package players;

import main.Field;

public class RandCatcher implements Catcher {
    public String getName(){
        return "RandCatcher";
    }
    public int[] takeTurn(Field f){
        int[] pos = {0,0};
        do {
            pos[0] = (int) (Math.random()*f.SIZE);
            pos[1] = (int) (Math.random()*f.SIZE);
        } while( f.isValidPosition(pos)==false );
        return pos;
    }

}

1

愚蠢的填充捕手

这仅用于测试控制器。它只是逐列填充直到抓到猫。

package players;

import main.Field;

public class StupidFillCatcher implements Catcher {
    public String getName(){
        return "StupidFillCatcher";
    }
    public int[] takeTurn(Field f){
        for(int i=0; i < f.SIZE; i++){
            for(int j=0; j < f.SIZE; j++){
                if(f.isValidPosition(new int[] {i,j})){
                    return new int[] {i,j};
                }
            }
        }
        return new int[] {0,0};
    }

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