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


55

Ваш доброзичливий сусід, доктор Дере, щойно подарував вам три магічні істоти під назвою Кодемон. У сусідньому місті Колордвілл є бойовий турнір. Ти найкращий, як ніхто ніколи не був?

Огляд

Це бойовий турнір. Кожен гравець контролює команду з трьох монстрів, а мета - вибити (вбити) іншу команду. Існує 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 статтю, але кожен Codémon має 100 HP, що не змінюються. Коли HP впаде до нуля, вони не можуть продовжувати боротьбу. HP поповнюється до 100 перед кожним боєм.

Рухи

Кожен монстр знає три бойові рухи. Вибрані три повинні бути чіткими, тому жодного Удар / Удар / Удар.

Є 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% шансів на те, що кожен ефект спрацює, крім «Зцілення», який завжди працює.

Для ефектів, що змінюють статистику монстра, ефекти можуть зберігатися . Наприклад, використання Слабкого двічі може знизити атаку опонента до 0,64 ефективності. Ефекти, які не змінюють статистику монстра (сон, спалювання тощо) , не стикуються .

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

Опік пошкоджує суперника на 10 к.с. в кінці кожного повороту, коли він активний . Отрута працює аналогічно, але щомісяця збільшує кількість. На першому кроці - 5, і він набирає 5 поворотів після цього. Таким чином, до четвертої черги це буде збитковим для 20. Це плоскі збитки, на які не впливає тип монстра або не нараховуються бонуси.

Плутанина може змусити нападу монстра самостійно замість того, щоб робити те, про що йому сказали. Ця атака має потужність 10 і має 30% шансів на те, що це станеться за певний поворот.

Щоб було зрозуміло, ефекти тривають до кінця бою (крім сну, як зазначено вище).

Рухи також отримують 20-відсотковий приріст потужності, якщо їх використовує монстр відповідного типу. Наприклад, монстр Трави, що використовує Vine, підсилюється, тоді як з використанням Punch він не є.

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

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

Зокрема, після кожні два бої ви отримуватимете один "бонусний" статистичний бал за кожного монстра вашої команди. Очки видаються всім монстрам, загиблим чи живим, переможцю чи програвшему. Ви можете призначити це будь-якій із трьох вибраних статистичних даних. Ви не можете скласти їх на одного монстра; кожен монстр отримує один раз. Ці пункти не застраховані від межі 100. Оскільки буде 100 бойових раундів, це означає, що ви можете отримати єдину статистику до 149, якщо ви виділите всі свої бонуси. Знову ж таки, опонент побачить лише вашу "базову" статистику, тому чим далі ви знаходитесь на турнірі, тим далі їх знання знаходяться в стороні від правди.

Битва

Бій ведеться між трьома командами, по одна активна в кожній команді одночасно. На початку вам покажуть команду суперника і попросять вибрати, який монстр буде вашим першим «активним» гравцем.

Після цього повороти відбуваються з наступними кроками:

  • Перемикач: відбуваються обов'язкові перемикачі монстрів (якщо такі є)
  • Виберіть бойові дії
  • Перемикач: Будь-які необов'язкові перемикачі монстрів (вибрані як бойові дії) мають місце
  • Перевірка сну: шанс прокинутися зі сну
  • Атака 1: Якщо можливо, швидше монстр використовує вибраний хід
  • Атака 2: Якщо можливо, інший монстр використовує вибраний хід
  • Пошкодження наслідками: нанесіть шкоду опіку / отруту живим монстрам

"Швидше" означає монстра з більшою швидкістю. Якщо обидві статистичні показники швидкості однакові, її вибирають монети PRNG, що перевертають кожен виток.

Наприкінці будь-якого повороту, де помирає ваш активний монстр, вам запропонують вибрати нового активного. Ви також можете переключити активних монстрів як ваш рух на будь-який хід (за умови, що у вас більше одного живого). Знову ж таки, якщо ви переключитесь як ваш хід, ви не зробите бойовий хід, що повернеться.

Монстри не «обробляються», коли неактивні. Це означає , що вони не приймають ніяких пошкоджень Опік / отруту, лічильники отрута не буде накопичуватися, що не неспання від сну і т.д. ефекту не будуть видалені або змінені при перемиканні . Це не та інша гра з монстрами. Якщо ви вимкнетесь із атакою, піднятою та спаленою, вони все одно будуть там, коли ви повернетесь назад.

