KOTH bất đối xứng: Bắt mèo (Chủ đề bắt chuột)


17

KOTH bất đối xứng: Bắt mèo

CẬP NHẬT : Các tệp chính được cập nhật (bao gồm cả các tệp con mới) vì Trình điều khiển.java không bắt Ngoại lệ (chỉ có lỗi). Bây giờ nó bắt lỗi và ngoại lệ và cũng in chúng.

Thử thách này bao gồm hai luồng, đây là luồng bắt, sợi mèo có thể tìm thấy ở đây .

Bộ điều khiển có thể được tải xuống ở đây .

Đây là một KOTH bất đối xứng: Mỗi lần gửi là một con mèo hoặc một người bắt . Có những trò chơi giữa mỗi cặp của một con mèo và một người bắt. Những con mèo và những người bắt có bảng xếp hạng riêng biệt.

Bắt bóng

Có một con mèo trên lưới lục giác. Nhiệm vụ của bạn là bắt nó càng nhanh càng tốt. Mỗi lượt, bạn có thể đặt một xô nước trên một ô lưới để ngăn mèo không thể đến đó. Nhưng con mèo không (có lẽ) bị câm, và bất cứ khi nào bạn đặt một cái xô, con mèo sẽ di chuyển đến một ô lưới khác. Vì lưới là hình lục giác, con mèo có thể đi theo 6 hướng khác nhau. Mục tiêu của bạn là bao quanh con mèo bằng xô nước, càng nhanh càng tốt.

Con mèo

Bạn biết người bắt bóng muốn bắt bạn bằng cách đặt xô nước xung quanh bạn. Tất nhiên bạn cố gắng trốn tránh, nhưng vì bạn là một con mèo lười biếng (như mèo), bạn chính xác thực hiện một bước tại thời điểm đó. Điều này có nghĩa là bạn không thể ở cùng một nơi với bạn, nhưng bạn phải di chuyển đến một trong sáu điểm xung quanh. Bất cứ khi nào bạn thấy rằng người bắt được đặt một thùng nước mới, bạn đi đến một tế bào khác. Tất nhiên bạn cố gắng trốn tránh càng lâu càng tốt.

Lưới

Lưới là hình lục giác, nhưng vì chúng tôi không có cấu trúc dữ liệu hình lục giác, chúng tôi lấy một 11 x 11mảng 2d vuông và bắt chước 'hành vi' hình lục giác mà con mèo chỉ có thể di chuyển theo 6 hướng:

nhập mô tả hình ảnh ở đây

Cấu trúc liên kết là hình xuyến, có nghĩa là nếu bạn bước vào một ô 'bên ngoài' của mảng, bạn sẽ chỉ được chuyển đến ô tương ứng ở phía bên kia của mảng.

Trò chơi

Con mèo bắt đầu ở vị trí nhất định trong lưới. Người bắt có thể thực hiện động tác đầu tiên, sau đó con mèo và người bắt nó thay phiên nhau di chuyển cho đến khi con mèo bị bắt. Số bước là số điểm cho trò chơi đó. Con mèo cố gắng để có được điểm số lớn nhất có thể, người bắt bóng cố gắng để có được điểm càng thấp càng tốt. Tổng số trung bình trên tất cả các trò chơi bạn tham gia sẽ là số điểm bạn gửi. Có hai bảng xếp hạng riêng biệt, một cho mèo, một cho người bắt.

Bộ điều khiển

Bộ điều khiển đã cho được viết bằng Java. Là một người bắt hoặc một con mèo, mỗi người phải hoàn thành một lớp Java (đã có một số ví dụ nguyên thủy) và đặt nó trong playersgói (và cập nhật danh sách các con mèo / người bắt trong lớp Trình điều khiển), nhưng bạn cũng có thể viết chức năng bổ sung trong lớp đó. Bộ điều khiển đi kèm với mỗi hai ví dụ hoạt động của các lớp bắt / mèo đơn giản.

Trường này là một mảng 11 x 112D- intlưu trữ các giá trị của trạng thái hiện tại của các ô. Nếu một ô trống, nó có giá trị 0, nếu có một con mèo thì nó có giá trị -1và nếu có một cái xô thì có a 1.

Có một số chức năng nhất định bạn có thể sử dụng: isValidMove()/ isValidPosition()là để kiểm tra xem di chuyển (con mèo) / vị trí (người bắt) của bạn có hợp lệ không.

