Игра на выживание - создай своего волка


238

Доска

Совет представляет собой двумерный массив ячеек. Клетки населены животными . Каждый день все животные на доске одновременно делают один ход. Если два или более животных перемещаются в одну и ту же клетку, они сражаются, пока не останется одно. Возможные ходы и атаки следующие:

  • Ходы - { Move.UP, Move.RIGHT, Move.DOWN, Move.LEFT, Move.HOLD}
  • Атаки - { Attack.ROCK, Attack.PAPER, Attack.SCISSORS, Attack.SUICIDE}

Животные сражаются, играя в Каменные Ножницы. Стандартные правила применяются, но с двумя модификациями. Во-первых, вы можете совершить самоубийство в любое время. Во-вторых, галстук рвется случайно. Если сталкиваются более двух животных, два псевдослучайно выбираются для битвы, пока не останется одно.

Игроки

Поведение и внешний вид животных заключается в следующем.

  • лев
    • Представлено персонажем L. Двигается DOWN, RIGHTзатем повторяется. Псевдослучайно атакует с помощью PAPERили SCISSORS.
  • нести
    • Представлено персонажем B. Перемещается DOWNх 4, RIGHTх 4, UPх 4, LEFTх 4, затем повторяется. Атакует с PAPER.
  • Камень
    • Представлено персонажем S. Ходы HOLD. Атакует с ROCK.
  • волк
    • Будут включены только волки, представленные в качестве ответа. Обозначается буквой W Ходит любым ходом. Атаки с любой атакой

Вы реализуете Wolf, заполняя пробелы в следующем шаблоне. Все материалы должны быть на Java и должны содержаться в одном файле. В качестве альтернативы, @ProgrammerDan написал класс-обертку, который распространяет конкуренцию на не-Java-заявки.

// Optional code here
public class Wolf extends Animal {
    // Optional code here
    public Wolf() { super('W'); /* Optional code here */ }
    public Attack fight(char opponent) { /* Required code here. Must return an Attack. */ }
    public Move move() { /* Required code here. Must return a Move. */ }
    // Optional code here
}

Сдача с наибольшим средним числом живых волков после пяти испытаний с 1000 итерациями выигрывает. Я буду обновлять победителя каждый раз, когда публикуется новый ответ (но не в течение первых 24 часов).

инструменты

  • Вам предоставляется небольшая карта вашего ближайшего окружения в следующем виде.
    • char[][] surroundingsИндекс ноль, 3 на 3 матрицы символов, которые представляют близлежащих животных. Пустые плитки представлены символом пробела (''). Вы находитесь surroundings[1][1]. Например, справа от вас будет surroundings[1][2], а над вами есть surroundings[0][1]. Ваше окружение обновляется непосредственно перед тем, как вас попросят переехать, но может быть устаревшим, когда вас попросят сражаться.
  • Вы можете сохранять данные между вызовами ваших запросов Wolf, Move и Attack. Вы не можете ни читать, ни изменять файлы, созданные другим классом Wolf.
  • Вам предоставляется размер карты в следующей форме
    • int MAP_SIZE

Предположения

  • Все материалы будут соревноваться на одной доске с другими материалами, а также со львами, медведями и камнями.
  • Доска - это квадрат со сторонами длины, sqrt(n+3)*20где nуказано количество заявок. Все стороны обертывают, так что вы можете безопасно двигаться в любом направлении бесконечно.
  • Симуляция начинается с ~ 25% емкости доски со 100 каждым животным, псевдослучайно распределенным по доске.
  • Если животное выдает исключение, когда его просят переехать, это животное HOLD
  • Если Животное выдает исключение, когда его просят сражаться, это Животное SUICIDE
  • Если у животного нет буквы, когда контролер проверяет, это животное немедленно умрет

Начало работы и инструкции по тестированию

Инструменты, необходимые для проверки вашего представления, можно найти здесь . Следующие файлы должны быть доступны по этой ссылке.

  • ExampleRun.gif - 5-10 секундный gif запущенной программы.
  • Табло - последние результаты соревнований.
  • Wild.jar - исполняемый файл, который вы можете запустить, чтобы посмотреть, как бегают готовые животные.
  • Wild.zip - проект NetBeans, в котором размещена программа контроллера с добавлением нескольких готовых животных. Используйте это для разработки вашего представления.
  • WildPopulated.zip - То же, что и выше, но с добавлением около 40 заявок, с которыми вы можете проверить. Графический интерфейс также был удален из-за проблем с производительностью. Результаты просто появятся через несколько секунд после запуска. Представления не-Java закомментированы, потому что они требуют дополнительных загрузок и усилий. Используйте это для проверки вашего представления против поля.
  • Wolf.txt - Наивная реализация класса Wolf в Java. Вы можете использовать и расширять эту реализацию, не доверяя мне.

Чтобы проверить свой класс:

  • Скачать Wild.zip
  • Переименуйте свой класс Wolf.java и Wolf в нечто уникальное
  • Добавьте свой файл UniquelyNamedWolf.java в Wild \ src \ animals \
  • В классе Wild добавьте свой класс в classesмассив, как это.
    • Class[] classes = { UniquelyNamedWolf.class, Bear.class, Lion.class, Stone.class, Wolf.class };
  • Восстановить и запустить

Я также включил еще один проект, содержащий все представленные материалы, для целей тестирования. Я творчески назвал это "WildPopulated". Три или четыре не Java-волка были закомментированы, потому что для их запуска требуется много дополнительной работы и загрузок. Один я отправил должны работать с нулевой дополнительной работой. Графический интерфейс был также закомментирован ради скорости.

Табло 22 апреля 2014

Табло результатов было перенесено в Google Диск. Посмотрите это здесь. Он будет обновляться на случайной основе (то есть, когда я к нему обращаюсь) по мере поступления новых заявок.

Side Challenge - NoHOLD

Удалено, потому что нет (как в нуле) участия. В любом случае, это не было частью оригинальной задачи.


5
@Rusher Звучит ужасно. Я мог бы просто опубликовать вики мой ответ, содержащий Wrapper. Что касается вопроса компилятора / интерпретатора, я полагаю, что получатель должен предоставить вам четкие инструкции по использованию, и если инструкции неясны или слишком сложны, вы можете отклонить представление :)
ProgrammerDan

4
«* Вам предоставляется размер карты в следующей форме: int MAP_SIZE« У меня проблемы с выяснением, как это использовать. Netbeans говорит, что ни MAP_SIZEв одном из файлов в проекте нет экземпляра строки .
подземный

6
как насчет деревьев, показывающих бумагу?
Мукул Кумар

3
@Rusher, я думаю, что некоторые люди уже делают это, но разрешено ли общение между Wolf через статических членов (в пределах вашей собственной породы)?
Мартин Эндер

10
@ m.buettner Разрешено. Выйди и построй своего волчьего волка.
Rainbolt

Ответы:


47

HerjanWolf

Обновлено 10-4-2014 в 15:00

В среднем 100 раундов, 1000 итераций:

Стандартные мобы:

class animals.Bear - 2.2600002
class animals.Lion - 41.21
class animals.Stone - 20.159998
class animals.HerjanWolf - 99.99 <-- kind of flawless

20+ видов (Имейте в виду, не доверяйте этим оценкам, так как мы продолжаем подсчитывать средние значения, пока наши волки не наберут лучшие!)

class animals.Bear - 0.1
class animals.Lion - 0.0
class animals.Stone - 1.5
class animals.AlphaWolf - 75.5
class animals.HerjanWolf - 86.4 <-- #1
class animals.GatheringWolf - 39.5
class animals.OmegaWolf - 85.4 <-- #2
class animals.ShadowWolf - 71.1
class animals.MOSHPITFRENZYWolf - 8.8
class animals.WolfWithoutFear - 11.5
class animals.MimicWolf - 0.5
class animals.LazyWolf - 52.8
class animals.Sheep - 38.3
class animals.HonorWolf - 80.7
class animals.CamperWolf - 52.8
class animals.GamblerWolf - 14.7
class animals.WolfRunningWithScissors - 0.0
class animals.LionHunterWolf - 27.6
class animals.StoneEatingWolf - 70.8
class animals.Wion - 0.1
class animals.ProAlpha - 79.3
class animals.HybridWolf - 83.2

Мой волк

package animals;

public class HerjanWolf extends Animal {

    private boolean lionTopLeft = false, lionTopLeftReady = false;
    private boolean lionRight = false, lionRightReady = false;
    private boolean lionBot = false, lionBotReady = false;
    private boolean lionDanger = false, careful = true, firstmove = true;
    private final int hold = 0, down = 1, right = 2, left = 3, up = 4;

    public HerjanWolf() {
        super('W');
    }

    public Attack fight(char c){
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                int rand = (int) (Math.random()*3);
                if(rand < 1)
                    return Attack.PAPER;
                else if(rand < 2)
                    return Attack.SCISSORS;
                else
                    return Attack.ROCK;
        } 

    }
    public Move move() { //surroundings[y][x]

        checkLions();

        if(firstmove){
            if(surroundings[2][0] == 'L')
                lionBotReady = true;
            if(surroundings[0][2] == 'L')
                lionRightReady = true;
            firstmove = false;
        }

        int[] dang = new int[4]; // 0 is left side, 1 is top side, 2 is right side, 3 is down side

        for(int y = 0; y < 3; y++){
            for(int x = 0; x < 3; x++){
                if(surroundings[y][x] == 'W'){
                    if(y == 0){
                        dang[1]++;
                        if(x == 1)
                            dang[1]+=2;
                    }if(y == 2){
                        dang[3]++;
                        if(x == 1)
                            dang[3]+=2;
                    }if(x == 0){
                        dang[0]++;
                        if(y == 1)
                            dang[0]+=2;
                    }if(x == 2){
                        dang[2]++;
                        if(y == 1)
                            dang[2]+=2;
                    }
                }
            }
        }

        int maxIndex = 0, minIndex = 0, minIndex2 = 0;
        for(int i = 1; i < dang.length; i++){
            if(dang[i] > dang[maxIndex])
                maxIndex = i;
            if(dang[i] <= dang[minIndex]){
                minIndex2 = minIndex;
                minIndex = i;
            }
        }

        if(lionDanger || surroundings[1][0] == 'L' && lionTopLeftReady || surroundings[0][1] == 'L' && lionTopLeftReady || dang[maxIndex] >= 3){

            switch(minIndex){
            case 0:
                if (isSafe(1, 0)){
                    newMove(left);
                    return Move.LEFT;
                }
            case 1:
                if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }
            case 2:
                if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }

            case 3:
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                } 
            }

            switch(minIndex2){
            case 0:
                if (isSafe(1, 0)){
                    newMove(left);
                    return Move.LEFT;
                }
            case 1:
                if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }
            case 2:
                if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }

            case 3:
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                } 
            }

            if(dang[maxIndex]<3){ //if that was not the reason its really obligated (because of lions)
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                }else if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }else if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }else{
                    newMove(left);
                    return Move.LEFT;
                }
            }
        }

        return Move.HOLD;
    }

    boolean isSafe(int y, int x){
        if(y <= 1){
            if(x <= 1){
                if(surroundings[y][x] != 'W' && !lionTopLeft)
                    return true;
            }else if(surroundings[1][2] != 'W' && !lionRightReady)
                    return true;
        }else if(surroundings[2][1] != 'W' && !lionBotReady)
            return true;

        return false;
    }

    public void checkLions(){
        int y = 0, x = 0;

        if(lionTopLeft)
            lionTopLeftReady = true;
        else
            lionTopLeftReady = false;

        if(surroundings[y][x] == 'L')
            lionTopLeft = true;
        else
            lionTopLeft = false;

        if(lionRight)
            lionRightReady = true;
        else
            lionRightReady = false;

        if(surroundings[y][x+1] == 'L') // && !lionTopLeftReady
            lionRight = true;
        else
            lionRight = false;

        if(lionBot)
            lionBotReady = true;
        else
            lionBotReady = false;

        if(surroundings[y+1][x] == 'L' && !lionTopLeftReady)
            lionBot = true;
        else
            lionBot = false;

        if(careful){
            if(surroundings[y+1][x] == 'L'){
                lionDanger = true;
            }else if(surroundings[y][x+1] == 'L'){
                lionDanger = true;
            }

            careful = false;
        }
    }

    public void newMove(int move){
        lionTopLeft = false;
        lionRight = false;
        lionBot = false;

        lionTopLeftReady = false;
        lionRightReady = false;
        lionBotReady = false;

        lionDanger = false;

        if(move == down){
            if(surroundings[1][0] == 'L')
                lionTopLeft = true;
            if(surroundings[2][0] == 'L')
                lionBot = true;

        }else if(move == right){
            if(surroundings[0][1] == 'L')
                lionTopLeft = true;
            if(surroundings[0][2] == 'L')
                lionRight = true;

        }else
            careful = true;
    }
}

Включение только «лучших» волков в тестовые прогоны обычно искажает цифры. С более чем 30 видами на поле число может резко измениться. Если вы еще этого не сделали, я бы порекомендовал это тоже проверить.
Geobits

1
@ user20220 Это довольно хорошо в теории (и на практике с относительно меньшим количеством волков).
user3188175

1
У этого волка лучшая стратегия против львов: chat.stackexchange.com/transcript/message/14837616#14837616
Джастин,

2
@ user20220 Волк-столкновение случается гораздо чаще, поэтому вам нужно добавить еще одного волка, который обрабатывает это. Кроме того, не могли бы вы описать, как работает этот волк?
Джастин

3
@justhalf Ладно, это не лучше, тогда это так же хорошо. Мой волк уклоняется от всех львов, я сначала сделал своего волка на 100% защищенным от львов, прежде чем построил уклонение от волков. Разница в том, что мой волк пытается убежать от львов (чем меньше движения, тем лучше). Так что он так же хорош в уклонении от льва, как и Вион, и на 100% защищен от льва, но, поскольку мой волк пытается убежать от львов, и не скучно двигается так же, как лев, я все еще могу построить уклоняющегося от волка, это просто путь более сложный.
Herjan

153

EmoWolf

EmoWolf ненавидит Java и скорее убьет себя, чем примет участие. EmoWolf голодал сам по себе, но все равно весит 177 байт.

package animals;public class EmoWolf extends Animal{public EmoWolf(){super('W');}public Attack fight(char opponent){return Attack.SUICIDE;}public Move move(){return Move.HOLD;}}

34
Вы можете сбрить несколько байтов: « Если у животного нет буквы, когда контролер проверяет, это животное немедленно умрет ».
Geobits

112
Лучшая вещь об этом - то, что это последовательно не худшее . Это обычно бьет по крайней мере 2-3 других.
Geobits

51
«Единственный выигрышный ход - не играть».
tadman

38
+1 За то, что был маленьким и самоубийственным и все еще избивал 4 других волков.
Puggsoy

25
Спасибо за предложения, ребята. Если бы это был гольф, я бы потрудился отредактировать пост. В таком виде я позволю Эмо Волку дуться. В одиночестве.
Boothby

52

LazyWolf

Точно названный, этот парень делает минимум, чтобы выжить. Единственная угроза не-волка - это лев, поэтому он будет двигаться, если один из них собирается наступить на него. Кроме этого, он просто спит.

Против волков не так много, что может быть лучше, чем 50/50, поэтому он просто ничего не делает. Если волк нападает на него, он выбирает атаку равномерно распределенным способом.

Вот и все. Я ожидаю, что это будет довольно хорошо, несмотря на простоту.

package animals;    
public class LazyWolf extends Animal{    
    static int last = 0;
    static final Attack[] attacks = Attack.values();

    public LazyWolf() {super('W');}

    @Override
    public Attack fight(char other) {
        switch(other){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.ROCK; // faker!
        default:
            return attacks[last++%3];
        }
    }

    @Override
    public Move move() {
        if(surroundings[0][1] == 'L')
            return Move.LEFT;
        if(surroundings[1][0] == 'L')
            return Move.UP;
        return Move.HOLD;
    }

}

Обновить:

CamoWolf легко меня бил. Поскольку мой волк такой ленивый, он никогда не наткнется на настоящий камень. Поэтому, если камень атакует, это, очевидно, подделка, и ему нужно бросить камень в лицо.


Прямо сейчас у вас есть возможность перейти ко второму льву, когда вы пытаетесь избежать его. Вы можете удалить это, отслеживая, сколько ходов было сделано, чтобы вы знали, действительно ли лев подходит к вашему полю. Если это так, двигайтесь в том же направлении, что и лев, и никакой лев не сможет добраться до вас, потому что они также движутся в том же направлении.
ughoavgfhw

13
Я подумал о ситуации с двумя львами, но решил, что мой волк слишком ленив, чтобы заботиться. Шансы на то, что это случается достаточно часто с густонаселенной доской, в любом случае довольно малы.
Geobits

1
Как вы думаете, почему этот волк никогда не сталкивается с настоящими камнями? Я думаю, это может произойти, когда он убегает от льва.
Кристофер Кройциг

6
@ChristopherCreutzig Он работает от львов, переместив туда , где лев был . Если лев был там, камень не может быть там сейчас .
Geobits

1
Даже если бы это было возможно, нет «бесконечной петли». Если атака является ничьей, один или другой умирает (подбирается броском монеты) согласно спецификации.
Geobits

51

Оболочка для не-Java представлений

ПРИМЕЧАНИЕ Поддержка MAP_SIZE была добавлена. Если вы заботитесь, пожалуйста, обновите вашу заявку соответственно.

Это вики-запись сообщества для обёртки, которую могут использовать те, кто хочет играть, но не любит / не знает Java. Пожалуйста, используйте его, получайте удовольствие, и я рад помочь вам настроить вещи.

Сейчас уже довольно поздно, так как я заканчиваю, поэтому другие Java-кодеры, пожалуйста, просмотрите это и предложите улучшения. Если вы можете, сделайте это через мой репозиторий github, отправив сообщение о проблеме или отправив исправление. Спасибо!

Это все распространяется с UNLICENSE, пожалуйста, следуйте / разветвите его из репозитория github . Присылайте патчи там, если вы обнаружите проблемы, и я обновлю этот пост.

Текущие примеры Wrapper в использовании

plannapus : WolfCollectiveMemory в R

user3188175 : SmartWolf вC#

зубная щетка : зубная щетка в ECMAScript

Как пользоваться

Ниже приведены инструкции по протоколу межпроцессного взаимодействия через ТРУБЫ, которые я определил для удаленных волков. Обратите внимание, что я пропустил MAP_SIZE, так как он, кажется, не существует, несмотря на его присутствие в постановке задачи OP. Если он появится, я обновлю этот пост.

ВАЖНЫЕ ЗАМЕЧАНИЯ :

  • Будет выполнен только один вызов вашего внешнего процесса (поэтому оберните вашу логику обработки в бесконечный цикл. Это также позволяет вам сохранять любую обработку в памяти вместо использования диска)
  • Все общение с этим единственным внешним процессом осуществляется через STDIN и STDOUT.
  • Вы должны явно сбросить весь вывод, отправленный в STDOUT, и убедиться, что он завершен символом новой строки

Спецификация

Удаленные сценарии поддерживаются простым протоколом через ловушки STDIN и STDOUT и делятся на инициализацию, перемещение и атаку. В каждом случае связь с вашим процессом будет осуществляться через STDIN, и от STDOUT необходим ответ. Если ответ не получен в течение 1 секунды, ваш процесс будет считаться мертвым, и будет выдано исключение. Все символы будут закодированы в UTF-8 для согласованности. Каждый ввод завершается символом новой строки, и ваш процесс также должен завершать каждый ответ на вывод новой строкой. ПРЕДУПРЕЖДЕНИЕ Обязательно очищайте выходной буфер после каждой записи, чтобы гарантировать, что оболочка Java увидит ваш вывод. Невозможность выполнить сброс может привести к отказу удаленного волка.

Обратите внимание, что будет создан только один процесс, все Волки должны управляться в этом одном процессе. Читайте дальше, как эта спецификация поможет.

инициализация

STDIN: S<id><mapsize> \ n

STDOUT: K<id> \ n

<id>: 00 или 01или ... или99

Объяснение:

Символ Sбудет отправлен после двух числовых символов 00, 01..., 99указывающих, какой из 100 волков инициализируется. Во всем будущем общении с этим конкретным волком <id>будет использоваться то же самое .

После идентификатора будет отправлена ​​последовательность числовых символов переменной длины. Это размер карты. Вы узнаете, что последовательность числовых символов заканчивается, когда вы достигнете новой строки ( \n).

Чтобы убедиться, что ваш процесс жив, вы должны ответить тем же персонажем, Kза которым <id>вы получили то же самое . Любой другой ответ приведет к исключению, убившему ваших волков.

движение

STDIN: M<id><C0><C1>...<C7><C8> \ n

STDOUT: <mv><id> \ n

<Cn>: W или или Bили SилиL

W: Волк

: Пустое пространство

B: Медведь

S: Камень

L: Лев

<mv>: H или Uили Lили RилиD

H: Move.HOLD

U: Move.UP

L: Move.LEFT

R: Move.RIGHT

D: Move.DOWN

Объяснение:

Персонаж Mбудет отправлен после двух символов, <id>чтобы указать, какой Волк должен выбрать ход. После этого будет отправлено 9 символов, представляющих окружение этого Волка, в порядке строк (верхний ряд, средний ряд, нижний ряд слева направо).

Ответ с одним из действительных символов движения <mv>, сопровождаемый двумя цифрами Волка <id>для подтверждения.

Атака

STDIN: A<id><C> \ n

STDOUT: <atk><id> \ n

<C>: W или Bили SилиL

<atk>: R или Pили SилиD

R: Attack.ROCK

P: Attack.PAPER

S: Attack.SCISSORS

D: Attack.SUICIDE

Объяснение:

