Кодемон, я выбираю тебя!


55

Ваш добрый сосед, Доктор Три, только что подарил вам три магических существа по имени Кодемон. В соседнем городе Colorville есть боевой турнир. Ты самый лучший, как никто и никогда не был?

обзор

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

Монстры

Кодемон - сложное маленькое существо. Есть пять типов (элементов) на выбор, три характеристики и три слота перемещения на каждом.

Типы

Каждому Кодемону присваивается один тип. Пять типов: Нормальный, Психический, Огонь, Вода и Трава. У каждого есть свои сильные и слабые стороны. Ущерб основан на следующем графике:

типа диаграммы

Числа являются множителями урона. Например, у воды, атакующей огонь, есть модификатор 0.5 (половина урона), тогда как трава, атакующая огонь, удваивается (2).

Статистика

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

Каждый монстр имеет начальное значение 50 для каждого персонажа и максимум 100. Когда вы создаете своих монстров, вы сможете назначить 80 дополнительных очков статов (каждый). Помните, что никакая индивидуальная статистика не может превышать 100. Таким образом, вы можете иметь распределение 100/80/50, 90/80/60 или 65/65/100, но 120/50/60 недопустимо. Любая команда с нелегальной статистикой дисквалифицируется. Вы не обязаны использовать все 80 баллов, но вы, вероятно, не должны идти с минимумом 50/50/50.

Вы также можете считать HP статом, но каждый Кодемон имеет неизменяемые 100 HP. Когда HP падает до нуля, они не могут продолжать бой. HP пополняется до 100 перед каждой битвой.

Ходы

Каждый монстр знает три боевых хода. Три выбранных должны быть отличными, так что нет Punch / Punch / Punch.

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

id  name        type    power   uses    usable  effect

0   Punch       N       20      -       NFWG
1   Heal        N        0      3       NFWG    Heals 50 HP
2   Slow        N       10      5       NFWG    Enemy speed x0.8
3   Pain        P       20      -       PFWG
4   Sleep       P        0      3       PFWG    No enemy action until wake
5   Weaken      P       10      5       PFWG    Enemy Atk x0.8
6   Fireball    F       20      -       NPFW
7   Burn        F        0      3       NPFW    Enemy -10 HP each turn
8   Sharpen     F       10      5       NPFW    Own Atk x1.25
9   Watergun    W       20      -       NPWG    
10  Confuse     W        0      3       NPWG    Enemy may strike itself (10 power)
11  Shield      W       10      5       NPWG    Own Def x1.25
12  Vine        G       20      -       NPFG
13  Poison      G        0      3       NPFG    Enemy -5xTurns HP each turn
14  Sap         G       10      5       NPFG    Enemy Def x0.8

typeотносится к типу движения. powerэто его поразительная сила. usesуказывает, сколько раз его можно использовать за бой ( -не ограничено). usableпоказывает, какими типами он может быть использован (например, Punch не может быть назначен психическому типу, поскольку его нет P). effectпоказывает, какие эффекты имеют ходы. С вероятностью 75% каждый эффект работает, кроме Heal, который всегда работает.

Для эффектов, которые изменяют характеристики монстров, эффекты могут быть сложены . Например, использование Weaken дважды может снизить атаку вашего противника до 0,64 эффективности. Эффекты, которые не изменяют характеристики монстров (Sleep, Burn и т. Д.) , Не суммируются .

Сон усыпляет противника с вероятностью 60% пробуждения в начале каждого хода. Спящие монстры не будут предпринимать никаких действий.

Ожог наносит противнику 10 HP в конце каждого хода, когда он активен . Яд действует аналогично, но с каждым ходом его количество увеличивается. В первый ход это 5, и после этого он получает 5 каждый ход. Таким образом, к четвертому ходу он будет наносить урон в течение 20. Это плоский урон, не зависящий от типа монстра или подверженный бонусам.

Путаница может привести к нападению монстра, вместо того, чтобы делать то, что ему велели. Эта атака имеет силу 10 и вероятность 30% произойти в данный ход.

Для ясности, эффекты сохраняются до конца битвы (кроме Sleep, как отмечено выше).

Ходы также получают 20% прироста силы, если используются монстром соответствующего типа. Например, монстр Грасса, использующий Vine, усиливается, а Punch - нет.

Секретная статистика

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

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

Боевой

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

После этого выполняются повороты со следующими шагами:

  • Переключатель: происходят обязательные переключения монстров (если есть)
  • Выберите боевые действия
  • Переключатель: любые дополнительные переключатели монстров (выбран в качестве боевого действия) имеют место
  • Проверка сна: шанс проснуться от сна
  • Атака 1: Если возможно, более быстрый монстр использует выбранный ход
  • Атака 2: Если возможно, другой монстр использует выбранный ход
  • Эффект урона: нанесите урон от ожогов / ядов живым монстрам

«Speedier» означает монстра с более высокой скоростью. Если обе характеристики скорости одинаковы, она выбирается подбрасыванием монеты PRNG каждый ход.

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

Монстры не «обрабатываются», когда неактивны. Это означает, что они не получают урона от ожогов / ядов, счетчики ядов не накапливаются, не просыпаются ото сна и т. Д. При переключении никакие эффекты не удаляются и не изменяются . Это не та другая битва с монстрами. Если вы переключитесь с поднятой и сожженной атакой, они все равно будут там, когда вы вернетесь обратно.

Эффект урона происходит независимо от того, убиваете вы вашего активного противника или нет. Таким образом, члены обеих команд могут умереть за один ход.

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

Формула для определения ущерба:

floor((effAttack / effDefense) * movePower * typeMultiplier * moveBoost)

effAttackи effDefenseявляется эффективной статистикой для монстров. Эффективная атака получается путем добавления Attack и Bonus Attack, а затем умножения (на 0,8 или 1,25), если какие-либо эффекты меняют его. Помните, что эти эффекты могут складываться.

Урон может быть только 0, когда модификатор типа равен 0 (Normal <-> Psychic) ​​или сила хода равна 0 (Heal, Burn и т. Д.). В противном случае минимум применяется в 1.

Турнир

Турниры длятся 100 раундов. В каждом раунде команды перетасовываются и случайным образом соединяются друг с другом. Если есть нечетное количество команд, остаток получает прощай (счет как ничья). Победа в битве приносит команде 2 очка, связи стоят 1 , а потери ничто. Команда с наибольшим количеством очков в конце побеждает!

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

протокол

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

Ваша программа примет команду в качестве аргумента и ответит на STDOUT в течение одной секунды . Не оставайтесь в живых, слушая STDIN, его там не будет. Каждая команда порождает новый процесс.

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

команды

Данные команды

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

Запрос:

T

Отклик:

name|member0|member1|member2

nameэто строка с названием вашей команды. Пожалуйста, используйте только буквенно-цифровой, для простоты анализа. memberNявляется строкой члена, дающей детали каждого монстра:

