Цгк – Взгляд Изнутри

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

  1. Состав системы Для начала определимся, из чего состоит система такого рода.

    Ну, во-первых, самое главное — это модуль моделирования.

    Затем, конечно же, есть клиент и сервер, и, наконец, самая важная часть Code Game Show — это визуализатор.

    Теперь давайте рассмотрим каждую из этих частей отдельно.

    1. Симулятор Модуль симуляции определяет физику мира, набор юнитов и вообще все, что связано с игровым миром.

      Кроме того, этот модуль отвечает за моделирование сражений между стратегиями.

      Здесь возникает первый вопрос – чем нам следует фиксировать результаты боев? Первый вариант — записать некоторый рассказ о ходе боя, который впоследствии можно будет воспроизвести с помощью визуализатора.

      Второй подход – одновременное моделирование и воспроизведение.

      У каждого подхода есть свои плюсы и минусы.

      Преимущество второго подхода в том, что он сокращает время, затрачиваемое участниками на анализ своих стратегий в процессе их разработки.

      Однако первый подход позволяет реализовать функционал установки скорости и точки воспроизведения.

      Еще одна важная деталь симулятора — он должен уметь собирать данные из стратегий, написанных на разных языках.

      Здесь тоже есть несколько вариантов реализации.

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

      Однако этот вариант несет в себе несколько проблем:

      • не все языки могут обеспечить вывод DLL
      • при использовании DLL они загружаются в общий процесс и могут намеренно его «выбросить».

      Более безопасный вариант — скомпилировать исполняемые файлы и использовать межпроцессорную связь для связи между симулятором и стратегиями участников.

      Для связи можно использовать все что угодно — на практике я видел системы, использующие стандартный ввод/вывод (но не рекомендую), системы, общающиеся через сокеты.

      Ну а логика симулятора довольно проста:

      • на вход поступает информация об участвующих стратегиях и игровом мире (например, идентификатор используемой карты)
      • симулятор запускает стратегии участников и поочередно отправляет им команды на выполнение метода Init
      • симулятор получает результаты выполнения метода Init каждой стратегии и обрабатывает ошибки (время выполнения, ограничение по времени, ограничение памяти) пользовательского кода
      • симулятор поочередно отправляет команды на выполнение метода Move и собирает результаты
      • приводит значения в приемлемые интервалы и имитирует бой
      • обновляет значения игровых переменных и снова вызывает метод Move
      • в конце боя записывает результаты боя
    2. Клиент Основная задача клиента — отправить решения и начать просмотр боёв.

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

      Иногда возникают ситуации, когда клиент меняется во время самого соревнования и функция автообновления тоже может пригодиться.

      Никаких особенностей в клиенте нет.

    3. Сервер Сервер — одна из самых серьезных частей.

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

      Что входит в состав сервера? подаются в модуль моделирования.

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

      Эти решения затем компилируются.

      Успешно скомпилированные решения передаются в модуль моделирования.

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

      Для обеспечения высокой скорости обработки пользовательских решений можно использовать кластер (как это делают в ТТИ СФУ), но при отсутствии кластера можно реализовать распределенный сервер.

    4. Визуализатор Этот модуль используется для отображения сражений.

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

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

  2. Пользовательский API Ну тут все зависит от вашей фантазии, единственное, что хотелось бы отметить, это то, что я рекомендую создавать методы отладки стратегий - например вывод отладочных сообщений (вывод только при написании стратегии), вывод точек и векторов.

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

    В качестве примера в конце статьи приведен API одного из CGC.

  3. Примечания Еще несколько замечаний по игровому миру.

    Для начала посчитайте сложность – ведь на исследование игрового мира и реализацию стратегии у участников будет всего 4-5 часов.

    Чем сложнее игровой мир, тем менее интересными стратегиями в конечном итоге будут обладать игроки и тем менее зрелищным будет Code Game Show. Если ваш мир очень сложен, но вы не хотите его менять, попробуйте включить в пользовательский API методы более высокого уровня (например, методы поиска пути между двумя точками).

    Вам придется потратить не один-два дня – обычно это занимает от недели до месяца.

    Старайтесь поддерживать самые распространенные языки — это расширит круг участников.

    Уделите время балансировке игры — для хорошего баланса вам придется потратить не один и не два дня — обычно на это уходит от недели до месяца.

  4. Пример пользовательского API Интерфейс IБонус – описывает интерфейс бонусных объектов IBonus: публичный IMoveableObject Получите бонусные очки жизни Возвращаемое значение: количество очков жизни, которое получит бот, если получит бонус.

    интервал GetHP() Получите бонус к патронам для пулемета Возвращаемое значение: количество патронов для автомата, которое получит бот, если возьмет бонус.

    int GetMashinegunAmmo() Получите бонус к боеприпасам к лазеру Возвращаемое значение: количество зарядов пулемета, которое получит бот, если возьмет бонус.

    int GetLaserAmmo() Получите бонус к боезапасу для своей пушки Возвращаемое значение: количество пулеметных снарядов, которое получит бот, если возьмет бонус.

    int GetCannonAmmo() Получите бонус к боеприпасам для ракетницы.

    Возвращаемое значение: количество ракет, которые получит бот, если получит бонус.

    int GetRocketAmmo() Получить время жизни бота Возвращаемое значение: оставшееся время действия бонуса по очереди.

    int GetElapsedTime() Интерфейс IBot – описывает интерфейс игрового устройства IBot: публичный IMoveableObject Получить название команды Возвращаемое значение: возвращает имя команды строка GetTeamName() Получить имя бота Возвращаемое значение: возвращает имя бота или пустую строку, если оно не указано.

    строка GetName() Получить информацию о боекомплекте и состоянии пистолета В информации содержится информация о боекомплекте (количестве снарядов) и времени, через которое орудие будет готово к стрельбе.

    Возвращаемое значение: текущее состояние пистолета.

    SWeaponInfo GetCannon() Получить информацию о боекомплекте и состоянии пулемета В информации содержится информация о боекомплекте (количестве снарядов) и времени, через которое пулемет будет готов к стрельбе.

    Возвращаемое значение: текущее состояние пулемета.

    SWeaponInfo GetMashineGun() Получить информацию о боеприпасах и состоянии лазера В информации содержится информация о боекомплекте (количестве зарядов) и времени, через которое лазер будет готов к стрельбе.

    Возвращаемое значение: текущее состояние лазера.

    SWeaponInfo GetLaser() Получите информацию о боекомплекте и состоянии ракетной установки.

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

    Возвращаемое значение: текущее состояние ракетницы.

    SWeaponInfo GetRocket() Получить тип бота Возвращаемое значение: возвращает тип текущего бота.

    Тип бота GetType() Получить вращение башни Вращение башни измеряется относительно диаметральной плоскости бота.

    Возвращаемое значение: относительное вращение башни в радианах.

    поплавок GetTurrelAngle() Получить уровень здоровья бота Возвращаемое значение: текущее количество очков жизни.

    интервал GetHP() Интерфейс ИМовеаблеОбъект – описывает интерфейс объектов, которые могут двигаться.

    Получить положение объекта Возвращает координату центра объекта.

    Возвращаемое значение: координата верхнего левого угла.

    Точка ПолучитьПозицию() Получить угол поворота объекта Подробнее о системе координат смотрите в описании интерфейса IWorld. Возвращаемое значение: возвращает поворот объекта в радианах.

    поплавок GetDirection() Получить радиус объекта Бонусы, снаряды и боты представлены кружками, Возвращаемое значение: возвращает радиус объекта.

    поплавок GetRadius() Получить скорость объекта Возвращаемое значение: возвращает величину вектора скорости.

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

    Возвращаемое значение: вектор скорости импульса Вектор GetImpulseVelocity() Установка текстовой метки для объекта Установка текстовых меток позволяет идентифицировать объекты.

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

    Текстовые метки нигде не отображаются.

    Участники не видят текстовые метки других участников.

    Запрещено отмечать ботов - такие отметки будут сбрасываться каждый ход. Параметры: пометить текстовую метку объекта void SetMark (целая отметка) Получить текущую метку объекта Возвращаемое значение: текущая метка объекта, если метка не установлена, возвращается -1. int GetMark() Интерфейс Я сам – описывает интерфейс управляемого устройства.

    ISelf: публичный IBot Установить имя бота Установка имени бота возможна только внутри функции Init. Вызовы внутри Move игнорируются Длина имени бота не должна превышать 20 символов.

    Если имя длиннее указанного, оно будет сокращено до необходимой длины.

    Параметры: имя имя бота void SetName (имя строки) Установить тип бота Разные типы ботов имеют разные характеристики.

    Установка типа бота возможна только внутри функции Init. Вызовы внутри Move игнорируются.

    Параметры: Тип Тип бота void SetType (тип BotType) Установить скорость движения Изменяет значение вектора скорости.

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

    Параметры: скорость Новая скорость void SetSpeed (плавающая скорость) Установить ротацию ботов Параметры: угол Новый угол поворота в радианах void SetDirection (угол с плавающей запятой) Изменить вращение башни ботов Параметры: Приращение угла поворота башни Delta Tower в радианах void TurnTurrel (дельта с плавающей запятой) Сделать выстрел из пулемета Делает выстрел из пулемета.

    Пулемет всегда стреляет в направлении движения бота.

    Если пулемет не готов к стрельбе, ничего не происходит. void ShotMashinegun() Сделать выстрел из пушки Производит пушечный выстрел.

    Пушка установлена на башне.

    Если ружье не готово к стрельбе, ничего не происходит. пустота ШотКэннон() Сделайте лазерный выстрел Выпускает лазерный выстрел.

    Лазер всегда стреляет в направлении движения бота.

    Если лазер не готов к стрельбе, ничего не происходит. Параметры: Угол поворота лазера void ShotLaser(плавающий угол) Выстрелить из ракетницы Стреляет из ракетницы.

    Если ракетница не готова к выстрелу, ничего не происходит. Параметры: цель Цель void ShotRocket (IMoveableObject *target) Интерфейс IShell – описывает интерфейс снаряда, расположенного на карте.

    IShell: общедоступный IMoveableObject Получить владельца.

    Возвращаемое значение: бот, выпустивший этот снаряд. IBot* GetOwner() Получите цель.

    Для лазерных, пушечных и пулеметных снарядов цель равна NULL. Если объект был уничтожен, возвращается NULL Возвращаемое значение: целевой объект снаряда.

    IMoveableObject* GetTarget() Получите тип снаряда.

    Возвращаемое значение: тип оболочки, подробности см.

    в описании ShellType. ShellType GetType() Возвращаемое значение: Получите урон, нанесенный снарядом.

    Возвращаемое значение: Урон, нанесенный снарядом.

    интервал GetHP() Интерфейс ИСтатикОбъект – описывает интерфейс объектов статической карты.

    Получить количество очков жизни объекта Возвращаемое значение: текущее значение хит-пойнта.

    интервал GetHP() Получить координаты объекта Координаты статического объекта соответствуют его левому верхнему углу.

    Дополнительную информацию о системе координат см.

    в разделе IWorld. Возвращаемое значение: координаты объекта Точка ПолучитьПозицию() Получить размер объекта Возвращаемое значение: размер объекта Размер GetSize() Интерфейс IМир – описывает интерфейс игрового мира.

    Получить текущий номер хода Нумерация начинается с 1. Нулевой ход соответствует вызову Init Возвращаемое значение: текущий номер хода.

    int GetCurrentStep() Получить общее количество ходов Возвращаемое значение: общее количество ходов (исключая ход инициализации).

    int GetTotalStep() Получить список статических объектов Список основан на типе std::vector и доступен по индексу.

    Разрушенные объекты удаляются из игры и не отображаются в этом списке.

    Возвращаемое значение: список объектов статической карты.

    IStaticObjectList GetStaticObjects() Получить список вражеских ботов Список основан на типе std::vector и доступен по индексу.

    Убитые боты удаляются из игры и не отображаются в этом списке.

    Возвращаемое значение: список вражеских ботов.

    IEnemyList GetEnemies() Получите список ваших ботов Список основан на типе std::vector и доступен по индексу.

    Убитые боты удаляются из игры и не отображаются в этом списке.

    Возвращаемое значение: список ваших ботов.

    ISelfList GetSelfs() Получить список снарядов, расположенных на карте Список основан на типе std::vector и доступен по индексу.

    Снаряды, вылетающие за пределы карты или сталкивающиеся с объектом, удаляются из игры и не отображаются в этом списке.

    Возвращаемое значение: список снарядов, расположенных на карте.

    IShellList GetShells() Получить список бонусов на карту Список основан на типе std::vector и доступен по индексу.

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

    Возвращаемое значение: список ботов, расположенных на карте.

    IBonusList GetBonuses() Получить объект по метке Параметры: пометка пометка полученного объекта Возвращаемое значение: если найден объект с такой меткой, то возвращается указатель на него, в противном случае возвращается NULL IMoveableObject* GetByMark(целое число) Добавить отладочное сообщение Добавляет сообщение отладки, отображаемое при рендеринге для отладки.

    Параметры: format Формат сообщения представляет собой строку длиной n символов.

    Далее идут n параметров в соответствии с форматом задачи.

    d — целое число (int) f — дробное число (с плавающей запятой) с — строка все остальные символы не интерпретируются и попадают в сообщение Общая длина одного сообщения не должна превышать 255 символов.

    Если линия длиннее, она будет укорочена до необходимого размера.

    void AddMessage (формат строки, .

    ) Добавить точку отладки Добавляет точку отладки, которая отображается при рендеринге для отладки.

    Параметры: координата точки p время жизни векторного отображения в движениях void AddPoint (точка p, время жизни int) Добавить вектор отладки Добавляет вектор отладки, который отображается при рендеринге для отладки.

    Параметры: начать отправную точку конечная точка время жизни векторного отображения в движениях void AddVector (начало точки, конец точки, время жизни int) Получить ширину карты Возвращаемое значение: ширина карты интервал GetWidth() Получить высоту карты Возвращаемое значение: высота карты.

    интервал GetHeight()

Теги: #CGC #олимпиада по программированию #Code Game Challenge #Code Game Show #Чулан
Вместе с данным постом часто просматривают: