Открытое соревнование по программированию искусственного интеллекта

Быстрый старт

Раунд 1: до начала

Проект

Песочница

Раунд 1

Раунд 2

Финал

Последние комментарии

18 ноября 20:20: SladeThe написал комментарий в посте Утилита Repeater
18 ноября 19:45: Jeners написал комментарий в посте Local runner
18 ноября 19:42: dimir написал комментарий в посте Раунд 1
18 ноября 19:10: ykaland написал комментарий в посте Утилита Repeater
18 ноября 18:30: dimir написал комментарий в посте Раунд 1
18 ноября 17:21: tyamgin написал комментарий в посте Раунд 1
18 ноября 16:21: malinovsky239 написал комментарий в посте Раунд 1
18 ноября 16:10: tyamgin написал комментарий в посте Правила
18 ноября 12:10: doratio написал комментарий в посте Языковые пакеты
18 ноября 10:56: third112 написал комментарий в посте Языковые пакеты

Группа ВКонтакте

Telegram-чат

 

Ниже мы расскажем, как присоединиться к CodeWars буквально за несколько минут.

Зарегистрируйтесь

Разумеется, для участия необходимо зарегистрироваться. Мы убедительно просим всех участников использовать достоверные и полные данные о себе. Загружайте аватарки — всем интересно знать противников в лицо.

Скачайте языковой пакет

Скачайте пакет для любимого языка программирования со страницы языковые пакеты. Поддерживаются C++, Java, C#, Pascal, Python2, Python3 и Ruby. Распакуйте ZIP-архив в удобное для вас место и откройте существующий проект или создайте новый с нуля. Для некоторых IDE мы уже подготовили проекты. Возможно, вам надо будет настроить некоторые пути.

Скачайте Local runner

Local runner — это специальная версия симулятора игры для участников. Local runner предоставляет вам возможность запускать тестовые игры локально на своём компьютере. Подробнее об этом здесь.

Прочитайте документацию

В разделе Правила опубликованы официальные и полные правила, обязательно прочитайте их. Некоторые организационные моменты вы можете найти в описаниях Песочницы и этапов чемпионата (Раунд 1, Раунд 2, Финал).

Отошлите свою стратегию

Это можно сделать на странице отослать стратегию. Прежде, чем система примет вашу стратегию, она будет скомпилирована и протестирована в нескольких коротких играх. Если всё в порядке, ваша стратегия автоматически начнёт участвовать в регулярных квалификационных играх Песочницы. Внимательно изучите в секции “На что стоит обратить внимание” различные моменты, вследствие которых ваша стратегия может получить вердикт “Ошибка верификации”. Суммарное количество посылок не ограничено, однако в системе есть ограничения на слишком частую отправку стратегий, а любые попытки дестабилизировать работу системы приведут к дисквалификации. Вы можете написать свою стратегию в произвольном количестве файлов, вам нужно будет лишь упаковать всё необходимое в ZIP-архив и отослать его. Все файлы должны находиться в корне архива. К сожалению, создание пользовательских пакетов в стратегии на Java недопустимо. Помните, что в стартовом пакете вы можете менять только файл MyStrategy.${ext} (где ${ext} — расширение используемого вами языка), и даже если вы измените какой-то другой файл и тоже приложите его в архив, всё равно при тестировании он будет заменён на стандартный (кроме MyStrategy.h в C++).

На что стоит обратить внимание

  • запрещается взаимодействие с сетью, файловой системой и другими ресурсами, кроме оперативной памяти и текущего каталога, нарушители будут дисквалифицированы;
  • процессорное время работы вашей стратегии достаточно сильно ограничено (точные сведения вы можете найти в документации);
  • запускаемая стратегия не должна использовать более 256 мегабайт оперативной памяти (в это количество включается вся память, используемая запускаемым процессом);
  • если ваша стратегия превышает ограничение по времени или памяти, а также в случае ошибок исполнения (например, неожиданное падение), она перестаёт участвовать в этой игре, при этом как бы “замораживается”, то есть ваши очки не обнуляются;
  • стратегия каждого участника запускается в отдельном процессе.

Напишем простую стратегию на Java

Простейшая стратегия ничего не делает и никуда не перемещается (в этом можно убедиться, отослав код в систему):

import model.*;

public final class MyStrategy implements Strategy {
    @Override
    public void move(Player me, World world, Game game, Move move) {
    }
}

