Асиметрична КОТЯ: Лови кота (нитка видовища)


17

Асиметрична КОТЯ: Лови кота

ОНОВЛЕННЯ : Файли gist оновлюються (включаючи нові підрозділи), оскільки Controller.java не вловлює Винятки (лише помилки). Тепер він вловлює помилки та винятки, а також друкує їх.

Цей виклик складається з двох ниток, це нитка виловлювача, котячу нитку можна знайти тут .

Контролер можна завантажити тут .

Це асиметрична КОТЯ: Кожне подання - це кішка чи ловець . Існують ігри між кожною парою кожної кішки та видовищем. Коти та ловці мають окремий рейтинг.

Ловець

На шестикутній сітці лежить кішка. Ваше завдання - зловити це якомога швидше. Щоразу, ви можете розмістити відро з водою на одній осередку сітки, щоб не допустити, щоб кішка могла туди ходити. Але кішка не є (можливо) такою німою, і кожен раз, коли ви помістите відро, кішка перейде до іншої сітки для сітки. Оскільки сітка є шестикутною, кішка може йти в 6 різних напрямках. Ваша мета - оточити кота відрами з водою, чим швидше, тим краще.

Кіт

Ви знаєте, що ловець хоче зловити вас, розміщуючи навколо себе відра з водою. Звичайно, ви намагаєтесь ухилитися, але, як ви ледачий кіт (як і кішки), ви точно робите один крок на час. Це означає, що ви не можете залишитися на тому ж самому місці, але вам доведеться переїхати до одного з шести навколишніх місць. Щоразу, коли ви побачите, що ловитель помістив нове відро з водою, ви переходите до іншої камери. Звичайно, ви намагаєтесь уникнути якомога довше.

Сітка

Сітка є гексагональною, але оскільки у нас немає шестикутної структури даних, ми беремо 11 x 11квадратний 2d масив і імітуємо шестикутну «поведінку», якою кішка може рухатись лише у 6 напрямках:

введіть тут опис зображення

Топологія є тороїдальною, це означає, що якщо ви наступите на клітинку "поза" масиву, вас просто перенесуть до відповідної комірки з іншого боку масиву.

Гра

Кішка починає в заданому положенні в сітці. Ловець може зробити перший хід, тоді кішка та її ловець чергують рухи, поки кішка не буде спіймана. Кількість кроків - оцінка за цю гру. Кіт намагається отримати максимально високий бал, видовище намагається отримати бал якомога нижче. Середня сума за всі ігри, в яких ви брали участь, становитиме бал за вашу заявку. Є два окремі рейтинги: один для кота, один для виловлювачів.

Контролер

Даний контролер написаний на Java. Як ловець або кішка, ви повинні кожен із них реалізувати клас Java (вже є кілька примітивних прикладів) і помістити його вplayers пакет (і оновити список котів / виловлювачів у класі Controller), але ви також можете написати додаткові функції в межах цього класу. Контролер постачається з двома робочими прикладами простих класів кішок / виловлювачів.

Поле - це 11 x 112D- intмасив, який зберігає значення поточних станів комірок. Якщо клітинка порожня, вона має значення 0, якщо є кішка, вона має значення, -1а якщо є відро - є 1.

Ви можете використовувати декілька заданих функцій: isValidMove()/ isValidPosition()для перевірки, чи ваш рух (кішка) / положення (ловець) дійсний.

Кожен раз, коли настає ваша черга, ваша функція takeTurn()викликається. Аргумент містить копію поточної сітки an має такі методи, як read(i,j)зчитування комірки at (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 --> вихідного коду, щоб отримати автоматичне виділення синтаксису.

Оцінка балів

Усі коти змагатимуться проти всіх ловців однаково стільки разів. Я намагаюся часто оновлювати поточні результати, переможці визначатимуться, коли активність зменшиться.

Цей виклик натхненний цю стару флеш-гру

Дякуємо @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

Анімація - це просто графічний інтерфейс (при запуску контролера вам доведеться встановити PRINT_STEPS = trueбільш детальні налаштування у файлі MyFrame.java). Потім я записав це за допомогою LICEcap і відредагував це за допомогою GIMP . Якщо у вас є додаткові запитання, просто запитайте!
недолік

Якщо ви додасте вхід користувача до контролера, це може зробити приємне програмне забезпечення з графічним інтерфейсом та вже написаними ботами. Було б також цікаво подивитися, наскільки люди можуть розламати / зловживати конкретними стратегіями бота.
випадкова

Також, чи може мій бот зберігати інформацію з попереднього матчу, щоб спробувати знайти кращу послідовність переміщення проти того самого бота? Я гадаю, що не тому, що стає краще, чим більше турів. Також слід було б здогадатися, чи грає він проти нового бота, тому порядок роботи теж матиме значення.
випадкова

1
Чому партитура кішок не впорядкована?
Spikatrix

Відповіді:


6

Ахілл

Ахілл не надто яскравий, але він безжально ефективний. Спочатку він зупиняє кішку від використання обгортки навколо дошки, потім розділяє дошку на дві частини. Потім він продовжує ділити частину дошки, кота знаходиться навпіл, поки кішка не потрапить у пастку.

Демонстрація RandCat проти Ахілла

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



}

Ну який це зараз, Ахілл чи Гектор? (Або хтось із диссіоціативним розладом ідентичності? =)
недолік