Mỗi khi đến lượt của bạn, chức năng của bạn takeTurn()được gọi. Đối số chứa bản sao của lưới hiện tại và có các phương thức như read(i,j)để đọc ô tại (i,j), cũng như isValidMove()/ isValidPosition()kiểm tra tính hợp lệ của câu trả lời của bạn. Điều này cũng quản lý việc bao bọc cấu trúc liên kết hình xuyến, có nghĩa là ngay cả khi lưới chỉ có 11 x 11, bạn vẫn có thể truy cập vào ô (-5,13).

Phương thức sẽ trả về một intmảng gồm hai phần tử, đại diện cho các di chuyển có thể. Đối với những con mèo này là {-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}những vị trí đại diện cho vị trí tương đối của nơi con mèo muốn đi và người bắt trả lại tọa độ tuyệt đối của nơi chúng muốn đặt một cái xô {i,j}.

Nếu phương pháp của bạn tạo ra một động thái không hợp lệ, việc gửi của bạn sẽ bị loại. Di chuyển được coi là không hợp lệ, nếu tại điểm đến của bạn đã là một cái xô hoặc di chuyển không được phép / đích đã bị chiếm đóng (như một con mèo) hoặc nếu đã có một cái xô / con mèo (như một người bắt). Bạn có thể kiểm tra trước khi thực hiện với các chức năng nhất định.

Trình của bạn nên làm việc hợp lý nhanh chóng. Nếu phương pháp của bạn mất hơn 200ms cho mỗi bước thì nó cũng sẽ bị loại. (Tốt hơn là ít hơn nhiều ...)

Các chương trình được phép lưu trữ thông tin giữa các bước.

Đệ trình

  • Bạn có thể thực hiện nhiều bài nộp như bạn muốn.
  • Vui lòng không thay đổi đáng kể các bài nộp bạn đã gửi.
  • Xin vui lòng mỗi bài nộp trong một câu trả lời mới.
  • Mỗi bài nộp tốt nhất nên có tên duy nhất của nó.
  • Việc gửi phải bao gồm mã của lớp của bạn cũng như một mô tả cho chúng tôi biết cách gửi của bạn hoạt động.
  • Bạn có thể viết dòng trước <!-- language: lang-java -->mã nguồn của bạn để có được tô sáng cú pháp tự động.

Chấm điểm

Tất cả các con mèo sẽ cạnh tranh với tất cả những người bắt cùng một số lần. Tôi sẽ cố gắng cập nhật điểm số hiện tại thường xuyên, người chiến thắng sẽ được xác định khi hoạt động đã giảm.

Thử thách này được lấy cảm hứng từ trò chơi flash cũ này

Cảm ơn @PhiNotPi đã thử nghiệm và đưa ra một số phản hồi mang tính xây dựng.

Điểm hiện tại (100 trò chơi cho mỗi cặp)

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

Chương trình nào làm cho hình ảnh động?
MegaTom

Hoạt hình chỉ là GUI (khi khởi động bộ điều khiển bạn phải đặt PRINT_STEPS = true, cài đặt chi tiết hơn trong tệp MyFrame.java). Sau đó, tôi đã ghi lại điều này với LICEcap và chỉnh sửa nó bằng GIMP . Nếu bạn có thêm câu hỏi chỉ cần hỏi!
flawr

Nếu bạn thêm đầu vào của người dùng vào bộ điều khiển, nó có thể tạo ra một phần mềm đẹp với GUI và các bot đã được viết. Sẽ rất thú vị khi xem con người có thể bẻ khóa / lạm dụng các chiến lược bot cụ thể đến mức nào.
ngẫu nhiên

Ngoài ra, bot của tôi có thể giữ thông tin từ trận đấu trước để cố gắng tìm chuỗi di chuyển tốt hơn so với cùng bot không? Tôi cho rằng không phải vì nó trở nên tốt hơn khi bạn làm nhiều vòng hơn. Nó cũng sẽ phải đoán nếu nó đang chơi với một bot mới, vì vậy thứ tự chạy cũng rất quan trọng.
ngẫu nhiên

1
Tại sao điểm số của những con mèo không được sắp xếp?
Spikatrix

Câu trả lời:


6

Achilles

Achilles không quá sáng nhưng anh ta hiệu quả một cách tàn nhẫn. Đầu tiên anh ta ngăn con mèo sử dụng cái bọc quanh tấm ván, sau đó anh ta chia tấm ván thành hai. Sau đó, anh ta tiếp tục chia phần của tấm ván cho con mèo thành một nửa cho đến khi con mèo bị mắc kẹt.

Trình diễn RandCat vs Achilles

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



}

Chà cái nào bây giờ, Achilles hay Hector? (Hoặc ai đó bị rối loạn nhận dạng phân ly? =)
flawr 30/05/2015