Теперь выделим наши войска и отправим их по направлению к противнику на следующем тике. Метод move примет вид:

public void move(Player me, World world, Game game, Move move) {
    if (world.getTickIndex() == 0) {
        move.setAction(ActionType.CLEAR_AND_SELECT);
        move.setRight(world.getWidth());
        move.setBottom(world.getHeight());
        return;
    }

    if (world.getTickIndex() == 1) {
        move.setAction(ActionType.MOVE);
        move.setX(world.getWidth() / 2.0D);
        move.setY(world.getHeight() / 2.0D);
    }
}

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

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

import model.*;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;

@SuppressWarnings({"UnsecureRandomNumberGeneration", "FieldCanBeLocal", "unused", "OverlyLongMethod"})
public final class MyStrategy implements Strategy {
    /**
     * Список целей для каждого типа техники, упорядоченных по убыванию урона по ним.
     */
    private static final Map<VehicleType, VehicleType[]> preferredTargetTypesByVehicleType;

    static {
        preferredTargetTypesByVehicleType = new EnumMap<>(VehicleType.class);

        preferredTargetTypesByVehicleType.put(VehicleType.FIGHTER, new VehicleType[] {
                VehicleType.HELICOPTER, VehicleType.FIGHTER
        });

        preferredTargetTypesByVehicleType.put(VehicleType.HELICOPTER, new VehicleType[] {
                VehicleType.TANK, VehicleType.ARRV, VehicleType.HELICOPTER, VehicleType.IFV, VehicleType.FIGHTER
        });

        preferredTargetTypesByVehicleType.put(VehicleType.IFV, new VehicleType[] {
                VehicleType.HELICOPTER, VehicleType.ARRV, VehicleType.IFV, VehicleType.FIGHTER, VehicleType.TANK
        });

        preferredTargetTypesByVehicleType.put(VehicleType.TANK, new VehicleType[] {
                VehicleType.IFV, VehicleType.ARRV, VehicleType.TANK, VehicleType.FIGHTER, VehicleType.HELICOPTER
        });
    }

    private Random random;

    private TerrainType[][] terrainTypeByCellXY;
    private WeatherType[][] weatherTypeByCellXY;

    private Player me;
    private World world;
    private Game game;
    private Move move;

    private final Map<Long, Vehicle> vehicleById = new HashMap<>();
    private final Map<Long, Integer> updateTickByVehicleId = new HashMap<>();
    private final Queue<Consumer<Move>> delayedMoves = new ArrayDeque<>();

    /**
     * Основной метод стратегии, осуществляющий управление армией. Вызывается каждый тик.
     *
     * @param me    Информация о вашем игроке.
     * @param world Текущее состояние мира.
     * @param game  Различные игровые константы.
     * @param move  Результатом работы метода является изменение полей данного объекта.
     */
    @Override
    public void move(Player me, World world, Game game, Move move) {
        initializeStrategy(world, game);
        initializeTick(me, world, game, move);

        if (me.getRemainingActionCooldownTicks() > 0) {
            return;
        }

        if (executeDelayedMove()) {
            return;
        }

        move();

        executeDelayedMove();
    }

    /**
     * Инциализируем стратегию.
     * <p>
     * Для этих целей обычно можно использовать конструктор, однако в данном случае мы хотим инициализировать генератор
     * случайных чисел значением, полученным от симулятора игры.
     */
    private void initializeStrategy(World world, Game game) {
        if (random == null) {
            random = new Random(game.getRandomSeed());

            terrainTypeByCellXY = world.getTerrainByCellXY();
            weatherTypeByCellXY = world.getWeatherByCellXY();
        }
    }

    /**
     * Сохраняем все входные данные в полях класса для упрощения доступа к ним, а также актуализируем сведения о каждой
     * технике и времени последнего изменения её состояния.
     */
    private void initializeTick(Player me, World world, Game game, Move move) {
        this.me = me;
        this.world = world;
        this.game = game;
        this.move = move;

        for (Vehicle vehicle : world.getNewVehicles()) {
            vehicleById.put(vehicle.getId(), vehicle);
            updateTickByVehicleId.put(vehicle.getId(), world.getTickIndex());
        }

        for (VehicleUpdate vehicleUpdate : world.getVehicleUpdates()) {
            long vehicleId = vehicleUpdate.getId();

            if (vehicleUpdate.getDurability() == 0) {
                vehicleById.remove(vehicleId);
                updateTickByVehicleId.remove(vehicleId);
            } else {
                vehicleById.put(vehicleId, new Vehicle(vehicleById.get(vehicleId), vehicleUpdate));
                updateTickByVehicleId.put(vehicleId, world.getTickIndex());
            }
        }
    }