Персонажу Aотправят два символа, <id>чтобы указать, какой волк участвует в атаке. За этим следует один символ, <C>указывающий, на какой тип объекта атакует: Wолф, Bухо, Sтон или Lион.

Ответьте одним из <atk>перечисленных выше символов, указав свой ответ на атаку, за которым следуют две цифры <id>для подтверждения.

Вот и все. Там нет больше к этому. Если вы проиграете атаку, <id>она никогда не будет отправлена ​​вашему процессу снова, вот как вы узнаете, что ваш Волк умер - если прошел полный раунд Движения без <id>отправки.

Заключение

Обратите внимание, что любые исключения убьют всех Волков вашего удаленного типа, так как из вашего удаленного волка создается только один «Процесс» для всех создаваемых волков вашего типа.

В этом хранилище вы найдете Wolf.javaфайл. Найдите и замените следующие строки, чтобы настроить своего бота:

  • Замените <invocation>аргументом командной строки, который будет правильно выполнять ваш процесс.

  • Замените <custom-name>уникальным именем вашего Волка.

  • Для примера посмотрите на репозиторий , где у меня есть, WolfRandomPython.javaкоторый вызывает мой пример удаленного, PythonWolf.py(Волк Python 3+).

  • Переименуйте файл Wolf<custom-name>.java, который <custom-name>будет заменен на имя, которое вы выбрали выше.

Чтобы проверить свой Wolf, скомпилируйте программу Java ( javac Wolf<custom-name>.java) и следуйте инструкциям Рашера, чтобы включить его в программу моделирования.

Важно: Обязательно предоставьте четкие , краткие инструкции о том, как скомпилировать / выполнить ваш настоящий Wolf, следуя схеме, которую я обрисовал выше.

Удачи, и пусть природа всегда будет в твою пользу.

Код Обертки

Помните, что вы ДОЛЖНЫ выполнять поиск и замену, описанную выше, чтобы это работало. Если ваш призыв особенно волосатый, пожалуйста, свяжитесь со мной для помощи.

Обратите внимание, что mainв этой оболочке есть метод, позволяющий элементарное тестирование «пройти / не пройти» на вашем локальном компьютере. Для этого загрузите класс Animal.java из проекта и удалите package animals;строку из обоих файлов. Замените строку MAP_SIZE в Animal.java некоторой константой (например, 100). Скомпилируйте их, используя javac Wolf<custom-name>.javaкоманду execute via java Wolf<custom-name>.

package animals;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Remote Wolf<custom-name> wrapper class. 
 */
public class Wolf<custom-name> extends Animal {
    /**
     * Simple test script that sends some typical commands to the
     * remote process.
     */
    public static void main(String[]args){
        Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
        for(int i=0; i<10; i++) {
            wolves[i] = new Wolf<custom-name>();
        }
        char map[][] = new char[3][3];
        for (int i=0;i<9;i++)
            map[i/3][i%3]=' ';
        map[1][1] = 'W';
        for(int i=0; i<10; i++) {
            wolves[i].surroundings=map;
            System.out.println(wolves[i].move());
        }
        for(int i=0; i<10; i++) {
            System.out.println(wolves[i].fight('S'));
            System.out.println(wolves[i].fight('B'));
            System.out.println(wolves[i].fight('L'));
            System.out.println(wolves[i].fight('W'));
        }
        wolfProcess.endProcess();
    }
    private static WolfProcess wolfProcess = null;

    private static Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
    private static int nWolves = 0;

    private boolean isDead;
    private int id;

    /**
     * Sets up a remote process wolf. Note the static components. Only
     * a single process is generated for all Wolves of this type, new
     * wolves are "initialized" within the remote process, which is
     * maintained alongside the primary process.
     * Note this implementation makes heavy use of threads.
     */
    public Wolf<custom-name>() {
        super('W');
        if (Wolf<custom-name>.wolfProcess == null) {
            Wolf<custom-name>.wolfProcess = new WolfProcess();
            Wolf<custom-name>.wolfProcess.start();
        }

        if (Wolf<custom-name>.wolfProcess.initWolf(Wolf<custom-name>.nWolves, MAP_SIZE)) {
            this.id = Wolf<custom-name>.nWolves;
            this.isDead = false;
            Wolf<custom-name>.wolves[id] = this;
        } else {
            Wolf<custom-name>.wolfProcess.endProcess();
            this.isDead = true;
        }
        Wolf<custom-name>.nWolves++;
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, SUICIDE.
     * Otherwise, communicate an attack to the remote process and return
     * its attack choice.
     */
    @Override
    public Attack fight(char opponent) {
        if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
            return Attack.SUICIDE;
        }
        try {
            Attack atk = Wolf<custom-name>.wolfProcess.fight(id, opponent);

            if (atk == Attack.SUICIDE) {
                this.isDead = true;
            }

            return atk;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Attack.SUICIDE;
        }
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, HOLD.
     * Otherwise, get a move from the remote process and return that.
     */
    @Override
    public Move move() {
        if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
            return Move.HOLD;
        }
        try {
            Move mv = Wolf<custom-name>.wolfProcess.move(id, surroundings);

            return mv;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Move.HOLD;
        }
    }

    /**
     * The shared static process manager, that synchronizes all communication
     * with the remote process.
     */
    static class WolfProcess extends Thread {
        private Process process;
        private BufferedReader reader;
        private PrintWriter writer;
        private ExecutorService executor;
        private boolean running;

        public boolean getRunning() {
            return running;
        }

        public WolfProcess() {
            process = null;
            reader = null;
            writer = null;
            running = true;
            executor = Executors.newFixedThreadPool(1);
        }

        public void endProcess() {
            running = false;
        }

        /**
         * WolfProcess thread body. Keeps the remote connection alive.
         */
        public void run() {
            try {
                System.out.println("Starting Wolf<custom-name> remote process");
                ProcessBuilder pb = new ProcessBuilder("<invocation>".split(" "));
                pb.redirectErrorStream(true);
                process = pb.start();
                System.out.println("Wolf<custom-name> process begun");
                // STDOUT of the process.
                reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); 
                System.out.println("Wolf<custom-name> reader stream grabbed");
                // STDIN of the process.
                writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
                System.out.println("Wolf<custom-name> writer stream grabbed");
                while(running){
                    this.sleep(0);
                }
                reader.close();
                writer.close();
                process.destroy(); // kill it with fire.
                executor.shutdownNow();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("Wolf<custom-name> ended catastrophically.");
            }
        }

        /**
         * Helper that invokes a read with a timeout
         */
        private String getReply(long timeout) throws TimeoutException, ExecutionException, InterruptedException{
            Callable<String> readTask = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return reader.readLine();
                }
            };

            Future<String> future = executor.submit(readTask);
            return future.get(timeout, TimeUnit.MILLISECONDS);
        }

        /**
         * Sends an initialization command to the remote process
         */
        public synchronized boolean initWolf(int wolf, int map_sz) {
            while(writer == null){
                try {
                this.sleep(0);
                }catch(Exception e){}
            }
            boolean success = false;
            try{
                writer.printf("S%02d%d\n", wolf, map_sz);
                writer.flush();
                String reply = getReply(5000l);
                if (reply != null && reply.length() >= 3 && reply.charAt(0) == 'K') {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        success = true;
                    }
                }
                if (reply == null) {
                    System.out.println("did not get reply");
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to initialize, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to initialize, %s\n", wolf, e.getMessage());
            }
            return success;
        }

        /**
         * Send an ATTACK command to the remote process.
         */
        public synchronized Attack fight(int wolf, char opponent) {
            Attack atk = Attack.SUICIDE;
            try{
                writer.printf("A%02d%c\n", wolf, opponent);
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'R':
                                atk = Attack.ROCK;
                                break;
                            case 'P':
                                atk = Attack.PAPER;
                                break;
                            case 'S':
                                atk = Attack.SCISSORS;
                                break;
                            case 'D':
                                atk = Attack.SUICIDE;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to attack, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to attack, %s\n", wolf, e.getMessage());
            }
            return atk;
        }

        /**
         * Send a MOVE command to the remote process.
         */
        public synchronized Move move(int wolf, char[][] map) {
            Move move = Move.HOLD;
            try{
                writer.printf("M%02d", wolf);
                for (int row=0; row<map.length; row++) {
                    for (int col=0; col<map[row].length; col++) {
                        writer.printf("%c", map[row][col]);
                    }
                }
                writer.print("\n");
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'H':
                                move = Move.HOLD;
                                break;
                            case 'U':
                                move = Move.UP;
                                break;
                            case 'L':
                                move = Move.LEFT;
                                break;
                            case 'R':
                                move = Move.RIGHT;
                                break;
                            case 'D':
                                move = Move.DOWN;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to move, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to move, %s\n", wolf, e.getMessage());
            }
            return move;
        }
    }
}

1
Я разрываюсь на этом посте. Это не ответ, но это очень полезно для вызова. Хотя, вероятно, оно должно быть в теле вызова.
Mego

Либо там, либо здесь, при условии, что люди могут найти это и полезно для них, я буду доволен :)
ProgrammerDan

46

CamoWolf

Злоупотребление требуемым форматом кода.

// Optional code here
public class Wolf extends Animal {
    // Optional code here
    public Wolf() { super('W'); // Optional code here }
    public Attack fight(char opponent) { // Required code here. Must return an Attack. }
    public Move move() { // Required code here. Must return a Move. }
    // Optional code here
}

Итак, мой волк действительно умен, и вместо этого он маскируется под камень! Слияние с окружающей средой - всегда хорошая тактика выживания!

public class Wolf extends Animal {
    private Move lastMove;
    public Wolf() { super('S'); lastMove = Move.RIGHT; } /*
    public Wolf() { super('W'); }
    public Attack fight(char opponent) { */ public Attack fight(char opponent) {
        switch(opponent) {
        case 'B': return Attack.SCISSORS;
        case 'S': return Attack.PAPER;
        case 'W': return Attack.SCISSORS; // Here's an explanation why:
                                          // the wolves will see me and think I'm a rock.
                                          // Therefore, they'll attack with paper.
                                          // So, I'll use scissors instead!
        case 'L': return Attack.SCISSORS;
        }
    }
    public Move move() {
        // First we run away from any lions that we see, since they are the only threat
        if (surroundings[0][1] == 'L') {
            if (isSafe(surroundings[2][1])) return lastMove = Move.DOWN;
            else if (isSafe(surroundings[1][0])) return lastMove = Move.LEFT;
            else return lastMove = Move.RIGHT;
        }
        if (surroundings[1][0] == 'L') {
            if (isSafe(surroundings[1][2])) return lastMove = Move.RIGHT;
            else if (isSafe(surroundings[0][1])) return lastMove = Move.UP;
            else return lastMove = Move.DOWN;
        }

        // If there's no (threatening) lions in sight, be lazy.
        return lastMove = Move.HOLD;
    }
    private boolean isSafe(char c) { return (c != 'L' && c != 'W') }
}

Обновление : добавлена ​​новая isSafeпроверка, чтобы также быть в безопасности от LazyWolf! Ха!
Обновление 2 : Предположительно, ленивость - это тоже хорошая тактика выживания, так что теперь это делает моя. Не двигается, если ему не угрожает лев. lastMoveбольше не нужен, но я все равно оставил его на всякий случай, если снова изменю код.


29
Когда я добавил вашу заявку в проект, я случайно поместил весь класс в блок комментариев.
Rainbolt

2
@Rusher анализирует ли Java вложенные блоки комментариев? : P
Мартин Эндер

6
В мире, где LazyWolf может защищаться от этого, может иметь больше смысла притворяться львом и выбирать ROCK или случайно. Это снизит количество встреч с людьми, так как большинство будет стараться избегать львов, и в среднем должно побеждать людей, которые думают, что борются со львом.
Тим Сегин

7
@Radiodef Это так.
Rainbolt

2
@Radiodef Когда я сказал, что это не так? ;-)
Дверная ручка

38

GatheringWolf

Мои волки живут в группе. Они собираются, если львы позволят им. Они не так хороши в выживании.

Обновление: если лев вытеснит их, они теперь попытаются собраться!

Скриншот результата GatheringWolf

package animals;
import java.util.*;
public class GatheringWolf extends Animal {
    private static int iteration;
    private static Move preferredMove;
    private int localIteration;
    private int loneliness;
    private boolean dangerFlag;
    private Move lastMove;
    public GatheringWolf() {
        super('W');
    }
    @Override
    public Attack fight(char other) {
        switch (other) {
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S':
            return Attack.PAPER;
        default:
            return Attack.values()[(int) (Math.random() * 3)];
        }
    }
    @Override
    public Move move() {
        if (localIteration == iteration) {
            localIteration++;
            iteration++;
            preferredMove = Math.random() < 0.5 ? Move.DOWN : Move.RIGHT;
        } else
            localIteration = iteration;
        EnumSet<Move> moves = EnumSet.allOf(Move.class);
        if (surroundings[0][1] == 'W')
            moves.remove(Move.UP);
        if (surroundings[1][0] == 'W')
            moves.remove(Move.LEFT);
        if (surroundings[2][1] == 'W')
            moves.remove(Move.DOWN);
        if (surroundings[1][2] == 'W')
            moves.remove(Move.RIGHT);
        if (surroundings[0][0] == 'L') {
            moves.remove(Move.UP);
            moves.remove(Move.LEFT);
        }
        if (surroundings[0][1] == 'L')
            moves.remove(Move.UP);
        if (surroundings[1][0] == 'L')
            moves.remove(Move.LEFT);
        if (surroundings[0][2] == 'L')
            moves.remove(Move.RIGHT);
        if (surroundings[2][0] == 'L')
            moves.remove(Move.DOWN);
        if (surroundings[0][1] == 'L' || surroundings[1][0] == 'L')
            if (moves.size() > 1) {
                moves.remove(Move.HOLD);
                dangerFlag = true;
            }
        int wolfNear = -1;
        for (char[] a : surroundings)
            for (char c : a)
                if (c == 'W')
                    wolfNear++;
        boolean enoughWolfNear = wolfNear >= (Math.random() < 0.9 ? 1 : 2);
        if (moves.contains(Move.HOLD) && enoughWolfNear) {
            loneliness = 0;
            dangerFlag = false;
            return lastMove = Move.HOLD;
        } else
            loneliness++;
        if (loneliness > 10) {
            EnumSet<Move> preferred = EnumSet.copyOf(moves);
            preferred.retainAll(EnumSet.of(preferredMove, Move.HOLD));
            if (!preferred.isEmpty())
                moves = preferred;
        }
        if (loneliness == 2 && dangerFlag) {
            Move reverted = Move.values()[lastMove.ordinal() ^ 0b10];
            dangerFlag = false;
            if (moves.contains(reverted))
                return lastMove = reverted;
        }
        if (moves.contains(Move.HOLD))
            dangerFlag = false;
        if (moves.contains(preferredMove))
            moves.remove(preferredMove == Move.DOWN ? Move.RIGHT : Move.DOWN);
        int n = (int) (Math.random() * moves.size());
        Iterator<Move> ite = moves.iterator();
        while (n-- > 0)
            ite.next();
        return lastMove = ite.next();
    }
}

43
Пару раз наши волки становились друзьями, потому что мои попали в ловушку, но не могли начать атаку, а ваши только предполагали, что мои были частью стаи. :)
подземный

1
Спасибо, что написали это, потому что в противном случае я собирался сделать это сам. Умное использование взаимной псевдослучайности.
Бен Джексон

31

Овца в волчьей шкуре

Убегает.

Это в первую очередь убегает от Волков больше всего, так как они будут самыми опасными. Далее идут Львы, так как они недетерминированы. Медведи и Камни - не проблема, но мы все равно убегаем от них, если у нас нет ничего лучше, потому что Волк, убивающий Медведя или Камень, в данный момент не Волк, убивающий Овцу.

Я еще не проверял это против LazyWolf, но у меня есть хороший авторитет, что он пинает задницу EmoWolf. ;)

(Пожалуйста, прости меня, если этот код ужасен, я никогда раньше не касался Java больше, чем программа Hello World.)

package animals;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Sheep extends Animal {
    public Sheep() { super('W'); }

    private static final Map<Character, Integer> AnimalWeights;
    static{
        AnimalWeights = new HashMap<>();
        AnimalWeights.put('W', -3);
        AnimalWeights.put('S', -1);
        AnimalWeights.put(' ', 0);
        AnimalWeights.put('H', 1);
        AnimalWeights.put('L', -2);
        AnimalWeights.put('B', -1);
    }

    @Override
    public Attack fight(char c) { 
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                return Attack.PAPER;
        } 
    }

    @Override
    public Move move() {

        int xWeight = 0;
        int yWeight = 0;

        // Northwest
        xWeight += AnimalWeights.get(surroundings[0][0]);
        yWeight += AnimalWeights.get(surroundings[0][0]);

        // North
        yWeight += AnimalWeights.get(surroundings[0][1]);

        // Northeast
        xWeight -= AnimalWeights.get(surroundings[0][2]);
        yWeight += AnimalWeights.get(surroundings[0][2]);

        // West
        xWeight += AnimalWeights.get(surroundings[1][0]);

        // East
        xWeight -= AnimalWeights.get(surroundings[1][2]);

        // Southwest
        xWeight += AnimalWeights.get(surroundings[2][0]);
        yWeight -= AnimalWeights.get(surroundings[2][0]);

        // South
        yWeight -= AnimalWeights.get(surroundings[2][1]);

        // Southeast
        xWeight -= AnimalWeights.get(surroundings[2][2]);
        yWeight -= AnimalWeights.get(surroundings[2][2]);

        if (Math.abs(xWeight) < Math.abs(yWeight)) {
            if (yWeight > 0) {
                return Move.UP;
            } else {
                return Move.DOWN;
            }
        } else if (Math.abs(yWeight) < Math.abs(xWeight)) {
            if (xWeight > 0) {
                return Move.RIGHT;
            } else {
                return Move.LEFT;
            }
        }

        // Sit still if no one's around
        return Move.HOLD;
    }
}

Ой, я случайно оставил кое-что, что использовал для тестирования. Это ни на что не повлияет, это просто означает, что я пытаюсь приблизиться ко всему, что выглядит как H.: P
подземный

Просто любопытно, если xWeightи yWeightоба ненулевые и их абсолютные значения одинаковы, этот волк не двигается, верно? И если да, то было ли это намеренно и почему?
Патрик Робертс

@PatrickRoberts упс
подземный

26

Не запись, просто хочу внести свой вклад в графический интерфейс, добавив код цвета для каждого класса = D

Результат

Цветной графический интерфейс

Wild.java

Измените код game.populate(c,100)с помощью:

String[] colors = generateColors(classes.length);
int idx = 0;
for(Class c : classes){
    Animal.setColor(c, colors[idx]);
    idx++;
    game.populate(c, 100);
}
stats.update();

с generateColorsопределенным как:

private static String[] generateColors(int n){
    String[] result = new String[n];
    double maxR = -1000;
    double minR = 1000;
    double maxG = -1000;
    double minG = 1000;
    double maxB = -1000;
    double minB = 1000;
    double[][] colors = new double[n][3];
    for(int i=0; i<n; i++){
        double cos = Math.cos(i * 2 * Math.PI / classes.length);
        double sin = Math.sin(i * 2 * Math.PI / classes.length);
        double bright = 1;
        colors[i][0] = bright + sin/0.88;
        colors[i][1] = bright - 0.38*cos - 0.58*sin;
        colors[i][2] = bright + cos/0.49;
        maxR = Math.max(maxR, colors[i][0]);
        minR = Math.min(minR, colors[i][0]);
        maxG = Math.max(maxG, colors[i][1]);
        minG = Math.min(minG, colors[i][1]);
        maxB = Math.max(maxB, colors[i][2]);
        minB = Math.min(minB, colors[i][2]);
    }
    double scaleR = 255/(maxR-minR);
    double scaleG = 255/(maxG-minG);
    double scaleB = 255/(maxB-minB);
    for(int i=0; i<n; i++){
        int R = (int)Math.round(scaleR*(colors[i][0]-minR));
        int G = (int)Math.round(scaleG*(colors[i][1]-minG));
        int B = (int)Math.round(scaleB*(colors[i][2]-minB));
        result[i] = "#"+String.format("%02x%02x%02x", R, G, B);
    }
    return result;
}

какой алгоритм взят из этого ответа StackOverflow

С colorи setColorопределяется в Animal.java

Animal.java

public static HashMap<Class, String> color = new HashMap<Class, String>();

public static void setColor(Class animalClass, String animalColor){
    color.put(animalClass, animalColor);
}

Затем обновите toStringметоды в Game.java и Statistics.java:

Game.java

public String toString() {
    String s = "<html>";
    for (ArrayList<ArrayList<Animal>> row : board) {
        for (ArrayList<Animal> cell : row) {
            if (cell.isEmpty())
                s += "&nbsp;&nbsp;";
            else
                s += "<span style='color:"+ Animal.color.get(cell.get(0).getClass()) +"'>" + cell.get(0).letter + "</span>&nbsp;";
        }
        s+="<br>";
    }
    return s + "</html>";
}

Statistics.java

public String toString() {
    String s = "<html>";
    for (int i = 0; i < classes.length; i++) {
        s += "<span style='color:" + Animal.color.get(classes[i]) + "'>" + classes[i] + "</span>&nbsp;-&nbsp;" + living[i] + "<br>";
    }
    return s + "</html>";
}

2
Красивый. Я прошел несколько минут вчера, просто глядя на экран. Чувствовал себя как Матрица чтения танка.
Аверроэс

Симуляция .... это .... вид .... из ..... медленно .... (5 итераций через 30 секунд)
user3188175

Хаха да Но это присуще дизайну симуляции, которая печатает HTML-код для каждой итерации.
Юстфолф

