비대칭 KOTH : 고양이를 잡아라 (캐처 실)


17

비대칭 KOTH : 고양이를 잡아라

UPDATE : Controller.java가 예외를 포착하지 않아 (오류 만) gist 파일이 업데이트됩니다 (새로운 서브 미슨 포함). 이제 오류와 예외를 포착하고 인쇄합니다.

이 도전은 두 개의 스레드로 구성되며, 이것은 포수 스레드이며, 고양이 스레드는 여기 에서 찾을 수 있습니다 .

컨트롤러는 여기에서 다운로드 할 수 있습니다 .

이것은 비대칭 KOTH입니다. 각 제출물은 고양이 또는 포수 입니다. 고양이와 포수의 각 쌍 사이에 게임이 있습니다. 고양이와 포수는 별개의 순위를 가지고 있습니다.

포수

육각형 격자에 고양이가 있습니다. 당신의 임무는 가능한 한 빨리 잡는 것입니다. 매 턴마다 고양이가 물에 빠지지 않도록 물통을 하나의 격자 셀에 놓을 수 있습니다. 그러나 고양이는 어리석지 않으며, 양동이를 넣을 때마다 고양이는 다른 격자 셀로 이동합니다. 격자는 육각형이므로 고양이는 6 가지 방향으로 갈 수 있습니다. 당신의 목표는 물통으로 고양이를 둘러싸고, 더 빠를수록 좋습니다.

고양이

당신은 포수가 당신 주위에 물통을 놓아서 당신을 붙잡고 싶어한다는 것을 알고 있습니다. 물론 당신은 피하려고 노력하지만, 당신은 게으른 고양이 (고양이처럼)로서 한 번에 정확히 한 걸음을 내딛습니다. 이것은 당신이 같은 곳에 머물 수는 없지만 6 개의 주변 지점 중 하나로 이동해야한다는 것을 의미합니다. 포수가 새로운 물통을 놓은 것을 볼 때마다 다른 세포로갑니다. 물론 당신은 가능한 한 오랫동안 피하려고 노력합니다.

그리드

격자는 육각형이지만 육각형 데이터 구조가 없으므로 11 x 11정사각형 2d 배열을 취하여 고양이가 6 방향으로 만 이동할 수있는 육각형 '동작'을 모방합니다.

여기에 이미지 설명을 입력하십시오

토폴로지는 환상적입니다. 즉, 어레이의 '외부'셀을 밟으면 어레이의 다른쪽에있는 해당 셀로 전송됩니다.

경기

고양이는 그리드의 지정된 위치에서 시작합니다. 포수는 첫 번째 이동을 할 수 있으며, 고양이와 캐처는 고양이가 잡힐 때까지 교대로 움직입니다. 걸음 수는 해당 게임의 점수입니다. 고양이는 가능한 한 높은 점수를 얻으려고 노력하고, 포수는 가능한 한 낮은 점수를 얻으려고 노력합니다. 참여한 모든 게임의 평균 합계가 제출 점수가됩니다. 고양이와 포수를위한 두 가지 등급이 있습니다.

제어 장치

주어진 컨트롤러는 Java로 작성되었습니다. 포수 또는 고양이는 각각 Java 클래스를 구현하고 (이미 몇 가지 기본 예제가 있음) players패키지에 배치해야 하며 컨트롤러 클래스의 고양이 / 포수 목록을 업데이트해야합니다. 해당 클래스 내의 추가 기능. 컨트롤러에는 간단한 고양이 / 캐처 클래스의 두 가지 실제 예제가 제공됩니다.

이 필드는 셀의 현재 상태 값을 저장 하는 11 x 112D 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}.

분석법이 유효하지 않은 이동을 제출하면 제출이 실격 처리됩니다. 목적지에서 버킷이 이미 있거나 이동이 이미 허용 된 목적지 / 고양이 (고양이) 또는 버킷 / 고양이 (캐처) 인 경우 이동은 유효하지 않은 것으로 간주됩니다. 주어진 기능으로 미리 확인할 수 있습니다.

제출물은 합리적으로 빠르게 작동해야합니다. 각 단계마다 방법이 200ms보다 오래 걸리면 실격 처리됩니다. (바람직하게는 훨씬 적습니다 ...)

프로그램은 단계 사이에 정보를 저장할 수 있습니다.

제출물

  • 원하는만큼 제출할 수 있습니다.
  • 이미 제출 한 제출물을 크게 변경하지 마십시오.
  • 각 답변을 새로운 답변으로 작성하십시오.
  • 각 제출물에는 고유 한 이름이 있어야합니다.
  • 제출물은 수업 코드와 제출 방식을 알려주는 설명으로 구성되어야합니다.
  • <!-- language: lang-java -->자동 구문 강조를 얻기 위해 소스 코드에 대한 행을 작성할 수 있습니다 .

채점

모든 고양이 는 모든 포수 와 같은 횟수로 경쟁 합니다. 나는 현재 점수를 자주 업데이트하려고 노력할 것이며, 활동이 감소하면 승자가 결정될 것입니다.

이 도전은 이 오래된 플래시 게임에서 영감을 얻었습니다.

테스트하고 건설적인 피드백을 준 @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

애니메이션은 GUI 일뿐입니다 (컨트롤러를 시작할 때 PRINT_STEPS = true파일에서 더 자세한 설정을해야합니다 MyFrame.java). 그런 다음 LICEcap으로 이것을 기록 하고 GIMP로 편집했습니다 . 더 궁금한 점이 있으면 물어보십시오!
flawr

컨트롤러에 사용자 입력을 추가하면 GUI와 봇이 이미 작성된 멋진 소프트웨어를 만들 수 있습니다. 인간이 특정 봇 전략을 얼마나 많이 크랙 / 오용 할 수 있는지 보는 것도 흥미로울 것입니다.
randomra