    /**
     * Достаём отложенное действие из очереди и выполняем его.
     *
     * @return Возвращает {@code true}, если и только если отложенное действие было найдено и выполнено.
     */
    private boolean executeDelayedMove() {
        Consumer<Move> delayedMove = delayedMoves.poll();
        if (delayedMove == null) {
            return false;
        }

        delayedMove.accept(move);
        return true;
    }

    /**
     * Основная логика нашей стратегии.
     */
    private void move() {
        // Каждые 180 тиков ...
        if (world.getTickIndex() % 180 == 0) {
            // ... для каждого типа техники ...
            for (VehicleType vehicleType : VehicleType.values()) {
                VehicleType[] targetTypes = preferredTargetTypesByVehicleType.get(vehicleType);

                // ... если этот тип может атаковать ...
                if (targetTypes == null || targetTypes.length == 0) {
                    continue;
                }

                // ... получаем центр формации ...
                double x = streamVehicles(
                        Ownership.ALLY, vehicleType
                ).mapToDouble(Vehicle::getX).average().orElse(Double.NaN);

                double y = streamVehicles(
                        Ownership.ALLY, vehicleType
                ).mapToDouble(Vehicle::getY).average().orElse(Double.NaN);

                // ... получаем центр формации противника или центр мира ...
                double targetX = Arrays.stream(targetTypes).map(
                        targetType -> streamVehicles(
                                Ownership.ENEMY, targetType
                        ).mapToDouble(Vehicle::getX).average().orElse(Double.NaN)
                ).filter(Double::isFinite).findFirst().orElseGet(
                        () -> streamVehicles(
                                Ownership.ENEMY
                        ).mapToDouble(Vehicle::getX).average().orElse(world.getWidth() / 2.0D)
                );

                double targetY = Arrays.stream(targetTypes).map(
                        targetType -> streamVehicles(
                                Ownership.ENEMY, targetType
                        ).mapToDouble(Vehicle::getY).average().orElse(Double.NaN)
                ).filter(Double::isFinite).findFirst().orElseGet(
                        () -> streamVehicles(
                                Ownership.ENEMY
                        ).mapToDouble(Vehicle::getY).average().orElse(world.getHeight() / 2.0D)
                );

                // .. и добавляем в очередь отложенные действия для выделения и перемещения техники.
                if (!Double.isNaN(x) && !Double.isNaN(y)) {
                    delayedMoves.add(move -> {
                        move.setAction(ActionType.CLEAR_AND_SELECT);
                        move.setRight(world.getWidth());
                        move.setBottom(world.getHeight());
                        move.setVehicleType(vehicleType);
                    });

                    delayedMoves.add(move -> {
                        move.setAction(ActionType.MOVE);
                        move.setX(targetX - x);
                        move.setY(targetY - y);
                    });
                }
            }

            // Также находим центр формации наших БРЭМ ...
            double x = streamVehicles(
                    Ownership.ALLY, VehicleType.ARRV
            ).mapToDouble(Vehicle::getX).average().orElse(Double.NaN);

            double y = streamVehicles(
                    Ownership.ALLY, VehicleType.ARRV
            ).mapToDouble(Vehicle::getY).average().orElse(Double.NaN);

            // .. и отправляем их в центр мира.
            if (!Double.isNaN(x) && !Double.isNaN(y)) {
                delayedMoves.add(move -> {
                    move.setAction(ActionType.CLEAR_AND_SELECT);
                    move.setRight(world.getWidth());
                    move.setBottom(world.getHeight());
                    move.setVehicleType(VehicleType.ARRV);
                });

                delayedMoves.add(move -> {
                    move.setAction(ActionType.MOVE);
                    move.setX(world.getWidth() / 2.0D - x);
                    move.setY(world.getHeight() / 2.0D - y);
                });
            }

            return;
        }

        // Если ни один наш юнит не мог двигаться в течение 60 тиков ...
        if (streamVehicles(Ownership.ALLY).allMatch(
                vehicle -> world.getTickIndex() - updateTickByVehicleId.get(vehicle.getId()) > 60
        )) {
            // ... находим центр нашей формации ...
            double x = streamVehicles(Ownership.ALLY).mapToDouble(Vehicle::getX).average().orElse(Double.NaN);
            double y = streamVehicles(Ownership.ALLY).mapToDouble(Vehicle::getY).average().orElse(Double.NaN);

            // ... и поворачиваем её на случайный угол.
            if (!Double.isNaN(x) && !Double.isNaN(y)) {
                delayedMoves.add(move -> {
                    move.setAction(ActionType.CLEAR_AND_SELECT);
                    move.setRight(world.getWidth());
                    move.setBottom(world.getHeight());
                });

                delayedMoves.add(move -> {
                    move.setAction(ActionType.ROTATE);
                    move.setX(x);
                    move.setY(y);
                    move.setAngle(random.nextBoolean() ? StrictMath.PI : -StrictMath.PI);
                });
            }
        }
    }