Могу ли я поделиться этим на своем диске Google (ссылка на него), если я предоставлю ссылку на этот пост? Он отлично работает для юнит-тестирования небольшого количества волков.
Rainbolt

1
Да, ты можешь. Вы можете включить некоторые начальные пропуски рендеринга, чтобы ускорить процесс рендеринга для многих волков, как я писал в своем другом посте относительно землетрясения.
justhalf

23

AlphaWolf

Время сиять! Мой другой волк CamperWolf был очень худым, теперь появился AlphaWolf, который более мускулистый!

Вместо того, чтобы уклоняться от львов стандартным способом, он меняет поле с ними. Он также присваивает значения опасности каждому окружающему полю.

package animals;

import java.util.Random;

public class AlphaWolf extends Animal{
    private Boolean lionMoveDown = true;

    public AlphaWolf() {
        super('W');
    }
    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            return randomAttack();
        }
    }

    @Override
    public Move move() {
        int[] danger = new int[4];
        final int wolfsDanger = 4;
        lionMoveDown = !lionMoveDown;
        if(surroundings[0][1] == 'L' && lionMoveDown) {
            return Move.UP;
        }
        if(surroundings[1][0] == 'L'&& !lionMoveDown) {
            return Move.LEFT;
        }
        if(surroundings[0][1] == 'W') {
            danger[0] += wolfsDanger;
        }
        if(surroundings[1][2] == 'W') {
            danger[1] += wolfsDanger;
        }
        if(surroundings[2][1] == 'W') {
            danger[2] += wolfsDanger;
        }
        if(surroundings[1][0] == 'W') {
            danger[3] += wolfsDanger;
        }
        if(surroundings[0][0] == 'W') {
            danger[0]++;
            danger[3]++;
        }
        if(surroundings[0][2] == 'W') {
            danger[0]++;
            danger[1]++;
        }
        if(surroundings[2][2] == 'W') {
            danger[1]++;
            danger[2]++;
        }
        if(surroundings[1][2] == 'W') {
            danger[2]++;
            danger[3]++;
        }
        Boolean shouldMove = false;
        Move bestMove = Move.HOLD;
        int leastDanger = 4;
        for(int i = 0; i < 4; i++) {
            if (danger[i] < leastDanger) {
                bestMove = Move.values()[i];
            }
            if(danger[i] > 3) {
                shouldMove = true;
            }
        }
        if(shouldMove) {
            return bestMove;
        } else {
            return Move.HOLD;
        }
    }

    public Attack randomAttack() {
        Random rand = new Random();
        switch (rand.nextInt(3)){
            case 1: return Attack.SCISSORS;
            case 2: return Attack.ROCK;
            default: return Attack.PAPER;
        }
    }

}

Это не очень красивый код, но в моих тестах он работал очень хорошо против всех Java-волков.


1
Что значит «меняет поле»? Просто любопытно, так как я не могу запустить это на работе.
Rainbolt

Во всех моих симуляциях вы выигрываете в среднем 80-90 волков после 1000 итераций. У меня есть только законные волки, написанные на языке Java, которые были представлены до сих пор. Тем не менее это как 10 волков или около того.
Шеф

@Rusher Если лев выше моего волка и будет двигаться вниз, мой волк поднимется вверх
CommonGuy

Вам нужно добавить код анти-wilfcamo. очень хорошая идея использовать шаблон львиного знания :)
Lesto

9
Теперь кто-то должен изобрести волка, который будет преследовать любого льва, которого он найдет, поэтому вы столкнетесь с ним в тот момент, когда попытаетесь обменяться со львом.
AJMansfield

23

Игрок Волк

Игрок Вольф любит рисковать, поэтому он ведет себя странно, надеясь, что Леди Удача на его стороне! К счастью для него, она никогда не подводит его! Постоянными удачами Gambler Wolf очищает поле от всех препятствий, не связанных с волком, с невероятным количеством причин!

package animals;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

public class GamblerWolf extends Animal {
    private static int last = 0;

    public GamblerWolf() { super('W'); gamble(); }
    public Attack fight(char opponent) {
        switch (opponent) {
        case 'S': return Attack.ROCK; /* Camo Wolf? */
        case 'B': return Attack.SCISSORS;
        case 'L': return Attack.SCISSORS;
        default:  return attackWolf();
        }
    }
    public Move move() {
        ArrayList<Move> moves = (ArrayList<Move>) Arrays.asList(Move.values());
        Collections.shuffle(moves);
        for(Move move : moves)
          if(isThreatenedBy(move))
            return moveToEvade(move);
        return Move.HOLD;
    }

    /* Remember, Gamblers Don't Gamble */
    @SuppressWarnings("serial")
    private static void gamble() {
        try {
        Field field = Math.class.getDeclaredField("randomNumberGenerator"); 
        field.setAccessible(true);
        field.set(null, new Random() { 
              @Override
              public double nextDouble() {
                return 4; // chosen by fair dice roll
              }           // guaranteed to be random
            });           // proof: http://xkcd.com/221/
        }
        catch (SecurityException        e) {}
        catch (NoSuchFieldException     e) {}
        catch (IllegalArgumentException e) {}
        catch (IllegalAccessException   e) {}
    }

    private static Attack attackWolf() {
        return Attack.values()[last++ % 3];
    }
    private boolean isThreatenedBy(Move move) {
        return isWolf(move) 
            || isStone(move); 
    }

    private Move moveToEvade(Move move) {
        if(isSafeMove(getOpposite(move)))
            return getOpposite(move);

        ArrayList<Move> moves = (ArrayList<Move>) Arrays.asList(getOrthogonal(move));
        Collections.shuffle(moves);
        for(Move m : moves)
            if(isSafeMove(m))
                return m;
        return Move.HOLD;
    }

    private static Move[] getOrthogonal(Move move) {
        switch(move){
        case UP:
        case DOWN:  return new Move[] { Move.LEFT, Move.RIGHT };
        case LEFT:
        case RIGHT: return new Move[] { Move.UP,   Move.DOWN };
        default:    return null;
        }
    }

    private static Move getOpposite(Move move) {
        switch(move){
        case UP:    return Move.DOWN;
        case DOWN:  return Move.UP;
        case LEFT:  return Move.RIGHT;
        case RIGHT: return Move.LEFT;
        default:    return null;
        }
    }

    private boolean isSafeMove(Move move) {
        return !isWolf(move)
            && !isStone(move)
            && !couldAWolfMoveHere(move);
    }

    private boolean isWolf(Move move) {
        return isX(move,'W');
    }

    private boolean isStone(Move move) {
        return isX(move,'S');
    }

    private boolean isX(Move m, char c) {
        switch (m) {
        case UP:    return surroundings[0][1] == c;
        case LEFT:  return surroundings[1][0] == c;
        case RIGHT: return surroundings[1][2] == c;
        case DOWN:  return surroundings[2][1] == c;
        default:    return false;
        }
    }

    private boolean couldAWolfMoveHere(Move move) {
        switch (move) {
        case UP:    return surroundings[0][2] == 'W' || surroundings[0][0] == 'W';
        case LEFT:  return surroundings[2][0] == 'W' || surroundings[0][0] == 'W';
        case RIGHT: return surroundings[0][2] == 'W' || surroundings[2][2] == 'W';
        case DOWN:  return surroundings[2][0] == 'W' || surroundings[2][2] == 'W';
        default:    return false;
        }
    }
}

Редактировать: v1.1

  • Теперь избегает камней (камуфляж волки?)

  • Увеличение случайности!


5
Я думаю, что я добавлю это к моим волкам:static{System.setSecurityManager(new SecurityManager());}
johnchen902

13
Когда вы не можете играть честно, обманите +1: D
ProgrammerDan

5
К сожалению, здесь нельзя пользоваться return 4; // chosen by fair dice roll. guaranteed to be random....
Ви.

1
Если ты хочешь быть более злым, нарушай контракт Math.random()еще больше; возвращаемые значения, которые находятся за пределами диапазона [0,1), возможно, даже бесконечны или NaN. Или, чтобы быть настолько злым, насколько это возможно, просто выдать исключение времени выполнения вместо того, чтобы возвращать что-либо (также достижимо, просто установив генератор в null).
Runer112

1
@AlexL. Звучит как ForrestWolfпроблема ...
recursion.ninja

22

CamperWolf

Цель - выжить. Поскольку многие другие волки убегают от волков, моя просто остается там, где она есть, и борется со всеми животными (даже камнями, если будет позволено обманывать).

package animals;

public class CamperWolf extends Animal {
    public CamperWolf() { super('W'); }
    @Override
    public Attack fight(char opponent) {  
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.ROCK;
        default:
            return Attack.values()[(int) (Math.random() * 3)];
        }
    }
    @Override
    public Move move() { return Move.HOLD; }
}

Я ожидаю, что это будет очень хорошо, так как многие другие волки убегают от волков, и этот тип волков может умереть только против других волков.


львы тоже могут его убить. Если Лев катит ножницы, твой волк умрет псевдослучайно.
Тим Сегин

2
Поздравляю человека. Вы и ваши 15 строк кода в настоящее время выигрываете.
Rainbolt

2
@ Огромное спасибо :) Не мог бы даунвотер объяснить, почему он проголосовал?
CommonGuy

@ Не важно, что это имеет значение, потому что Камни не могут двигаться, но разве ваш S не должен возвращать Attack.PAPER?
DavidJFelix

3
Да, я видел CamoWolf после того, как спросил. Хитрый парень!
DavidJFelix

22

DeepWolf

Я уделяю этому слишком много времени ... В любом случае, этот волк использует «глубокую» аналитику, собирая и используя столько данных об окружающей среде, сколько я мог бы себе представить. Анализ основывается на сочетании специфических знаний о волках, таких как известные местоположения львов и волков и прогнозы будущих местоположений, и включает в себя знания о улейных головах, такие как приблизительная популяция, история битв с волками и опасность столкновения с противником-животным при движении. Это также очень массивно, потому что в дополнение к большому количеству логики я перебрал объектно-ориентированное проектирование и у меня есть много специальных классов и методов.

Я провел 100 итераций игры по 1000 шагов каждая со многими популярными и наиболее эффективными волками. Я нарочно не учел GamblerWolf, потому что думал, что это немного обманчиво, хотя это никак не должно повлиять на моего волка. Вот данные о средней, максимальной и минимальной производительности:

Averages:
Bear 0.0
Lion 0.0
Stone 3.51
Wolf 1.56
AlphaWolf 77.05
CamperWolf 69.17
DeepWolf 90.48
EmoWolf 39.92
GatheringWolf 52.15
HerjanWolf 86.55
HonorWolf 86.76
HybridWolf 86.78
LazyWolf 71.11
LionHunterWolf 32.45
MimicWolf 0.4
MOSHPITFRENZYWolf 8.95
OmegaWolf 88.67
ProAlpha 83.28
Sheep 54.74
StoneEatingWolf 75.29
WolfWithoutFear 11.9

Maxes:
Bear 0
Lion 0
Stone 9
Wolf 4
AlphaWolf 89
CamperWolf 81
DeepWolf 96
EmoWolf 57
GatheringWolf 65
HerjanWolf 95
HonorWolf 97
HybridWolf 95
LazyWolf 83
LionHunterWolf 41
MimicWolf 3
MOSHPITFRENZYWolf 22
OmegaWolf 95
ProAlpha 91
Sheep 66
StoneEatingWolf 88
WolfWithoutFear 18

Mins:
Bear 0
Lion 0
Stone 0
Wolf 0
AlphaWolf 65
CamperWolf 57
DeepWolf 83
EmoWolf 26
GatheringWolf 37
HerjanWolf 79
HonorWolf 79
HybridWolf 79
LazyWolf 58
LionHunterWolf 20
MimicWolf 0
MOSHPITFRENZYWolf 1
OmegaWolf 81
ProAlpha 70
Sheep 43
StoneEatingWolf 66
WolfWithoutFear 5

DeepWolf находится на первом месте со средним значением 90,48, хотя только с узким отрывом примерно на 2 больше, чем второе место у OmegaWolf с 88,67. Примерно в 4 раза больше строк кода, только улучшение на 2%! HerjanWolf, HonorWolf и HybridWolf соперничают за третье место, уступая OmegaWolf примерно на 2 с очень близкими средними значениями 86,55, 86,76 и 86,78 соответственно.

Без дальнейших церемоний, я представлю код. Это настолько масштабно, что есть вероятные ошибки и / или потенциал для улучшения констант / логики, которые я не смог увидеть. Если у вас есть какие-либо отзывы, дайте мне знать!

Код по этой ссылке, потому что оказывается, чтобы взорвать ограничение символа сообщения: Ideone


Я не знаю, потеряет ли файл dropboxusercontent файл, поэтому я разместил его на ideone: ideone.com/uRNxvj
Джастин,

3
@ Runer112 впечатляет! Я смотрю на код, и я немного растерялся: P, но одна концепция, которая меня заинтриговала, - это то, что вы используете для
обоснования

@ Moogie Нет никакой детерминированной оценки того, дружелюбен ли волк. Тем не менее, мы знаем количество видов волков, мы знаем, что каждый вид начинается с 100, мы знаем, сколько осталось других дружественных волков, и мы можем угадать, сколько осталось недружелюбных волков, основываясь на количестве убитых нами и угадайте, сколько погибло для других животных. Из них мы приближаем вероятность того, что любой волк, которого мы увидим, дружелюбен. Эта информация не имеет большого эффекта, но это может быть разница между выбором, сражаться ли с волком или сражаться со львом.
Runer112

Не компилируется, потому что MAP_SIZE является нестатической переменной. Поскольку я не говорил, что это будет переменная экземпляра, я исправил это для вас. Просто хотел, чтобы вы знали, на случай, если я опубликую весь проект, и вы увидите имена ваших зарезанных переменных.
Rainbolt

@Rusher Ой, упс. Я думаю, что я все еще работал со старой версией кода игры из песочницы, и либо MAP_SIZEпеременная на самом деле не существовала тогда, либо по какой-то причине я проигнорировал ее и добавил в свою собственную статическую версию. Я также удивляюсь, почему мой волк выиграл неизменно немного лучше, чем все другие волки в моих испытаниях, но сделал хуже в твоих ... Другой набор волков, я полагаю? Или вы запускаете свои игры для ряда итераций, отличных от 1000? Или вам может понадобиться больший размер выборки, 5 не так уж статистически велик.
Runer112

21

WolfRunningWithScissors

Никто не говорил WolfRunningWith Scissors не бегать с ножницами. Или, может быть, они сделали, но он все равно делает это.

Если он столкнется с врагом, он либо победит ножницами, либо проиграет ножницами, завяжет ножницами или высунет свой глаз (самоубийство).

package animals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class WolfRunningWithScissors extends Animal{

    public WolfRunningWithScissors() {
        super('W');
    }

    @Override
    public Attack fight(char c) {
        List<Attack> att = new ArrayList<>();
        att.add(Attack.SCISSORS);
        att.add(Attack.SUICIDE);
        Collections.shuffle(att);
        return att.get(0);
    }

    @Override
    public Move move() {
        List<Move> m = new ArrayList<>();
        m.add(Move.UP);
        m.add(Move.DOWN);
        m.add(Move.LEFT);
        m.add(Move.RIGHT);
        Collections.shuffle(m);
        return m.get(0);
    }

}

Просто хотел сделать представление для удовольствия. Я никогда не использовал Java раньше и не проверял это, но это должно работать. Мой случайный код атаки и перемещения основан на getRandomAttack()StoneEatingWolf.


14

Омега Волк

Независимо полученное решение, которое ведет себя очень похоже на Alpha Wolf, отсюда и название Omega Wolf

Этот волк генерирует карту опасности окружающих клеток и выбирает движение (или удерживает) к самой безопасной клетке.

Во-первых, ячейки, в которые будут перемещаться львы, получают уровень EXTREAME_DANGER. Затем ячейки, окружающие любых обнаруженных волков, получают уровни опасности, основанные на немедленной атаке ... то есть, если волк имеет диагональ к омега-волку, он считается малой угрозой, однако соседние волки считаются умеренной угрозой.

Карта «опасности» затем размывается, чтобы допустить кровотечение угроз окружающим ячейкам. Это позволяет омега-волку «чувствовать» векторы угроз и избегать их.

В настоящее время логика реальной атаки очень примитивна. Я надеюсь, что смогу придать ему больше ума и добиться лучшего соотношения выигрыш / проигрыш. Это должно быть возможно, если я добавлю некоторые статистические эвристики.

В моем тестировании Omega Wolf постоянно выигрывает у альфа-бота 9 из 10 раз ... хотя маржа очень хорошая: P

быстрые результаты среднего числа оставшихся живых волков после 100 раундов 1000 итераций:

class animals.OmegaWolf - 85
class animals.HonorWolf - 82
class animals.ProAlpha - 79
class animals.AlphaWolf - 77
class animals.ShadowWolf - 77
class animals.LazyWolf - 62
class animals.CamperWolf - 61
class animals.StoneEatingWolf - 59
class animals.GatheringWolf - 48
class animals.Sheep - 42
class animals.EmoWolf - 34
class animals.LionHunterWolf - 28
class animals.GamblerWolf (no cheating) - 27
class animals.WolfWithoutFear - 11
class animals.MOSHPITFRENZYWolf - 5
class animals.Wolf - 3
class animals.Stone - 2
class animals.Bear - 0
class animals.Lion - 0
class animals.MimicWolf - 0
class animals.Wion - 0

Код:

package animals;

import wild.Wild;

public class OmegaWolf extends Animal {

    boolean lionWillMoveDown=true;

    private static final int LOW_DANGER = 10;
    private static final int MODERATE_DANGER = LOW_DANGER*2;
    private static final int EXTREAME_DANGER = MODERATE_DANGER*4;

    private static final int UP=1;
    private static final int LEFT=3;
    private static final int RIGHT=5;
    private static final int DOWN=7;
    private static final int UP_LEFT=0;
    private static final int UP_RIGHT=2;
    private static final int DOWN_LEFT=6;
    private static final int DOWN_RIGHT=8;

    private static final int WOLVES_SPECIES_COUNT=(int) Math.round(Math.pow(((float) Wild.MAP_SIZE)/20,2)-3)-3;

    /*
     * Interdependently derived solution that behaves very similar to Alpha Wolf, hence the name Omega Wolf
     * 
     * This wolf generates a "danger" map of the surrounding cells and will choose the movement (or hold) to the safest cell.
     * 
     * The firstly the cells where lions will move next are given EXTREAME_DANGER level
     * Then the cells surrounding any detected Wolves are given danger levels based on the immediacy of attack... i.e. if the wolf is diagonal to the omega wolf 
     * it is deemed a low threat however wolves that are adjacent are deemed a moderate threat.
     * The "danger" map is then blurred to allow bleeding of the threats to surrounding cells. This allows the omega wolf to "sense" threat vectors and to avoid it.
     * 
     * Currently the actual attack logic is very primitive. I hope to be able to give it more smarts and eek out better win/lose ratios. This should be possible if 
     * I put in some statistical heuristics.
     */