Пошкодження від ефекту відбувається, вбиваєте ви активного опонента чи ні. Таким чином члени обох команд можуть загинути на одному кроці.

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

Формула для визначення шкоди:

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

effAttackі effDefenseє ефективною статистикою для монстрів. Ефективна атака отримується додаванням Attack та Bonus Attack, а потім множенням (на 0,8 або 1,25), якщо якісь ефекти змінюють її. Пам'ятайте, що ці ефекти можуть укладатися.

Пошкодження може становити 0 лише тоді, коли модифікатор типу 0 (Нормальний <--> Психічний) або Потужність ходу 0 (Зцілення, Опік тощо). Інакше мінімум застосовується в 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

Їх учасникдерж:

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

Просто киньте всі складені файли класу, подання та player.conf у папку та запустіть.

Основний клас контролера називається Tournament. Використання:

java Tournament [LOG_LEVEL]

Рівні журналів від 0-4 дають все більшу інформацію. Рівень 0 проводить турнір мовчки і просто дає результати, де рівень 3 дає коментарі покроково. Рівень 4 - вихід налагодження.

Ви можете додати подання на турнір players.confпросто: Додайте рядок командного рядка, необхідний для запуску програми, по одному на рядок. Рядки, що починаються з - #це коментарі.

У свою посаду включіть команду, яку мені потрібно буде додати до свого players.conf, та будь-які етапи компіляції (якщо потрібно).

В комплект входить фіктивна команда, що складається з усіх нормальних членів з трьома нормальними рухами. Вони вибирають ходи випадковим чином і мають жахливу статистику. Весело б’ючи їх.

Різні правила

  • Ви не можете читати чи записувати будь-які зовнішні ресурси (крім своєї власної підпапки, до 32 кБ, як зазначено вище).

  • Вашій команді потрібно вийти на турнір "сліпими". Це означає, що ви не можете проаналізувати джерело інших людей, щоб зрозуміти, що конкретна команда / монстр буде робити в тій чи іншій ситуації. Ви можете проаналізувати ходи / статистику опонента та відслідковувати, як турнір прогресує, але жодного жорсткого кодування цієї інформації немає.

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

  • Учасники конкурсу обмежені максимум двома записами. Якщо ви подасте більше, я наберу лише перші два подані. Якщо ви хочете відкликати його, видаліть його.

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

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

  • Турнір відбудеться на моєму комп’ютері під керуванням Ubuntu з процесором Intel i7 3770K.

Результати

Це результати нинішніх гравців. Це дуже близько між найкращими претендентами, і я думаю про збільшення кількості раундів до 500 (і коригування інтервалу бонусних очок відповідно до). Будь-які заперечення, коментарі?

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

158     Happy3Campers
157     LittleKid
71      InsideYourHead
68      HardenedTrio
46      BitterRivals

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


62
Я хочу бути найкращим / Як ніколи не було коду / Не руйнуватись - це мій тест / Налагодження - це моя справа! / Я буду подорожувати локальною мережею / Сценарій далеко і впоперек / Намагаюсь зрозуміти / Чому мій BIOS смажився! / Кодемон, це ти і я / Гольф усе бачить / Кодемон, ти мій найкращий друг / Після закінчення програми! / Кодемон, язик так правдивий / Ніякі segfaults не потягнуть нас / Ви навчите мене, і я навчу вас / Codémon, gotta golf em all!
Каз Вулф

1
Замість того, щоб збільшити раунди до 500, було б непогано, якби один раунд складався з усіх, хто бився з усіма. Тому більше не буде byeдля нерівномірної кількості конкурентів, і було б впевнено, що пари матчів будуть справедливими та рівномірними.
foobar

@foobar Я хотів цього уникнути, оскільки n^2замість цього він масштабує битви n. Що стосується нинішніх 7 конкурентів і 100 раундів, це 2100 боїв (проти 300 як є, так і 1500 з 500 раундів). Це стає тільки гірше, коли надходить більше записів. Я міг би зменшити кількість раундів, але я вагаюся зробити це через властиву йому мінливості (щодо статусів esp), а кратне число 50 (для бонусних очок) простіше.
Геобіт

Чи цей виклик не потребує оновлення? :)
GholGoth21