    private Stream<Vehicle> streamVehicles(Ownership ownership, VehicleType vehicleType) {
        Stream<Vehicle> stream = vehicleById.values().stream();

        switch (ownership) {
            case ALLY:
                stream = stream.filter(vehicle -> vehicle.getPlayerId() == me.getId());
                break;
            case ENEMY:
                stream = stream.filter(vehicle -> vehicle.getPlayerId() != me.getId());
                break;
            default:
        }

        if (vehicleType != null) {
            stream = stream.filter(vehicle -> vehicle.getType() == vehicleType);
        }

        return stream;
    }

    private Stream<Vehicle> streamVehicles(Ownership ownership) {
        return streamVehicles(ownership, null);
    }

    private Stream<Vehicle> streamVehicles() {
        return streamVehicles(Ownership.ANY);
    }

    private enum Ownership {
        ANY,

        ALLY,

        ENEMY
    }
}

Понятно, что это не самая эффективная стратегия и шансов выиграть у неё немного, но это всего-лишь пример. Удачи!



amurushkin

amurushkin

ХНУРЭ (бывш. ХИРЭ, ХТУРЭ)

так все же как задается движение? через координаты или относительное смещение? если через смещение, то почему в первом случае стратегия едет ровно до середины экрана и останавливается, а не продолжает движение?

07.11.2017 23:47:24
Dfire

Dfire

КРОК

А вы гарантируете hash и equals для Unit и Vehicle ?

07.11.2017 23:59:24
serlis

serlis

Харьковский НУ им. Каразина

amurushkin

amurushkin

ХНУРЭ (бывш. ХИРЭ, ХТУРЭ)

так все же как задается движение? через координаты или относительное смещение? если через смещение, то почему в первом случае стратегия едет ровно до середины экрана и останавливается, а не продолжает движение?

Вы указываете максимальное смещение (если указать пол карты, то вы как-раз доедите до середины)

08.11.2017 0:24:35
Nemzs1337

Nemzs1337

Университет ИТМО

А можно поинтересоваться, с чем связано отсутствие метода “Получить всю технику вне тумана войны”? Это ведь достаточно неудобно работать с обновлениями техники

09.11.2017 21:51:05
GreenTea

GreenTea

ISDDesign

Nemzs1337

Nemzs1337

Университет ИТМО

А можно поинтересоваться, с чем связано отсутствие метода “Получить всю технику вне тумана войны”? Это ведь достаточно неудобно работать с обновлениями техники

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

09.11.2017 22:31:07
tyamgin

tyamgin

Симферополь

Я правильно понимаю, что вы не рекомендуете хранить объекты модели с предыдущих тиков, но сами же храните их в карте vehicleById?

09.11.2017 23:15:04
Jeners

А почему нельзя было реализовать обновление массива данных о юнитах по средствам API? Ну т.е. хранить данные об объектах в теле некоего класса, автоматически их туда добавлять, ну и обновлять “по ходу пьесы” т.е. по сути реализовать то что, требуется реализовать от участников, но при этом чтобы оно было изначально вшито в API? Просто не совсем понятны телодвижения в этом направлении

09.11.2017 23:54:52
GS_Aero

GS_Aero

ИП

amurushkin

amurushkin

ХНУРЭ (бывш. ХИРЭ, ХТУРЭ)

так все же как задается движение? через координаты или относительное смещение? если через смещение, то почему в первом случае стратегия едет ровно до середины экрана и останавливается, а не продолжает движение?