Строка участника:

name:typeid:attack:defense:speed:moveid0:moveid1:moveid2

Опять же, «имя» - это строка, на этот раз с именем этого монстра. typeidэто его тип. Идентификаторы типов в порядке, показанном на диаграмме выше, с Normal = 0 и Grass = 4.

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

Последние три - ходы вашего монстра. Идентификаторы показаны на диаграмме перемещения выше.

Пример ответа с данными команды может выглядеть так:

DummyTeam|DummyA:0:50:60:70:0:1:2|DummyB:0:50:60:70:0:1:2|DummyC:0:50:60:70:0:1:2

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

Выберите Активный

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

Запрос:

C#battleState

battleStateпоказывает состояние текущего сражения. Терпите меня здесь, это ужасно

yourTeamState#theirTeamState

Где XteamStateвыглядит так:

name:activeSlot|member0state|member1state|member2state

activeSlotпоказывает, какой монстр в данный момент активен (0-2). Страны-участницы бывают двух видов. Если это ваша команда, это дает дополнительную информацию. Так,

Ваш членXstate:

name:id:attack:defense:speed:hp:typeid:poisonedturns:moveCount0:moveCount1:moveCount2:bonusAttack:bonusDefense:bonusSpeed:effectid:effectid:effectid

Их членXstate:

name:id:attack:defense:speed:hp:typeid:poisonedturns:effectid:effectid:effectid

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

attack:defense:speedваша базовая статистика.

poisonedturns говорит вам, за сколько ходов вы были отравлены.

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

bonus(stat) это количество бонусных баллов, которые вы присвоили каждой статистике.

effectidсписок эффектов переменного размера, которые были применены к вашему монстру В строке не будет запаздывания :, независимо от того, присутствуют ли активные эффекты или нет. Если есть комбинированные эффекты, они будут отображаться в списке как несколько эффектов.

Идентификаторы эффекта:

0  NONE           (should not appear, internal use)
1  POISON
2  CONFUSION 
3  BURN 
4  SLEEP 
5  HEAL           (should not appear, internal use)
6  ATTACK_UP
7  ATTACK_DOWN
8  DEFENSE_UP
9  DEFENSE_DOWN
10 SPEED_DOWN

Отклик:

memberSlot

Единственный требуемый ответ - это одно число 0,1,2, указывающее, какого члена вы хотите быть активным. Это должен быть участник, который способен сражаться. Не отправлять обратно, 1если участник 1 мертв.

Боевые действия

Каждый ход вам нужно решить, что делать.

Запрос:

A#battleState

battleStateЗдесь точно так , как описано выше.

Отклик:

Чтобы использовать перемещение, отправьте обратно слот, в котором он находится. Например, если я назначил Punch для слота 0, отправка 0выполняет Punch.

Чтобы переключиться на другого участника, отправьте слот участника плюс десять . Итак, чтобы перейти к участнику 2, отправьте 12.

Все, что не указано в [0,1,2,10,11,12], считается недействительным и в этот ход не предпринимает никаких действий.

Бонус Статистика

После каждых двух сражений вы получаете секретный бонусный балл за каждого члена команды.

Запрос:

B#yourTeamState

Состояние вашей команды такое же, как показано выше, не заставляйте меня повторять это.

Отклик:

stat0:stat1:stat2

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

Таким образом, чтобы повысить скорость первого члена, атаку второго и защиту третьего, вы должны ответить:

2:0:1

контроллер

Контроллер можно найти в BitBucket: https: //Geobits@bitbucket.org/Geobits/codemon.git

Просто бросьте все скомпилированные файлы классов, материалы и Players.conf в папку и запустите.

Основной класс контроллера называется Tournament. Использование это:

java Tournament [LOG_LEVEL]

Уровни журнала от 0 до 4 дают возрастающую информацию. Уровень 0 проводит турнир молча и просто дает результаты, тогда как уровень 3 дает пошаговые комментарии. Уровень 4 является выходом отладки.

Вы можете добавить заявки на турнир в разделе players.confПросто добавьте строку командной строки, необходимую для запуска программы, по одной на строку. Строки, начинающиеся с #комментариев.

В своем посте включите команду, которую мне нужно добавить в мои players.conf, и все этапы компиляции (если требуется).

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

Прочие правила

  • Вы не можете читать или писать на любые внешние ресурсы (за исключением вашей собственной подпапки, размером до 32 КБ, как указано выше).

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

  • Не вмешивайтесь в другие процессы / представления. Не вызывать их, использовать отражение, чтобы получить их данные и т. Д. Не связывайтесь с моим компьютером. Только не пытайся. Это на мое усмотрение. Нарушителям может быть запрещено вступление в будущем.

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

  • Записи могут не существовать исключительно для поддержки других записей. Кроме того, вы не можете пытаться косвенно дисквалифицировать других участников (например, используя имя команды персонажа 27M для игроков DQ, которые пытаются записать это на диск). Каждое представление должно играть, чтобы выиграть на свой счет.

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

  • Турнир будет проходить на моем компьютере под управлением Ubuntu с процессором Intel i7 3770K.

Результаты

Это результаты нынешних игроков. Это очень близко между ведущими соперниками, и я думаю об увеличении количества раундов до 500 (и корректировке расстояния между бонусными очками, чтобы соответствовать). Есть возражения, комментарии?

------- Final Results -------

158     Happy3Campers
157     LittleKid
71      InsideYourHead
68      HardenedTrio
46      BitterRivals

Полные результаты воспроизведения на Google Диске


62
Я хочу быть самым лучшим / Как никогда не было кода / Не сбой - мой тест / Отладка - моя причина! / Я буду путешествовать по локальной сети / Сценарии повсюду / Пытаюсь понять / Почему мой BIOS сгорел! / Codémon, это ты и я / Игра в гольф на все глаза / Codémon, ты мой лучший друг / После окончания программы! / Codémon, такой правдивый ланг / Никакие segfaults не проведут нас до конца / Ты научишь меня, и я научу тебя / Codémon, должен всех их сыграть в гольф!
Каз Вулф

1
Вместо увеличения раундов до 500 было бы хорошо, если бы один раунд состоял из всех, сражающихся со всеми. Так что больше byeне нужно разбираться с неравным количеством участников, и было бы необходимо убедиться, что пары совпадений справедливы и равномерно распределены.
foobar

@foobar Я хотел избежать этого, потому что это масштабирует сражения n^2вместо n. При нынешних 7 участниках и 100 раундах это 2100 битв (против 300 как есть и 1500 с 500 раундами). Это только усугубляется, когда приходит больше записей. Я мог бы уменьшить количество раундов, но я не решаюсь сделать это из-за присущей изменчивости (относительно статусов esp), и умножить на 50 (для бонусных баллов) проще.
Geobits

Разве этот вызов не требует обновления? :)
GholGoth21