@flawr Achilles, lol Tôi đã thay đổi tên nửa chừng (nên đặt tên cho người bắt Achilles và chú mèo Hector) nhưng quên thay đổi java - đó là điều xảy ra khi bạn lập trình sau khi uống trà :(
euanjt

Nhưng Hector thà là một tên chó =) Cảm ơn bạn đã gửi bài tuyệt vời. Tôi hy vọng bạn không bận tâm rằng tôi cũng bao gồm 'lời mở đầu' trong mã của bạn.
flawr

Vâng không có vấn đề. Hector nghe có vẻ giống tên một con chó ...
euanjt

Tôi chỉ chạy một mô phỏng (10000 trò chơi cho mỗi cặp) và Achilles đã bị loại, do StackOverflowError lặp đi lặp lại. Tôi nghĩ rằng đệ quy chưa kết thúc: pastebin.com/9n6SQQnd
flawr

5

Agamemnon

Agamemnon chia đôi khu vực mèo bằng một đường thẳng đứng cho đến khi con mèo chỉ có một dải rộng 2 để di chuyển vào, lúc đó nó bẫy con mèo.

Agamemnon vs RandCat:

nhập mô tả hình ảnh ở đây

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

Người bắt bóng này luôn giỏi hơn Achilles và tôi nghĩ anh ta đủ khác biệt để đảm bảo một câu trả lời mới.


Giải pháp rất hay, tôi chắc chắn rằng Achilles đã gần đạt đến mức tối ưu, nhưng bây giờ tôi nghĩ ngay cả Agamemnon cũng có thể được cải thiện một chút =)
flawr

Vâng, Agamemnon có thuật toán bẫy trò chơi kết thúc tốt hơn nhiều so với Achilles, nhưng tôi khá chắc chắn có một số điều chỉnh ... Bây giờ tôi sẽ thử và làm việc với một con mèo :)
euanjt

@flawr tinh chỉnh rất nhỏ được thêm vào để tăng tốc độ bắt trong một số trường hợp đặc biệt, điều này không ảnh hưởng đến hoạt hình ở đây (mặc dù tôi nghĩ rằng nó có thể ảnh hưởng đến hoạt hình của TwistCat)
euanjt

Câu hỏi! Điều gì xảy ra nếu bạn sắp đóng một dòng, nhưng con mèo đang đứng ở vị trí cuối cùng?
Ông Llama

@ Mr.Llama nó bắt đầu thực hiện dòng tiếp theo như thể dòng đó đã được lấp đầy (ví dụ: con mèo thực tế là một cái xô) - không phải là cách sử dụng lần lượt hiệu quả nhất nhưng rất hiếm khi nó không thực sự quan trọng sau đó con mèo phải di chuyển đi trong lượt tiếp theo để tôi có thể đặt cái xô của mình ở đó
euanjt

5

HexCatcher

Nếu người bắt có thể đưa con mèo vào bên trong một hình lục giác lớn với 3 đơn vị cạnh trong đó các góc của hình lục giác đã bị chiếm bởi xô, người bắt có thể giữ con mèo ở khu vực này và bắt nó. Hình lục giác trông như thế này:

nhập mô tả hình ảnh ở đây

Đây là những gì HexCatcher cố gắng đạt được. Nó tinh thần xếp trường với các hình lục giác lớn theo cách mà mỗi ô góc là một phần của 3 hình lục giác lớn.

Nếu có cơ hội giữ mèo trong khu vực hiện tại bằng cách kết nối hai góc bên cạnh con mèo, bot sẽ làm điều đó. (Ví dụ: trong hình ảnh nếu con mèo ở mức 7,5, chúng tôi chọn 7.6 ngay cả khi chỉ chiếm 6,6 và 8,5 ô.)

Nếu trước đó không phải là một lựa chọn, chúng tôi chọn chơi một góc là một phần của khu vực có con mèo. Nếu tất cả các góc như vậy đã được chọn (như trong ảnh), chúng tôi chọn một ô bên cạnh con mèo.

Nhiều cải tiến nhỏ có thể được thực hiện như xử lý bọc xung quanh tốt hơn (ốp lát ở đó) hoặc thực hiện cặp đôi cuối cùng di chuyển tối ưu. Tôi có thể làm một số trong số này. Nếu nó không được phép, tôi sẽ chỉ nối nó (ngoài cuộc thi) cho những người quan tâm.

DijkstrasCat vs HexCatcher:

nhập mô tả hình ảnh ở đây

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

Đóng