Т.к. это вектор, то будет смещение на длину вектора.

10.11.2017 16:26:34
GS_Aero

GS_Aero

ИП

GS_Aero

GS_Aero

ИП

Т.к. это вектор, то будет смещение на длину вектора.

Блин, не так. В базовом примере указан вектор: Move.setAction(ActionType::MOVE); Move.setX(MyWorld->getWidth() / 2.0); Move.setY(MyWorld->getHeight() / 2.0); Смещаемся на половину размера карты, т.е. до середины.

10.11.2017 16:50:17
third112

“Теперь напишем более сложный код”. Этот 2й пример только на Яве :( ИМХО в руководстве он должен быть переведен на все поддерживаемые языковые пакеты, иначе они будут в неравных условиях.

11.11.2017 14:26:53
mrsergkr

mrsergkr

КемГУ

“Теперь напишем более сложный код”. Этот 2й пример только на Яве :( ИМХО в руководстве он должен быть переведен на все поддерживаемые языковые пакеты, иначе они будут в неравных условиях.

Я потратил часа полтора на то, чтобы переписать эту стратегию на c++. Это при том, что у меня знаний практически нет. Нормальный программист потратит ещё меньше времени. Так что ни о каком неравенстве речи не идет.

11.11.2017 17:43:32
mrsergkr

mrsergkr

КемГУ

tyamgin

tyamgin

Симферополь

Я правильно понимаю, что вы не рекомендуете хранить объекты модели с предыдущих тиков, но сами же храните их в карте vehicleById?

Если я не ошибаюсь, то говорили про объекты Player, World, Game и Move.

11.11.2017 17:47:29
alkozel

alkozel

Калужский филиал ГУ СДА при Спецстрое России

Люди добрые, помогите. Изучаю Java, не получается отсортировать поток хотя бы по координате x. Запутался в компараторах и ламбда-выражениях. Покажите простой пример. Спасибо

11.11.2017 17:59:19
third112
mrsergkr

mrsergkr

КемГУ

Я потратил часа полтора на то, чтобы переписать эту стратегию на c++. Это при том, что у меня знаний практически нет. Нормальный программист потратит ещё меньше времени. Так что ни о каком неравенстве речи не идет.

Если у Вас нет знаний, то почему Вы думаете, что перевели верно?

11.11.2017 18:24:15
alkozel

alkozel

Калужский филиал ГУ СДА при Спецстрое России

alkozel

alkozel

Калужский филиал ГУ СДА при Спецстрое России

Люди добрые, помогите. Изучаю Java, не получается отсортировать поток хотя бы по координате x. Запутался в компараторах и ламбда-выражениях. Покажите простой пример. Спасибо

вроде разобрался stream.sorted(Comparator.comparing(Vehicle::getX))

11.11.2017 18:38:30
Dimon777

Dimon777

АО ЦКБА

При попытке отослать даже тестовую стратегию (ту, что написана в руководстве) идёт ошибка компиляции: MyStrategy.cpp: In member function ‘virtual void MyStrategy::move(const model::Player&, const model::World&, const model::Game&, model::Move&)’: MyStrategy.cpp:10:16: error: ‘ACTION_CLEAR_AND_SELECT’ was not declared in this scope move.setAction(ACTION_CLEAR_AND_SELECT); ^~~~~~~~~~~~~~~~~~~~~~~ MyStrategy.cpp:16:16: error: ‘ACTION_MOVE’ was not declared in this scope move.setAction(ACTION_MOVE); ^~~~~~~~~~~)

11.11.2017 18:46:23
Sanda

Sanda

JetBrains

Dimon777

Dimon777

АО ЦКБА

При попытке отослать даже тестовую стратегию (ту, что написана в руководстве) идёт ошибка компиляции: MyStrategy.cpp: In member function ‘virtual void MyStrategy::move(const model::Player&, const model::World&, const model::Game&, model::Move&)’: MyStrategy.cpp:10:16: error: ‘ACTION_CLEAR_AND_SELECT’ was not declared in this scope move.setAction(ACTION_CLEAR_AND_SELECT); ^~~~~~~~~~~~~~~~~~~~~~~ MyStrategy.cpp:16:16: error: ‘ACTION_MOVE’ was not declared in this scope move.setAction(ACTION_MOVE); ^~~~~~~~~~~)