@ GholGoth21 Да, я верю, что это так. Я, вероятно, не могу добраться до этого сегодня, но, возможно, завтра или на следующий день. Пинг мне в чате, если не обновляется к четвергу или около того, если хотите.
Geobits

Ответы:


16

Счастливые 3 туриста - PHP

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

РЕДАКТИРОВАТЬ : г-н Лампи был жестоко наказан и больше не будет говорить плохие слова


удобныйудобныйGrass - atk:50 def:99 spd:81 Confuse Poison Heal

Ядовитый безрукий бобер, который любит путать людей с проблемными рукопожатиями


FlippyFlippyWater - atk:50 def:99 spd:81 Confuse Burn Heal

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


увлекающийсяувлекающийсяFire - atk:50 def:99 spd:81 Burn Poison Heal

Оружие массового уничтожения - его любимые конфеты.


комковатыйкомковатыйPhp - lines:500 clarity:05 spd:01 Gather Guess Store

Благодаря его почти 2-значному IQ и феноменальной памяти, Lumpy может угадывать движения врага. Ну, в основном.


стратегия

Стратегия состоит в том, чтобы отравить, сжечь и запутать противников как можно скорее.
Сон не использовался, так как он казался менее мощным, чем три заклинания выше.
Путаница смертельна в долгосрочной перспективе, так как она уменьшает атаки на 30% (как нанесение урона, так и наложение заклинаний), предотвращает исцеление целителей и наносит тяжелый урон нападающим (монстр 50 def / 100 atk нанесет себе 20 пунктов урона). ).

Как только враг тщательно вставлен, мои отдыхающие просто наблюдают, как он шипит, гниет и бьет себя до смерти.

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

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

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

Атака не используется вообще.

Заклинания - главное оружие?

Заклинания типа яда, горения и запутывания избегают общей логики «камень / бумага / ножницы» других атак.

Как только на монстра воздействует, он продолжит терять HP даже после смерти заклинателя. Как будто призрак заклинателя продолжал нападать на него.
Кроме того, яд быстро становится сильнее мощной массированной атаки (более 50 очков после 5 ходов).

Продолжительность жизни отравленного и сожженного монстра не превышает 8 ходов, даже при 3 исцелениях.

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

Код

Вызвать с php campers.php

Это ужасный беспорядок, но, честно говоря, интерфейс тоже не помогает.

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

<?php

// ============================================================================
// Game
// ============================================================================
class G {
    static $code_type = array ("Normal", "Psychic", "Fire", "Water", "Grass", "?", "self"); 
    static $code_move = array    ("Punch", "Heal", "Slow", "Pain", "Sleep", "Weaken", "Fireball", "Burn", "Sharpen", "Watergun", "Confuse", "Shield", "Vine", "Poison", "Sap", "?", "self", "pass");
    static $move_uses = array (1000,3,5,1000,3,5,1000,3,5,1000,3,5,1000,3,5,   2000,2000);
    static $move_type      = array (0,0,0,1,1,1,2,2,2,3,3,3,4,4,4, 5,5,5);
    static $move_dmg       = array (20,0,10,20,0,10,20,0,10,20,0,10,20,0,10,  20,10,0);
    static $move_forbidden = array (1,1,1,0,0,0,4,4,4,2,2,2,3,3,3);
    static $code_effect = array ("N", "Poison", "Confuse", "Burn", "Sleep", "H", "Sharpen", "Weaken", "Shield", "Sap", "Slow"); 
    static $decode_type, $decode_move, $decode_effect;
    static $damage_multiplier = array (
        array (2, 0, 1, 1, 1, 0),
        array (0, 2, 1, 1, 1, 0),
        array (1, 1,.5, 2,.5, 0),
        array (1, 1,.5,.5, 2, 0),
        array (1, 1, 2,.5,.5, 0),
        array (2, 2, 2, 2, 2,-1),
        array (9, 9, 9, 9, 9, 9, 1));
    static $atk_score = array ("Poison"=> 1002, "Confuse"=>1001, "Burn"=>1000);
    static $status_field = "atk:def:spd:hp:type:Pturns";
    static $all_moves, $strong_moves, $medium_moves, $effect_moves, $possible_moves;

    function init()
    {
        self::$status_field = explode (":", self::$status_field);
        foreach (array ("type", "move", "effect") as $table) self::${"decode_$table"} = array_flip (self::${"code_$table"});
        foreach (self::$code_move as $c=>$m)
        {
            if ($m == "?") break;
            self::$all_moves[] = new Move($m);
            if (self::$move_uses[$c] >  5) self::$strong_moves[] = $m;
            if (self::$move_uses[$c] == 5) self::$medium_moves[] = $m;
            if (self::$move_uses[$c] == 3) self::$effect_moves[] = $m;
            for ($type = 0 ; $type != 5 ; $type++) if ((self::$move_uses[$c] >  5) && (self::$move_forbidden[$c] != $type)) self::$possible_moves[$type][] = $m;
        }
    }

    function __construct ($name, $team)
    {
        $this->turn = 0;
        $this->name = $name;
        $this->team = $team;
        $this->results_pending = false;
    }

    function parse_team ($tpack, $own_team)
    {
        $pack = explode ("|", $tpack);
        list ($name,$active) = explode (":", array_shift($pack));
        if ($own_team)
        {
            $team = $this->team;
        }
        else
        {
            if (!isset($this->enemies[$name])) $this->enemies[$name] = new Team(array (new Monster (), new Monster (), new Monster ()));
            $team = $this->foes = $this->enemies[$name];
        }
        $team->active = $active;
        foreach ($pack as $i=>$mpack) $team->monster[$i]->parse_monster ($own_team, $mpack);
    }

    function choose_active ()
    {
        // detect start of round
        $team = $this->team;
        $foes = $this->foes;
        foreach ($team->monster as $i=>$m) if ($m->hp > 0) $candidate[$i] = $m;
        if (count ($candidate) == 3)
        {
            $this->results_pending = false;
            $this->round++;

            // reinitialize all monsters
            foreach (array($team, $foes) as $t)
            foreach ($t->monster as $m)
                $m->start_round();

            // guess initial opponent
            $opponent = $foes->initial_opponent();
        }
        else
        {
            $this->analyze_last_round();
            $opponent = $foes->active();
        }
        return $this->do_switch ($opponent);
    }