@ GholGoth21 Так, я вірю, що так і є. Я, мабуть, не можу дістатися до цього сьогодні, але, можливо, завтра чи наступного дня. Пінг мені в чаті, якщо він не оновлюється до четверга чи так, якщо ви хочете.
Геобіт

Відповіді:


16

Щасливі 3 відпочиваючих - PHP

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

EDIT : Містер Лумпі був жорстоко покараний і більше не скаже поганих слів


ЗручноЗручноGrass - atk:50 def:99 spd:81 Confuse Poison Heal

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


ЛегкийЛегкийWater - 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

Завдяки майже двоцифровому IQ та феноменальній пам’яті, Lumpy може здогадатися про ворожі кроки. Ну, переважно.


Стратегія

Стратегія полягає в тому, щоб противники отруїлися, спалили і заплуталися якомога швидше.
Сон не використовувався, оскільки він здавався менш потужним, ніж 3 заклинання вище.
Плутанина в довгостроковій перспективі смертельна, оскільки зменшує напади на 30% (як нанесення шкоди, так і заклинання), заважає цілителю вилікувати себе і завдати шкоди важким ударам (монстр 50 деф / 100 атк нанесе 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. Ось в чому проблема зі складними правилами: велика ймовірність виникнення домінуючої стратегії. Оскільки від цих заклинань немає захисту, вони можуть бути товстуном та маленьким хлопчиком.

Я порівняв би це більше з неперехідною грою, як ножиці, папір, скеля - оскільки ефекти потребують певного часу, команда з повним нападом повинна мати змогу збити вас :)
Sp3000

2
Так, це я уявив, як тільки не бачу жодного засобу для отрути та опіку. Дякую, що втілила мою мрію в життя.
justhalf

1
Ось містер Лумпі висловлює свою головоломку, коли виявляє понад 3 різних атаки від одного і того ж противника :). У мене фіксована версія майже повна, але я зараз посеред якоїсь іншої речі, тому виправлення буде розміщено через день або близько того.

7

Загартований Тріо, Пітон 3

Оскільки Геобіт був досить приємний, щоб дати нам два подання, я подумав, що я надішлю щось нерозумно для першого: P

У партії є три Codemon (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. Це повертає істину, якщо він має статус статусу? І він використовує загартовування лише в тому випадку, якщо у нього є два наслідки на стан?
Mooing Duck

@MooingDuck Для вашого Codemon ви отримали moveCounts до effectidс, так що це перевірка , чи може він по- , як і раніше використовувати Харден. Я лінувався розбиратись, саме тому він забився туди.
Sp3000

@ Sp3000: О! Правильно! ХАХАХА!
Mooing Duck

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

Nodémon - Javascript

Оскільки статус, як видається, є домінуючою стратегією, ця команда зосереджується на швидкості, щоб спершу отримати такі статуси, як отрута та плутанина, а потім перестає зцілюватися та / або спати, поки опонент відпадає.

У мене не встановлено PHP, тому це не перевірено на Campers, але, здається, це є гідним конкурентом для LittleKid у моїх випробуваннях (і знижує гіркі сутички).

/*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 Вибачте нодемон .


Це

4

Гіркі сутички - Java

Команда з трави / вогню / води, яка любить перемикати її.

Greenosaur

Має принаймні нейтральне покриття для будь-кого. Висока швидкість, щоб компенсувати відсутність оборони.

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

Searizard

Намагається Сап ворогів з низькою атакою. Опіки та вогняні кулі після цього.

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

Доменний щит

Використовує Щит для підвищення його і без того високої оборони. Заживає при необхідності.

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

Антидот любить отруту. Настільки, що я не можу перешкодити йому кинутися на напади отрути.


Дзен(зображення)

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

Дзен - дуже дивовижний кодемон, який вміщує всі ефекти. Він вважає за краще спостерігати за тим, як вороги прагнуть і виснажуються проти його мовчання.


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

Цього бота виганяють за те, що він намагався "вибрати активних" мертвих членів після першої смерті. Він ніколи не проходить перший бій, який я можу побачити.
Геобіт

Дійсно? Я думав, що раніше отримав помилку, можливо, це старіша версія цього коду ...
mezzoEmrys

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

Ага, так, це зробить це.
mezzoEmrys

0

Команда пустушок - Java

(неконкуруючий CW)

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

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.