Попробуйте обновить языковой пакет

11.11.2017 18:54:21
Dimon777

Dimon777

АО ЦКБА

Sanda

Sanda

JetBrains

Попробуйте обновить языковой пакет

тестовую стратегию отправлял не файлом, а вставив код в форму…

11.11.2017 18:57:00
infsega

infsega

Align Technology Inc

“Теперь напишем более сложный код”. Этот 2й пример только на Яве :( ИМХО в руководстве он должен быть переведен на все поддерживаемые языковые пакеты, иначе они будут в неравных условиях.

Наоборот, пока переписываешь код на свой язык, понимаешь, к чему он вообще :)

11.11.2017 18:57:24
Dimon777

Dimon777

АО ЦКБА

Dimon777

Dimon777

АО ЦКБА

тестовую стратегию отправлял не файлом, а вставив код в форму…

спасибо, кажись разобрался

11.11.2017 19:04:32
third112
infsega

infsega

Align Technology Inc

Наоборот, пока переписываешь код на свой язык, понимаешь, к чему он вообще :)

Значит неравные условия, т.к. тем кто работает на Яве не придется переписывать код.

11.11.2017 20:05:19
alkozel

alkozel

Калужский филиал ГУ СДА при Спецстрое России

А смысл его переписывать? С этим кодом далеко не уйдешь))

11.11.2017 20:13:53
AlexKol

AlexKol

BB

alkozel

alkozel

Калужский филиал ГУ СДА при Спецстрое России

А смысл его переписывать? С этим кодом далеко не уйдешь))

Пфф, человек 500 точно будет со стратегией из примера)

11.11.2017 20:14:59
aabzac

aabzac

БГУИР

alkozel

alkozel

Калужский филиал ГУ СДА при Спецстрое России

А смысл его переписывать? С этим кодом далеко не уйдешь))

Ну я пока загрузил код из примера и выйти с ним в 1 раунд видимо не составит труда )

11.11.2017 21:43:11
Borisov

Borisov

НИТУ "МИСиС"

 private final Queue<Consumer<Move>> delayedMoves = new ArrayDeque<>();    
 delayedMoves.add(move -> {
                move.setAction(ActionType.CLEAR_AND_SELECT);
                move.setRight(world.getWidth());
                move.setBottom(world.getHeight());
                move.setVehicleType(VehicleType.ARRV);
            });

Не подскажете, как аналогичное реализовать в C++?

13.11.2017 1:40:14
SladeThe

SladeThe

Команда Russian AI Cup

alkozel

alkozel

Калужский филиал ГУ СДА при Спецстрое России

вроде разобрался stream.sorted(Comparator.comparing(Vehicle::getX))

В данном случае лучше использовать Comparator.comparingDouble, так как он работает с примитивным типом double, а Comparator.comparing преобразует значение в объект и сравнивает уже объекты, что значительно менее эффективно.

13.11.2017 2:22:21
SladeThe

SladeThe

Команда Russian AI Cup

Borisov

Borisov

НИТУ "МИСиС"

private final Queue<Consumer> delayedMoves = new ArrayDeque<>();
delayedMoves.add(move -> { move.setAction(ActionType.CLEAR_AND_SELECT); move.setRight(world.getWidth()); move.setBottom(world.getHeight()); move.setVehicleType(VehicleType.ARRV); }); …

Не знаю, как написать именно аналогичный код, но вы можете создавать новый объект Move и помещать его в очередь, а потом доставать его и копировать все поля.

13.11.2017 2:24:13
third112

Как вообще на Паскале выделить 10 юнитов, нпр., танков и послать их в точку с заданными координатами? Пробовал по разному - не работает. Может баг? А можно 10 танков послать в 10 разных точек за 1 тик? Мануалу явно не хватает примеров таких элементарных действий. Описание API слишком формальное, много второстепенных методов и добраться до основных за ограниченное время представляется проблематичным.

13.11.2017 10:46:41
AlexKol

Как вообще на Паскале выделить 10 юнитов, нпр., танков и послать их в точку с заданными координатами? Пробовал по разному - не работает. Может баг? А можно 10 танков послать в 10 разных точек за 1 тик? Мануалу явно не хватает примеров таких элементарных действий. Описание API слишком формальное, много второстепенных методов и добраться до основных за ограниченное время представляется проблематичным.

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

13.11.2017 10:48:30
third112

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