@flawr Achilles, lol Я змінив назву на півдорозі (це більш придатно назвати ловця Ахілла та кота Гектора), але забув змінити java - це те, що відбувається, коли ви програмуєте після чаю :(
euanjt

Але Гектор скоріше буде називати собаку =) Дякую за те, що ти подаєшся чудово Сподіваюсь, ви не заперечуєте, що я також включаю 'преамбулу' у ваш код.
невдача

Так, ніяких проблем. Гектор звучить як ім'я собак ...
euanjt

Я щойно запустив симуляцію (10000 ігор на кожне сполучення), і Ахілл був дискваліфікований через повторний StackOverflowError. Я думаю, що рекурсія не закінчилася: pastebin.com/9n6SQQnd
flawr

5

Агамемнон

Агамемнон розбиває ділянку котів навпіл вертикальною лінією, поки у кішки залишиться лише смужка шириною 2 для переміщення, і в цей момент він захопить кота.

Агамемнон проти RandCat:

введіть тут опис зображення

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

Цей виловлювач справляється незмінно краще, ніж Ахілл, і я думаю, що він досить інший, щоб вимагати нової відповіді.


Дуже приємне рішення, я був впевнений, що Ахілл був близький до оптимального, але зараз я думаю, що навіть Агамемнон можна було б трохи покращити =)
недолік

Так, у Агамемнона є набагато кращий алгоритм захоплення гри, ніж Ахілл, але я впевнений, що є якісь налаштування ... Тепер я спробую попрацювати над котом :)
euanjt

@flawr дуже крихітний твіт додається для прискорення лову в деяких особливих випадках, це не впливає на анімацію тут (хоча я думаю, це може вплинути на анімацію
SpiralCat

Питання! Що станеться, якщо ви збираєтеся закрити лінію, але кішка стоїть на останньому місці?
Містер Лама

@ Mr.Llama він починає робити наступний рядок так, ніби цей рядок був заповнений (тобто кішка насправді була відром) - не найефективніше використання повороту, але трапляється дуже рідко, що це насправді не має значення - потім кішка повинна переїхати на наступному кроці, щоб я міг помістити своє відро туди
euanjt

5

HexCatcher

Якщо видовище може завести кота всередину великого шестикутника з 3-х бокових сторін, де кути шестикутника вже зайняті відрами, то ловитель може утримувати кота в цій зоні і ловити його. Шестикутник виглядає так:

введіть тут опис зображення

Цього намагається досягти HexCatcher. Він подумки плитки поля цими великими шестикутниками таким чином, що кожна кутова клітина є частиною 3 великих шестикутників.

Якщо є шанс утримати кішку в поточній зоні, з'єднавши два куточки поруч з котом, бот зробить це. (Наприклад, на зображенні, якщо кішка в 7,5, ми вибираємо 7,6, навіть якщо тільки 6,6 та 8,5 клітини ще зайняті.)

Якщо попередній варіант не є, ми обираємо куточок, який є частиною області, де знаходиться кішка. Якщо всі такі куточки вже вибрані (як на зображенні), ми вибираємо клітинку поруч з котом.

Можливі кілька невеликих вдосконалень, такі як обробка обертання краще (обрив плитки там) або виконання останньої пари оптимально. Я можу зробити щось із цього. Якщо це не дозволено, я просто додати його (поза конкуренцією) для зацікавлених.

DijkstrasCat - 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

CloseCatcher

Вибирає одне з положень, куди кішка могла б наступити на наступному кроці. Він вибирає той, який дав би найбільш можливі шляхи через 3 кроки для кота, якщо він переміститься туди і поле не зміниться.

Код майже ідентичний моєму коту, FreeCat , який вибирає напрямок дуже подібним чином.

SpiralCat vs CloseCatcher:

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

}

Приємний +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.

Виправлено помилку.


Можу підтвердити, що вона працює досі, але, напевно, найповільніша, але одна з найкращих на даний момент, я думаю. Потрібно 134 секунди на 100 ігор проти RandCat, роблячи всього лише 4406 ходів! Я думаю, що мені доведеться дозволити моєму ПК працювати протягом ночі в один з наступних днів ... Чи можете ви сказати нам трохи мор про те, як це працює?
недолік

@flawr Додав опис.
TheNumberOne

Все ще не працює для мене. Подає мені одну помилку: error: cannot infer type arguments for PriorityQueue<>у цьому рядку PriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {.
Spikatrix

@CoolGuy Ви використовуєте java 6? Я думаю, вам потрібно оновити JDK.
TheNumberOne

@CoolGuy Ви також можете поставити int[]між двома порожніми діамантами після PriorityQueue.
TheNumberOne

2

ForwordCatcher

Розміщує відро перед котом, або якщо це взято, місця позаду.

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 виправлено. вибачте за помилки. Я цього не тестував, і моя Java не на користь.
MegaTom

Добре, поки що все працює гладко, але я все ще не впевнений, чи завжди це буде робити дійсні кроки =)
flawr

1
@flawr Місце для кота завжди буде порожнім для видовища :)
TheNumberOne

2

ChoiceCatcher

Використовується той же механізм оцінювання, що і мій запис ChoiceCat . Існує невелика модифікація, яка допомагає вибирати відповідні комірки на перших кроках, оскільки ChoiceCat не піклується про перші кілька відер, оскільки не сприймає їх як загрозу.

ChoiceCatcher, здається, набирає значно кращий результат, ніж нинішні виловлювачі.

ChoiceCat vs 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

StupidFillCatcher

Це було зроблено просто для тестування контролера. Він просто заповнює стовпчик за стовпцем, поки кішка не спіймана.

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

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.