Let the Grokk Be

Рубрика: Development | 22 December 2006, 13:35 | juriy

По заявкам трудящихся: как сделать простого зверя.

В этой статье описан процесс создания простого зверька для онлайн соревнования искусственных интеллектов: Электро Джунгли. Детальнее про то, что это за проект можно на официальном сайте: http://www.electricjungle.ru или прочитать в моем маленьком обзоре http://voituk.kiev.ua/2006/12/22/elecrojungle-hunters-twilight/

Я использую Eclipse, поэтому я буду описывать весь “процесс” именно на примере этой IDE.
Итак, для начала необходимо подготовить среду разработки.

1. Создаем новый Java проект.
2. Добавляем в Build Path библиотеку, которую скачали с сайта (для тех, кто еще не скачал – можно взять тут: http://www.electricjungle.ru:8080/main.jsp?page=sdk).
3. Создаем новый package. Создаем в этом package новый класс, который будет описывать логику поведения зверя. В моем примере я буду использовать пакет ua.net.lab.beings, а класс будет называться Grokk. Класс должен реализовывать интерфейс universum.bi.Being.
4. После создания и автоматической генерации заглушек для абстрактных классов код выглядит так:

[java]

package ua.net.lab.beings;

import universum.bi.Being;
import universum.bi.BeingInterface;
import universum.bi.BeingParams;
import universum.bi.Event;
import universum.bi.UserGameInfo;

public class Grokk implements Being {

  public String getName() {
    return null;
  }

  public String getOwnerName() {
    return null;
  }

  public BeingParams getParams() {
    return null;
  }

  public void reinit(UserGameInfo info) {
  }

  public Event makeTurn(BeingInterface world) {
    return null;
  }

  public void processEvent(BeingInterface bi, Event e) {}
}

[/java]

Теперь нужно заполнить заглушки кодом. Начнем с самого простого. Функции getName() и getOwnerName() возвращают, соответственно имя зверюшки и имя создателя.
[java]

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

public String getOwnerName() {
  return "Juriy";
}

[/java]

Дальше идет функция getParams() – она определяет начальные параметры первого существа (параметры следующих поколений могут быть другими): его массу и скорость. Эти параметры лучше сразу вынести в константы: их придется подбирать экспериментально. Поскольку менять легче в одном месте, то так и поступим:
[java]

private final static float MASS = 10f;
private final static float SPEED = 2f;

....

public BeingParams getParams() {
  return new BeingParams(MASS, SPEED);
}

[/java]

Функция reinit(UserGameInfo info) – вызывается при старте. Из нее зверек может узнать базовые сведения про мир. Здесь немного отвлечемся от кода и снова глянем на правила: есть на сайте описано 3 типа игры:

SINGLE – твоя зверюга – одна в джунглях. Цель – получить за ограниченное количество ходов максимальную массу популяции.
DUEL – думаю, без комментариев – в джунглях 2 вида. Победит тот, у кого после определенного количества ходов – максимальная масса популяции.
JUNGLE – то же самое, что и DUEL, только видов может быть до 8.

В файле с описанием констант: universum.bi.GameKind есть описание еще для двух типов игр: PEACE_DUEL и DEBUG. Поскольку комментариев про эти типы игр нет, то я оставляю читателям трактовать значения.

Вернемся к коду. Поскольку существо не настолько умное, чтобы его поведение менялось в зависимости от типа игры, то функцию reinit(UserGameInfo info) оставим пустой. В более продвинутом зверьке в этой функции можно инициализировать static переменные. Функция вызывается один раз, до установки первого зверя на поле.

Дальше – самое интересное. Функция makeTurn(BeingInterface world) – сердце (вернее, мозг) вашего зверя. Тут зверь решает, куда ему пойти.
Параметр, который передается в функцию, позволяет зверю получить данные о мире, который его окружает. Поскольку для принятия решений о действиях эта переменная будет нужна постоянно, лучше ее с самого начала сделать полем класса, и обновлять каждый раз при вызове makeTurn(BeingInterface world).

[java]

private BeingInterface world;
...
public Event makeTurn(BeingInterface world) {
  this.world = world;
  return null;
}

[/java]

Пускай зверек двигается случайным образом в любую доступную клетку. Для этого я создал отдельную функцию – makeRandomMove(), которая возвращает Event – решение зверька о том, что делать дальше.
[java]

private Event makeRandomMove() {
  // Получаем список клеток, в которые можно попасть за ход
  List<Location> canReach = world.getReachableLocations(this);

  // Выбираем клетку случайным образом и создаем событие - движение
  // в выбранную клетку.
  return new Event(
      EventKind.ACTION_MOVE_TO,
      canReach.get(Util.rnd(canReach.size())));
}[/java]

Обратите внимание на Util.rnd(canReach.size()). Авторы не рекомендуют пользоваться java.util.Random для выбора случайных чисел. Util.rnd() - тот же Random только в профиль. Все чем он отличается: в режиме отладки он генерирует одинаковые последовательности случайных чисел.

Теперь остается поменять makeTurn(BeingInterface world) так чтобы зверь двигался в случайном направлении каждый ход.

[java]
public Event makeTurn(BeingInterface world) {
  this.world = world;
  return makeRandomMove();
}

[/java]

Все что осталось сделать - запаковать зверя в jar и не забыть добавить в MANIFEST.MF строку

Main-Class: ua.net.lab.beings.Grokk

Теперь отпускаем зверя на волю: запускаем эмулятор джунглей:

java -jar ejungle_distr.jar

в GUI добавляем в джунгли нового зверя: Add Being -> Add from jar.

Зверек немного побегает и сдохнет от голода: кушать он не умеет. Но научим мы его позже, сейчас немного поработать надо :)

Вот код того что получилось:
[java]

package ua.net.lab.beings;

import java.util.List;

import universum.bi.Being;
import universum.bi.BeingInterface;
import universum.bi.BeingParams;
import universum.bi.Event;
import universum.bi.EventKind;
import universum.bi.Location;
import universum.bi.UserGameInfo;
import universum.util.Util;

public class Grokk implements Being {
  private final static float MASS = 10f;
  private final static float SPEED = 2f;

  private BeingInterface world;

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

  public String getOwnerName() {
    return "Juriy";
  }

  public BeingParams getParams() {
    return new BeingParams(MASS, SPEED);
  }

  public void reinit(UserGameInfo info) {}

  public Event makeTurn(BeingInterface world) {
    this.world = world;
    return makeRandomMove();
  }

  private Event makeRandomMove() {
    // Получаем список клеток, в которые можно попасть за ход
    List<Location> canReach = world.getReachableLocations(this);

    // Выбираем клетку случайным образом и создаем событие - движение
     // в выбранную клетку.
    return new Event(
      EventKind.ACTION_MOVE_TO,
      canReach.get(Util.rnd(canReach.size())));
  }
  public void processEvent(BeingInterface bi, Event e) {}
}

[/java]

Комментариев: 3

3 Responses to “Let the Grokk Be”

Комментарии:

  1. vadim

    обсуждение в тему
    http://yorool-gui.livejournal.com/141458.html

  2. Скакунов Александр

    Офигительно!

  3. vadim

    2Скакунов Александр:
    Хочу увидеть что ты скажешь когда узнаешь как это выглядит:)

Leave a Reply