Спасибо, уже взял. Но идей про 10 танков это не принесло

13.11.2017 10:51:51
dimir

dimir

СПбГЭТУ (ЛЭТИ)

Спасибо, уже взял. Но идей про 10 танков это не принесло

10 танков в 10 разных точек нельзя. В принципе чтобы кого-то куда послать вам понадобится два действия - выделение и движение (CLEAR_AND_SELECT, MOVE).

В идеале - сначала создаёте группы, потом когда нужно отправить куда-то группу - CLEAR_AND_SELECT(номер группы), MOVE(dx, dy)

13.11.2017 10:59:34
third112
dimir

dimir

СПбГЭТУ (ЛЭТИ)

10 танков в 10 разных точек нельзя. В принципе чтобы кого-то куда послать вам понадобится два действия - выделение и движение (CLEAR_AND_SELECT, MOVE). В идеале - сначала создаёте группы, потом когда нужно отправить куда-то группу - CLEAR_AND_SELECT(номер группы), MOVE(dx, dy)

А как выделять? Только прямоугольником? Или можно по номеру (id) танка? Как быстро получить диапазон валидных номеров? Я не понимаю: цель стратегию сделать или ребус (т.е. невнятный мануал) разгадать? Я предполагал, что 10 танков в 10 мест за раз не послать. Это обычный недостаток всех игр с большим числом юнитов, поэтому многие интересные ИИ-решания в таких играх оказываются невозможны.

13.11.2017 11:08:14
AlexKol

AlexKol

BB

dimir

dimir

СПбГЭТУ (ЛЭТИ)

10 танков в 10 разных точек нельзя. В принципе чтобы кого-то куда послать вам понадобится два действия - выделение и движение (CLEAR_AND_SELECT, MOVE). В идеале - сначала создаёте группы, потом когда нужно отправить куда-то группу - CLEAR_AND_SELECT(номер группы), MOVE(dx, dy)

Да всё можно, 10 раз последовательно добавляем. Или выделяем и берем по типу, короче вариантов много.

13.11.2017 11:08:18
Scarlet

Не путайте человека. Вопрос был про один тик. Если за один тик последовательно послать 10 танков в 10 мест (CLEAR_AND_SELECT и MOVE), то вообще ничего не случится. От слова совсем. За один тик даже один танк не послать. За один тик можно сделать одно действие (CLEAR_AND_SELECT или MOVE или др.). Так что 10 танков в 10 мест это 20 действий = 20 тиков. А если вспомнить про лимит в 12 действий на 60 тиков, то можно понять, это игра не про управление каждым танчиком, а про балланс (наконец-то, после введения ЯУ) между размерами управляемых групп и лимитом действий. Впрочем, это всё должно было стать понятно из правил.

13.11.2017 23:03:03
dimir

dimir

СПбГЭТУ (ЛЭТИ)

Не путайте человека. Вопрос был про один тик. Если за один тик последовательно послать 10 танков в 10 мест (CLEAR_AND_SELECT и MOVE), то вообще ничего не случится. От слова совсем. За один тик даже один танк не послать. За один тик можно сделать одно действие (CLEAR_AND_SELECT или MOVE или др.). Так что 10 танков в 10 мест это 20 действий = 20 тиков. А если вспомнить про лимит в 12 действий на 60 тиков, то можно понять, это игра не про управление каждым танчиком, а про балланс (наконец-то, после введения ЯУ) между размерами управляемых групп и лимитом действий. Впрочем, это всё должно было стать понятно из правил.

Ну я так и написал в целом =)

13.11.2017 23:43:44
dimir

dimir

СПбГЭТУ (ЛЭТИ)

А как выделять? Только прямоугольником? Или можно по номеру (id) танка? Как быстро получить диапазон валидных номеров? Я не понимаю: цель стратегию сделать или ребус (т.е. невнятный мануал) разгадать? Я предполагал, что 10 танков в 10 мест за раз не послать. Это обычный недостаток всех игр с большим числом юнитов, поэтому многие интересные ИИ-решания в таких играх оказываются невозможны.

Выделять (CLEAR_AND_SELECT, ADD_TO_SELECTION, DESELECT) - ЛИБО прямоугольником (к прямоугольнику опционально добавляется тип юнитов [танк, к примеру], которых хотите выделить), ЛИБО номером группы.

13.11.2017 23:46:29
dimir

dimir