    function choose_attacker ($foe)
    {
        foreach ($this->team->monster as $i=>$m) if ($m->can_attack($foe)) $candidate[$i] = $m;
        if (isset($candidate))
        {
            uasort ($candidate, function ($a,$b) use ($foe) { return ($a->atk_score != $b->atk_score) ? $b->atk_score - $a->atk_score : $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            return key($candidate);
        }
        return -1;
    }

    function do_switch ($foe)
    {
        $replacement = $this->choose_attacker ($foe);
        if ($replacement < 0)
        {
            $candidate =  $this->team->monster;
            uasort ($candidate, function ($a,$b) use ($foe) { return $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            $replacement = key($candidate);
        }

        $this->old_own = $this->team->monster[$replacement];
        $this->old_own->attack = "pass";
        return $replacement;
    }

    function choose_action ()
    {
        $this->analyze_last_round();
        $own = $this->team->active();
        $foe = $this->foes->active();
        $this->old_own = $own;

        if ($own->hp <= $own->max_damage($foe) && $own->can_do ("Heal")) return $own->execute("Heal");
        if ($attack = $own->can_attack($foe)) return $own->execute($attack);
        if ($own->hp <= 50 && $own->can_do ("Heal")) return $own->execute("Heal");

        return 10 + $this->do_switch ($foe);    
    }

    function choose_bonus()
    {
        foreach ($this->team->monster as $m)
        {
            if ($m->spd_b == 0) { $m->spd_b++; $res[] = 2; }
            else                { $m->def_b++; $res[] = 1; }
        }
        return implode (":", $res);
    }

    function parse ($parts)
    {
        self::parse_team ($parts[1], true);
        self::parse_team ($parts[2], false);    
    }

    function analyze_last_round()
    {
        if ($this->results_pending)
        {
            $this->results_pending = false;

            $foes = $this->foes;
            $foe = null;
            foreach ($foes->monster as $m) if ($m->hp != $m->old->hp) $foe = $m;
            if ($foe === null) $foe = $foes->monster[$foes->active];

            $this->old_own->guess_attack($foe);
        }
    }

    function process ($line)
    {
        $parts = explode ("#", $line);
        switch ($parts[0])
        {
        case "T": // register for tournament
            echo "$this->name|$this->team";
            break;
        case "C": // designate active monster
            $this->parse ($parts);
            echo $this->choose_active();
            break;
        case "A": // choose round action
            $this->parse ($parts);
            echo $this->choose_action();

            // save current state
            foreach (array($this->team, $this->foes) as $t)
            foreach ($t->monster as $m)
            {
                unset ($m->old);
                $m->old = clone ($m);
            }
            $this->results_pending = true;
            break;
        case "B": // distribute stat bonus
            echo $this->choose_bonus();
            break;
        }

    }
}
G::init();

// ============================================================================
// Move
// ============================================================================
class Move {
    function __construct ($move)
    {
        $this->register($move);
    }

    function register ($move)
    {
        $this->type = G::$decode_move[$move];
        $this->reinit();
    }

    function reinit()
    {
        $this->uses = G::$move_uses[$this->type];
    }

    function __tostring() { return G::$code_move[$this->type]."($this->uses)"; }
}

// ============================================================================
// Monster
// ============================================================================
class Monster { 
    function __construct ($name="?", $type="?", $atk=100, $def=100, $spd=100, $m0="?", $m1="?", $m2="?")
    {
        $this->name = $name;
        $this->type = G::$decode_type[$type];
        $this->atk  = $atk;
        $this->def  = $def;
        $this->spd  = $spd;
        $this->hp   = 100;
        $this->move = array (new Move($m0), new Move($m1), new Move($m2));
        $this->atk_b = 0;
        $this->def_b = 0;
        $this->spd_b = 0;
        foreach (G::$code_effect as $e) $this->$e = 0;
    }

    function __tostring ()
    {
        return implode (":", array (
            $this->name,
            $this->type,
            $this->atk,
            $this->def,
            $this->spd,
            $this->move[0]->type,
            $this->move[1]->type,
            $this->move[2]->type));
    }

    function start_round()
    {
        foreach ($this->move as $m) $m->reinit();
    }

    function parse_monster ($own_team, $spack)
    {
        $pack = explode (":", $spack);
        $name = array_shift ($pack); // get name
        array_shift ($pack); // skip id
        if ($this->name == "?") $this->name = $name; // get paranoid
        else if ($this->name != $name) die ("expected $this->name, got $name");

        // store updated values
        foreach (G::$status_field as $var) $this->$var = array_shift ($pack);
        if ($own_team)
        {
            foreach ($this->move as $m) $m->new_count = array_shift($pack);
            $pack = array_slice ($pack, 3); // these are maintained internally
        }
        $var = array();
        foreach ($pack as $e) @$var[G::$code_effect[$e]]++; 
        foreach (G::$code_effect as $e) $this->$e = @$var[$e]+0;
    }

    function damage_recieved ($attack, $foe=null)
    {
        if ($attack == "self") $foe = $this;
        $a = G::$decode_move[$attack];
        $type = G::$move_type[$a];
        $dmg = g::$move_dmg[$a];

        if ($dmg == 0) return 0;

        $atk = ($foe ->atk+$foe ->atk_b) * pow (.8, ($foe ->Weaken - $foe ->Sharpen));
        $def = ($this->def+$this->def_b) * pow (.8, ($this->Sap    - $this->Shield ));

        $boost = ($foe->type == $type) ? 1.2 : 1;
        return max (floor ($dmg * $atk / $def * $boost * G::$damage_multiplier[$this->type][$type]), 1);
    }

    function guess_attack_from_effect ($attacks)
    {
        foreach ($attacks as $status) if ($this->$status != $this->old->$status) return $status;
        return "?";
    }

    function guess_attack_from_damage ($foe, $damages)
    {
        $select = array();
        foreach (G::$possible_moves[$foe->type] as $attack)
        {
            $dmg = $this->damage_recieved ($attack, $foe);
            foreach ($damages as $damage) if ($damage != 0 && abs ($dmg/$damage-1) < 0.1) $select[$attack] = 1;
        }
        $res = array();
        foreach ($select as $a=>$x) $res[] = $a;
        return $res;
    }

    function guess_attack ($foe)
    {
        $attempt = G::$decode_move[$this->old->attack];
        $success = ($this->old->attack == "pass");
        foreach ($this->move as $m)
        {
            if ($m->type == $attempt)
            {
                if ($m->new_count == $m->uses-1)
                {
                    $m->uses--;
                    $success = true;
                }
                break;
            }
        }

        $possible = array();
        $attack = $this->guess_attack_from_effect (array("Burn", "Confuse", "Poison", "Sleep", "Slow", "Weaken", "Sap"));
        if ($attack == "?") $attack = $foe->guess_attack_from_effect (array("Sharpen", "Shield"));
        if ($attack == "?")
        {
            $foe_damage = $this->old->hp - $this->hp - (10 * $this->Burn + 5 * $this->Pturns*$this->Poison);
            if ($this->old->attack == "Heal" && $success) $foe_damage += 50;
            $possible_dmg[] = $foe_damage;
            //;!;if ($this->Confuse) $possible_dmg[] = $foe_damage + $this->damage_recieved ("self");
            $possible = $this->guess_attack_from_damage ($foe, $possible_dmg);
            if (count ($possible) == 1) $attack = $possible[0];
        }
        if ($attack == "?")
        {
            $own_damage = $foe->old->hp - $foe->hp 
                        - (10 * $foe->Burn + 5 * $foe->Pturns*$foe->Poison)
                        + $foe->damage_recieved ($this->attack);
            if (abs ($own_damage/50+1) < 0.1) $attack = "Heal";
        }
        if ($attack != "?")
        {
            $type = G::$decode_move[$attack];
            if ($attack != "?")
            {
                foreach ($foe->move as $m) if ($m->type == $type) goto found_old;
                foreach ($foe->move as $m) if ($m->type == 15) { $m->register($attack); goto found_new; }
            }
            found_new:
            found_old:
        }
    }

    function max_damage($foe)
    {
        $dmg = 0;
        foreach ($foe->move as $m) $dmg = max ($dmg, $this->damage_recieved (G::$code_move[$m->type], $foe));
        return $dmg;
    }

    function expected_damage ($foe)
    {
        return $this->max_damage($foe) + 10 * $this->Burn + 5 * ($this->Pturns+1);
    }

    function life_expectancy ($foe)
    {
        $hp = $this->hp;
        $poison = $this->Pturns;
        $heal = $this->can_do ("Heal");
        $dmg = $this->max_damage($foe);
        for ($turn = 0 ; $hp > 0 && $turn < 10; $turn++)
        {
            $hp -= 10 * $this->Burn + 5 * $poison;
            if ($poison > 0) $poison++;
            $hp -= $dmg;
            if ($hp <= 0 && $heal > 0) { $hp+=50; $heal--; }
        }
        return 100 * $turn + $this->hp;
    }

    function can_attack ($foe)
    {
        $attack = false;
        if ($this->hp > 0)
        {
            if      (!$foe->Poison  && $this->can_do ("Poison" )) $attack = "Poison";
            else if (!$foe->Confuse && $this->can_do ("Confuse")) $attack = "Confuse";
            else if (!$foe->Burn    && $this->can_do ("Burn"   )) $attack = "Burn";
        }
        $this->atk_score = ($attack === false) ? 0 : G::$atk_score[$attack];
        return $attack;
    }

    function can_do($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $m) if ($m->type == $type && $m->uses > 0) return $m->uses;
        return false;
    }

    function execute($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $i=>$m) if ($m->type == $type) 
        { 
            if ($m->uses > 0)
            {
//;!;               $m->uses--;
                $this->attack = $move;
            }
            else $this->attack = "pass";
            return $i; 
        }
        die ("$this asked to perform $move, available ".implode(",", $this->move));
    }
}

// ============================================================================
// Team
// ============================================================================
class Team {
    function __construct ($members)
    {
        $this->monster = $members;
    }

    function __tostring()
    {
        return implode ("|", $this->monster);
    }

    function active ()
    {
        return $this->monster[$this->active];
    }

    function initial_opponent()
    {
        return $this->monster[0];
    }
}

// ============================================================================
// main
// ============================================================================
$input = $argv[1];

$team_name = "H3C";
$mem_file = "$team_name/memory.txt";
$trc_file = "$team_name/trace.txt";
if (!file_exists($team_name)) mkdir($team_name, 0777, true) or die ("could not create storage directory '$team_name'");
if ($input == "T") array_map('unlink', glob("$team_name/*.txt"));

if (file_exists($mem_file)) $game = unserialize (file_get_contents ($mem_file));
else
{
    $team = new Team (
        array (
            new Monster ("Handy" , "Grass" , 50, 99, 81, "Confuse", "Poison", "Heal"),
            new Monster ("Nutty" , "Fire"  , 50, 99, 81, "Burn"   , "Poison", "Heal"),
            new Monster ("Flippy", "Water" , 50, 99, 81, "Confuse" , "Burn" , "Heal")));
    $game = new G($team_name,$team);
}

$game->process ($input);
file_put_contents ($mem_file, serialize($game));

Результаты

LittleKid все еще угрожающий, но мое трио победило его ядовитых уродов с достаточным отрывом.

Боты Мартина обречены на их отсутствие инициативы, и увеличение их скорости потребовало бы снижения атаки, что ослабило бы их преимущество в способности наносить урон.

Новые соперники с планеты JavaScript находятся на одном уровне с командой один на один, но они хуже других соперников. Они на самом деле помогают уменьшить счет LittleKid :).

Так что, кажется, мои приятные друзья остаются королями горы - пока ...

170             H3C
158             Nodemon
145             LittleKid
55              InsideYourHead
42              HardenedTrio
30              BitterRivals

И у меня нет PHP на моем тоже. Хотя я ожидаю, что вы вытерете пол метаподами, поскольку они идут на медленную страту и будут отравлены до смерти.
Sp3000

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

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

2
Да, это то, что я себе представлял, как только я не вижу лекарства от яда и ожога. Спасибо за то, что воплотили мою мечту в жизнь.
полугодие

1
Это мистер Лампи выражает свою озадаченность, когда обнаруживает более 3 различных атак одного и того же противника :). У меня исправленная версия почти завершена, но я сейчас занят чем-то другим, поэтому исправление будет опубликовано через день или около того.