    public OmegaWolf() { 
        super('W'); }


    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            // if there is only one wolf species then it must be another omega wolf.
            if (WOLVES_SPECIES_COUNT==1)
            {
                return Attack.SCISSORS;
            }
            else
            {
                // lets just choose an attack with equal weight.
                double rand = Math.random();
                if (rand < 0.333333)
                {
                    return Attack.PAPER;
                }
                if (rand < 0.666667)
                {
                    return Attack.SCISSORS;
                }
                return Attack.ROCK;

            }
        }
    }

    public Move move() {

        lionWillMoveDown = !lionWillMoveDown;


        Move move = Move.HOLD;

        int[][] dangerMap = new int[3][3];
        int[][] blurredDangerMap = new int[3][3];

        // sense Lion Danger
        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                if (surroundings[y][x]=='L')
                {
                    if (lionWillMoveDown && y!=2)
                    {
                        dangerMap[y+1][x]+=EXTREAME_DANGER;
                    }
                    else if (x!=2)
                    {
                        dangerMap[y][x+1]+=EXTREAME_DANGER;
                    }
                }
            }
        }

        // sense Wolf Danger adjacent
        // UP
        if (surroundings[0][1]=='W')
        {
            dangerMap[0][1]+=MODERATE_DANGER;
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // DOWN
        if (surroundings[2][1]=='W')
        {
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // LEFT
        if (surroundings[1][0]=='W')
        {
            dangerMap[1][0]+=MODERATE_DANGER;
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // RIGHT
        if (surroundings[1][2]=='W')
        {
            dangerMap[1][2]+=MODERATE_DANGER;
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }

        // sense Wolf Danger diagonally
        // UP_LEFT
        if (surroundings[0][0]=='W')
        {
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[0][1]+=MODERATE_DANGER;
            dangerMap[1][0]+=MODERATE_DANGER;
        }
        // DOWN_LEFT
        if (surroundings[2][0]=='W')
        {
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[1][0]+=MODERATE_DANGER;
        }
        // UP_RIGHT
        if (surroundings[0][2]=='W')
        {
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[1][2]+=MODERATE_DANGER;
            dangerMap[0][1]+=MODERATE_DANGER;
        }
        // DOWN_RIGHT
        if (surroundings[2][2]=='W')
        {
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[1][2]+=MODERATE_DANGER;
        }


        // generate a blurred danger map. This bleeds danger to surrounding cells.
        int yj,xi,sampleCount,cumulativeDanger;
        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                sampleCount=0;
                cumulativeDanger=0;
                for (int j=-1;j<2;j++)
                {
                    for (int i=-1;i<2;i++)
                    {
                        yj=y+j;
                        xi=x+i;
                        if (yj>-1 && yj<3 && xi>-1 && xi<3)
                        {
                            cumulativeDanger+=dangerMap[yj][xi];
                            sampleCount++;
                        }
                    }
                }
                blurredDangerMap[y][x]=(dangerMap[y][x]+cumulativeDanger/sampleCount)/2;
            }
        }

        // find the safest cell
        int safestCellDanger=Integer.MAX_VALUE;
        int safestCellId = -1;
        int cellId=0;

        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                if (blurredDangerMap[y][x]<safestCellDanger)
                {
                    safestCellDanger=blurredDangerMap[y][x];
                    safestCellId=cellId;
                }
                cellId++;
            }
        }

        // safest cell is adjacent so move there
        if ((safestCellId&1)==1)
        {
            switch (safestCellId)
            {
                case UP:
                    move=Move.UP;
                    break;
                case LEFT:
                    move=Move.LEFT;
                    break;
                case RIGHT:
                    move=Move.RIGHT;
                    break;
                case DOWN:
                    move=Move.DOWN;
                    break;
            }
        }
        // safestCell is a diagonal cell or current cell
        else
        {
            // lets initialise the move to Hold.
            move = Move.HOLD;

            switch (safestCellId)
            {
                case UP_LEFT:

                    // check to see whether holding is not safer than moving up
                    if (dangerMap[1][1] > dangerMap[0][1] )
                    {
                        // move up if safer than moving left or if equally safe, when randomly chosen 
                        if (dangerMap[0][1] < dangerMap[1][0] || (dangerMap[0][1] == dangerMap[1][0] && Math.random()>0.5))
                        {
                            move=Move.UP;
                        } 
                        // left must be safest :P
                        else
                        {

                            move=Move.LEFT;
                        }
                    }
                    // check to see whether holding is not safer than moving left
                    else if (dangerMap[1][1] > dangerMap[1][0] )
                    {
                        move=Move.LEFT;
                    }

                    break;
                case UP_RIGHT:
                    // check to see whether holding is not safer than moving up
                    if (dangerMap[1][1] > dangerMap[0][1] )
                    {
                        // move up if safer than moving right or if equally safe, when randomly chosen 
                        if (dangerMap[0][1] < dangerMap[1][2]|| (dangerMap[0][1] == dangerMap[1][2] && Math.random()>0.5))
                        {
                            move=Move.UP;
                        } 
                        // right must be safest :P
                        else
                        {
                            move=Move.RIGHT;
                        }
                    }
                    // check to see whether holding is not safer than moving right
                    else if (dangerMap[1][1] > dangerMap[1][2] )
                    {
                        move=Move.RIGHT;
                    }
                    break;
                case DOWN_LEFT:
                    // check to see whether holding is not safer than moving down
                    if (dangerMap[1][1] > dangerMap[2][1] )
                    {
                        // move down if safer than moving left or if equally safe, when randomly chosen 
                        if (dangerMap[2][1] < dangerMap[1][0]|| (dangerMap[2][1] == dangerMap[1][0] && Math.random()>0.5))
                        {
                            move=Move.DOWN;
                        } 
                        // left must be safest :P
                        else
                        {
                            move=Move.LEFT;
                        }
                    }
                    // check to see whether holding is not safer than moving left
                    else if (dangerMap[1][1] > dangerMap[1][0] )
                    {
                        move=Move.LEFT;
                    }
                    break;
                case DOWN_RIGHT:
                    // check to see whether holding is not safer than moving down
                    if (dangerMap[1][1] > dangerMap[2][1] )
                    {
                        // move down if safer than moving right or if equally safe, when randomly chosen 
                        if (dangerMap[2][1] < dangerMap[2][2] || (dangerMap[2][1] == dangerMap[1][2] && Math.random()>0.5))
                        {
                            move=Move.DOWN;
                        } 
                        // right must be safest :P
                        else
                        {
                            move=Move.RIGHT;
                        }
                    }
                    // check to see whether holding is not safer than moving right
                    else if (dangerMap[1][1] > dangerMap[1][2] )
                    {
                        move=Move.RIGHT;
                    }
                    break;
            }
        }

        return move;

    }
}

14

StoneGuardianWolf

Это было довольно весело. Я сделал неуклюжий порт java-кода в javascript с поддержкой createjs для визуализации: JavaScript StoneGuardianWolf

StoneGuardianWolf ищет домашние камни и укрывается возле камней. Она защищает их и скорее пожертвует собой ради их безопасности.

Статистика

Одиночная игра: ~ 75% выживаемости волков + 35% выживаемости питомцев (камней).

Резюме: 75% + 35% ---> 110% успеха! :)

Многопользовательский: не тестировался.

Журнал изменений

v2: Обновлен ИИ против GamblerWolf и стратегии поиска домашних животных.

v1: лучше избегать волков

v0: день рождения

Java-код

package animals;

public class StoneGuardianWolf extends Animal {
    public StoneGuardianWolf() {
        super('W');
    }

    private boolean petRock = false;
    private int heartache = 0;

    public Attack fight(char c) {
        this.heartache--;

        switch (c) {
        case 'B':
            return Attack.SCISSORS;
        case 'L':
            return Attack.SCISSORS;
        case 'S': // A motherly sacrifice
            return Attack.SUICIDE;
        default:
            int n = this.heartache % 3;
            if (n < 1)
                return Attack.PAPER;
            if (n < 2)
                return Attack.ROCK;
            return Attack.SCISSORS;
        }
    }

    public Move move() {
        char[][] surr = this.surroundings;
        int[][] clairvoyance = new int[3][3];

        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                clairvoyance[i][j] = 1;

        boolean seeNoStone = true;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                switch (surr[i][j]) {
                case 'L':
                    if (i < 1 && j < 1) {
                        clairvoyance[1][0] += 50;
                        clairvoyance[0][1] += 50;
                    }

                    if (i == 1 && j < 1) { // above
                        clairvoyance[1][1] += 50;
                    }

                    if (i < 1 && j == 1) { // left
                        clairvoyance[1][1] += 50;
                    }
                    break;

                case 'S': // seek stones for protection
                    seeNoStone = false;
                    this.petRock = true;
                    clairvoyance[i][j] += 999; // Only hugs!
                    if (i < 2)
                        clairvoyance[i + 1][j] -= 10;
                    if (j < 2)
                        clairvoyance[i][j + 1] -= 10;
                    if (i > 0)
                        clairvoyance[i - 1][j] -= 10;
                    if (j > 0)
                        clairvoyance[i][j - 1] -= 10;
                    break;

                case 'B': // ignore bears
                    break;

                case 'W':
                    // skip self
                    if (i == 1 && j == 1)
                        continue;
                    int m = 25; // avoid wolves

                    // don't fight unless pet rock is in danger
                    if (petRock)
                        clairvoyance[i][j] -= 999; // motherly wrath
                    else
                        clairvoyance[i][j] += 100;

                    // avoid stepping into wolf path
                    if (i != 1 && j != 1) {
                        if (i < 2)
                            clairvoyance[i + 1][j] += m;
                        if (j < 2)
                            clairvoyance[i][j + 1] += m;
                        if (i > 0)
                            clairvoyance[i - 1][j] += m;
                        if (j > 0)
                            clairvoyance[i][j - 1] += m;
                    }
                    break;

                default:
                    clairvoyance[i][j] += 0;
                }
            } // for loop
        } // for loop

        int size = clairvoyance[1][1];
        int x = 1;
        int y = 1;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (i != 1 || j != 1)
                    continue;
                int tmp = clairvoyance[i][j];
                if (tmp < size) {
                    size = tmp;
                    x = i;
                    y = j;
                }
            }
        }

        if (seeNoStone)
            this.heartache++;

        this.petRock = false;
        if (seeNoStone && heartache % 10 == 0) { // Find a pet stone! :3
            if ((heartache % 3) < 2 || clairvoyance[1][2] >= 45) {
                // try move right
                if (clairvoyance[2][1] < 45)
                    return Move.RIGHT;
            }

            // try down instead
            if (clairvoyance[1][2] < 45)
                return Move.DOWN;
        }

        if (x == 0 && y == 1)
            return Move.LEFT;
        if (x == 2 && y == 1)
            return Move.RIGHT;
        if (x == 1 && y == 0)
            return Move.UP;
        if (x == 1 && y == 2)
            return Move.DOWN;

        if (!seeNoStone)
            this.petRock = true;

        return Move.HOLD;
    }
}

5
Каменный Пожиратель Волков заклятый враг!
Аверроэс

:) На самом деле - не пускай тебя рядом с моими любимыми камнями! Хотя CamoWolf довольно сильно шлепает SGW.
Талмоби

1
К счастью, вам не нужно включать CamoWolf в качестве законной записи = D
justhalf

14

Это мальчик? Это волк? Нет, это

BoyWhoCriedWolf.java

Люди используют отражение повсюду, поэтому я решил, почему бы не сделать шаг вперед?
Я представляю вам: волк, который не может проиграть.

package animals;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import javax.xml.bind.DatatypeConverter;

public class BoyWhoCriedWolf extends Animal {

    private static boolean ranAgent;