СПбГЭТУ (ЛЭТИ)

А как выделять? Только прямоугольником? Или можно по номеру (id) танка? Как быстро получить диапазон валидных номеров? Я не понимаю: цель стратегию сделать или ребус (т.е. невнятный мануал) разгадать? Я предполагал, что 10 танков в 10 мест за раз не послать. Это обычный недостаток всех игр с большим числом юнитов, поэтому многие интересные ИИ-решания в таких играх оказываются невозможны.

Если я правильно понял термин “диапазон валидных номеров”, то никак, так как выделять по id юнита нельзя, но Вы можете выбрать юнита по его id, получить его центр, вычислить прямоугольник размером 2*vehicleRadius x 2*vehicleRadius с центром в центре юнита, и отдать команду CLEAR_AND_SELECT с данным прямоугольником. И это, в общем случае, неэффективно, как заметил Scarlet в комментарии выше. Кроме случая когда вам нужно отправить одного единственного юнита куда-то там, допустим, на разведку.

13.11.2017 23:51:07
dimir

dimir

СПбГЭТУ (ЛЭТИ)

А как выделять? Только прямоугольником? Или можно по номеру (id) танка? Как быстро получить диапазон валидных номеров? Я не понимаю: цель стратегию сделать или ребус (т.е. невнятный мануал) разгадать? Я предполагал, что 10 танков в 10 мест за раз не послать. Это обычный недостаток всех игр с большим числом юнитов, поэтому многие интересные ИИ-решания в таких играх оказываются невозможны.

А ещё есть официальный Telegram канал (ссылка слева внизу), где Вам ответят на интересующие Вас вопросы гораздо быстрее.

13.11.2017 23:53:54
luckybet100

luckybet100

Москва

Помогите пожалуйста, запускаю compile_java.sh потом запускаю проект командой java -jar java-cgdk.jar, выдает такую ошибку no main manifest attribute, in java-cgdk.jar. Компилю просто самп, что делать?

16.11.2017 16:47:55
luckybet100

luckybet100

Москва

Система mac os high siera

16.11.2017 16:50:51
SladeThe

SladeThe

Команда Russian AI Cup

luckybet100

luckybet100

Москва

Помогите пожалуйста, запускаю compile_java.sh потом запускаю проект командой java -jar java-cgdk.jar, выдает такую ошибку no main manifest attribute, in java-cgdk.jar. Компилю просто самп, что делать?

У вас в манифесте JAR-файла не указан класс, запускаемый по умолчанию. Вам нужно либо изменить способ сборки JAR, либо способ запуска. Например, можно добавить ваш файл в classpath и явно указать запускаемый класс. Должно быть что-то вроде java -cp java-cgdk.jar Runner.

16.11.2017 19:12:47
dimir

dimir

СПбГЭТУ (ЛЭТИ)

SladeThe

SladeThe

Команда Russian AI Cup

У вас в манифесте JAR-файла не указан класс, запускаемый по умолчанию. Вам нужно либо изменить способ сборки JAR, либо способ запуска. Например, можно добавить ваш файл в classpath и явно указать запускаемый класс. Должно быть что-то вроде java -cp java-cgdk.jar Runner .

Ему уже в Telegram канале помогли.

16.11.2017 19:14:52
BaR5uk

BaR5uk

Карачев

Я прочитал документацию, но что-то так и не нашёл, как на каждом тике игры узнать, какими юнитами располагает моя стратегия и где они находятся. То есть, где они находятся понятно как узнать: в свойствах объекта, но как получить массив объектов с всеми юнитами?

18.11.2017 2:04:25
SladeThe

SladeThe

Команда Russian AI Cup

BaR5uk

BaR5uk

Карачев

Я прочитал документацию, но что-то так и не нашёл, как на каждом тике игры узнать, какими юнитами располагает моя стратегия и где они находятся. То есть, где они находятся понятно как узнать: в свойствах объекта, но как получить массив объектов с всеми юнитами?

Передавать такое количество юнитов каждый тик слишком ресурсозатратно. Поэтому полная информация о технике в мире отсутствует. В массиве new vehicles передаётся только новая техника, в vehicle updates — изменяемые поля. Вам нужно самостоятельно поддерживать актуальный список техники в мире, используя эти два массива. В “Быстром старте” есть пример, как это делать. Посмотрите метод initializeTick.

18.11.2017 2:11:34