7

HardenedTrio, Python 3

Так как Geobits был достаточно хорош, чтобы дать нам два представления, я подумал, что отправлю что-нибудь глупое для первого: P

Партия состоит из трех кодемонов (Metapod1, Metapod2, Metapod3) с одинаковыми характеристиками и ходами:

  • 80 атак, 100 обороны, 50 скоростей
  • Удар, Лечение, Укрепление Щитом

Все бонусные баллы также назначаются на защиту.


from collections import namedtuple
import sys

BattleState = namedtuple("BattleState", ["us", "them"])
TeamState = namedtuple("TeamState", ["name", "active", "members"])
MemberState = namedtuple("MemberState", ["name", "id", "attack", "defense", "speed", "hp",
                                         "typeid", "poisonedturns", "otherstats"])

def parse_battle_state(state):
    return BattleState(*map(parse_team_state, state.split("#")))

def parse_team_state(state):
    na, *members = state.split("|")
    name, active = na.split(":")
    return TeamState(name, int(active), list(map(parse_member_state, members)))

def parse_member_state(state):
    name, id_, attack, defense, speed, hp, typeid, poisonedturns, *rest = state.split(":")
    return MemberState(name, int(id_), float(attack), float(defense), float(speed),
                       float(hp), int(typeid), int(poisonedturns), rest)

command = sys.argv[1].strip()

if command.startswith("T"):
    print("HardenedTrio|Metapod1:0:80:100:50:0:1:11|"
          "Metapod2:0:80:100:50:0:1:11|Metapod3:0:80:100:50:0:1:11")

elif command.startswith("C"):
    battle_state = parse_battle_state(command[2:])

    for i, codemon in enumerate(battle_state.us.members):
        if codemon.hp > 0:
            print(i)
            break