또한 내 봇은 이전 봇의 정보를 유지하여 동일한 봇에 대해 더 나은 이동 순서를 찾을 수 있습니까? 나는 당신이 더 많은 라운드를 더 좋아지기 때문에 생각하지 않습니다. 또한 새로운 봇을 상대로 플레이하고 있는지 추측해야하므로 실행 순서도 중요합니다.
randomra

1
고양이의 점수가 정렬되지 않은 이유는 무엇입니까?
Spikatrix

답변:


6

아킬레스

아킬레스는 너무 밝지는 않지만 무자비하게 효율적입니다. 먼저 고양이가 보드를 감싸는 것을 막고 보드를 둘로 나눕니다. 그런 다음 그는 고양이가 갇힐 때까지 고양이의 보드 부분을 반으로 나눕니다.

RandCat vs Achilles 데모

랜드 캣 vs 아킬레스

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



}

아킬레스, 헥터? (또는 dissiociative identity disorder를 가진 사람? =)
flawr

당신이 차 후 프로그램 할 때 :( 발생하는 상황 - @flawr 아킬레스는, 롤 나는 (이 포수 아킬레스와 고양이 헥터의 이름을 더 쉽다이다)을 통해 이름 반 방식을 변경하지만 자바를 변경하는 것을 잊었다
euanjt

그러나 Hector는 오히려 개 이름이 될 것입니다 =) 제출해 주셔서 감사합니다. 코드에 '프리앰블'도 포함되어 있기를 바랍니다.
flawr

그래 문제 없어 헥터는 개 이름처럼
들리지만

방금 시뮬레이션을 실행했으며 (각 페어링 당 10000 게임) StackOverflowError가 반복되어 Achilles가 실격되었습니다. 재귀가 끝나지 않았다고 생각합니다. pastebin.com/9n6SQQnd
flawr

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

이 포수는 Achilles보다 일관되게 더 우수하며 새로운 답변을 보장 할만큼 충분히 다르다고 생각합니다.


아주 좋은 해결책, 나는 Achilles가 최적에 가깝다고 확신했지만, 이제 Agamemnon조차 약간 개선 될 수 있다고 생각합니다 =)
flawr

예, Agamemnon은 Achilles보다 훨씬 나은 엔드 게임 트래핑 알고리즘을 가지고 있지만 약간의 조정이있을 것입니다 ... 이제 고양이를 시도하고 작업
하겠습니다

@flawr 매우 특별한 조정은 특별한 경우에 잡기 속도를 높이기 위해 추가되었지만 여기의 애니메이션에는 영향을 미치지 않습니다 (SpiralCat의 애니메이션에 영향을 줄 수 있다고 생각하지만)
euanjt

질문! 줄을 닫으려고하지만 고양이가 마지막 자리에 서 있으면 어떻게됩니까?
Mr. Llama

@ Mr.Llama는 그 라인이 채워진 것처럼 다음 라인을 만들기 시작합니다 (즉, 고양이는 실제로 양동이였습니다)-가장 효과적인 턴 사용은 아니지만 실제로 중요하지 않은 경우는 거의 없습니다. 고양이가 다음 차례에
물러나서

5

육각 캐처

포수가 육각형의 모서리가 이미 양동이로 채워져있는 3 개의 측면이있는 큰 육각형 내부에 고양이를 넣을 수 있다면, 포수는이 지역에 고양이를 유지하고 그를 잡을 수 있습니다. 육각형은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

이것이 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 vs. CloseCatcher :

스파이럴 캣 vs 클로즈 캐쳐

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 회의 게임에 총 406 초가 필요합니다. 다음 날 중 하나에 PC를 밤새 가동시켜야한다고 생각합니다. 어떻게 작동하는지 조금 말씀해 주시겠습니까?
flawr

@flawr 설명을 추가했습니다.
TheNumberOne

여전히 나를 위해 작동하지 않습니다. error: cannot infer type arguments for PriorityQueue<>이 줄에 하나의 오류가 발생합니다 PriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {.
Spikatrix

@CoolGuy java 6을 사용하고 있습니까? JDK를 업데이트해야한다고 생각합니다.
TheNumberOne 2016 년

@CoolGuy 또한 int[]두 개의 빈 다이아몬드 사이에 사이를 둘 수도 있습니다 PriorityQueue.
TheNumberOne

2

포워드 캐쳐

고양이 앞에 양동이를 두거나, 가지고 있다면, 뒤에 배치하십시오.

RabidCat 및 ForwordCatcher :

RabidCat 및 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

@flawr가 수정되었습니다. 오류에 대해 죄송합니다. 나는 그것을 테스트하지 않았고 나의 Java는 좋지 않다.
MegaTom 2016 년

좋았습니다. 지금까지 모든 것이 순조롭게 진행되고 있지만, 여전히 유효한 움직임을 만들어
낼지

1
@flawr 고양이 뒤의 공간은 항상 포수를 위해 비어있을 것입니다 :)
TheNumberOne

2

초이스 캐처

내 ChoiceCat 항목 과 동일한 점수 매기기 메커니즘을 사용합니다 . ChoiceCat은 위협으로 간주되지 않으므로 처음 몇 개의 버킷에 대해서는 신경 쓰지 않기 때문에 처음 몇 단계에서 관련 셀을 선택하는 데 도움이되는 약간의 수정이 있습니다.

ChoiceCatcher는 현재 포수보다 훨씬 높은 점수를 얻는 것으로 보입니다.

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

랜드 캐처

이것은 컨트롤러를 테스트하기 위해 만들어졌으며 버킷을 무작위로 배치합니다 (매우 비효율적).

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

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.