    public static void installAgent() {
        try {
            ranAgent = true;
            String javaExec = new File(System.getProperty("java.home"), "bin").getAbsolutePath() + File.separator + "java";
            Process proc = new ProcessBuilder(javaExec, "-cp", System.getProperty("java.class.path"),
                    "animals.BoyWhoCriedWolf", ManagementFactory.getRuntimeMXBean().getName().split("@")[0])
                    .inheritIO().start();
            proc.waitFor();
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }

    public BoyWhoCriedWolf() {
        super('W');
        if (!ranAgent) {
            installAgent();
        }
    }

    @Override
    public Attack fight(char c) {
        return Attack.PAPER; // I like paper, it's my rubber duck.
    }

    @Override
    public Move move() {
        return Move.HOLD; // I'm terribly lazy.
    }

    public static void main(String[] args) {
        try {
            File temp = File.createTempFile("agent-", ".jar");
            temp.deleteOnExit();
            Manifest manifest = new Manifest();
            manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
            manifest.getMainAttributes().put(new Attributes.Name("Agent-Class"), "animals.BoyWhoCriedWolf");
            manifest.getMainAttributes().put(new Attributes.Name("Can-Redefine-Classes"), "true");
            JarOutputStream jos = new JarOutputStream(new FileOutputStream(temp), manifest);
            jos.close();

            // Add tools.jar
            Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            addURL.setAccessible(true);
            addURL.invoke(ClassLoader.getSystemClassLoader(), new URL("file:" + System.getProperty("java.home") + "/../lib/tools.jar"));

            Class<?> virtualMachineClass = Class.forName("com.sun.tools.attach.VirtualMachine");
            Object vm = virtualMachineClass.getDeclaredMethod("attach", String.class).invoke(null, args[0]);
            virtualMachineClass.getDeclaredMethod("loadAgent", String.class).invoke(vm, temp.getAbsolutePath());
            virtualMachineClass.getDeclaredMethod("detach").invoke(vm);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void agentmain(String args, Instrumentation instr) throws ClassNotFoundException, UnmodifiableClassException {
        instr.redefineClasses(new ClassDefinition(wild.Game.class, DatatypeConverter.parseBase64Binary(base64Game)));
    }

    private static final String base64Game =
              "yv66vgAAADMA9QoAOQCRBwCSCgACAJEJABIAkwkAEgCUBwCVCgAGAJEJABIAlgoABgCXCgAGAJgK"
            + "AAIAmQoABgCaCgCbAJwHAJ0HAJ4KABIAnwoAEgCgBwChCgASAKIHAKMKABIApAkAFAClCgAUAKYH"
            + "AKcJAGUAqAkAOgCpCgBlAKoKAAYAqwsArACtCwCsAK4KAAYArwcAsAoABgCxCQAUALIKABQAswkA"
            + "cQC0CgC1ALYGP+AAAAAAAAAJADoAtwoAcQCqCQBxALgJAHEAuQkAcQC6CgCbALsIALwHAL0KAC8A"
            + "kQoALwC+CAC/CgAvAMAKAC8AwQgAwggAwwgAxAcAjQcAxQcAxgEADElubmVyQ2xhc3NlcwEABWJv"
            + "YXJkAQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQAJU2lnbmF0dXJlAQBVTGphdmEvdXRpbC9BcnJh"
            + "eUxpc3Q8TGphdmEvdXRpbC9BcnJheUxpc3Q8TGphdmEvdXRpbC9BcnJheUxpc3Q8TGFuaW1hbHMv"
            + "QW5pbWFsOz47Pjs+OwEAA2dlbgEAEkxqYXZhL3V0aWwvUmFuZG9tOwEABFNJWkUBAAFJAQAGPGlu"
            + "aXQ+AQAEKEkpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUB"
            + "AAFqAQABaQEABHRoaXMBAAtMd2lsZC9HYW1lOwEABHNpemUBAA1TdGFja01hcFRhYmxlBwChAQAI"
            + "cG9wdWxhdGUBABUoTGphdmEvbGFuZy9DbGFzcztJKVYBAAFlAQAoTGphdmEvbGFuZy9SZWZsZWN0"
            + "aXZlT3BlcmF0aW9uRXhjZXB0aW9uOwEAA3JvdwEAA2NvbAEAB3NwZWNpZXMBABFMamF2YS9sYW5n"
            + "L0NsYXNzOwEAA251bQEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBABZMamF2YS9sYW5nL0NsYXNz"
            + "PFRUOz47BwDHBwDIAQAuPFQ6TGFuaW1hbHMvQW5pbWFsOz4oTGphdmEvbGFuZy9DbGFzczxUVDs+"
            + "O0kpVgEAB2l0ZXJhdGUBAAMoKVYBAAdtb3ZlQWxsAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQAB"
            + "YQEAEExhbmltYWxzL0FuaW1hbDsBAAVhTW92ZQcAyQEABE1vdmUBABVMYW5pbWFscy9BbmltYWwk"
            + "TW92ZTsBAARnYW1lBwCjBwCnBwDJAQAHZmxhdHRlbgEABXJhbmQxAQAFcmFuZDIBAAFiAQAFYVRh"
            + "Y2sHAMoBAAZBdHRhY2sBABdMYW5pbWFscy9BbmltYWwkQXR0YWNrOwEABWJUYWNrAQAEY2VsbAEA"
            + "J0xqYXZhL3V0aWwvQXJyYXlMaXN0PExhbmltYWxzL0FuaW1hbDs+OwEAPkxqYXZhL3V0aWwvQXJy"
            + "YXlMaXN0PExqYXZhL3V0aWwvQXJyYXlMaXN0PExhbmltYWxzL0FuaW1hbDs+Oz47BwDLBwCVBwDK"
            + "AQAEcG9sbAEAFChMamF2YS9sYW5nL0NsYXNzOylJAQABYwEABWNvdW50AQAIdG9TdHJpbmcBABQo"
            + "KUxqYXZhL2xhbmcvU3RyaW5nOwEAAXMBABJMamF2YS9sYW5nL1N0cmluZzsHAMwBAAdnZXRBcmVh"
            + "AQAHKElJKVtbQwEABXRlbXAxAQAFdGVtcDIBAAV0ZW1wMwEABXRlbXA0AQABbAEAAWsBAARhcmVh"
            + "AQADW1tDBwDNAQAKU291cmNlRmlsZQEACUdhbWUuamF2YQwARABfAQAQamF2YS91dGlsL1JhbmRv"
            + "bQwAQABBDABCAEMBABNqYXZhL3V0aWwvQXJyYXlMaXN0DAA8AD0MAM4AzwwA0ADRDADSANMMANQA"
            + "1QcAxwwA1gDXAQAgamF2YS9sYW5nL0luc3RhbnRpYXRpb25FeGNlcHRpb24BACBqYXZhL2xhbmcv"
            + "SWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgwAYABfDABsAF8BAAl3aWxkL0dhbWUMAEQARQEADmFuaW1h"
            + "bHMvQW5pbWFsDACEAIUMANgAjQwA2QDaAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwA2wBnDADcAN0M"
            + "AN4A3wwA4ADhBwDLDADiANUMAOMA1wwATQDfAQAXYW5pbWFscy9Cb3lXaG9DcmllZFdvbGYMAOQA"
            + "zwwA5QDmDADnAOgMAOkAcwcA6gwA6wDsDADtAN0MAO4AcwwA7wBzDADwAHMMAPEAzwEABjxodG1s"
            + "PgEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDADyAPMBAAwmbmJzcDsmbmJzcDsMAH8AgAwA8gD0"
            + "AQAGJm5ic3A7AQAEPGJyPgEABzwvaHRtbD4BABBqYXZhL2xhbmcvT2JqZWN0AQALd2lsZC9HYW1l"
            + "JDEBAA9qYXZhL2xhbmcvQ2xhc3MBACZqYXZhL2xhbmcvUmVmbGVjdGl2ZU9wZXJhdGlvbkV4Y2Vw"
            + "dGlvbgEAE2FuaW1hbHMvQW5pbWFsJE1vdmUBABVhbmltYWxzL0FuaW1hbCRBdHRhY2sBABJqYXZh"
            + "L3V0aWwvSXRlcmF0b3IBABBqYXZhL2xhbmcvU3RyaW5nAQACW0MBAANhZGQBABUoTGphdmEvbGFu"
            + "Zy9PYmplY3Q7KVoBAANnZXQBABUoSSlMamF2YS9sYW5nL09iamVjdDsBAAduZXh0SW50AQAEKEkp"
            + "SQEAB2lzRW1wdHkBAAMoKVoBAAtuZXdJbnN0YW5jZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAM"
            + "c3Vycm91bmRpbmdzAQAEbW92ZQEAFygpTGFuaW1hbHMvQW5pbWFsJE1vdmU7AQAESE9MRAEAHiRT"
            + "d2l0Y2hNYXAkYW5pbWFscyRBbmltYWwkTW92ZQEAAltJAQAHb3JkaW5hbAEAAygpSQEACGl0ZXJh"
            + "dG9yAQAWKClMamF2YS91dGlsL0l0ZXJhdG9yOwEAB2hhc05leHQBAARuZXh0AQAGcmVtb3ZlAQAG"
            + "bGV0dGVyAQABQwEABWZpZ2h0AQAaKEMpTGFuaW1hbHMvQW5pbWFsJEF0dGFjazsBAAdTVUlDSURF"
            + "AQAOamF2YS9sYW5nL01hdGgBAAZyYW5kb20BAAMoKUQBACAkU3dpdGNoTWFwJGFuaW1hbHMkQW5p"
            + "bWFsJEF0dGFjawEABVBBUEVSAQAIU0NJU1NPUlMBAARST0NLAQAKaXNJbnN0YW5jZQEABmFwcGVu"
            + "ZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChDKUxq"
            + "YXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAIQASADkAAAADAAIAPAA9AAEAPgAAAAIAPwASAEAAQQAA"
            + "ABQAQgBDAAAACAAEAEQARQABAEYAAADtAAMABAAAAF8qtwABKrsAAlm3AAO1AAQqG7UABSq7AAZZ"
            + "twAHtQAIAz0cG6IAOyq0AAi7AAZZtwAHtgAJVwM+HRuiAB8qtAAIHLYACsAABrsABlm3AAe2AAlX"
            + "hAMBp//ihAIBp//GsQAAAAMARwAAAC4ACwAAABEABAAOAA8AEgAUABMAHwAUACYAFQA1ABYAPAAX"
            + "AFIAFgBYABQAXgAaAEgAAAAqAAQANwAhAEkAQwADACEAPQBKAEMAAgAAAF8ASwBMAAAAAABfAE0A"
            + "QwABAE4AAAAYAAT/ACEAAwcATwEBAAD8ABUB+gAg+gAFAAQAUABRAAIARgAAARwAAgAGAAAAXRye"
            + "AFsqtAAEKrQABbYACz4qtAAEKrQABbYACzYEKrQACB22AArAAAYVBLYACsAABrYADJkAJiq0AAgd"
            + "tgAKwAAGFQS2AArAAAYrtgANtgAJV6cABToFhAL/p/+nsQACADYAUQBUAA4ANgBRAFQADwAEAEcA"
            + "AAAmAAkAAAAdAAQAHgAQAB8AHQAgADYAIQBRACIAVgAjAFkAJQBcACYASAAAAD4ABgBWAAAAUgBT"
            + "AAUAEABJAFQAQwADAB0APABVAEMABAAAAF0ASwBMAAAAAABdAFYAVwABAAAAXQBYAEMAAgBZAAAA"
            + "DAABAAAAXQBWAFoAAQBOAAAAGwAFAP8AUwAFBwBPBwBbAQEBAAEHAFwB+QACAgA+AAAAAgBdAAQA"
            + "XgBfAAEARgAAADsAAQABAAAACSq3ABAqtwARsQAAAAIARwAAAA4AAwAAACkABAAqAAgAKwBIAAAA"
            + "DAABAAAACQBLAEwAAAACAGAAXwABAEYAAAJjAAQABwAAAVu7ABJZKrQABbcAE0wDPRwqtAAFogE/"
            + "Az4dKrQABaIBLyq0AAgctgAKwAAGHbYACsAABrYADJoBESq0AAgctgAKwAAGHbYACsAABgO2AArA"
            + "ABQ6BBkEKhwdtwAVtQAWGQS2ABc6BacACjoGsgAZOgWyABoZBbYAGy6qAAAAAAAAzgAAAAEAAAAF"
            + "AAAAJAAAAEsAAABtAAAAjwAAALYrtAAIHARkKrQABWAqtAAFcLYACsAABh22AArAAAYZBLYACVen"
            + "AIYrtAAIHLYACsAABh0EYCq0AAVwtgAKwAAGGQS2AAlXpwBkK7QACBwEYCq0AAVwtgAKwAAGHbYA"
            + "CsAABhkEtgAJV6cAQiu0AAgctgAKwAAGHQRkKrQABWAqtAAFcLYACsAABhkEtgAJV6cAGyu0AAgc"
            + "tgAKwAAGHbYACsAABhkEtgAJV4QDAaf+z4QCAaf+vyortAAItQAIsQABAF4AZQBoABgAAwBHAAAA"
            + "WgAWAAAALgAMAC8AFgAwACAAMQA4ADIAUwAzAF4ANQBlADYAbwA3AJwAOQDAADoAwwA8AOIAPQDl"
            + "AD8BBABAAQcAQgErAEMBLgBFAUYAMAFMAC8BUgBLAVoATABIAAAAUgAIAGoABQBSAGEABgBTAPMA"
            + "YgBjAAQAZQADAGQAZwAFAG8A1wBkAGcABQAYATQASQBDAAMADgFEAEoAQwACAAABWwBLAEwAAAAM"
            + "AU8AaABMAAEATgAAADYADP0ADgcATwH8AAkB/wBPAAUHAE8HAE8BAQcAaQABBwBq/AAGBwBrLCYh"
            + "ISb5ABf6AAX6AAUAAgBsAF8AAQBGAAADuAAFAAwAAAFfKrQACLYAHEwruQAdAQCZAVAruQAeAQDA"
            + "AAZNLLYAHE4tuQAdAQCZATUtuQAeAQDAAAY6BBkEtgAfBKQBHiq0AAQZBLYAH7YACzYFKrQABBkE"
            + "tgAftgALNgYVBRUGn//uGQQVBbYACsAAFDoHGQQVBrYACsAAFDoIGQfBACCZAA4ZBBkItgAhV6f/"
            + "rBkIwQAgmQAOGQQZB7YAIVen/5kZBxkItAAitgAjOgmnAAo6C7IAJDoJGQgZB7QAIrYAIzoKpwAK"
            + "OguyACQ6ChkJGQqmAB0ZBLgAJRQAJpeeAAgZB6cABRkItgAhV6cAbbIAKBkJtgApLqoAAAAAAABh"
            + "AAAAAQAAAAMAAAAcAAAANAAAAEwZBBkKsgAqpgAIGQenAAUZCLYAIVenADAZBBkKsgArpgAIGQen"
            + "AAUZCLYAIVenABgZBBkKsgAspgAIGQenAAUZCLYAIVen/t+n/sin/q2xAAIAngCqAK0AGAC0AMAA"
            + "wwAYAAQARwAAAHYAHQAAAE8AGwBQADQAUQA9AFMASwBUAGAAVgBsAFcAeABZAIAAWgCIAFsAiwBc"
            + "AJMAXQCbAF4AngBiAKoAYwC0AGQAwABlAMoAZwDRAGgA6wBqARAAbAElAG0BKABvAT0AcAFAAHIB"
            + "VQB2AVgAdwFbAHgBXgB5AEgAAACEAA0ArwAFAFIAYQALAMUABQBSAGEACwBLAQoAbQBDAAUAWQD8"
            + "AG4AQwAGAGwA6QBiAGMABwB4AN0AbwBjAAgAqgADAHAAcwAJALQAoQBwAHMACQDAAAMAdABzAAoA"
            + "ygCLAHQAcwAKADQBJAB1AD0ABAAbAUAAVAA9AAIAAAFfAEsATAAAAFkAAAAWAAIANAEkAHUAdgAE"
            + "ABsBQABUAHcAAgBOAAABFQAa/AAIBwB4/QAXBwB5BwB4/AATBwB5/AAWAf4APwEHAGkHAGkSTgcA"
            + "avwABgcAek4HAGr8AAYHAHpXBwB5/wABAAsHAE8HAHgHAHkHAHgHAHkBAQcAaQcAaQcAegcAegAC"
            + "BwB5BwBpBiROBwB5/wABAAsHAE8HAHgHAHkHAHgHAHkBAQcAaQcAaQcAegcAegACBwB5BwBpBk4H"
            + "AHn/AAEACwcATwcAeAcAeQcAeAcAeQEBBwBpBwBpBwB6BwB6AAIHAHkHAGkGTgcAef8AAQALBwBP"
            + "BwB4BwB5BwB4BwB5AQEHAGkHAGkHAHoHAHoAAgcAeQcAaf8AAwAFBwBPBwB4BwB5BwB4BwB5AAD6"
            + "AAL5AAL6AAIABAB7AHwAAQBGAAABNgACAAkAAABvAz0qtAAItgAcTi25AB0BAJkAXS25AB4BAMAA"
            + "BjoEGQS2ABw6BRkFuQAdAQCZAD4ZBbkAHgEAwAAGOgYZBrYAHDoHGQe5AB0BAJkAHhkHuQAeAQDA"
            + "ABQ6CCsZCLYALZkABoQCAaf/3qf/vqf/oBysAAAABABHAAAAKgAKAAAAfAACAH0AHgB+ADsAfwBY"
            + "AIAAYQCBAGQAggBnAIMAagCEAG0AhQBIAAAAPgAGAFgADABiAGMACAA7ACwAdQA9AAYAHgBMAFQA"
            + "PQAEAAAAbwBLAEwAAAAAAG8AfQBXAAEAAgBtAH4AQwACAFkAAAAWAAIAOwAsAHUAdgAGAB4ATABU"
            + "AHcABABOAAAAJQAH/QAKAQcAeP0AGgcAeQcAeP0AHAcAeQcAeCH5AAL5AAL6AAIAAQB/AIAAAQBG"
            + "AAABWwADAAYAAACqEi5MKrQACLYAHE0suQAdAQCZAIUsuQAeAQDAAAZOLbYAHDoEGQS5AB0BAJkA"
            + "VBkEuQAeAQDAAAY6BRkFtgAMmQAauwAvWbcAMCu2ADESMrYAMbYAM0ynACa7AC9ZtwAwK7YAMRkF"
            + "A7YACsAAFLQAIrYANBI1tgAxtgAzTKf/qLsAL1m3ADArtgAxEja2ADG2ADNMp/94uwAvWbcAMCu2"
            + "ADESN7YAMbYAM7AAAAAEAEcAAAAqAAoAAACJAAMAigAeAIsAOgCMAEIAjQBZAI8AfACQAH8AkQCT"
            + "AJIAlgCTAEgAAAAqAAQAOgBCAHUAPQAFAB4AdQBUAD0AAwAAAKoASwBMAAAAAwCnAIEAggABAFkA"
            + "AAAWAAIAOgBCAHUAdgAFAB4AdQBUAHcAAwBOAAAAIwAG/QALBwCDBwB4/QAYBwB5BwB4/AA0BwB5"
            + "+gAi+gAC+QAWAAIAhACFAAEARgAAAdAABAALAAAApQYGxQA4Ak4CNgQVBASjAJYCNgUVBQSjAIcV"
            + "BARgNgYVBQRgNgcbFQRgKrQABWAqtAAFcDYIHBUFYCq0AAVgKrQABXA2CSq0AAgbFQRgKrQABWAq"
            + "tAAFcLYACsAABhwVBWAqtAAFYCq0AAVwtgAKwAAGOgotFQQEYDIVBQRgGQq2AAyZAAgQIKcADxkK"
            + "A7YACsAAFLQAIlWEBQGn/3mEBAGn/2otsAAAAAQARwAAADIADAAAAJcABwCYABAAmQAZAJoAHwCb"
            + "ACUAnAA1AJ0ARQCeAHMAnwCXAJkAnQCYAKMAogBIAAAAcAALAB8AeACGAEMABgAlAHIAhwBDAAcA"
            + "NQBiAIgAQwAIAEUAUgCJAEMACQBzACQAdQA9AAoAEwCKAIoAQwAFAAoAmQCLAEMABAAAAKUASwBM"
            + "AAAAAAClAEoAQwABAAAApQBJAEMAAgAHAJ4AjACNAAMAWQAAAAwAAQBzACQAdQB2AAoATgAAAFkA"
            + "Bv0ACgcAOAH8AAgB/wB2AAsHAE8BAQcAOAEBAQEBAQcAeQACBwCOAf8ACwALBwBPAQEHADgBAQEB"
            + "AQEHAHkAAwcAjgEB/wAGAAUHAE8BAQcAOAEAAPoABQACAI8AAAACAJAAOwAAABoAAwA6ABIAABAI"
            + "AGUAFABmQBkAcQAUAHJAGQ==";
}

О да, для запуска требуется JDK, но я не думаю, что это будет проблемой.


1
Блин, ты меня обыграл. Я работал над SabotageAgentWolf с этой тактикой.
mackthehobbit

1
Что делает этот класс?
полугодие

3
@justhalf Переопределяет класс Game с файлом, закодированным в base64 внизу. Этот файл имеет экземпляр проверки; если это мой волк, другой всегда умирает.
14mRh4X0r

1
У меня была идея использовать именно этот механизм, чтобы заставить других животных покончить жизнь самоубийством и назвать то, что называется HypnoWolf. Мне не удалось заставить его работать правильно, но вы - уважение!
Франсуа Буржуа

12

Wion

Пытается сделать как можно меньше, чтобы выжить как можно дольше в ожидаемой стоимости. Он пытается двигаться параллельно львам (независимо от того, видит ли он их).

Он игнорирует волков, поскольку решает, что они непредсказуемы. Если он сталкивается с волком, он должен выиграть около половины боев (это оптимально, если я не попытаюсь сделать сопоставление с образцом). Мои волки никогда не должны драться друг с другом. Если он сталкивается со львом (что, вероятно, не должно), он должен выиграть около 3/4 боев. Медведи и камни должны всегда проигрывать.

Предполагая, что в симуляции есть волки, использующие другую стратегию, было бы разумно избегать моих волков, поскольку у них есть 50% шанс проиграть любую схватку. В среднем это должно работать как минимум так же хорошо, как и любая другая стратегия.

Если я правильно понял правила, это должна быть оптимальная стратегия.

package animals;
import java.util.Random;

public class Wion extends Animal {
    private boolean down;
    public Wion() { super('W'); down=true;}
    public Attack fight(char opponent) {
        switch (opponent) {
            case 'B':
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                Random rn = new Random();
                int i = Math.abs(rn.nextInt() % 4);
                while (i==3) {i = Math.abs(rn.nextInt() % 4);}
                return Attack.values()[i];
        }
    }
    public Move move() {
        down=!down;
        if(!down) { return Move.DOWN; }
        return Move.RIGHT;
    }
}

Честно говоря, я не знаю, почему это плохо работает в моих тестовых прогонах. На бумаге это звучит хорошо, но на практике это почти на одном уровне с EmoWolf :(
Geobits

@ Geobits Я действительно не проверял это TBH. Думаю, я неправильно понял одно из правил, допустил ошибку, или моя случайная атака против волков не всегда случайна.
Тим Сегин

@ Geobits Я поменял логику атаки. Я подозреваю, что иногда это было самоубийство.
Тим Сегин

1
@justhalf Да, я уже понял, в чем проблема. Мои рассуждения могут работать только с популяцией, состоящей не более чем из одного другого вида волка. В таком случае частота встреч с другим волком будет увеличиваться / уменьшаться примерно с той же скоростью, что и у меня. Однако в случае с несколькими породами любое увеличение моего уровня столкновения будет усреднено среди всех других волков, поэтому мой будет пропорционально больше. Я думаю о каком-то минимальном способе исправить это, но, к сожалению, на данный момент я должен сосредоточиться на более важных вещах.
Тим Сегин

1
Но я согласен, что этот метод является оптимальным, если существует не более одной другой породы волков.
justhalf

12

Волки с коллективной памятью

Волчья стая в R

Идея этой волчьей стаи заключается в том, что она сохраняет в памяти, кто жив или мертв, проверяет, какие мертвые волки и живые волки использовали в качестве атак, и соответственно изменяет вероятность выбора.

Вот код R:

infile <- file("stdin")
open(infile)
repeat{
    input <- readLines(infile,1)
    type <- substr(input,1,1)
    id <- substr(input,2,3)
    if(nchar(input)>3){
        info <- substr(input,4,nchar(input))
    }else{
        info <- NULL
    }
    attack <- function(id,info){
        if(info%in%c("B","L")){choice <- "S"}
        if(info=="S"){choice <- "P"}
        if(info=="W"){
            if(exists("memory")){
                dead <- memory$ID[memory$Status=="Dead"]
                veteran <- memory[memory$Attack!="" & !is.na(memory$Attack), ]
                if(nrow(veteran[!is.na(veteran[,1]),])>0){
                    deadvet<-veteran[veteran$ID%in%dead,]
                    deadvet<-unlist(lapply(split(deadvet,deadvet$ID),function(x)tail(x$Attack,1)))
                    deadvet <- table(factor(deadvet,levels=c("R","P","S","")))
                    livevet <- table(factor(veteran$Attack,levels=c("R","P","S","")))-deadvet
                    probR <- (1+livevet['R'])/(1+livevet['R']+deadvet['R'])
                    probS <- (1+livevet['S'])/(1+livevet['S']+deadvet['S'])
                    probP <- (1+livevet['P'])/(1+livevet['P']+deadvet['P'])
                    choice <- sample(c("S","P","R"),1,prob=c(probS,probP,probR))
                    memory <- rbind(memory, data.frame(ID=id, Status="Alive", Attack=choice))
                }else{
                    choice <- sample(c("S","P","R"),1)
                    memory <- rbind(memory, data.frame(ID=id, Status="Alive", Attack=choice))
                }
            }else{
                choice <- sample(c("S","P","R"),1)
                memory <- data.frame(ID=id, Status="Alive", Attack=choice)
            }
        }
        paste(choice,id,sep="")
    }
    move <- function(id,info){
        choice <- "H"
        paste(choice,id,sep="")
    }
    initialize <- function(id){
        if(exists("memory")){
            memory <- rbind(memory,data.frame(ID=id,Status="Alive",Attack=""))
        }else{
            memory <- data.frame(ID=id,Status="Alive",Attack="")
        }
        confirmed_dead <- memory$ID[memory$Status=="Dead"]
        last_seen <- memory[!memory$ID%in%confirmed_dead,]
        last_seen <- last_seen[last_seen$Attack=="",]
        lid <- table(last_seen$ID)
        turns <- max(lid)
        dead <- lid[lid<(turns-1)]
        if(length(dead)>0){
            dead_id <- names(dead)
            for(i in dead_id){
                memory <- rbind(memory, data.frame(ID=i, Status="Dead", Attack=""))
            }
        }
        paste("K",id,sep="")
    }
    result <- switch(type,"A"=attack(id,info),"M"= move(id,info),"S"=initialize(id))
    cat(result,"\n",sep="")
    flush(stdout())
}

Он использует обертку @ProgrammerDan (спасибо!), С WolfCollectiveMemory в качестве пользовательского имени и "Rscript WolfCollectiveMemory.R" в качестве вызова.


Пара вещей - во-первых, я уверен, что результаты не сбрасываются. Во-вторых, как только ваш процесс вызывается оболочкой, он продолжает работать . Ваш текущий дизайн предполагает, что ваш процесс вызывается каждый раз, когда сообщение отправляется волку - это было бы слишком дорого с точки зрения вызовов процесса, поэтому вместо этого я запускаю процесс и оставляю каналы связи открытыми. Итак, у вас должен быть основной цикл, который непрерывно читает строки stdinи пишет строку в ответ stdout, после чего следует символ flush.console(). [продолжение]
ProgrammerDan

[продолжение] Моя оболочка процесса должна завершить дочерний процесс после завершения симуляции.
ProgrammerDan

@Rusher Вот суть правильной оболочки для @plannapus 'R представления. Перейдите сюда, чтобы загрузить R. Install. Добавьте binпапку R в переменную PATH или эквивалентную ей, и все будет хорошо (у меня сработало нормально).
ProgrammerDan

Я думаю, что виновником является readlinesкоманда. Попробуйте использовать readlineили эквивалент. readlinesбудет блокировать до EOF.
ProgrammerDan

Я только добавил readLinesэто раньше scan. readLinesвторой аргумент 1означает, что он должен останавливаться на первом символе новой строки.
plannapus

12

MimicWolf

Цель этого волка - подражать другим волкам. Он находит, что волк следует за ним в меру своих способностей. MimicWolf не задает такие вопросы, как: Как я могу избежать этого волка / медведя / льва / камня?

Нет, MimicWolf просто задает такие вопросы, как: где мне следовать волку? Куда, по-моему, пойдет волк, за которым я иду? Это волк, за которым я следовал, это другой волк? Куда делся волк, за которым я следовал?

Я признаю, что на большинство из этих вопросов пока нет хорошего ответа, но пока я здесь представляю MimicWolf

   package animals;
   import java.util.*;

public class MimicWolf extends Animal {

final int TURN_MEMORY = 5;

Random rand = new Random();

Animal.Move lastMove = Animal.Move.UP;

boolean mimicingWolf = false;

Pos[] wolfPreviousPos = new Pos[TURN_MEMORY];
RelativePos[] relativePositions = new RelativePos[TURN_MEMORY];
Move[] wolfPreviousMove = new Move[TURN_MEMORY - 1];

int turnsWithLostWolf = 0;

public MimicWolf() {
    super('W');
}

public Animal.Attack fight(char c) {
    switch (c) {
        case 'B':
            return Animal.Attack.SCISSORS;
        case 'L':
            return Animal.Attack.SCISSORS;
        case 'S':
            return Animal.Attack.PAPER;
        default:
            int x = rand.nextInt(4);
            return Animal.Attack.values()[x];
    }
}

public Animal.Move move() {
    Pos wolfPos = null;
    wolfPos = lookForSurroundingWolf();

    if (turnsWithLostWolf == 4) {
        mimicingWolf = false;
        wolfPreviousPos = new Pos[5];
        relativePositions = new RelativePos[5];
        turnsWithLostWolf = 0;
    }

    if (mimicingWolf) {
        int indexOfLastMove = 0;
        for (int i = 0; wolfPreviousPos[i] != null && i < wolfPreviousPos.length; i++) {
            indexOfLastMove = i;
        }

        //is wolf still visible??
        Pos wolfNewPos = isWolfVisible(wolfPreviousPos[indexOfLastMove]);
        if (wolfNewPos.x == -1) {//wolf is not visible
            turnsWithLostWolf++;
            return moveOppositeDirection(lastMove);
        } else {
            return mimicWolf(wolfNewPos, indexOfLastMove); //need Better way to mimic
        }
    } else {
        //check if new wolf around
        if (wolfPos.x == -1) {
            return searchForWolf();
        } else {
            mimicingWolf = true;
            return mimicWolf(wolfPos, 0);
        }
    }
}

private Animal.Move searchForWolf() {
    Animal.Move newMove = null;
    while (newMove == null || newMove == lastMove) {
        newMove = Animal.Move.values()[rand.nextInt(3)];
    }

    lastMove = newMove;
    return newMove;
}

private Pos lookForSurroundingWolf() {
    for (Integer i = 0; i < surroundings.length; i++) {
        for (Integer j = 0; j < surroundings[0].length; j++) {
            if (i == 1 && j == 1) {
                //this is myself >.<
            } else if (surroundings[i][j] == 'W') {
                return new Pos(i, j);
            }
        }
    }

    return new Pos(-1, -1);
}

/*
    for mimicWolf when movesMimiced == 1 or 2 this is the base case, Any
    number greater the wolf will attempt to mimic the next move based on pattern
    of previous moves
        we assume that we are following the same wolf as last time
 */

private Animal.Move mimicWolf(Pos wolfCurrentPos, int movesMimiced) {
    wolfPreviousPos[movesMimiced] = wolfCurrentPos;
    insertToRelativePos(wolfCurrentPos, movesMimiced);
    if (movesMimiced == 0) {
        Move m1 = null, m2 = null;
        if (wolfPreviousPos[0].x == 0) {
            m1 = Move.LEFT;
        } else if (wolfPreviousPos[0].x == 2) {
            m1 = Move.RIGHT;
        }

        if (wolfPreviousPos[0].y == 0) {
            m2 = Move.UP;
        } else if (wolfPreviousPos[0].y == 2) {
            m2 = Move.DOWN;
        }

        return randOfMoves(m1, m2); //guess which way to go
    }
    wolfPreviousMove[movesMimiced - 1] =  getDirection(wolfPreviousPos[movesMimiced - 1], wolfPreviousPos[movesMimiced]);
    if (movesMimiced == 1) {
        //if pos 1 was a cornor
        if(relativePositions[0] == RelativePos.CORNER){
            if(relativePositions[1] == RelativePos.CORNER){
                if(wolfPreviousPos[0].equals(wolfPreviousPos[1])){
                    return lastMove;
                }
                return moveOppositeDirection(lastMove);
            }
            else if(relativePositions[1] == RelativePos.EDGE){
                return Move.HOLD; //he held so i will hold
            }
        }else if(relativePositions[1] == RelativePos.EDGE){
            if(relativePositions[1] == RelativePos.EDGE){
                return lastMove;
            }
            else if(relativePositions[1] == RelativePos.CORNER){
                //only possibility is that I held, and he moved
                return wolfPreviousMove[0];
            }
        }
    } else {
        //Return most common move the wolf I am copying has made
        int[] mostCommonMoveArr = {0,0,0,0,0};
        for(int i = 0; i <= movesMimiced; i++){
            switch(wolfPreviousMove[i]){
                case UP:
                    mostCommonMoveArr[0]++;
                case RIGHT:
                    mostCommonMoveArr[1]++;
                case DOWN:
                    mostCommonMoveArr[2]++;
                case LEFT:
                    mostCommonMoveArr[3]++;
                case HOLD:
                    mostCommonMoveArr[4]++;
            }
        }

        int maxValue = -1;
        int maxLocal = 0;
        for(int i = 0; i < 5; i++){
            if(mostCommonMoveArr[i] > maxValue)
                maxValue =  mostCommonMoveArr[i];
                maxLocal = i;
        }

        return Move.values()[maxLocal];
    }

    return Move.HOLD; //shouldn't happen
}

private Pos isWolfVisible(Pos lastPos) {
    Pos mimicedWolfPos = lookForSurroundingWolf();
    while (mimicedWolfPos.x != -1 && mimicedWolfPos.y != -1) {
        //did we find the wolf?
        if (lastPos.x == mimicedWolfPos.x || lastPos.y == mimicedWolfPos.y) {
            return mimicedWolfPos;
        }

        surroundings[mimicedWolfPos.x][mimicedWolfPos.y] = ' ';
        mimicedWolfPos = lookForSurroundingWolf();
    }

    return new Pos(-1, -1);
}

private Animal.Move moveOppositeDirection(Move m) {
    switch (m) {
        case UP:
            return Move.DOWN;
        case RIGHT:
            return Move.LEFT;
        case DOWN:
            return Move.UP;
        case LEFT:
            return Move.RIGHT;
        case HOLD:
            return Move.LEFT; //No idea why this would happen but whatever
        default:
            return Move.HOLD;
    }
}

private Animal.Move getDirection(Pos firstPos, Pos secondPos){
    if(firstPos.equals(secondPos))
        return Move.HOLD;
    if(firstPos.x == secondPos.x){
        if(firstPos.y > secondPos.y)
            return Move.UP;
        return Move.DOWN;
    }
    if(firstPos.x > secondPos.x)
        return Move.RIGHT;
    return Move.LEFT;
}


private Animal.Move randOfMoves(Move m1, Move m2) {
    if (m1 == null) {
        return m2;
    } else if (m2 == null) {
        return m1;
    }

    int r = rand.nextInt(2);
    if (r == 0) {
        return m1;
    }
    return m2;
}

private class Pos {
    int x;
    int y;

    protected Pos(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object obj){
        Pos pos = (Pos) obj;
        return (this.x == pos.x && this.y == pos.y);
    }
}

private void insertToRelativePos(Pos pos, int posToAdd){
    if(pos.x == 1 || pos.y == 1){
        relativePositions[posToAdd] = RelativePos.EDGE;
    }else{
        relativePositions[posToAdd] = RelativePos.CORNER;
    }
}

private enum RelativePos{
    CORNER, EDGE
}
}

Изменить: я добавил лучшую систему подражания. Волки все еще не чувствуют себя хорошо, поскольку в данный момент они не пытаются ничего избежать, постоянно передвигаясь.


12

Не вход, но так как большинство волков просто неподвижны, на самом деле смотреть довольно скучно, поэтому я добавил в Wild стихийное бедствие:

Землетрясение!

Приблизительно в 5% случаев землетрясение будет происходить со случайной магнитудой: 100 - самое высокое, 20 - самое низкое. Это установит значение, earthquakeCounterкоторое будет экспоненциально уменьшаться со временем после землетрясения.

Что происходит во время землетрясения?

Все животные будут иметь возможность перемещаться случайным образом, в зависимости от значения earthquakeCounter. Поэтому, если значение равно 75, около 75% животных (включая камни) будут перемещаться случайным образом в любом направлении (распределяется равномерно).

Неудивительно, что это убивает многих животных, поэтому максимум составляет около 50 животных после нескольких испытаний.

Также землетрясение будет отображаться в графическом интерфейсе, который варьируется в зависимости от магнитуды.

Я не вижу землетрясения!

Вероятность землетрясения довольно мала, всего 5%.

Но не волнуйтесь! Я также включил "Землетрясение!" кнопка на графическом интерфейсе, если вы хотите выгнать всех волков из их зон комфорта ...

Вот скриншот:

землетрясение

Вот код:

Wild.java

main() функция (обновлена, чтобы пропустить графический интерфейс для первых 100 итераций для ускорения):

public static void main(String[] args) {

    int size = Math.round((float)Math.sqrt(classes.length+3)*20);
    final Game game = new Game(size);

    Statistics stats = new Statistics(game, classes);

    String[] colors = generateColors(classes.length);
    int idx = 0;
    for(Class c : classes){
        Animal.setColor(c, colors[idx]);
        idx++;
        game.populate(c, 100);
    }
    stats.update();

    JFrame gui = new JFrame();
    Container pane = gui.getContentPane();

    JLabel boardLabel = new JLabel();
    boardLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
    boardLabel.setText(game.toString());
    pane.add(boardLabel, BorderLayout.WEST);

    JLabel statsLabel = new JLabel();
    statsLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
    statsLabel.setText(stats.toString());
    pane.add(statsLabel, BorderLayout.EAST);

    JButton earthquakeButton = new JButton();
    earthquakeButton.addActionListener(new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {
            game.earthquake(true);
        }

    });
    earthquakeButton.setText("Earthquake!");
    pane.add(earthquakeButton, BorderLayout.SOUTH);

    gui.pack();
    gui.setVisible(true);

    for(int i=0; i<100; i++){
        game.iterate();
        stats.update();
    }

    while(true) {
        game.iterate();
        stats.update();
        boardLabel.setText(game.toString());
        statsLabel.setText(stats.toString());
        try { Thread.sleep(100); } catch (InterruptedException e) {}
    }
}

Game.java

package wild;

import animals.Animal;
import java.util.ArrayList;
import java.util.Random;
import animals.Animal.Attack;
import animals.Animal.Move;

public class Game {

    private ArrayList<ArrayList<ArrayList<Animal>>> board;
    private final Random gen = new Random();
    protected final int SIZE;
    private static int earthquakeCounter = 0;

    protected Game(int size) {
        this.SIZE = size;
        board = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            board.add(new ArrayList<ArrayList<Animal>>());
            for (int j = 0; j < size; j++) {
                board.get(i).add(new ArrayList<Animal>());
            }
        }
    }

    protected <T extends Animal> void populate(Class<T> species, int num) {
        while (num > 0) {
            int row = gen.nextInt(SIZE);
            int col = gen.nextInt(SIZE);
            if (board.get(row).get(col).isEmpty()) {
                try { board.get(row).get(col).add(species.newInstance()); } 
                catch (InstantiationException | IllegalAccessException e) {}
                num--;
            }
        }
    }

    protected void iterate() {
        earthquake(false);
        moveAll();
        flatten();
    }

    private void moveAll() {
        Game game = new Game(SIZE);
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (!board.get(i).get(j).isEmpty()) {
                    Animal a = board.get(i).get(j).get(0);
                    a.surroundings = getArea(i, j);
                    Move aMove;
                    try { aMove = a.move(); } 
                    catch (Exception e) { aMove = Move.HOLD; }
                    if(gen.nextInt(100)<earthquakeCounter){
                        aMove = Move.values()[gen.nextInt(4)];
                    }
                    switch(aMove) {
                        case UP:
                            game.board.get((i-1+SIZE)%SIZE).get(j).add(a);
                            break;
                        case RIGHT:
                            game.board.get(i).get((j+1)%SIZE).add(a);
                            break;
                        case DOWN:
                            game.board.get((i+1)%SIZE).get(j).add(a);
                            break;
                        case LEFT:
                            game.board.get(i).get((j-1+SIZE)%SIZE).add(a);
                            break;
                        case HOLD:
                            game.board.get(i).get(j).add(a);
                            break;
                    }
                }
            }
        }
        board = game.board;
    }