elif command.startswith("A"):
    battle_state = parse_battle_state(command[2:])
    current_codemon = battle_state.us.members[battle_state.us.active]

    if current_codemon.hp < 50 and int(current_codemon.otherstats[1]) > 0:
        print(1) # Heal up if low

    elif int(current_codemon.otherstats[2]) > 0:
        print(2) # Harden!

    else:
        print(0) # Punch!

elif command.startswith("B"):
    print("1:1:1")

Бежать с

py -3 <filename>

(или с python/ python3вместо pyзависимости от вашей установки)



1
@FryAmTheEggman Metapod, HARDEN!
Sp3000

Я пытаюсь прочитать ваш код, но запутался в int(current_codemon.otherstats[1])>0. Что возвращает истину, если он имеет статус эффекта? И он использует харден, только если у него два эффекта статуса?
Утка

@MooingDuck Для вашего Codemon у вас есть moveCounts перед effectids, поэтому он проверяет, может ли он по-прежнему использовать Harden. Мне стало лень с разбором, вот почему он сосредоточен там.
Sp3000

@ Sp3000: Ой! Правильно! Хахаха!
Утка

6

В твоей голове, Руби

  • Брайан : Экстрасенс, Атака: 100, Защита: 50, Скорость: 80, Боль, Огненный шар, Пистолет
  • Elemon1 : Экстрасенс, Атака: 100, Защита: 50, Скорость: 80, Огненный шар, Пистолет, Виноградная лоза
  • Elemon2 : Экстрасенс, Атака: 100, Защита: 50, Скорость: 80, Огненный шар, Пистолет, Виноградная лоза
TEAM_SPEC = "InsideYourHead"+
            "|Brian:1:100:50:80:3:6:9"+
            "|Elemon1:1:100:50:80:6:9:12"+
            "|Elemon2:1:100:50:80:6:9:12"

def parse_battle_state request
    request.map do |team_state|
        state = {}
        parts = team_state.split '|'
        state[:active] = parts.shift.split(':')[1].to_i
        state[:monsters] = parts.map do |monster_state|
            monster = {}
            parts = monster_state.split(':')
            monster[:name] = parts[0]
            monster[:hp] = parts[5].to_i
            monster[:type] = parts[6].to_i
            monster
        end
        state
    end
end

request = ARGV[0].split '#'
case request.shift
when 'T'
    puts TEAM_SPEC
when 'C'
    battle_state = parse_battle_state request
    my_state = battle_state[0]
    puts my_state[:monsters].find_index {|monster| monster[:hp] > 0}
when 'A'
    battle_state = parse_battle_state request
    my_state, their_state = *battle_state
    my_monster = my_state[:monsters][my_state[:active]]
    their_monster = their_state[:monsters][their_state[:active]]
    puts [1,0,1,2,0][their_monster[:type]]
when 'B'
    puts '0:0:0'
end

Бежать с

ruby InsideYourHead.rb

Это не очень хорошо работает против бота Ману, но лучше остальных трех. Названия команд и монстров довольно случайны ... Я могу поменять их, если найду что-нибудь получше

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

Я мог бы поэкспериментировать с добавлением лечения позже.


1
Хе-хе, это становится интереснее. Я знал, что могу рассчитывать на тебя, Мартин :)

6

LittleKid, Java

Маленький ребенок нашел 3 одинаковых кодемона и обучил их. Они очень раздражают своими атаками исцеления + яда. Использование только кодемонов нормального типа избавляет от необходимости объединять их против определенных врагов, поскольку яд хорошо работает против всех типов.