Chọn một trong những vị trí mà con mèo có thể bước trong bước tiếp theo. Nó chọn con đường nào sẽ đưa ra những con đường khả dĩ nhất sau 3 bước cho con mèo nếu nó di chuyển đến đó và cánh đồng sẽ không thay đổi.

Mã gần giống với mục Cat của tôi, FreeCat , chọn hướng theo cách rất giống nhau.

Xoắn ốc vs CloseCatcher:

Xoắn ốc vs 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;
    }

}

Đẹp +1. CloseCatcher dễ dàng chụp StraightCat
Spikatrix

3

Dijkstra

Anh ấy không thích mèo lắm (:v{ >

FreeCat vs Dijkstra (cần cập nhật) :

nhập mô tả hình ảnh ở đây

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

Làm thế nào anh ta cố gắng để bắt con mèo:

Ông phân tích tất cả các ô vuông của bảng và cố gắng tìm ra ô vuông giảm thiểu độ mở của bảng, và tối đa hóa mức độ của bảng được xâu ra; liên quan đến con mèo. Độ mở và tính nghiêm ngặt của một bảng được tính toán bằng cách sửa đổi thuật toán nổi tiếng của ông .

Sự cởi mở:

Độ mở của một bảng so với vị trí là số lượng vị trí có thể tiếp cận từ vị trí đó.

Tính nghiêm ngặt:

Sự nghiêm ngặt của một bảng so với một vị trí là tổng khoảng cách giữa các vị trí có thể tiếp cận và vị trí.

Với bản cập nhật mới nhất:

Bây giờ, anh ấy đã tốt hơn rất nhiều khi bắt FreeCat và con mèo của anh ấy đều là mèo.Thật không may, anh ta cũng tệ hơn nhiều khi bắt những con mèo bất hợp tác điên rồ. Anh ta có thể được cải thiện bằng cách phát hiện nếu con mèo là một trong những kẻ điên và sau đó đóng vai trò là CloseCatcher.

Đã sửa chữa lỗi không mong muốn.


Có thể xác nhận nó hoạt động cho đến nay, nhưng cho đến nay chậm nhất nhưng là một trong những tốt nhất cho đến nay tôi nghĩ. Cần 134 giây cho 100 trận đấu với RandCat trong khi thực hiện tổng cộng chỉ 4406 lần di chuyển! Tôi nghĩ rằng tôi sẽ phải để máy tính của mình chạy qua đêm vào một trong những ngày tiếp theo ... Bạn có thể cho chúng tôi biết một chút về cách thức hoạt động của nó không?
flawr

@flawr Đã thêm mô tả.
TheNumberOne

Vẫn không làm việc cho tôi. Cung cấp cho tôi một lỗi: error: cannot infer type arguments for PriorityQueue<>trên dòng này PriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {.
Spikatrix

@CoolGuy Bạn đang sử dụng java 6? Tôi nghĩ bạn cần cập nhật JDK của bạn.
TheNumberOne

@CoolGuy Bạn cũng có thể đặt một int[]giữa hai viên kim cương rỗng sau PriorityQueue.
TheNumberOne

2

ForwordCatcher

Đặt một cái xô ở phía trước con mèo, hoặc nếu nó được lấy, đặt phía sau.

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
Có một vài lỗi dẫn đến giả định rằng bạn không kiểm tra chương trình của mình. Hãy sửa những ...
flawr

@flawr đã sửa. xin lỗi về các lỗi Tôi đã không kiểm tra nó và Java của tôi không tốt.
MegaTom

Thật tuyệt, cho đến nay mọi thứ đều diễn ra suôn sẻ, nhưng tôi vẫn không chắc liệu nó có luôn tạo ra những bước đi hợp lệ không =)
flawr

1
@flawr Không gian phía sau một con mèo sẽ luôn trống cho người bắt :)
TheNumberOne

2

Lựa chọn

Sử dụng cơ chế tính điểm tương tự như mục Lựa chọn của tôi . Có một sửa đổi nhỏ giúp chọn các ô có liên quan ở một số bước đầu tiên vì ChoiceCat không quan tâm đến một số nhóm đầu tiên vì nó không xem chúng là mối đe dọa.

ChoiceCatcher dường như ghi điểm tốt hơn đáng kể so với những người bắt hiện tại.

Lựa chọn so với Lựa chọn:

Lựa chọn vs Lựa chọn

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

Điều này được thực hiện chỉ để kiểm tra bộ điều khiển và chỉ đặt ngẫu nhiên các thùng (rất không hiệu quả).

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

St nguFillCatcher

Điều này đã được thực hiện chỉ để thử nghiệm bộ điều khiển. Nó chỉ lấp đầy từng cột cho đến khi con mèo bị bắt.

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

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.