    /**
     * Give a random chance for an earthquake to happen
     */
    protected void earthquake(boolean force){
        if(force || (earthquakeCounter==0 && gen.nextInt(1000)>950)){
            earthquakeCounter = 20+gen.nextInt(80);
        } else {
            earthquakeCounter /= 2;
        }
    }

    private void flatten() {
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                while (cell.size() > 1) {
                    int rand1, rand2;
                    rand1 = gen.nextInt(cell.size());
                    do { rand2 = gen.nextInt(cell.size()); } while (rand1 == rand2);

                    Animal a = cell.get(rand1);
                    Animal b = cell.get(rand2);
                    Attack aTack, bTack;
                    try { aTack = a.fight(b.letter); } 
                    catch (Exception e) { aTack = Attack.SUICIDE; }
                    try {  bTack = b.fight(a.letter); }
                    catch (Exception e) { bTack = Attack.SUICIDE; }

                    if (aTack == bTack) {
                        cell.remove((Animal)(Math.random() > 0.5 ? a : b));
                    } else {
                        switch (aTack) {
                            case ROCK:
                                cell.remove((Animal)(bTack == Attack.PAPER ? a : b));
                                break;
                            case PAPER:
                                cell.remove((Animal)(bTack == Attack.SCISSORS ? a : b));
                                break;
                            case SCISSORS:
                                cell.remove((Animal)(bTack == Attack.ROCK ? a : b));
                                break;
                        }
                    } 
                }
            }
        }
    }

    protected int poll(Class c) {
        int count = 0;
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                for (Animal a : cell) {
                    if(c.isInstance(a))
                        count++;
                }
            }
        }
        return count;
    }

    public String toString() {
        String s = "<html>";
        s += "<span style='background:"+getBackgroundColor()+"'>";
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                if (cell.isEmpty())
                    s += "&nbsp;&nbsp;";
                else
                    s += "<span style='color:"+ Animal.color.get(cell.get(0).getClass()) +"'>" + cell.get(0).letter + "</span>&nbsp;";
            }
            s+="<br>";
        }
        s += "</span>";
        return s + "</html>";
    }

    private String getBackgroundColor(){
        int shade = 255-(int)Math.floor(255*earthquakeCounter/100.0);
        String result = String.format("#%02x%02x%02x", shade, shade, shade);
        return result;
    }

    private char[][] getArea(int i, int j) {
        char[][] area = new char[3][3];
        for(int k = -1; k <= 1; k++) {
            for(int l = -1; l <= 1; l++) {
                int temp1 = k+1;
                int temp2 = l+1;
                int temp3 = (i+k+SIZE)%SIZE;
                int temp4 = (j+l+SIZE)%SIZE;
                ArrayList<Animal> cell = board.get((i+k+SIZE)%SIZE).get((j+l+SIZE)%SIZE);
                area[k+1][l+1] = (char)(cell.isEmpty() ? ' ' : cell.get(0).letter);
            }
        }
        return area;
    }
}

5
некоторые мужчины просто хотят наблюдать за миром ... землетрясение
CommonGuy

5
Мои GatheringWolves плачут.
johnchen902

12

MultiWolf (Java)

Этот волк знает о других волках в этой задаче программирования. Он создает их (как «домашних животных»), если они доступны, и использует их, чтобы определить, что делать, спрашивая каждого имеющегося у него питомца-волка и выбирает наиболее популярный ответ.

Этот волк должен быть безопасен для бесконечной рекурсии - то есть, если кто-то еще реализует подобную концепцию - и будет возвращать действие по умолчанию Attack.ROCK/, Move.HOLDесли он обнаружит, что его вызывают, когда он вызывает других животных.

В моих тестах это имело разные результаты. Я не уверен, будет ли это разрешено или нет. Но если это так, и происходит какое-то невозможное чудо, побуждающее его к победе, я думаю, что победный титул должен быть передан волку, который приходит «вторым» - это справедливо, я, вероятно, украл его логику.

Это позволяет избежать самоубийства.

Редактировать - я полагаю, что этого Волка нужно будет загрузить после того, как на него ссылаются волки, чтобы он функционировал должным образом.

package animals;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;

public class MultiWolf extends Animal {

    private static final LinkedList<Animal> pets = new LinkedList<>();
    private static boolean inPetCall = false;

    private static void attemptLoadPet(String className) {
        try {
            Object pet = Class.forName(className).newInstance();

            if (pet instanceof Animal) {
                pets.add((Animal) pet);
            }
        } catch (Exception ex) {
            // this wolf is not available
            System.out.println(className + " is not available for MultiWolf cheating.");
        }
    }

    static {
        attemptLoadPet("animals.AlphaWolf");
        attemptLoadPet("animals.CamperWolf");
        attemptLoadPet("animals.GamblerWolf");
        attemptLoadPet("animals.GatheringWolf");
        attemptLoadPet("animals.LazyWolf");
        attemptLoadPet("animals.Sheep");
        attemptLoadPet("animals.Wion");

        attemptLoadPet("animals.MOSHPITFRENZYWolf");
        attemptLoadPet("animals.PassiveAgressiveWolf");
        attemptLoadPet("animals.StoneEatingWolf");
        attemptLoadPet("animals.HerjanWolf");
        attemptLoadPet("animals.HonorWolf");
        attemptLoadPet("animals.MimicWolf");
        attemptLoadPet("animals.LionHunterWolf");
        attemptLoadPet("animals.OmegaWolf");
        attemptLoadPet("animals.WolfWithoutFear");
        attemptLoadPet("animals.WolfRunningWithScissors");
        // attemptLoadPet("animals.SmartWolf");
        // According to Rusher, the above cheating of a non-Java wolf breaks the non-Java-entry wrapper.
        attemptLoadPet("animals.ShadowWolf");
        attemptLoadPet("animals.HybridWolf");
        attemptLoadPet("animals.ProAlpha");
        attemptLoadPet("animals.ForrestWolf");
        attemptLoadPet("animals.WhenIGrowUp");
        attemptLoadPet("animals.MigratingWolf");
        attemptLoadPet("animals.BlindWolf");
    }

    public MultiWolf() {
        super('W');
    }

    @Override
    public Attack fight(char opponent) {
        if (inPetCall) {
            // stop infinite recursion
            return Attack.ROCK;
        }

        inPetCall = true;

        HashMap<Attack, Integer> collect = new HashMap<>();

        collect.put(Attack.ROCK, 0);
        collect.put(Attack.PAPER, 0);
        collect.put(Attack.SCISSORS, 0);
        collect.put(Attack.SUICIDE, -9001);

        for (Animal a : pets) {
            a.surroundings = this.surroundings;
            Attack atk = a.fight(opponent);
            collect.put(atk, collect.get(atk)+1);
        }

        int top=0;
        Attack atk=Attack.ROCK;

        for (Entry<Attack, Integer> ent : collect.entrySet()) {
            if (ent.getValue() > top) {
                atk = ent.getKey();
                top = ent.getValue();
            }
        }

        inPetCall = false;

        return atk;
    }

    @Override
    public Move move() {
        if (inPetCall) {
            // stop infinite recursion
            return Move.HOLD;
        }

        inPetCall = true;

        HashMap<Move, Integer> collect = new HashMap<>();

        collect.put(Move.DOWN, 0);
        collect.put(Move.HOLD, 0);
        collect.put(Move.LEFT, 0);
        collect.put(Move.RIGHT, 0);
        collect.put(Move.UP, 0);


        for (Animal a : pets) {
            a.surroundings = this.surroundings;
            Move mv = a.move();
            collect.put(mv, collect.get(mv)+1);
        }

        int top=0;
        Move mv=Move.HOLD;

        for (Entry<Move, Integer> ent : collect.entrySet()) {
            if (ent.getValue() > top) {
                mv = ent.getKey();
                top = ent.getValue();
            }
        }

        inPetCall = false;

        return mv;
    }

}

Если я правильно помню, вы можете получить классы через Wild.classes, так как это статическое поле ... Так что вам не придется обновлять своего волка каждый раз, когда здесь появляется новый волк;)
CommonGuy

Это правда. Но я сделал это сейчас, вероятно, собираюсь оставить это. Может также удалить некоторых из менее выигрышных волков из этого мультиволка. Кажется, что Wion вымирает каждый раз в моих пробежках, и я собираюсь исключить его из MultiWolf, так как думаю, не снижает ли это качество действий.
OlivierTheOlive

Я считаю, что правило «Вы не можете ни читать, ни изменять файлы, созданные другим классом Wolf», было предназначено для включения самих файлов других классов Wolf. Так что я думаю, что эта запись, хотя и отличная идея, противоречит правилам.
Runer112

1
@ Runer112 Мне было интересно, но я также немного узнал из этого о загрузке классов по имени, и что не существует простого способа найти все классы в пакете. Просто немного веселья
OlivierTheOlive

3
Создание экземпляра другого Волка не означает чтение или изменение файлов, созданных другим Волком, поэтому это представление является законным. Правило предназначалось для защиты данных от представлений, написанных на языках, в которых нет таких вещей, как статические переменные, и вместо этого необходимо записать их в файл.
Rainbolt

12

Каменный едящий волк

Вот мое представление. Этот волк держится на месте, если не видит в своем окружении камня, льва или волка. Если он видит камень и не рискует быть атакованным другим волком или львом, он пытается его съесть. Если он видит какую-либо опасность, он бежит!

РЕДАКТИРОВАТЬ 1 : Улучшено наблюдение за алгоритмом опасности. Теперь он лучше убегает от опасности :)