public class LittleKid {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("Geobits says you can't do this.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "LittleKid";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                break;
            case "B":
                out = "1:1:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];
                int pick = 0;

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = String.valueOf(pick);
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int enemyActive = getActive(them);
                if (getField(me, HP, active) < 50 && getField(me, MOVE1, active) != 0) {
                    out = "1";
                } else if (getEffectCount(them, POISON, enemyActive, false) < 1 && getField(me, MOVE2, active) != 0) {
                    out = "2";
                } else {
                    out = "0";
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6;
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10;

    final static int POISON =           1;
}

5
« Geobits говорит, что вы не можете сделать это »: D
Geobits

Кажется, яд - настоящая

5

Нодемон - Javascript

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

У меня не установлен PHP, поэтому он не проверен на Campers, но, похоже, он является достойным конкурентом для LittleKid в моих испытаниях (и уничтожает Bitter Rivals).

/*jshint node:true*/
'use strict';

var fs = require('fs');

var dataFile = 'Nodemon/data.json';
function getData(callback) {
  fs.readFile(dataFile, 'utf8', function(err, contents) {
    var data = {round: 0};

    if(!err) {
      data = JSON.parse(contents);
    }

    callback(data);
  });
}

function saveData(data, callback) {
  fs.mkdir('Nodemon', function() {    
    fs.writeFile(dataFile, JSON.stringify(data), callback);
  });
}

var effect = {
  poison: '1',
  confusion: '2',
  burn: '3',
  sleep: '4',
  heal: '5',
  attackUp: '6',
  attackDown: '7',
  defenseUp: '8',
  defenseDown: '9',
  speedDown: '10'
};

function parseMemberCommon(args) {
  return {
    name: args[0],
    id: args[1],
    baseAttack: +args[2],
    baseDefense: +args[3],
    baseSpeed: +args[4],
    hp: +args[5],
    typeId: args[6],
    poisonedTurns: +args[7],
    effects: args.slice(8)
  };
}

function parseOwnMember(arg) {
  var args = arg.split(':');

  var ownArgs = args.splice(8, 6);

  var member = parseMemberCommon(args);

  member.moveCount = [
    +ownArgs[0],
    +ownArgs[1],
    +ownArgs[2]
  ];

  member.bonusAttack = +ownArgs[3];
  member.bonusDefense = +ownArgs[3];
  member.bonusSpeed = +ownArgs[3];

  return member;
}

function parseOpponentMember(arg) {
  return parseMemberCommon(arg.split(':'));
}

function parseTeamStateCommon(arg, memberParse) {
  var args = arg.split(':');
  var state = {
    name: args[0],
    members: []
  };
  args = arg.substring(state.name.length + 1).split('|');
  var activeSlot = args[0];
  for(var index = 1; index < args.length; index++) {
    state.members.push(memberParse(args[index]));
  }
  state.activeMember = state.members[activeSlot];
  return state;
}

function parseOwnState(arg) {
  return parseTeamStateCommon(arg, parseOwnMember);
}

function parseOpponentState(arg) {
  return parseTeamStateCommon(arg, parseOpponentMember);
}

function parseBattleState(arg) {
  var args = arg.split('#');
  return {
    own: parseOwnState(args[0]),
    opponent: parseOpponentState(args[1])
  };
}

function teamData() {

  saveData({round:0}, function() {
    console.log('Nodemon|' + 
      'Charasaur:0:50:80:100:10:13:1|' +
      'Bulbtortle:4:50:80:100:10:13:1|' +
      'Squirtmander:1:50:80:100:10:13:4');
  });
}

function getActiveIndex(battleState) {
  for(var index = 0; index < battleState.own.members.length; index++) {
    var member = battleState.own.members[index];
    if(member.hp > 0) {
      return index;
    }
  }
}

function chooseActive(arg) {
  var battleState = parseBattleState(arg);

  getData(function(data) {
    var allFull = true;
    for(var index = 0; index < battleState.opponent.members.length; index++) {
      var member = battleState.opponent.members[index];
      if(!data.maxSpeed || member.baseSpeed > data.maxSpeed) {
        data.maxSpeed = member.baseSpeed;
      }
      if(member.hp < 100) {
        allFull = false;
      }
    }

    if(allFull) {
      data.round++;
    }

    saveData(data, function() {
      console.log(getActiveIndex(battleState));
    });    
  });
}

function useMove(moves, battleState) {
  var fighter = battleState.own.activeMember;

  for(var moveIndex = 0; moveIndex < moves.length; moveIndex++) {
    var move = moves[moveIndex];
    if(fighter.moveCount[move]) {
      return move;
    }

    for(var memberIndex = 0; memberIndex < battleState.own.members.length; memberIndex++) {
      var member = battleState.own.members[memberIndex];

      if(member.hp > 0 && member.moveCount[move] > 0) {
        return 10 + memberIndex;
      }
    }
  }

  return -1;  //do nothing
}

function battleAction(arg) {
  var battleState = parseBattleState(arg);

  var fighter = battleState.own.activeMember;
  var opponent = battleState.opponent.activeMember;

  var attemptedMoves = [];

  if(opponent.effects.indexOf(effect.poison) === -1) {
    attemptedMoves.push(1);
  }

  if(opponent.effects.indexOf(effect.confusion) === -1) {
    attemptedMoves.push(0);
  }

  if(fighter.name === 'Squirtmander') {
    //sleep
    if(opponent.effects.indexOf(effect.sleep) === -1) {
      attemptedMoves.push(2);
    }
  }
  else {
    //heal
    if(fighter.hp <= 60) {
      attemptedMoves.push(2);
    }
  }

  console.log(useMove(attemptedMoves, battleState));
}

function bonusStats(arg) {
  var teamState = parseOwnState(arg);

  getData(function(data) {
    var result = '1:';

    if(data.round % 4 === 0) {
      result += '1:';
    }
    else {
      result += '2:';
    }
    if(teamState.members[2].baseSpeed + teamState.members[2].bonusSpeed > data.maxSpeed + (data.round / 2)) {
      result += '1';
    }
    else {
      result += '2';
    }
    console.log(result);
  });
}

var actions = {
  'T': teamData,
  'C': chooseActive,
  'A': battleAction,
  'B': bonusStats
};

var arg = process.argv[2];
actions[arg[0]](arg.substring(2));

Бежать с

node nodemon

PS извиняюсь перед nodemon .


Это перерастает в сценарий глобальной войны на стороне сервера: D

4

Горькие соперники - Ява

Команда «Трава / Огонь / Вода», которая любит это менять.

Greenosaur

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

Type: Grass
Attack:   80     Vine
Defense:  50     Punch
Speed:   100     Pain

Searizard

Пытается сокрушить врагов с низкой атакой. Ожоги и Огненные шары после этого.

Type: Fire
Attack:  100     Fireball
Defense:  50     Burn
Speed:    80     Sap

Blastshield

Использует Shield для усиления своей уже высокой защиты. Лечит при необходимости.

Type: Water
Attack:   80     Watergun
Defense: 100     Shield
Speed:    50     Heal

Код

Это также входит в состав контроллера. Это является конкурирующей команды, в отличие от DummyTeam. Команда, необходимая для players.conf:

java BitterRivals

public class BitterRivals {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You're not doing this right. Read the spec and try again.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "BitterRivals";
                out += "|Greenosaur:4:80:50:100:12:0:3";
                out += "|Searizard:2:100:50:80:6:7:14";
                out += "|Blastshield:3:80:100:50:9:11:1";
                break;
            case "B":
                out = "2:0:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];

                int pick = 0;
                switch(getField(them, TYPE, getActive(them))){
                    case 0:
                    case 1:
                    case 3:
                        pick = 0;
                        break;
                    case 2:
                        pick = 2;
                        break;
                    case 4:
                        pick = 1;
                        break;
                }

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = pick + "";
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int oType = getField(them, TYPE, getActive(them));
                switch(active){
                    case 0:         // Greenosaur
                        switch(oType){
                            case 0:
                            case 4:
                                out = "1";
                                break;
                            case 1:
                                out = "2";
                                break;
                            case 3:
                                out = "0";
                                break;
                            case 2:
                                if(isAlive(me, 2)){
                                    out = "12";
                                } else if(isAlive(me, 1)){
                                    out = "11";
                                } else {
                                    out = "1";
                                }
                                break;
                        }
                        break;
                    case 1:         // Searizard
                        if(oType == 3){
                            if(isAlive(me, 0)){
                                out = "10";
                                break;
                            } else if(isAlive(me, 2)){
                                out = "12";
                                break;
                            }
                            if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                out = "1";
                            } else if(getField(me, MOVE2, active) > 0){
                                out = "2";
                            } else {
                                out = "3";
                            }                           
                        } else {
                            if(getField(them, ATTACK, getActive(them)) < 80){
                                if(getEffectCount(them, DEFENSE_DOWN, getActive(them), false) < 1 && getField(me, MOVE2, active) > 0){
                                    out = "2";
                                    break;
                                } else if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                    out = "1";
                                    break;
                                }
                            }
                            out = "0";
                        }
                        break;
                    case 2:         // Blastshield
                        if(oType == 4){
                            if(isAlive(me, 1)){
                                out = "11";
                                break;
                            } else if(isAlive(me, 0)){
                                out = "10";
                                break;
                            }
                        }
                        if(getField(me, HP, active) < 50 && getField(me, MOVE2, active) > 0){
                            out = "2";
                        } else if(getEffectCount(me, DEFENSE_UP, active, true) < 3 && getField(me, MOVE1, active) > 0){
                            out = "1";
                        } else {
                            out = "0";
                        }
                        break;
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6; 
    final static int PTURNS =   7; 
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10; 
    final static int HA =       11; 
    final static int HD =       12; 
    final static int HS =       13; 

    final static int POISON =           1;
    final static int CONFUSION =        2;
    final static int BURN =             3;
    final static int SLEEP =            4;
    final static int ATTACK_UP =        6;
    final static int ATTACK_DOWN =      7;
    final static int DEFENSE_UP =       8;
    final static int DEFENSE_DOWN =     9;
    final static int SPEED_DOWN =       10;
}

4

Ошибка 310: слишком много перенаправлений - C ++

Высококвалифицированная и организованная команда, чтобы противостоять разрушительному действию яда

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


антидот(образ)

Type : Normal - atk:50 def:100 spd:80 - Poison/Burn/Heal

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


Zen(образ)

Type : Fire - atk:100 def:80 spd:50 - Poison/Vine/Heal

Zen - очень удивительный кодемон, который сочетает в себе все эффекты. Он предпочитает смотреть, как его враги борются и истощают его молчание.


Triforce(образ)

Type : Psychic - atk:88 def:60 spd:82 - Fireball/Watergun/Vine

Triforce - классический кодемон, всегда готовый к бою. Этот использует свою психическую силу, чтобы контролировать три элемента и наносить как можно больше урона.


Вы можете скачать команду здесь:

Linux:

http://dl.free.fr/iHYlmTOQ2

запустить с ./Error310TMR

Windows:

http://dl.free.fr/vCyjtqo2s

запустить с ./Error310TMR.exe

Код представляет собой законченный проект C ++. Я не знаю, как это опубликовать.

$ wc -l src/*
    165 src/BruteForce.cpp
     26 src/BruteForce.h
    349 src/Codemon.cpp
     77 src/Codemon.h
     21 src/Logger.cpp
     35 src/Logger.h
    105 src/NoTimeToExplain.cpp
     27 src/NoTimeToExplain.h
    240 src/Recoverator.cpp
     31 src/Recoverator.h
     26 src/StrManip.cpp
     16 src/StrManip.h
    303 src/Team.cpp
     68 src/Team.h
     88 src/TooManyRedirects.cpp
     24 src/TooManyRedirects.h
     87 src/Unrecoverable.cpp
     27 src/Unrecoverable.h
     59 src/enums.cpp
    119 src/enums.h
     68 src/main.cpp
   1961 total

Но это очень эффективно:

------- Final Results -------

176     Error310TMR
131     H3C
130     LittleKid
121     Nodemon
58      InsideYourHead
47      HardenedTrio
37      BitterRivals

2

Сказка

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

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

#!/bin/perl
use 5.20.0;
use strict;

use constant MINE => 0;
use constant THEIRS => 1;

$_ = $ARGV[0];

if(/^T/){
    say 'FairyTale|Fairy:1:89:90:51:3:4:13|Dragon:2:100:50:80:6:1:8|Assassin:0:70:60:100:0:1:10';

} elsif(/^C#(.*)/){
    my $state = readBattleState($1);
    if($state->[MINE]->{$state->[MINE]->{slot}}{hp}){
        say $state->[MINE]->{slot};
    } elsif($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp}){
        say (($state->[MINE]->{slot}+1)%3);
    } else {
        say (($state->[MINE]->{slot}+2)%3);
    }

} elsif(/^A#(.*)/){
    my $state = readBattleState($1);
    my @actives = (
        $state->[MINE]->{$state->[MINE]->{slot}},
        $state->[THEIRS]->{$state->[THEIRS]->{slot}}
    );
    if($state->[MINE]->{slot} == 0){
        if(!exists($actives[THEIRS]{effects}{4}) && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif(!exists($actives[THEIRS]{effects}{1}) && $actives[MINE]{pp}->[2]) {
            say 2;
        } elsif(!$actives[THEIRS]{type}) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 1){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 2){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif($actives[THEIRS]{type} == 1) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    }

} elsif(/^B#(.*)/){
    my $state = readTeam($1, 1);
    say '1:0:2';
}

sub readBattleState {
    local $_ = $_[0];
    if(/^(.*?)#(.*?)$/){
        my @teams;
        $teams[0] = readTeam($1, 1);
        $teams[1] = readTeam($2, 0);
        return \@teams;
    }
}

sub readTeam {
    my $isMine = $_[1];
    local $_ = $_[0];
    if(/.*?:(?<slot>.*?)\|(.*?)\|(.*?)\|(.*?)$/){
        my %team;
        $team{slot} = $1;
        $team{0} = $isMine ? readYourMember($2) : readTheirMember($2);
        $team{1} = $isMine ? readYourMember($3) : readTheirMember($3);
        $team{2} = $isMine ? readYourMember($4) : readTheirMember($4);
        return \%team;
    }
    return 0;
}

sub readYourMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?):(?<move0>.*?):(?<move1>.*?):(?<move2>.*?):(?<batk>.*?):(?<bdef>.*?):(?<bspd>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk}+$+{batk},
            def    => $+{def}+$+{bdef},
            spd    => $+{spd}+$+{bspd},
            type   => $+{type},
            pp     => [$+{move0}, $+{move1}, $+{move2}],
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
}

sub readTheirMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk},
            def    => $+{def},
            spd    => $+{spd},
            type   => $+{type},
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
    return 0;
}

sub readEffects {
    local $_ = $_[0];
    my @retval = /:([^:]*)/g;
    if(!@retval){
        @retval = (0);
    }
    return @retval;
}

Бежать с

perl fairytale.pl

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

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

Не забывайте, что когда кодемон отключается, его лечебные точки уменьшаются до 0 или меньше . Таким образом, if($state->[MINE]->{$state->[MINE]->{slot}}{hp})заявление не будет работать правильно без >0.
GholGoth21

Ах, да, это сделало бы это.
mezzoEmrys

0

Dummy Team - Java

(неконкурентный CW)

Это пустая команда для тренировок. Это все нормальные типы, которые случайным образом выбирают между ходами (Punch, Heal, Slow) каждый ход. Веселитесь с этим.

public class DummyTeam {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You need to run this from the tournament. Try to keep up.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String out = "";
        switch(sections[0]){
            // team data
            //      sends back all Normal types with minimum stats and Normal moves (randomized name suffixes to distinguish in tests)
            case "T":
                out = "DummyTeam";
                for(int i=0;i<3;i++)
                    out += "|Dummy"+((char)(Math.random()*26)+65) + i + ":0:50:50:50:0:1:2";
                break;
            // bonus points
            //      shoves them all in defense every time
            case "B":
                out = "1:1:1";
                break;
            // choose active
            //      picks last active if alive, otherwise loops to find first living member
            case "C":
                String[] team = sections[1].split("\\|");
                int current = Integer.parseInt(team[0].split(":")[1]);
                if(Integer.parseInt(team[current+1].split(":")[5]) > 0){
                    out = current + "";
                } else {
                    for(int i=1;i<team.length;i++){
                        if(Integer.parseInt(team[i].split(":")[5]) > 0){
                            out = (i - 1) + "";
                        }
                    }
                }               
                break;
            // choose action
            //      chooses a random move. does not check if it ran out of uses, so wastes turns quite often
            case "A":
                out = ((int)(Math.random()*3)) + "";
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }


}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.