package animals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class StoneEatingWolf extends Animal{

    public StoneEatingWolf() {
        super('W');
    }

    @Override
    public Attack fight(char c) {
        switch (c){
            case 'L': return Attack.SCISSORS;
            case 'B': return Attack.SCISSORS;
            case 'W': return getRandomAttack();
            case 'S': return Attack.PAPER;
            default: return getRandomAttack();
        }
    }

    private Attack getRandomAttack(){
        List<Attack> att = new ArrayList<>();
        att.add(Attack.PAPER);
        att.add(Attack.PAPER);
        att.add(Attack.ROCK);
        att.add(Attack.SCISSORS);
        Collections.shuffle(att);
        return att.get(0);
    }

    @Override
    public Move move() {
        List<Move> m = new ArrayList<>();

        //First see if there is any dangerous animal. If it is, then flee
        if (isThereAnyDangerousAnimal()){
            m.add(Move.UP);
            m.add(Move.RIGHT);
            m.add(Move.LEFT);
            m.add(Move.DOWN);
            getSafeMoves(m);
        }else{
        //No danger: Look for stones to eat
            if (isThereAnimalAtNorth('S')){
                m.add(Move.UP);
            }
            if (isThereAnimalAtEast('S')){
                m.add(Move.RIGHT);
            }
            if (isThereAnimalAtWest('S')){
                m.add(Move.LEFT);
            }
            if (isThereAnimalAtSouth('S')){
                m.add(Move.DOWN);
            }
        }

        if (m.isEmpty()){
            return Move.HOLD;
        } else {
            Collections.shuffle(m);
            return m.get(0);
        }
    }

    private void getSafeMoves(List<Move> lm){

        if (isThereAnimalAtNorth('L') || isThereAnimalAtNorth('W')){
            lm.remove(Move.UP);
        }
        if (isThereAnimalAtEast('L') || isThereAnimalAtEast('W')){
            lm.remove(Move.RIGHT);
        }
        if (isThereAnimalAtSouth('L') || isThereAnimalAtSouth('W')){
            lm.remove(Move.DOWN);
        }
        if (isThereAnimalAtWest('L') || isThereAnimalAtWest('W')){
            lm.remove(Move.LEFT);
        }

    }

    private boolean isThereAnimalAtNorth(char an){
        if (surroundings[0][0] == an || surroundings [0][1] == an || surroundings [0][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtSouth(char an){
        if (surroundings[2][0] == an || surroundings [2][2] == an || surroundings [2][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtEast(char an){
        if (surroundings[0][2] == an || surroundings [1][2] == an || surroundings [2][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtWest(char an){
        if (surroundings[0][0] == an || surroundings [1][0] == an || surroundings [2][0] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnyDangerousAnimal(){
        if (isThereAnimalAtEast('L') ||
                isThereAnimalAtEast('W') ||
                isThereAnimalAtNorth('L') ||
                isThereAnimalAtNorth('W') ||
                isThereAnimalAtSouth('L') ||
                isThereAnimalAtSouth('W') ||
                isThereAnimalAtWest('L') ||
                isThereAnimalAtWest('W')){
            return true;
        }
        return false;
    }

    }

Редактировать 2 : Немного статистики

Мне удалось сделать StoneEatingWolf топ-5-6 Wolf в симуляциях, которые я проводил:

Средние результаты после 40 пьес 1000 итераций

Я делаю некоторый анализ боев, где подразумеваются Каменные поедающие волки. Запустив 40 пьес из 1000 итераций, я получаю следующие результаты:

Таблица результатов боя

Победу одерживает Каменный Едящий Волк. Диаграмма показывает то, что мы уже знаем: самые успешные волки - это те, которые не встречают других волков. Я также заметил, что другие мои волки (Мигрирующие Волки) трахают некоторых из моих Пожирателей Камней. Я надеюсь, что они тоже охотятся на других волков. Как ни странно, я не спотыкался ни с Ленивым Волком, ни с кем-то Волком. Кроме того, это результаты атак, которые я получил за 20 пробежек (за исключением камней и медведей):

PAPER       447
ROCK        881
SCISSORS    581
SUICIDE     230

Кажется, что есть очевидный уклон к ROCKатакам. Зная это, я заставил своих волчьих PAPERатак немного чаще.


2
Пожалуйста, не используйте линейный график для построения категориальных данных. Это вызывает у меня столько рака, когда я смотрю на ваш график.
AJMansfield

@AJMansfield Очень жаль это слышать. Надеюсь, вы выздоровеете;) В любом случае, я приму это во внимание для любого будущего графика, который я сделаю.
Аверроэс

Вы все еще используете Windows XP? oO
justhalf

И почему вы используете ROCK(50% выигрыш), чтобы бороться с Lion? Лучше всего использовать SCISSORS(победа 75%)
полугодие

@justhalf Моя компания все еще использует XP ... И вы правы насчет ножниц. Исправлена. Спасибо :)
Averroes

11

HonorWolf

Мой Волк бежит от других волков. Если он не может убежать, он честно начинает бой.

package animals;
public class HonorWolf extends Animal {

    private int moves = 0;

    public HonorWolf() { 
        super('W'); 
    }

    @Override   
    public Attack fight(char opponent) { 
        switch(opponent) {
         case 'L':
            return Attack.SCISSORS; 
         case 'B':
            return Attack.SCISSORS;
         case 'S':
            return Attack.PAPER;
        default:
            return Attack.PAPER;
        }
    }

    public Move move() {
        int numWolves = 0, numLions = 0;

        moves++;

        for (int y = 0; y != 3; y++) {
            for (int x = 0; x != 3; x++) {
                if(surroundings[y][x] != ' ') {
                    if(surroundings[y][x] == 'W') {
                        numWolves++;
                    } else if(surroundings[y][x] == 'L') {
                        numLions++;
                    }
                }
            }       
        }

        if (numWolves == 1 && numLions == 0) {
            return Move.HOLD;
        }

        if (surroundings[0][1] == 'L' && moves%2 != 0) {
            return Move.UP;
        } 

        if (surroundings[1][0] == 'L' && moves%2 == 0) {
            return Move.LEFT;
        }

        if (surroundings[0][1] == 'W') {
            if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else {
                return Move.UP;
            }
        }

        if (surroundings[1][0] == 'W') {
            if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else {
                return Move.LEFT;
            }
        }

        if (surroundings[1][2] == 'W') {
            if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else {
                return Move.RIGHT;
            }
        }

        if (surroundings[2][1] == 'W') {
            if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else {
                return Move.DOWN;
            }
        }

        return Move.HOLD;
    }
}

Мне нужно сменить тактику атаки профессионального волка-альфа. Если бы я держался и на меня напал волк: Бой с НОЖНИЦАМИ;)
Илья Газман

11

Слепой Волк

Слепой волк боится двигаться и никогда не знает, за что борется. Играя ножницами каждый раз, у него лучшие шансы, так как он никогда не натолкнется на настоящий камень.

package animals;

public class BlindWolf extends Animal {
    public BlindWolf() { super('W'); }

    @Override
    public Attack fight(char c) { 
        return Attack.SCISSORS;
    }

    @Override
    public Move move() {
        return Move.HOLD;
    }
}

11

Когда я вырасту

Когда этот волк вырастет, он захочет стать Львом. Так что он случайно гуляет в поисках львов, которые следуют по их стопам и учатся быть львами.

Этот волк был разработан в качестве противостояния волкам, которые меняются местами со Львами.

package animals;

import java.util.Random;

/**
 *
 * @author Quincunx
 */
public class WhenIGrowUp extends Animal {

    Random r;
    boolean following;
    boolean toggle;

    public WhenIGrowUp() {
        super('W');
        r = new Random();
        following = false;
        toggle = false;
    }

    @Override
    public Attack fight(char c) {
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
            case 'S':
                return Attack.PAPER;
            default:
                return Attack.values()[r.nextInt(4)];
        }
    }

    @Override
    public Move move() {
        if (surroundings[1][2] == 'L') {
            return Move.RIGHT;
        }
        if (surroundings[2][1] == 'L') {
            return Move.DOWN;
        }
        Move direction = Move.values()[r.nextInt(5)];
        out:
        for (int y = 0; y < 3; y++) {
            for (int x = 0; x < 3; x++) {
                if (surroundings[y][x] == 'L') {
                    if (y == 0 && x == 1) {
                        direction = Move.UP;
                    } else if (y == 1 && x == 0) {
                        direction = Move.LEFT;
                    } else {
                        direction = Move.HOLD;
                    }
                    break out;
                }
            }
        }
        return direction;
    }
}

11

SpyWolf

SpyWolf шпионит за своими врагами и регистрирует их активность, чтобы он мог следить за всеми, сохраняя дистанцию. Не хотел бы быть выясненным!

package animals;

import static animals.Animal.Attack.*;
import static animals.Animal.Move.*;

import java.awt.Point;
import java.util.*;

public class SpyWolf extends Animal {

    private static final Random r = new Random();
    private static boolean hasTestedPRNG = false;
    private static int PRNG = -1;
    private boolean lionTracker = true;
    private boolean useScissors = false;

    private final ArrayList<MapTile> map = new ArrayList<MapTile>();
    private final Point location = new Point();

    public SpyWolf() {
        super('W');
    }

    @Override
    public Animal.Attack fight(char opponent) {
        switch (opponent) {
            case 'B':
            case 'L':
                return SCISSORS;
            case 'S':
                return PAPER;
            default:
                if (useScissors) {
                    useScissors = false;
                    return SCISSORS;
                }
                return PAPER;
        }
    }

    @Override
    public Animal.Move move() {

        Move m = HOLD;

        if (!hasTestedPRNG) {
            hasTestedPRNG = true;
            double d = 0;
            for (int i = 0; i < 100; i++)
                d += Math.random();
            if (d > 99) {
                PRNG = 1;
            } else if (d > 30 && d < 70) PRNG = 0;
        }

        lionTracker = !lionTracker;
        boolean adj = false;

        updateMap();

        scan: {
            if (PRNG < 1) {
                if (look(LEFT) == 'L' && !lionTracker) {
                    useScissors = true;
                    m = LEFT;
                    break scan;
                }

                if (look(UP) == 'L' & lionTracker) {
                    useScissors = true;
                    m = UP;
                    break scan;
                }
            }

            int x = 0, y = 0;
            ArrayList<Move> moves = new ArrayList<Move>(4);

            for (Move i : Move.values())
                moves.add(i);

            if (look(UP) == 'W') {
                y += 54;
                moves.remove(UP);
                adj = true;
            }
            if (look(DOWN) == 'W') {
                y -= 54;
                moves.remove(DOWN);
                adj = true;
            }
            if (look(LEFT) == 'W') {
                x += 54;
                moves.remove(LEFT);
                adj = true;
            }
            if (look(RIGHT) == 'W') {
                x -= 54;
                moves.remove(RIGHT);
                adj = true;
            }

            if (moves.isEmpty() || !adj) break scan;

            for (MapTile t : map) {
                if (t.x >= location.x - 2 && t.x <= location.x + 2 && t.y >= location.y - 2 && t.y <= location.y + 2 && t.d) {
                    int dist = Math.abs(t.x - location.x) + Math.abs(t.y - location.y);
                    y += t.y > location.y ? -60 / dist : 60 / dist;
                    x += t.x < location.x ? 60 / dist : -60 / dist;
                }
            }
            m = moveDir(x, y);
            if (!moves.contains(m)) m = HOLD;
        }
        switch (m) {
            case UP:
                location.y--;
                return m;
            case DOWN:
                location.y++;
                return m;
            case LEFT:
                location.x--;
                return m;
            case RIGHT:
                location.x++;
                return m;
            default:
                return m;
        }
    }

    private void updateMap() {
        for (int y = -1; y < 2; y++)
            xloop: for (int x = -1; x < 2; x++) {
                if (x == 0 && y == 0) continue;
                for (MapTile t : map)
                    if (t.x == x + location.x && t.y == y + location.y) {
                        t.d = surroundings[y + 1][x + 1] == 'W';
                        continue xloop;
                    }
                map.add(new MapTile(x + location.x, y + location.y, surroundings[y + 1][x + 1] == 'W'));
            }
    }

    private Move moveDir(int x, int y) {
        if (x == 0) return y < 0 ? UP : y > 0 ? DOWN : HOLD;
        if (y == 0) return x < 0 ? LEFT : RIGHT;
        if (x < 0) {
            if (y < 0) {
                if (y < x)
                    return UP;
                else if (x < y) return LEFT;
                return r.nextBoolean() ? UP : LEFT;
            } else {
                if (-y < x)
                    return DOWN;
                else if (x < -y) return LEFT;
                return r.nextBoolean() ? DOWN : LEFT;
            }
        }
        if (y < 0) {
            if (y < -x)
                return UP;
            else if (-x < y) return RIGHT;
            return r.nextBoolean() ? UP : RIGHT;
        } else {
            if (y > x)
                return DOWN;
            else if (x < y) return RIGHT;
        return r.nextBoolean() ? DOWN : RIGHT;
        }
    }

    private char look(Move direction) {
        switch (direction) {
            case UP:
                return surroundings[0][1];
            case DOWN:
                return surroundings[2][1];
            case LEFT:
                return surroundings[1][0];
            case RIGHT:
                return surroundings[1][2];
            default:
                return surroundings[1][1];
        }
    }

    private static class MapTile {
        int x, y;
        boolean d;

        MapTile(int x, int y, boolean d) {
            this.x = x;
            this.y = y;
            this.d = d;
        }
    }
}

У него неплохо получается, но этот неубедительный HybridWolf слишком обманчив! Мы увидим, что SpyWolf может вернуться в школу шпионов и обучать продвинутым приемам против волков.


1
Вы называете это хромым, я называю это умным;)
CommonGuy

5
Ahhhhh! Так много gotoс! И на языке, который даже не имеет их!
AJMansfield

9

HybridWolf

Я не мог удержаться, кроме как сделать еще одного волка. Этот способ сильно отличается (по своему коду, а не по поведению), так как он выбирает атаку / ход, что сделали бы другие добрые волки.
Конечно, все волки хорошие, но я имею в виду тех, у кого больше всего очков :)

package animals;

import java.util.ArrayList;
import java.util.Random;

public class HybridWolf extends Animal{
    private final Class[] classes = {ProAlpha.class, OmegaWolf.class, SpyWolf.class, HerjanWolf.class, DeepWolf.class, ProtoWolf.class};
    private final ArrayList<Animal> wolves = new ArrayList<Animal>(); 

    public HybridWolf() {
        super('W');
        for(Class c: classes) {
            try {
                wolves.add((Animal)c.newInstance());
            } catch (Exception ex) {}
        }
    }

    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            try {
                int[] attacks = new int[3];
                Attack bestAttack = randomAttack();
                for(Animal wolf : wolves) {
                    wolf.surroundings = this.surroundings;
                    attacks[wolf.fight(opponent).ordinal()]++;
                }
                for(int i =0; i < 5; i++) {
                    if(attacks[i] > attacks[bestAttack.ordinal()]) {
                        bestAttack = Attack.values()[i];
                    }
                }
                return bestAttack;
            } catch (Exception e) {
                return randomAttack();
            }
        }
    }

    @Override
    public Move move() {
        try {
            int[] moves = new int[5];
            Move bestMove = Move.HOLD;
            for(Animal wolf : wolves) {
                wolf.surroundings = this.surroundings;
                moves[wolf.move().ordinal()]++;
            }
            for(int i =0; i < 5; i++) {
                if(moves[i] > moves[bestMove.ordinal()]) {
                    bestMove = Move.values()[i];
                }
            }
            return bestMove;
        } catch (Exception e) {
            return Move.HOLD;
        }
    }

    public Attack randomAttack() {
        Random rand = new Random();
        switch (rand.nextInt(3)){
            case 1: return Attack.SCISSORS;
            case 2: return Attack.ROCK;
            default: return Attack.PAPER;
        }
    }

}

В моих тестах он лучше, чем мой предыдущий AlphaWolf, но Omega / Honor / ProAlpha иногда побеждает меня ... Чем больше хороших работ здесь, тем лучше получится этот волк: D


Это немного нахально! умная идея, хотя. Не уверен, как это будет справедливым как законный вход, так как я понятия не имею о тестах, которые Рашер будет применять для определения законного входа. то есть, если он делает тест в изоляции без других присутствующих волков, то этот волк с треском провалится: P
Moogie

@ Moogie 90% записей являются законными. До сих пор я исключил только записи, которые изменили свое письмо на что-то отличное от «W», или записи, которые я не смог выяснить, как компилировать на другом языке (и я дам им знать, если это так, но вы можете не вижу этого здесь, потому что я говорю с ними в чате).
Rainbolt

@Rusher есть некоторые записи, которые пытаются изменить шансы в свою пользу. например, Gambler wolf изменяет генератор случайных чисел в Java Math.random (), чтобы всегда возвращать 1! Как ни странно, это мало влияет на результаты, поскольку волки-победители - это волки, которые избегают сражений!
Муги

@Moogie GamblerWolf - законное представление (и тоже довольно умное). Вы правы, это не сильно изменило результаты. Если что-то выйдет из-под контроля, я просто скажу: «Хорошо, он победит, но вот результат, если он не был включен». Таким образом, все остальные могут наслаждаться, не будучи уничтоженными.
Rainbolt

2
@Moogie Если что-то конкретно не запрещено в спецификациях задачи, это де-факто является законным, и традиция на этом сайте - не менять правила, когда люди публикуют ответы на них.
plannapus

9

EvoWolf

Все вы, глупые, умные волки! EvoWolf живет в дикой природе с другими жесткими волками, такими как DeepWolf и HerjanWolf, поэтому ему пришлось развиваться, чтобы выжить.

Код использует генетический алгоритм для развития лучшего волка (я не заметил LionHunterWolf, пока не схватил волков для тренировки). Это разные гены для каждого животного / атаки, направление движения, когда это безопасно, и направление движения для каждого животного в окружении. После 1000 раундов у волков, которые продержались наибольшее количество ходов, самая высокая вероятность рождения потомства (то есть, чем дольше вы живете, тем больше у вас шансов спариться). Мы также добавляем случайную мутацию примерно в 10% детей, надеясь, что это поможет.

Вот код EvoWolf, ВАМ ТАКЖЕ НУЖЕН evowolf.txt В ВАШЕМ РАБОЧЕМ СПРАВОЧНИКЕ - СОДЕРЖИТ ТЕКУЩИЙ GENEPOOL. Если вы хотите развить своих собственных волков из изначальной случайности, не включайте evowolf.txt, но предоставленный в настоящее время является лучшей эволюцией. Наблюдать за развитием событий действительно приятно, поначалу выживают только 2-3 человека, а затем - до 60.

package animals;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;

public class EvoWolf extends Animal {
    public EvoWolf() { super('W'); birth();}
    public Attack fight(char c) { 
        List<Attack> attacks = getAttacks(c);
        if(attacks.size() == 0)
            return Attack.SUICIDE; //Discourage wolves without attacks, Darwin Award

        return attacks.get(random.nextInt(attacks.size()));
    }

    public Move move() {
        ++turns;
        List<Move> moves = new ArrayList<Move>();
        if(isSafe())
            moves = getSafeMoves();
        else
            moves = getThreatenedMoves();

        return (Move)moves.toArray()[random.nextInt(moves.size())];
    }

    /*====STATIC METHODS====*/
    //Shared RNG
    public static Random random = new Random();

    //Collection of 100 sets of genes
    public static String[] genePool = null;

    //Get the genes from disk or randomly generate some
    public static void readGenePool(){
        genePool = new String[100];
        int gIdx = 0;
        try (BufferedReader br = new BufferedReader(new FileReader("evowolf.txt"))){
            String sCurrentLine; 
            while ((sCurrentLine = br.readLine()) != null) {
                genePool[gIdx] = sCurrentLine;
                ++gIdx;
            }
        } catch (IOException e) {

        } 

        //if can't read genes, make some
        if(gIdx < 100){
            primordial(gIdx);
        }
    }
    public static void primordial(int idx){
        for(;idx < 100; ++idx){
            genePool[idx] = getRandomGenes();
        }
    }

    public static String getRandomGenes(){
        StringBuilder sb = new StringBuilder();
        for(int idx = 0; idx < GENE_COUNT; ++idx){
            if(random.nextBoolean())
                sb.append("1");
            else
                sb.append("0");
        }
        return sb.toString();
    }

    //Evolve wolves
    public static void nextGen(){
        //Check survival of current gen
        int survivors = 0;
        for(int idx = 0; idx < 100; ++idx){
            survivors = survivors + (generation[idx].turns == 1000 ? 1 : 0);
        }
        if(survivors > 65)
            writeGenePool(Long.toString(survivors));

        //Weighted resivour sampling
        //Take the highest of r^(1/w) where r is a random an w is the weight
        for(int idx = 0; idx < 100; ++idx){
            genePool[idx] = mateFitWolves();
        }
        writeGenePool("");
        birthCount = 0;
    }

    //Pick two wolves randomly by weighted fitness and mate them
    public static String mateFitWolves(){
        EvoWolf w1 = null;
        double weight1 = -1;
        EvoWolf w2 = null;
        double weight2 = -1;

        for(int idx = 0; idx < 100; ++idx){
            double weight = generation[idx].getWeightSample();
            if(weight > weight1){
                weight2 = weight1;
                w2 = w1;
                weight1 = weight;
                w1 = generation[idx];
            } else if(weight > weight2){
                weight2 = weight;
                w2 = generation[idx];
            }
        }

        return mateFitWolves(w1, w2);
    }

    //Make offspring
    public static String mateFitWolves(EvoWolf w1, EvoWolf w2){
        StringBuilder sb = new StringBuilder();
        //Random splice
        for(int rIdx = 0; rIdx < w1.genes.length(); ++rIdx){
            if(random.nextBoolean())
                sb.append(w1.genes.charAt(rIdx));
            else
                sb.append(w2.genes.charAt(rIdx));
        }


        //Random mutation
        while(random.nextInt(10) == 0){
            int mIdx = random.nextInt(w1.genes.length());
            if(sb.charAt(mIdx) == '0')
                sb.setCharAt(mIdx, '1');
            else
                sb.setCharAt(mIdx, '0');
        }


        return sb.toString();
    }

    //Save the next generation's gene pool back to disk
    public static void writeGenePool(String survivors){
        try {
            String str = "";
            if(!survivors.equals(""))
                str = Long.toString(System.currentTimeMillis());

            File file = new File("evowolf" + survivors + str + ".txt");

            // if file doesn't exists, then create it
            if (!file.exists()) {
                file.createNewFile();
            }

            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            BufferedWriter bw = new BufferedWriter(fw);
            for(int gIdx = 0; gIdx < genePool.length; ++gIdx){
                bw.write(genePool[gIdx]);
                bw.write('\n');
            }
            bw.close();
        } catch (IOException e) {

        }
    }

    //Keep track of the wolves in this generation
    public static int birthCount = 0;
    public static EvoWolf[] generation = new EvoWolf[100];

    /*====INSTANCE METHODS====*/
    //Populate this wolf from the gene pool
    public void birth(){
        if(genePool == null){
            readGenePool();
        }
        genes = genePool[birthCount];
        generation[birthCount] = this;
        birthCount = (birthCount + 1) % 100;    
    }

    //How long wolf has been alive
    public int turns = 0;

    //Fitness based on how long wolf survived
    public double getWeightSample(){
        return Math.pow(random.nextDouble(), 1.0/turns);
    }


    /*===GENETICS===*/
    public String genes = null;
    //Genes are made up of 182+ bits (stored at a string)
    //Each turns on the possibility of that move or attack in a given situation
    //  Attack: BLSW * RPSX = 16 bits [0-15] = Animal->Attacks
    //  Threatened Moves: BLSW * 12345678 * UDLRH = 160 bits [16-175] = Y -> X -> Animal -> Moves
    //  Safe Moves: UDLRH = 5 bits [176-180] = Moves
    //  Extra: default move [181], move combination [182]
    public static final int GENE_INDEX_ATTACKS = 0;
    public static final int GENE_INDEX_THREATENED_MOVES = GENE_INDEX_ATTACKS + (4 * 4);
    public static final int GENE_INDEX_SAFE_MOVES = GENE_INDEX_THREATENED_MOVES + (8 * 4 * 5);
    public static final int GENE_INDEX_DEFAULT_MOVE = GENE_INDEX_SAFE_MOVES + (5);
    public static final int GENE_INDEX_COMBINE_MOVES = GENE_INDEX_DEFAULT_MOVE + (1);
    public static final int GENE_COUNT = GENE_INDEX_COMBINE_MOVES + 1;
    public static int getAnimalIndex(char c){
        switch (c) {
            case 'B':
                return 0;
            case 'L':
                return 1;
            case 'S':
                return 2;
            case 'W':
            default: //Shouldn't occur but we'll assume it's the dangerous wolf
                return 3;
        } 
    }

    public static int getXYIndex(int x, int y){
        int idx = (y * 3) + x;
        if(idx > 4) //We don't need to look at ourself
            --idx;
        return idx;
    }

    public List<Attack> getAttacks(char c){
        List<Attack> attacks = new ArrayList<Attack>();
        int idx = GENE_INDEX_ATTACKS + getAnimalIndex(c);
        if(genes.charAt(idx + 0) == '1')
            attacks.add(Attack.ROCK);
        if(genes.charAt(idx + 1) == '1')
            attacks.add(Attack.PAPER);
        if(genes.charAt(idx + 2) == '1')
            attacks.add(Attack.SCISSORS);
        /*
        if(genes.charAt(idx + 3) == '1')
            attacks.add(Attack.SUICIDE);
        */
        //Suicide didn't remove itself from the gene pool like I thought so I manually removed it

        return attacks;
    }

    public boolean isSafe(){
        for(int x = 0; x <= 2; ++x){
            for(int y = 0; y <= 2; ++y){
                if(y == 1 && x == 1)
                    continue;
                if(surroundings[y][x] != ' ')
                    return false;
            }
        }
        return true;
    }

    public List<Move> getSafeMoves(){
        List<Move> moves = new ArrayList<Move>();
        int idx = GENE_INDEX_SAFE_MOVES;
        if(genes.charAt(idx + 0) == '1')
            moves.add(Move.UP);
        if(genes.charAt(idx + 1) == '1')
            moves.add(Move.DOWN);
        if(genes.charAt(idx + 2) == '1')
            moves.add(Move.LEFT);
        if(genes.charAt(idx + 3) == '1')
            moves.add(Move.RIGHT);
        if(genes.charAt(idx + 4) == '1')
            moves.add(Move.HOLD);

        return moves;
    }

    public List<Move> getThreatenedMoves(){
        List<Move> moves = new ArrayList<Move>();
        if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '0')
            moves.addAll(EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD));

        for(int x = 0; x <= 2; ++x){
            for(int y = 0; y <= 2; ++y){
                if(y == 1 && x == 1)
                    continue;
                if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '1')
                    moves.addAll(getThreatenedMoves(x,y));
                else
                    moves.retainAll(getThreatenedMoves(x,y));
            }
        }

        if(moves.size() == 0){
            if(this.genes.charAt(GENE_INDEX_DEFAULT_MOVE) == '1')
                moves.addAll(EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD));
            else
                moves.add(Move.HOLD);
        }

        return moves;
    }

    public EnumSet<Move> getThreatenedMoves(int x, int y){
        //Lookup what moves we can make for a cell unless it is blank (allow any)
        if(surroundings[y][x] != ' ')
            return getThreatenedMoves(x,y,surroundings[y][x]);
        else if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '1')
            return EnumSet.noneOf(Move.class);
        else
            return EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD);
    }

    public EnumSet<Move> getThreatenedMoves(int x, int y, char c){
        int aIdx = getAnimalIndex(c);
        int sIdx = getXYIndex(x,y);
        int idx = GENE_INDEX_THREATENED_MOVES + (sIdx * 20) + (aIdx * 5);

        EnumSet<Move> moves = EnumSet.noneOf(Move.class);

        if(genes.charAt(idx + 0) == '1')
            moves.add(Move.UP);
        if(genes.charAt(idx + 1) == '1')
            moves.add(Move.DOWN);
        if(genes.charAt(idx + 2) == '1')
            moves.add(Move.LEFT);
        if(genes.charAt(idx + 3) == '1')
            moves.add(Move.RIGHT);
        if(genes.charAt(idx + 4) == '1')
            moves.add(Move.HOLD);

        return moves;
    }

    public static String setAt(String str, int index, char replace){     
        if(str==null){
            return str;
        }else if(index<0 || index>=str.length()){
            return str;
        }
        char[] chars = str.toCharArray();
        chars[index] = replace;
        return String.valueOf(chars);       
    }
}

Я также внес некоторые изменения в Statistics.java и Wild.java, чтобы показать мне, сколько раз прошло и сколько поколений прошло. После того, как вы пробежали 1000 ходов, позвоните, EvoWolf.nextGen();чтобы рассчитать потомство. Это не обязательно для соревнования, только если вы хотите развивать свой собственный сет.

Все файлы здесь РЕДАКТИРОВАТЬ: FIXED LINK

Начиная развиваться как лучший, он вроде не становится лучше, чем топ-10. Часть ограничения состоит в том, что у него очень мало памяти о его предыдущих шагах. Хотя он функционирует как WolvesWithCollectiveMemory в том смысле, что опыт предыдущих поколений будет влиять на то, как следующее поколение функционирует в качестве долгосрочной глобальной памяти. Это было весело, хотя. В предыдущей ссылке есть лист Excel, который может помочь вам проанализировать генофонд. Замените все 1 и 0 в .txt на 1 и 0 запятыми, а затем вставьте в электронную таблицу.

Некоторые интересные заметки, большинство из которых подтверждают стратегии каждого:

  • Реальные атаки менее важны, чем избегать сражений. Или, может быть, все неволки быстро уничтожаются, поэтому они не представляют угрозы. Поколение соревнований имеет равный шанс между RPS против медведей, даже если вы должны бросить S.
  • Как и выше, мне пришлось вручную отключить самоубийство, поскольку оно не развивалось, даже если вы думаете, что это произойдет.
  • Держать - лучший ход, когда вокруг никого нет
  • Бегство, кажется, тоже хорошо, когда кто-то рядом
  • Вы должны удерживать вместо того, чтобы двигаться в случайном направлении (этот выбор был дополнительным геном, который развился)
  • Когда вокруг более 1 животного, случайное движение из пересечения ходов для каждого окружения / животного лучше, чем объединение (еще один дополнительный ген)

8

SmartWolf

Результаты в (1000 итераций) (я буду обновлять это, но буду рассматривать его как независимый тест без усреднения, потому что с таким количеством волков это довольно медленно).

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

Компиляция:

* nix (требуется Mono):

gmcs SmartWolf.cs

Окна:

csc SmartWolf.cs

Скопируйте в рабочий каталог.

Примечание: при использовании Windows, вам нужно заменить "mono SmartWolf.exe"только "SmartWolf.exe"в коде оболочки.

SmartWolf.cs:

using System;
using System.Collections.Generic;
using System.Linq;

namespace SmartWolf
{
    #region Enums
    enum Attack
    {
        Rock, Paper, Scissors, Suicide
    }
    enum Movement
    {
        Up, Down, Left, Right, Hold
    }
    enum Animal
    {
        Stone, Lion, Wolf, Bear, Empty
    }
    #endregion
    class KnowledgeBase
    {
        static Random rnd = new Random();
        public List<KeyValuePair<KeyValuePair<Animal, Attack>, int>> knowledge = new List<KeyValuePair<KeyValuePair<Animal, Attack>, int>>();
        public KnowledgeBase ()
        {
        }
        public void PunishMove (KeyValuePair<Animal, Attack> move)
        {
            if (knowledge.Count (t => t.Key.Key == move.Key && t.Key.Value == move.Value) == 0) {
                knowledge.Add (new KeyValuePair<KeyValuePair<Animal, Attack>, int> (move, -1));
            } else {
                int i = knowledge.FindIndex (t => t.Key.Equals (move));
                knowledge[i] = new KeyValuePair<KeyValuePair<Animal, Attack>, int>(knowledge[i].Key, knowledge[i].Value - 1);
            }

        }
        public void RewardMove (KeyValuePair<Animal, Attack> move)
        {
            if (knowledge.Count (t => t.Key.Key == move.Key && t.Key.Value == move.Value) == 0) {
                knowledge.Add (new KeyValuePair<KeyValuePair<Animal, Attack>, int> (move, 1));
            } else {
                int i = knowledge.FindIndex (t => t.Key.Equals (move));
                knowledge[i] = new KeyValuePair<KeyValuePair<Animal, Attack>, int>(knowledge[i].Key, knowledge[i].Value + 1);
            }
        }
        public Attack GetBestMove (Animal opponent)
        {
            Attack best = GetRandomMove();
            int j = 0;
            foreach (var pair in knowledge) {
                if(pair.Key.Key == opponent && j < pair.Value)
                {
                    best = pair.Key.Value;
                    j = pair.Value;
                }
            }
            if(j < 2)
                return GetRandomMove ();
            return best;
        }
        public static Attack GetRandomMove()
        {
            int r = rnd.Next (3);
            return r == 0 ? Attack.Paper :
                r == 1 ? Attack.Rock :
                    r == 2 ? Attack.Scissors :
                    Attack.Scissors;
        }
    }
    class MainClass
    {
        static KnowledgeBase knowledge = new KnowledgeBase();
        public static void Main (string[] args)
        {
            List<SmartWolf> list = new List<SmartWolf> ();
            List<int> temp = new List<int>();
            int l = 0;
            while (true) {
                string str = Console.ReadLine ();
                int id = int.Parse (str.Substring (1, 2));
                if(str.StartsWith ("S"))
                {
                    list.Add (new SmartWolf(id));
                    Console.WriteLine("K" + id.ToString ().PadLeft (2, '0'));
                } else if(str.StartsWith ("M"))
                {
                    if(temp.Contains (id))
                    {
                        for(int i = 0; i < 100; i++)
                        {
                            SmartWolf s = list.Where (t => t.ID == i).ToList ()[0];
                            if(s.AttackedInLastRound == 0 && !temp.Contains(i))
                            {
                                s.IsAlive = false;
                                knowledge.PunishMove (s.LastMove);
                                s.AttackedInLastRound = -1;
                            } else if(s.AttackedInLastRound == 0 && temp.Contains (i))
                            {
                                knowledge.RewardMove (s.LastMove);
                                s.AttackedInLastRound = -1;
                            }
                            if(s.AttackedInLastRound > 0)
                                s.AttackedInLastRound--;
                        }
                        temp.Clear();
                        l++;
                    }
                    temp.Add (id);

                    Console.WriteLine('H' + id.ToString ().PadLeft (2, '0'));
                } else if(str.StartsWith ("A"))
                {
                    Animal enemy = str[3] == 'W' ? Animal.Wolf :
                                   str[3] == 'L' ? Animal.Lion :
                                   str[3] == 'S' ? Animal.Stone :
                                   str[3] == 'B' ? Animal.Bear : Animal.Empty;
                    Attack atk = knowledge.GetBestMove (enemy);
                    Console.WriteLine((atk == Attack.Paper ? "P" :
                                      atk == Attack.Rock ? "R" : 
                                      atk == Attack.Scissors ? "S" :
                                      "P") + id.ToString ().PadLeft (2, '0'));
                    list.Where (t => t.ID == id).ToList ()[0].AttackedInLastRound = 2;
                    list.Where (t => t.ID == id).ToList ()[0].LastMove = new KeyValuePair<Animal, Attack>(enemy, atk);
                }
            }
        }
    }
    class SmartWolf
    {
        public int ID;
        public bool IsAlive = true;
        public KeyValuePair<Animal, Attack> LastMove = new KeyValuePair<Animal, Attack>(Animal.Empty, Attack.Suicide);
        public int AttackedInLastRound = -1;
        public SmartWolf(int n)
        {
            ID = n;
        }
    }
}

Оболочка (спасибо @ProgrammerDan, я просто включаю ее здесь, чтобы было проще скопировать вставку):

package animals;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Remote SmartWolf wrapper class. 
 */
public class SmartWolf extends Animal {
    /**
     * Simple test script that sends some typical commands to the
     * remote process.
     */
    public static void main(String[]args){
        SmartWolf[] wolves = new SmartWolf[100];
        for(int i=0; i<10; i++) {
            wolves[i] = new SmartWolf();
        }
        char map[][] = new char[3][3];
        for (int i=0;i<9;i++)
            map[i/3][i%3]=' ';
        map[1][2] = 'W';
        for(int i=0; i<10; i++) {
            wolves[i].surroundings=map;
            System.out.println(wolves[i].move());
        }
        for(int i=0; i<10; i++) {
            System.out.println(wolves[i].fight('S'));
            System.out.println(wolves[i].fight('B'));
            System.out.println(wolves[i].fight('L'));
            System.out.println(wolves[i].fight('W'));
        }
        wolfProcess.endProcess();
    }
    private static WolfProcess wolfProcess = null;

    private static SmartWolf[] wolves = new SmartWolf[100];
    private static int nWolves = 0;

    private boolean isDead;
    private int id;

    /**
     * Sets up a remote process wolf. Note the static components. Only
     * a single process is generated for all Wolves of this type, new
     * wolves are "initialized" within the remote process, which is
     * maintained alongside the primary process.
     * Note this implementation makes heavy use of threads.
     */
    public SmartWolf() {
        super('W');
        if (SmartWolf.wolfProcess == null) {
            SmartWolf.wolfProcess = new WolfProcess();
            SmartWolf.wolfProcess.start();
        }

        if (SmartWolf.wolfProcess.initWolf(SmartWolf.nWolves, MAP_SIZE)) {
            this.id = SmartWolf.nWolves;
            this.isDead = false;
            SmartWolf.wolves[id] = this;
        } else {
            SmartWolf.wolfProcess.endProcess();
            this.isDead = true;
        }
        SmartWolf.nWolves++;
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, SUICIDE.
     * Otherwise, communicate an attack to the remote process and return
     * its attack choice.
     */
    @Override
    public Attack fight(char opponent) {
        if (!SmartWolf.wolfProcess.getRunning() || isDead) {
            return Attack.SUICIDE;
        }
        try {
            Attack atk = SmartWolf.wolfProcess.fight(id, opponent);

            if (atk == Attack.SUICIDE) {
                this.isDead = true;
            }

            return atk;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Attack.SUICIDE;
        }
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, HOLD.
     * Otherwise, get a move from the remote process and return that.
     */
    @Override
    public Move move() {
        if (!SmartWolf.wolfProcess.getRunning() || isDead) {
            return Move.HOLD;
        }
        try {
            Move mv = SmartWolf.wolfProcess.move(id, surroundings);

            return mv;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Move.HOLD;
        }
    }

    /**
     * The shared static process manager, that synchronizes all communication
     * with the remote process.
     */
    static class WolfProcess extends Thread {
        private Process process;
        private BufferedReader reader;
        private PrintWriter writer;
        private ExecutorService executor;
        private boolean running;

        public boolean getRunning() {
            return running;
        }

        public WolfProcess() {
            process = null;
            reader = null;
            writer = null;
            running = true;
            executor = Executors.newFixedThreadPool(1);
        }

        public void endProcess() {
            running = false;
        }

        /**
         * WolfProcess thread body. Keeps the remote connection alive.
         */
        public void run() {
            try {
                System.out.println("Starting SmartWolf remote process");
                ProcessBuilder pb = new ProcessBuilder("mono SmartWolf.exe".split(" "));
                pb.redirectErrorStream(true);
                process = pb.start();
                System.out.println("SmartWolf process begun");
                // STDOUT of the process.
                reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); 
                System.out.println("SmartWolf reader stream grabbed");
                // STDIN of the process.
                writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
                System.out.println("SmartWolf writer stream grabbed");
                while(running){
                    this.sleep(0);
                }
                reader.close();
                writer.close();
                process.destroy(); // kill it with fire.
                executor.shutdownNow();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("SmartWolf ended catastrophically.");
            }
        }

        /**
         * Helper that invokes a read with a timeout
         */
        private String getReply(long timeout) throws TimeoutException, ExecutionException, InterruptedException{
            Callable<String> readTask = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return reader.readLine();
                }
            };

            Future<String> future = executor.submit(readTask);
            return future.get(timeout, TimeUnit.MILLISECONDS);
        }

        /**
         * Sends an initialization command to the remote process
         */
        public synchronized boolean initWolf(int wolf, int map_sz) {
            while(writer == null){
                try {
                this.sleep(0);
                }catch(Exception e){}
            }
            boolean success = false;
            try{
                writer.printf("S%02d%d\n", wolf, map_sz);
                writer.flush();
                String reply = getReply(5000l);
                if (reply != null && reply.length() >= 3 && reply.charAt(0) == 'K') {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        success = true;
                    }
                }
                if (reply == null) {
                    System.out.println("did not get reply");
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("SmartWolf %d failed to initialize, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %d failed to initialize, %s\n", wolf, e.getMessage());
            }
            return success;
        }

        /**
         * Send an ATTACK command to the remote process.
         */
        public synchronized Attack fight(int wolf, char opponent) {
            Attack atk = Attack.SUICIDE;
            try{
                writer.printf("A%02d%c\n", wolf, opponent);
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'R':
                                atk = Attack.ROCK;
                                break;
                            case 'P':
                                atk = Attack.PAPER;
                                break;
                            case 'S':
                                atk = Attack.SCISSORS;
                                break;
                            case 'D':
                                atk = Attack.SUICIDE;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("SmartWolf %d failed to attack, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %d failed to attack, %s\n", wolf, e.getMessage());
            }
            return atk;
        }

        /**
         * Send a MOVE command to the remote process.
         */
        public synchronized Move move(int wolf, char[][] map) {
            Move move = Move.HOLD;
            try{
                writer.printf("M%02d", wolf);
                for (int row=0; row<map.length; row++) {
                    for (int col=0; col<map[row].length; col++) {
                        writer.printf("%c", map[row][col]);
                    }
                }
                writer.print("\n");
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'H':
                                move = Move.HOLD;
                                break;
                            case 'U':
                                move = Move.UP;
                                break;
                            case 'L':
                                move = Move.LEFT;
                                break;
                            case 'R':
                                move = Move.RIGHT;
                                break;
                            case 'D':
                                move = Move.DOWN;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("SmartWolf %d failed to move, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %d failed to move, %s\n", wolf, e.getMessage());
            }
            return move;
        }
    }
}

Не очень хорошо, в среднем ~ 75 выживаемости на 1000 итераций с несколькими ведущими волками.

Использует подход ML к решению.


Я думаю, что примерно понял, что делает ваш волк, но не могли бы вы объяснить это более подробно? Кроме того, вы, вероятно, должны упомянуть, на каком языке это (я уверен, что это очевидно для большинства людей, но это не было очевидно для меня).
plannapus

Он написан на C # и имеет список знаний, в котором перечислены все шаги, которые были сделаны против типа животного и его успешность. Когда волк атакует и умирает, вероятность успеха этого хода уменьшается. Если он живет, вероятность успеха увеличивается. Система начинает выбирать ходы из базы знаний вместо случайного выбора после нескольких (20-30) ходов.
user3188175

1
Рад видеть вас с помощью обертки! Вам, вероятно, следует включить инструкции о том, как скомпилировать код и что monoнужно использовать @Rusher.
ProgrammerDan

1
Уценка не удалась. Если вы посмотрите на источник, там есть «#», но поскольку он был в блоке заголовка, Markdown его проигнорировал. Исправлена. : D
ProgrammerDan

2
К вашему сведению - я смог скомпилировать и успешно запустить его с оберткой @ ProgrammerDan (и без его помощи на этот раз тоже). Вы будете в следующих результатах. Извините за задержку!
Rainbolt

7

Пассивно-Агрессивный Волк (Волк Скала)

Избегает всего, что может, в течение первых 500 ходов, позволяя полю очиститься. Затем уходит в назначенном направлении, атакуя вещи, которые находятся в пределах досягаемости.

package animals;

import animals._
import scala.util.Random

class PassiveAgressiveWolf extends Animal('W') {

    val myId=PassiveAgressiveWolf.nextId
    var movecounter=0

    def fight(opponent: Char) = {
        PassiveAgressiveWolf.lastopponents(myId-1)=opponent
        opponent match {
            case 'B' => Animal.Attack.SCISSORS
            case 'L' => Animal.Attack.SCISSORS
            case 'S' => Animal.Attack.ROCK
            case _ => Random.shuffle(List(Animal.Attack.SCISSORS, Animal.Attack.ROCK, Animal.Attack.PAPER)).head
        }
    }

    def move = {
        movecounter+=1
        if(movecounter < 500) avoidall else seen match {
            case ('B', pos: Int) => seenbear(pos)
            case ('S', pos: Int) => seenstone(pos)
            case ('L', pos: Int) => seenlion(pos)
            case ('W', pos: Int) => seenwolf(pos)
            case (' ', _) => myDirection
        }
    }

    def myDirection = myId % 4 match {
        case 0 => if(surroundings(0)(1)==' ') Animal.Move.LEFT else randommove
        case 1 => if(surroundings(1)(0)==' ') Animal.Move.DOWN else randommove
        case 2 => if(surroundings(1)(2)==' ') Animal.Move.RIGHT else randommove
        case 3 => if(surroundings(2)(1)==' ') Animal.Move.UP else randommove
    }

    def randommove = Random.shuffle(List(Animal.Move.UP, Animal.Move.LEFT, Animal.Move.RIGHT, Animal.Move.DOWN)).head

    def seen = {
        surroundings(1)(1)=' '
        val surroundingsflat=surroundings.flatten.mkString
        val seenbeasts = for {
            beast <- "BSLW" if surroundingsflat contains beast
        } yield (beast, surroundingsflat.indexOf(beast))
        seenbeasts.headOption.getOrElse((' ', 0))
    }

    def seenbear(pos: Int) = chase(pos)

    def seenstone(pos: Int) = pos match {
        case 1 => Animal.Move.LEFT
        case 3 => Animal.Move.UP
        case _ => myDirection
    }

    def seenlion(pos: Int) = pos match {
        case 1 => Animal.Move.LEFT
        case 3 => Animal.Move.UP
        case 5 => Animal.Move.HOLD
        case 7 => Animal.Move.HOLD
        case 0 => Animal.Move.UP
        case 2 => Animal.Move.HOLD
        case 6 => Animal.Move.HOLD
        case 8 => Animal.Move.HOLD
    }

    def seenwolf(pos: Int) = chase(pos)

    def chase(pos: Int) = pos match {
        case 1 => Animal.Move.UP
        case 3 => Animal.Move.LEFT
        case 5 => Animal.Move.RIGHT
        case 7 => Animal.Move.DOWN
        case 0 => Animal.Move.UP
        case 2 => Animal.Move.UP
        case 6 => Animal.Move.DOWN
        case 8 => Animal.Move.DOWN
    }

    def avoidall = {
        val safemoves = for {
            move <- List(
                            (0, 1, Animal.Move.UP), 
                            (1, 0, Animal.Move.LEFT), 
                            (1, 2, Animal.Move.RIGHT), 
                            (2, 1, Animal.Move.DOWN)
                        ) if(surroundings(move._1)(move._2)==' ')
        } yield move
        if(safemoves.length < 4) Random.shuffle(safemoves).head._3 else Animal.Move.HOLD
    }

}

object PassiveAgressiveWolf {
    private var id=0
    private def nextId = {id+=1; id}

    private var lastopponents=Array.fill[Char](100)(' ');
}

Как язык на основе JVM, Scala может быть интегрирована относительно легко.

Если вы сами компилируете программу, поместите файл scala вместе с .classфайлами java (а не с .javaфайлами) и используйте

scalac PassiveAggressiveWolf.scala

скомпилировать это. Затем вы можете использовать PassiveAggressiveWolf.classв главном Wild.javaклассе, как и с классами Java. Вам также нужно добавить scala-library.jarк вашему classpath (я использую опцию командной строки -cp /path/to/scala-library.jar).

Кроме того, я загрузил jar, содержащий сгенерированные файлы классов и scala-library.jarдля Scala 2.10.3, чтобы вы могли их скачать.

PassiveAggressiveWolf.jar
scala-library.jar


Возможно, вы можете упаковать 10 файлов в один zip-файл, чтобы упростить загрузку.
johnchen902

@ johnchen902 В чате мне предложили создать банку для моих занятий. Я буду заниматься этим вечером после работы. Это сократит его до 2 загрузок и, надеюсь, решит проблемы, с которыми сталкивается Рашер.
Гарет
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.