КОТ: Воюющие города


22

Окончательные результаты здесь!

Введение

Взятие игры сильно вдохновлено игрой Manu's Town . Это происходит в мире мечей и магии. Король, который управлял всем континентом, только что умер, и теперь правители многих городов-государств сражаются за территорию. Вы один из этих лордов, и ваша цель - завоевать и управлять каждым городом.

Принцип

Люди делятся на 8 классов :

Warlocks : Fighter (magic)
Crusaders : Fighter (melee)
Amazons : Fighter (range)
Corsairs : Utility (steal, guard, transport)
Bishops : Utility (convert, exorcize)
Necromancers : Utility (resurrect)
Architects : Utility (build)
Peons : Resource (income, recruits)

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

Затем начинается настоящая игра, которая пошаговая. Ход состоит из 12 фаз , 7 из которых являются интерактивными (запрос ботов для команды). Следующая фаза начинается, когда предыдущая фаза была выполнена каждым городом (Фаза 1: Город 1, Город 2, Город 3 ...; Этап 2: Город 1, Город 2, Город 3 ...):

1. Raise Taxes                              - AUTOMATED 
2. Steal Money                              - INTERACTIVE
3. Recruit Troops                           - INTERACTIVE
4. Pay Wages                                - AUTOMATED
5. Try Revolt                               - AUTOMATED
6. Convert Soldiers                         - INTERACTIVE
7. Attack Town                              - INTERACTIVE
8. Raise Corpses                            - INTERACTIVE
9. Move Army or Tribute                     - INTERACTIVE
10. Defend against Threats                  - AUTOMATED
11. Construct Buildings                     - INTERACTIVE
12. Make Children                           - AUTOMATED

Контроллер предоставляет вам ввод через аргументы команды, ваша программа должна выводить через stdout.

Синтаксис

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

Вам необходимо вывести: Warlocks Crusaders Amazons Corsairs Bishops Necromancers Architects Peons

Например: 15 10 12 10 7 5 1 40.

Каждый город также начинается с 500 золотых и 5 трупов.

Входные
данные Каждый раз , когда ваша программа называется, он будет получать аргументы в следующем формате:Round;Phase;YourPlayerId;YourTownId;PlayerId_TownId_Gold_Corpses_Warlocks_Crusaders_Amazons_Corsairs_Bishops_Necromances_Architects_Peons_Temples_Barracks_Estates_Palaces;PlayerId_TownId_Gold_Corpses_Warlocks_Crusaders_Amazons_Corsairs_Bishops_Necromances_Architects_Peons_Temples_Barracks_Estates_Palaces;...

Пример ввода 1;2;1;1;0_0_600_5_15_10_12_10_7_5_1_40_0_0_0_0;1_1_700_5_15_10_12_10_7_5_1_40_0_1_0_2;...

Здесь вы видите, что это 1-й раунд, 2-й этап, вы являетесь игроком 1 в городе 1. У вас есть 700 золотых, 5 трупов, 15 колдунов, 10 крестоносцев, 12 амазонок, 10 корсаров, 7 епископов, 5 некромантов, 1 архитектор, 40 пеонов, 0 храмов, 1 казарма, 0 поместий и 2 дворца.

Выход

Смотрите геймплей.

Игровой процесс

Все фазы

Команда W = ПОДОЖДИТЕ

Неверная команда = ПОДОЖДИТЕ

Этап 1: повышение налогов

Доход генерируется в зависимости от вашего населения и ваших завершенных зданий:

+5 gold * Peons
+2 gold * (Warlocks + Bishops + Necromancers) * TEMPLES
+2 gold * (Crusaders + Amazons) * BARRACKS
+2 gold * (Corsairs + Peons) * ESTATES
+10 gold * PALACES

Этап 2: украсть деньги

На этом этапе вы можете украсть деньги из одного города, отправив корсары. Каждый Корсар может украсть до 10 золотых (т.е. 12 Корсаров могут украсть до 120 золотых). Если у целевого города недостаточно золота, ваши корсары украдут все, вплоть до максимальной суммы долга: 200 золота . Если вы попытаетесь отправить больше корсаров, чем у вас, программа будет использовать все ваши доступные корсары.

Синтаксис команды :S DestinationId Corsairs

Этап 3: набор войск

Здесь вы можете тренировать своих людей, потратив немного золота. Вы можете набирать столько юнитов, сколько захотите, при условии, что у вас есть достаточно пионов и золота. Если вы попытаетесь набрать больше, чем можете, игра будет набираться случайным образом, пока все не будет потрачено. Программа учитывает ваши максимальные квоты (если вы попытаетесь набрать 10 крестоносцев и 5 амазонок только с 8 пионами, она, например, наберет 6 крестоносцев и 2 амазонки, а не 8 амазонок или 8 чернокнижников).

Warlock :       10 gold
Crusader :      10 gold
Amazon :        10 gold
Corsair :       12 gold 
Bishop :        20 gold
Necromancer :   20 gold
Architect :     15 gold

Синтаксис команды :R Warlocks Crusaders Amazons Corsairs Bishops Necromancers Architects

Этап 4: Заработная плата

Заработная плата списывается в зависимости от вашего населения:

-1 gold * (Warlock + Crusaders + Amazons)
-2 gold * (Corsairs + Bishops + Necromancers + Architects)

Фаза 5: Попробуйте Восстание

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

Этап 6: конвертировать солдат

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

Синтаксис команды :C DestinationId Warlocks Crusaders Amazons

Фаза 7: Город атаки

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

Солдаты получают 1,5 боевых бонуса по этой схеме: Mage > Range > Melee > Mage(т.е. Чернокнижник, сражающийся с Амазонкой, получает 1,5 силы). Только избыточные единицы получают этот бонус (т.е. Чернокнижник сражается с Чернокнижником, а Амазонка не получает этот бонус). Бонус относится как к атаке, так и к защите.

Убытки распределяются случайным образом между отрядами победителя в соответствии с меньшей общей мощью (т.е. сила атаки: 12 против силы защиты: 14, защита побеждает и проигрывает 12 единиц). Проигравший теряет все свои юниты. Каждая мертвая единица добавляется к количеству трупов атакованного города. Если преступление побеждает, город захватывается и теперь принадлежит атакующему. Он также хранит золото, трупы и пионы, которые были в этом городе. Корсары, епископы, некроманты и архитекторы бегут перед потенциальным притеснением.

Защита ничего не получает.

Синтаксис команды :A DestinationId Warlocks Crusaders Amazons

Этап 8: Поднять трупы

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

Синтаксис команды :R Corpses

Фаза 9: Переместить армию или дань

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

Синтаксис команды :M DestinationId Warlocks Crusaders Amazons Corsairs Bishops Necromancers Architects

Или вы можете отправить золото, заказав корабли Корсаров. Каждый корсар может перевозить до 200 золотых . Если вы попытаетесь отправить больше, чем имеете, программа отправит то, что у вас есть.

Синтаксис команды :T DestinationId Gold

Этап 10: защита от угроз

Несколько угроз угрожают нанести вред вашему городу:

  • Зомби: мертвые не всегда такие мертвые, как выглядят. 10% (испорченных) трупов в вашем городе проснутся и съедят мозги. Каждый зомби съест 1 пеона, а затем отправится в небытие (трупы как зомби, так и съеденных пионов потребляются).
  • Демоны: Ваши пионы должны слышать проповеди, иначе они начнут призывать Темных Духов. Каждый ваш епископ покрывает потребности до 50 пеонов. 10% (испорченных) ваших еретиков (Peons в избытке) будут порождать демонов. Демоны убивают 1 Пиона каждый и возвращаются в ад (трупы Пионов добавляются в счет города).
  • Бандиты: По соседству живут преступники. Общая численность преступников делится на равные части между городами и направляется на кражу богатства. Ваша единственная защита - ваши патрули Корсаров. Каждый корсар может остановить до 5 преступников. Каждый незаконный преступник крадет 10 золотых из вашего города (максимальный долг города составляет 200 золотых)

По крайней мере, 1 город Outlaws (100 жителей) генерируется в начале игры, затем еще 1 на каждые 5 игроков (т.е. 1-4 игрока: 1 Outlaws, 5-9 Players: 2 Outlaws ...). Преступники могут быть признаны сid = -1

Этап 11: Построить здание

По достижении этого этапа строительство зданий в вашем городе продвигается в соответствии с количеством архитекторов. Каждый Архитектор увеличивает завершение одного здания на 8%. Когда здание достигает 100%, оно завершается и начинает генерировать доходы в следующей фазе «Налоги». Очередь строительства управляется автоматически (первым пришел, первым обслужен).

Затем вы можете также начать строительство других зданий (BuildingId = Letter в скобках):

TEMPLE (T) :        200 Gold
BARRACKS (B) :      200 Gold
ESTATE (E) :        200 Gold
PALACE (P) :        500 Gold

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

Синтаксис команды :B BuildingId BuildingId BuildingId ...

Этап 12: сделать детей

Каждые пять раундов (раунд 5, 10, 15 ...), новые Peons будут рождаться и готовы к бою. Каждая пара Пионов будет приносить 1 Пион (т.е. 23 Пиона генерируют 11 новых Пионов).

правила

  • Боты не должны быть написаны, чтобы побеждать или поддерживать определенных других ботов.
  • Запись в файлы разрешена. Пожалуйста, напишите «yoursubmissionname.txt», папка будет очищена перед началом игры. Другие внешние ресурсы запрещены.
  • Ваше представление имеет 1 секунду, чтобы ответить (в каждом городе).
  • Предоставьте команды для компиляции и запуска ваших представлений.

выигрыш

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

контроллер

Вы можете найти контроллер на GitHub. Он также содержит 2 примера ботов, написанных на Java. Откройте его в Eclipse, поместите скомпилированные боты в корневую папку и добавьте класс в управляющую программу (так же, как в примере с ботами).

Поединки

Формула боя выглядит примерно так:

Для каждого класса солдат (Чернокнижник, Крестоносец, Амазонка):

  • Рассчитайте баланс между нападением и защитой (т.е. у кого больше каждого класса и сколько еще?)
  • Для лишних солдат (т. Е. Значения положительного баланса) посмотрите, сколько «слабых целей» (см. Диаграмму Фазы 7).
  • Умножьте боевую силу подходящих солдат (т.е. «слабых целей» по сравнению с «лишними солдатами») на бонус и добавьте остальных с боевой силой 1.

Вы можете попробовать симулятор здесь: http://ideone.com/ArJosE (просто измените значения солдат, вы получите бонусы и общие силы)

Вот несколько тестовых случаев:

Attack      Defense     A. Bonus    D. Bonus   A. Str      D. Str    Winner
20/10/0     12/12/12    8/0/0       0/2/10     34.0        42.0      Defense
40/0/5      12/12/12    12/0/0      0/12/0     51.0        42.0      Attack
0/60/8      10/30/2     0/10/6      8/0/0      76.0        46.0      Attack
20/20/40    90/5/5      0/15/5      40/0/0     90.0        120.0     Defense

Окончательные результаты

В среднем 10 игр. Синтаксис:Player(Towns, Population, Gold)

1. Opportunist(6.4, 4165, 2895626)
2. Politician(6.4, 1048, 42542)
3. Outlaw(2.8, 1575, 349073)
4. YoungEarl(0.4, 3424, 941624)
5. Aegis(0, 0, 0)
 . Butter(0, 0, 0)
 . Commander(0, 0, 0)
 . Lannister(0, 0, 0)
 . Machiaveli(0, 0, 0)
 . Monarch(0, 0, 0)
 . Serenity(0, 0, 0)
 . Sehtimianer(0, 0, 0)
 . Sleeper(0, 0, 0)
 . Zealots(0, 0, 0)

Результаты 10 игр: http://pastebin.com/GdufEYjm

Полные журналы 2 игр: http://pastebin.com/GQDZ0JdY & http://pastebin.com/m3UBTDuC

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


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

The total Outlaws population is divided equitably between towns and sent to steal wealth.Сколько всего бандитов?
MegaTom

@MegaTorn В начале, есть один город Outlaws для 5 игроков (минимум 1) и 100 человек внутри каждого из них. Затем, по ходу игры, вне закона могут появляться восстания или быть убитыми другими игроками.
Thrax

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

Когда город попадает в фазу 5, могут ли другие города-игроки захватить этот город? Если да, то сохраняются ли типы населения? То есть: если у них было 20/20/40 бойцов в чернокнижниках, крестоносцах, амазонках, это то, что вам нужно, чтобы сражаться, чтобы захватить этот город?
Логика Найт

Ответы:


8

Оппортунист, Java v2

Он пытается использовать возможности, когда они представляют себя ... но если никто не представит себя (и он все еще в споре) в конце игры, то он изо всех сил.

UDPATE:

Включены некоторые идеи durron597. Теперь перестает набирать епископов, когда в состоянии полностью преобразовать силу самого сильного противника, и вместо этого сосредотачивается на покупке солдат.

Также у v1 был начальный гандикап, когда начальный разброс населения не составлял 100 ... только 98!

package moogiesoft;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

public class Opportunist  {

private static final float FIGHTING_BONUS = 1.5f;
public static final int GOLD_PER_PEON = 5;
public static final int GOLD_PER_TEMPLE = 2;
public static final int GOLD_PER_BARRACKS = 2;
public static final int GOLD_PER_ESTATE = 2;
public static final int GOLD_PER_PALACE = 10;
private static final int CONVERSION_COST = 50;
private static final int GOLD_PER_STEAL = 10;
private static final int GOLD_MAX_DEBT = 200;
private static final int CORSAIR_COST = 12;
private static final int BISHOP_COST = 20;
private static final int ARCHITECT_COST = 15;
private static final int BARRACKS_COST = 200;
private static final int MILITARY_COST = 10;

int round;
int phase;
int playerID;
int thisTownID;


List<Town> towns;
List<Town> myTowns;
List<Town> otherTowns;
List<Town> otherNonOutlawTowns;
List<Town> otherOutlawTowns;

Town thisTown;

public static void main(String[] args){
    if (args.length == 0) {
        System.out.println("8 8 9 22 8 0 13 32");
    } else {
        new Opportunist().respond(args[0].split(";"));
    }
}

private void respond(String[] args) {

    round = Integer.parseInt(args[0]);
    phase = Integer.parseInt(args[1]);
    playerID = Integer.parseInt(args[2]);
    thisTownID = Integer.parseInt(args[3]);

    towns = new ArrayList<>();
    myTowns = new ArrayList<>();
    otherTowns = new ArrayList<>();
    otherNonOutlawTowns= new ArrayList<>();
    otherOutlawTowns= new ArrayList<>();

    for (int i = 4; i < args.length; i++){
        towns.add(new Town(args[i]));
    }

    for (Town town : towns){
        if (town.isMine()){
            myTowns.add(town);
            if (town.isThisTown()){
                thisTown = town;
            }
        } else {
            otherTowns.add(town);
            if (town.getOwnerId()!=-1)
            {
                otherNonOutlawTowns.add(town);
            }
            else
            {
                otherOutlawTowns.add(town);
            }
        }
    }


    switch (phase)
    {
        case 2: steal(); break;
        case 3: recruit(); break;
        case 6: convert(); break;
        case 7: attack(); break;
        case 8: resurrect(); break;
        case 9: move(); break;
        case 11: build(); break;
        default: System.out.println("W"); break;
    }
}

private void steal() {
    ArrayList<Town> architectSoldierSortedNonOutlawTowns = new ArrayList<>(otherNonOutlawTowns);
    architectSoldierSortedNonOutlawTowns.sort((a,b)->b.getArchitects()-a.getArchitects()==0?a.getSoldiers()-b.getSoldiers():b.getArchitects()-a.getArchitects());
    Town targetTown =null;
    int targetTownStolenGold = 0;

    // Try to steal from the towns that have the most architects as they are the long term threat.
    for (Town town : architectSoldierSortedNonOutlawTowns)
    {
        if (estimateProceedsOfTheft(town,thisTown)>thisTown.calculateTaxes())
        {
              targetTown=town;
              break;
        }
    }

    // see if we can cause revolution in any non outlaw towns or if the target proceeds of theft is not sufficent to support this town...
    if (targetTown==null || estimateProceedsOfTheft(targetTown,thisTown)+thisTown.calculateTaxes()<thisTown.calculateSalary()*2)
    {
        for (Town town : otherNonOutlawTowns)
        {

            if (town.getGold()-town.calculateSalary()-thisTown.getCorsairs()*GOLD_PER_STEAL<0)
            {
               int stolenGold = estimateProceedsOfTheft(town,thisTown);
               if (stolenGold>targetTownStolenGold)
               {
                   targetTownStolenGold=stolenGold;
                   targetTown=town;
               }
            }

        }
    }

    // just pick the strongest opponent
    if (targetTown==null && round<5)
    {
        targetTown = otherNonOutlawTowns.stream().max((a,b) -> a.getSoldiers() - b.getSoldiers()).orElse(null);
    }

    // or if the target proceeds of theft is not sufficent to support this town... select the non outlaw town with the most gold!
    if (targetTown==null || estimateProceedsOfTheft(targetTown,thisTown)+thisTown.calculateTaxes()<thisTown.calculateSalary()*2)
    {
        targetTown = otherNonOutlawTowns.stream().max((a,b) -> a.gold - b.gold).orElse(null);
    }

    // otherwise just pick the outlaw town with the most gold.
    if (targetTown==null)
    {
        targetTown = otherTowns.stream().max((a,b) -> a.gold - b.gold).orElse(null);
    }

    System.out.println("S " + targetTown.getId() + " " + thisTown.getCorsairs());

}

private void recruit() {
    Town strongestTown=otherTowns.stream().max((a,b)->a.getSoldiers()-b.getSoldiers()).orElse(null);
    Town mostRepoductiveTown=otherTowns.stream().max((a,b)->a.getPeons()-b.getPeons()).orElse(null);

    int originalNoOfPeonsAvailableToConvert = 0;
    boolean recruitSoldiers=true;
    // last round... no point in keeping any peons... make them soldiers. 
    if (round==100)
    {
        originalNoOfPeonsAvailableToConvert = thisTown.getPeons();
    }
    // looks like our bishops can recruit the full force of the strongest enemy... so lets just recruit soldiers.
    else if (strongestTown!=null && strongestTown.getSoldiers()<thisTown.getBishops())
    {
        originalNoOfPeonsAvailableToConvert = thisTown.getPeons()-mostRepoductiveTown.getPeons();
    }
    // ok so we need more bishops...
    else if (round>5)
    {
        recruitSoldiers=false;
        originalNoOfPeonsAvailableToConvert = thisTown.getPeons()/10;
    }

    int amazonRecruit = 0;
    int crusaderRecruit = 0;
    int warlockRecruit = 0;
    int bishopRecruit = 0;
    int corsairRecruit = 0;
    int architectRecruit = 0;

    while (originalNoOfPeonsAvailableToConvert>0)
    {
        int noOfPeonsAvailableToConvert=originalNoOfPeonsAvailableToConvert;
        int recruitsLeft;
        do
        {
            recruitsLeft=noOfPeonsAvailableToConvert;

            if (recruitSoldiers)
            {
                if (noOfPeonsAvailableToConvert-->0) amazonRecruit++;
                if (noOfPeonsAvailableToConvert-->0) crusaderRecruit++;
                if (noOfPeonsAvailableToConvert-->0) warlockRecruit++;
            }
            // see if we want to recruit more bishops...
            else if (thisTown.getBishops()<(round<30?Math.pow(2,round/4):thisTown.getPeons()-50))
            {
               if (noOfPeonsAvailableToConvert-->0) bishopRecruit++;
            }
        } while (noOfPeonsAvailableToConvert>0 && noOfPeonsAvailableToConvert!=recruitsLeft);

        noOfPeonsAvailableToConvert = noOfPeonsAvailableToConvert<0?0:noOfPeonsAvailableToConvert;
        Town simulatedTown = new Town(thisTown);
        simulatedTown.setPeons(thisTown.getPeons()-(originalNoOfPeonsAvailableToConvert-noOfPeonsAvailableToConvert));
        simulatedTown.setAmazons(simulatedTown.getAmazons()+amazonRecruit);
        simulatedTown.setCrusaders(simulatedTown.getCrusaders()+crusaderRecruit);
        simulatedTown.setWarlocks(simulatedTown.getWarlocks()+warlockRecruit);
        simulatedTown.setBishops(simulatedTown.getWarlocks()+bishopRecruit);
        simulatedTown.setCorsairs(simulatedTown.getWarlocks()+corsairRecruit);
        simulatedTown.setArchitects(simulatedTown.getWarlocks()+architectRecruit);
        simulatedTown.setGold(simulatedTown.getGold()-amazonRecruit*MILITARY_COST
                                                     -crusaderRecruit*MILITARY_COST
                                                     -warlockRecruit*MILITARY_COST
                                                     -bishopRecruit*BISHOP_COST
                                                     -corsairRecruit*CORSAIR_COST
                                                     -architectRecruit*ARCHITECT_COST
                                                     -BARRACKS_COST // aways have enough to build a building!
                                                     );

        // ensure that we can afford (both now and in the future) to recruit this number of bishops...
        if (estimateProceedsOfTheft(thisTown) + simulatedTown.calculateTaxes()-simulatedTown.calculateSalary()>0 && simulatedTown.getGold()>simulatedTown.calculateSalary())
            break;
        originalNoOfPeonsAvailableToConvert--;
    }

    System.out.println("R " + warlockRecruit + " " + crusaderRecruit + " " + amazonRecruit + " " + corsairRecruit + " " + bishopRecruit + " 0 " + architectRecruit);
}

private void convert() {
    int currentGold = thisTown.getGold();
    int futureTaxGeneration = thisTown.calculateTaxes();
    int futureSalaryCost = thisTown.calculateSalary();
    int futureProceedsOfCrime = estimateProceedsOfTheft(thisTown);
    int futureCashFlow = futureTaxGeneration+futureProceedsOfCrime-futureSalaryCost;
    int goldAvailableToSpend = currentGold-=BARRACKS_COST;

    if (goldAvailableToSpend>CONVERSION_COST && futureCashFlow>0)
    {
        Town strongestTown = null;

        // sort towns by architects and then soldiers...
        ArrayList<Town> architectSoldierSortedNonOutlawTowns = new ArrayList<>(otherNonOutlawTowns);
        architectSoldierSortedNonOutlawTowns.sort((a,b)->b.getArchitects()-a.getArchitects()==0?a.getSoldiers()-b.getSoldiers():b.getArchitects()-a.getArchitects());
        for (Town town :architectSoldierSortedNonOutlawTowns)
        {
            // if we could use all our bishops...then we shall target this town...
            if (town.getSoldiers()-thisTown.getBishops()>0)
            {
                strongestTown =town;
                break;
            }
        }

        // no town targeted... select the town with the most soldiers then.
        if (strongestTown == null)
        {
            strongestTown = findStrongestTownThatCanDefeatGivenTown(thisTown);
        }

        if (strongestTown == null)
        {
            // this town is already surpreme! lets see if we can be fivolous and attempt to convert anyway...
            if (thisTown.getGold()>thisTown.calculateSalary()*2)
            {
                strongestTown=otherNonOutlawTowns.stream().max((a,b)->a.getSoldiers()-b.getSoldiers()).orElse(null);
            }
        }

        // no town targeted... select the town with the most soldiers then.
        if (strongestTown == null)
        {
            strongestTown=otherTowns.stream().max((a,b)->a.getSoldiers()-b.getSoldiers()).orElse(null);
        }

        // we have selected a town... try to convert from it...
        if (strongestTown != null)
        {
            Town simulatedThisTown = new Town(thisTown);
            int amazonConversionCount=0;
            int warlockConversionCount=0;
            int crusaderConversionCount=0;

            // iterate until we are unable to pay for conversion or unable to support converted forces
            while(true)
            {
                futureTaxGeneration = simulatedThisTown.calculateTaxes();
                futureSalaryCost = simulatedThisTown.calculateSalary();
                futureCashFlow = futureTaxGeneration+futureProceedsOfCrime-futureSalaryCost;

                goldAvailableToSpend-=CONVERSION_COST;

                // see if we can afford to convert another military unit or have run out of bishops to use...
                if (amazonConversionCount+warlockConversionCount+crusaderConversionCount==thisTown.getBishops() || goldAvailableToSpend < 0 || futureCashFlow<0) break;

                // convert a amazon... if any...
                if (strongestTown.getAmazons()>0)
                {
                    amazonConversionCount++;
                    simulatedThisTown.setAmazons(simulatedThisTown.getAmazons()+1);
                    strongestTown.setAmazons(strongestTown.getAmazons()-1);
                }
                // convert a crusader... if any...
                else if (strongestTown.getCrusaders()>0)
                {
                    crusaderConversionCount++;
                    simulatedThisTown.setCrusaders(simulatedThisTown.getCrusaders()+1);
                    strongestTown.setCrusaders(strongestTown.getCrusaders()-1);
                }
                // convert a warlock... if any...
                else if (strongestTown.getWarlocks()>0)
                {
                    warlockConversionCount++;
                    simulatedThisTown.setWarlocks(simulatedThisTown.getWarlocks()+1);
                    strongestTown.setWarlocks(strongestTown.getWarlocks()-1);
                }
                // no more units to convert from the targeted town...
                else
                {
                    break;
                }

            }

            System.out.println("C " + strongestTown.getId() + " " + warlockConversionCount + " " + crusaderConversionCount + " " + amazonConversionCount);
            return;
        }
    }
    System.out.println("W");
}

private void attack() {

    // nearing end game.. lets just attack every thing blindly :P
    if (round>=99)
    {
        for (Town town : towns)
        {
            if (!town.isMine())
            {
                Town simulatedThisTown = new Town(thisTown);
                Town simulatedOtherTown = new Town(town);

                // attempt to attack the opponent with all our soldiers.
                if (battle(simulatedThisTown,simulatedOtherTown,thisTown.getWarlocks(),thisTown.getCrusaders(),thisTown.getAmazons()))
                {
                    System.out.println("A "+ town.getId()+ " " + thisTown.getWarlocks()+ " " + thisTown.getCrusaders()+ " " + thisTown.getAmazons() );
                    return;
                }
            }
        }
    }

    // we should be in a good position... lets try to take over strongest opponent...
    if (round>32)
    {
        Town strongestTown = otherTowns.stream().max((a,b)->a.getSoldiers()-b.getSoldiers()).orElse(null);
        Town simulatedThisTown = new Town(thisTown);
        Town simulatedStrongestTown = new Town(strongestTown);

        int warlockRegiment = thisTown.getWarlocks();
        int crusaderRegiment = thisTown.getCrusaders();
        int amazonRegiment = thisTown.getAmazons();

        List<Town> remainderNonOutLawTowns = new ArrayList<Town>(otherNonOutlawTowns);
        remainderNonOutLawTowns.remove(strongestTown);

        Town nextStrongestTown = remainderNonOutLawTowns.stream().max((a,b)->a.getSoldiers()-b.getSoldiers()).orElse(null);
        boolean firstLoop=true;

        // attempt to attack the strongest opponent with the least number of soldiers possible and still be in a position to likely not succumb to the next strongest opponent.
        while (nextStrongestTown!=null && warlockRegiment+crusaderRegiment+amazonRegiment>0 && battle(simulatedThisTown,simulatedStrongestTown,warlockRegiment,crusaderRegiment,amazonRegiment))
        {

            Town simulatedThisTownAfterWinning = new Town(simulatedThisTown);
            Town simulatedNextStrongestTown = new Town(nextStrongestTown);

            if (nextStrongestTown==null ||
                battle(simulatedNextStrongestTown,simulatedThisTownAfterWinning,
                       simulatedNextStrongestTown.getWarlocks()*2/3,
                       simulatedNextStrongestTown.getCrusaders()*2/3,
                       simulatedNextStrongestTown.getAmazons()*2/3))
            {
                if (firstLoop) break;
                System.out.println("A "+ strongestTown.getId()+ " " + warlockRegiment+ " " + crusaderRegiment+ " " + amazonRegiment );
                return;
            }
            firstLoop=false;
            warlockRegiment-=warlockRegiment>0?1:0;
            crusaderRegiment-=crusaderRegiment>0?1:0;
            amazonRegiment-=amazonRegiment>0?1:0;

            simulatedThisTown = new Town(thisTown);
            simulatedStrongestTown = new Town(strongestTown);
        }

        // it looks like we are in a power deadlock with one other town... lets see if going all out will make us the victor....
        if (otherNonOutlawTowns.size()==1)
        {
            simulatedThisTown = new Town(thisTown);
            Town simulatedRemainingTown = new Town(otherNonOutlawTowns.get(0));

            if (battle(simulatedThisTown,simulatedRemainingTown,thisTown.getWarlocks(),thisTown.getCrusaders(),thisTown.getAmazons()))
            {
                System.out.println("A "+ simulatedRemainingTown.getId()+ " " + thisTown.getWarlocks()+ " " + thisTown.getCrusaders()+ " " + thisTown.getAmazons() );
                return;
            }
        }
    }

    System.out.println("W");
}

private void move() {

    // give half our funds to the most needy town...
    List<Town> poorMyTowns = myTowns.stream().filter(a->a.calculateTaxes()-a.calculateSalary()<0).collect(Collectors.toList());
    if (poorMyTowns.size()>0)
    {
        Town poorTown = poorMyTowns.get(new Random().nextInt(poorMyTowns.size()));

        if (poorTown.getId() != thisTownID)
        {
            System.out.println("T "+poorTown.getId()+ " "+ thisTown.getGold()/2);
            return;
        }
    }

    System.out.println("W");

}

private void resurrect() {
    // zombie shmozies!
    System.out.println("W");
}

private void build() {
    // endevour to always build a barracks or estate (which ever is more lucrative)
    int currentGold = thisTown.getGold();
    int futureTaxGeneration = thisTown.calculateTaxes();
    int futureSalaryCost = thisTown.calculateSalary();
    int futureProceedsOfCrime = estimateProceedsOfTheft(thisTown);
    int futureCashFlow = futureTaxGeneration+futureProceedsOfCrime-futureSalaryCost;
    int goldAvailableToSpend = currentGold;

    if (goldAvailableToSpend>BARRACKS_COST && futureCashFlow>0)
    {
        if (thisTown.getAmazons()+thisTown.getCrusaders()>thisTown.getCorsairs()+thisTown.getPeons())
        {
            System.out.println("B B");
            return;
        }
        else
        {
            System.out.println("B E");
            return;
        }
    }
    System.out.println("W");
}

private class Town  {

    private int ownerId =-1;
    private int id = -1;
    private int gold;
    private int corpses;
    private int warlocks;
    private int crusaders;
    private int amazons;
    private int corsairs;
    private int bishops;
    private int necromancers;
    private int architects;
    private int peons;
    private int temples;
    private int barracks;
    private int estates;
    private int palaces;

    public Town(String string){
        String[] args = string.split("_");
        ownerId = Integer.parseInt(args[0]);
        id = Integer.parseInt(args[1]);
        gold = Integer.parseInt(args[2]);
        corpses = Integer.parseInt(args[3]);
        warlocks = Integer.parseInt(args[4]);
        crusaders = Integer.parseInt(args[5]);
        amazons = Integer.parseInt(args[6]);
        corsairs = Integer.parseInt(args[7]);
        bishops = Integer.parseInt(args[8]);
        necromancers = Integer.parseInt(args[9]);
        architects = Integer.parseInt(args[10]);
        peons = Integer.parseInt(args[11]);
        temples = Integer.parseInt(args[12]);
        barracks = Integer.parseInt(args[13]);
        estates = Integer.parseInt(args[14]);
        palaces = Integer.parseInt(args[15]);
    }

    //Copy constructor
    public Town(Town source)
    {
        this.ownerId=source.ownerId;
        this.id=source.id;
        this.gold=source.gold;
        this.corpses=source.corpses;
        this.warlocks=source.warlocks;
        this.crusaders=source.crusaders;
        this.amazons=source.amazons;
        this.corsairs=source.corsairs;
        this.bishops=source.bishops;
        this.necromancers=source.necromancers;
        this.architects=source.architects;
        this.peons=source.peons;
        this.temples = source.temples;
        this.barracks = source.barracks;
        this.estates = source.estates;
        this.palaces = source.palaces;

    }

    public void setOwnerId(int ownerId)
    {
        this.ownerId = ownerId;
    }

    public void setGold(int gold)
    {
        this.gold = gold;
    }

    public void setCorpses(int corpses)
    {
        this.corpses = corpses;
    }

    public void setWarlocks(int warlocks)
    {
        this.warlocks = warlocks;
    }

    public void setCrusaders(int crusaders)
    {
        this.crusaders = crusaders;
    }

    public void setAmazons(int amazons)
    {
        this.amazons = amazons;
    }

    public void setCorsairs(int corsairs)
    {
        this.corsairs = corsairs;
    }

    public void setBishops(int bishops)
    {
        this.bishops = bishops;
    }

    public void setNecromancers(int necromancers)
    {
        this.necromancers = necromancers;
    }

    public void setArchitects(int architects)
    {
        this.architects = architects;
    }

    public void setPeons(int peons)
    {
        this.peons = peons;
    }

    public int getTemples()
    {
        return temples;
    }

    public int getBarracks()
    {
        return barracks;
    }

    public int getEstates()
    {
        return estates;
    }

    public int getPalaces()
    {
        return palaces;
    }

    public int getOwnerId() {
        return ownerId;
    }

    public int getId() {
        return id;
    }

    public int getGold() {
        return gold;
    }

    public int getCorpses() {
        return corpses;
    }

    public int getWarlocks() {
        return warlocks;
    }

    public int getCrusaders() {
        return crusaders;
    }

    public int getAmazons() {
        return amazons;
    }

    public int getCorsairs() {
        return corsairs;
    }

    public int getBishops() {
        return bishops;
    }

    public int getNecromancers() {
        return necromancers;
    }

    public int getArchitects() {
        return architects;
    }

    public int getPeons() {
        return peons;
    }

    public int getSoldiers() {
        return getWarlocks() + getCrusaders() + getAmazons();
    }

    public boolean isMine(){
        return getOwnerId() == playerID;
    }

    public boolean isThisTown(){
        return id == thisTownID;
    }

    public int calculateSalary()
    {
        return (getWarlocks() + getCrusaders() + getAmazons()) + 2*(getCorsairs()+getBishops()+ getArchitects()+ getNecromancers());
    }

 // algorithm taken from Game.java
    public int calculateTaxes()
    {
        int taxes = 0;
        taxes += (getPeons() * GOLD_PER_PEON);
        taxes += ((getWarlocks() + getBishops() + getNecromancers()) * (getTemples() * GOLD_PER_TEMPLE));
        taxes += ((getCrusaders() + getAmazons()) * (getBarracks() * GOLD_PER_BARRACKS));
        taxes += ((getPeons() + getCorsairs()) * (getEstates() * GOLD_PER_ESTATE));
        taxes += (getPalaces() * GOLD_PER_PALACE);
        return  taxes; 
    }

}

// algorithm taken from Game.java
private boolean battle(Town attackingTown, Town defendingTown, int attackingWarlocks, int attackingCrusaders, int attackingAmazons)
{
    int sourceWarlocks = Math.min(attackingTown.getWarlocks(), Math.max(0, attackingWarlocks));
    int sourceCrusaders = Math.min(attackingTown.getCrusaders(), Math.max(0, attackingCrusaders));
    int sourceAmazons = Math.min(attackingTown.getAmazons(), Math.max(0, attackingAmazons));

    int destinationWarlocks = defendingTown.getWarlocks();
    int destinationCrusaders = defendingTown.getCrusaders();
    int destinationAmazons = defendingTown.getAmazons();

    int sourceWarlocksBalance = Math.max(0, sourceWarlocks - destinationWarlocks);
    int sourceWarlocksBonus = Math.min(sourceWarlocksBalance, destinationAmazons);
    float sourceWarlocksStrength = (sourceWarlocks - sourceWarlocksBonus + (sourceWarlocksBonus * FIGHTING_BONUS));
    int sourceCrusadersBalance = Math.max(0, sourceCrusaders - destinationCrusaders);
    int sourceCrusadersBonus = Math.min(sourceCrusadersBalance, destinationWarlocks);
    float sourceCrusadersStrength = (sourceCrusaders - sourceCrusadersBonus + (sourceCrusadersBonus * FIGHTING_BONUS));
    int sourceAmazonsBalance = Math.max(0, sourceAmazons - destinationAmazons);
    int sourceAmazonsBonus = Math.min(sourceAmazonsBalance, destinationCrusaders);
    float sourceAmazonsStrength = (sourceAmazons - sourceAmazonsBonus + (sourceAmazonsBonus * FIGHTING_BONUS));
    float sourceTotalStrength = sourceWarlocksStrength + sourceCrusadersStrength + sourceAmazonsStrength;

    int destinationWarlocksBalance = Math.max(0, destinationWarlocks - sourceWarlocks);
    int destinationWarlocksBonus = Math.min(destinationWarlocksBalance, sourceAmazons);
    float destinationWarlocksStrength = (destinationWarlocks - destinationWarlocksBonus + (destinationWarlocksBonus * FIGHTING_BONUS));
    int destinationCrusadersBalance = Math.max(0, destinationCrusaders - sourceCrusaders);
    int destinationCrusadersBonus = Math.min(destinationCrusadersBalance, sourceWarlocks);
    float destinationCrusadersStrength = (destinationCrusaders - destinationCrusadersBonus + (destinationCrusadersBonus * FIGHTING_BONUS));
    int destinationAmazonsBalance = Math.max(0, destinationAmazons - sourceAmazons);
    int destinationAmazonsBonus = Math.min(destinationAmazonsBalance, sourceCrusaders);
    float destinationAmazonsStrength = (destinationAmazons - destinationAmazonsBonus + (destinationAmazonsBonus * FIGHTING_BONUS));
    float destinationTotalStrength = destinationWarlocksStrength + destinationCrusadersStrength + destinationAmazonsStrength;


    if (sourceTotalStrength > destinationTotalStrength) {

        RandomNumberGenerator rand = new RandomNumberGenerator();
        int[] limits = new int[3];
        limits[0] = sourceWarlocks;
        limits[1] = sourceCrusaders;
        limits[2] = sourceAmazons;
        int[] losses = rand.genNumberWithLimits((int) Math.ceil(destinationTotalStrength), limits);

        attackingTown.setWarlocks(attackingTown.getWarlocks() - sourceWarlocks);
        attackingTown.setCrusaders(attackingTown.getCrusaders() - sourceCrusaders);
        attackingTown.setAmazons(attackingTown.getAmazons() - sourceAmazons);

        defendingTown.setWarlocks(sourceWarlocks - losses[0]);
        defendingTown.setCrusaders(sourceCrusaders - losses[1]);
        defendingTown.setAmazons(sourceAmazons - losses[2]);
        defendingTown.setCorsairs(0);
        defendingTown.setBishops(0);
        defendingTown.setNecromancers(0);
        defendingTown.setArchitects(0);

        defendingTown.setCorpses(defendingTown.getCorpses() + destinationWarlocks + destinationCrusaders + destinationAmazons + losses[0] + losses[1] + losses[2]);
        defendingTown.setOwnerId(attackingTown.getOwnerId());
        return true;
    } else if (sourceTotalStrength <= destinationTotalStrength) {

        RandomNumberGenerator rand = new RandomNumberGenerator();
        int[] limits = new int[3];
        limits[0] = destinationWarlocks;
        limits[1] = destinationCrusaders;
        limits[2] = destinationAmazons;
        int[] losses = rand.genNumberWithLimits((int) Math.ceil(sourceTotalStrength), limits);

        attackingTown.setWarlocks(attackingTown.getWarlocks() - sourceWarlocks);
        attackingTown.setCrusaders(attackingTown.getCrusaders() - sourceCrusaders);
        attackingTown.setAmazons(attackingTown.getAmazons() - sourceAmazons);

        defendingTown.setWarlocks(destinationWarlocks - losses[0]);
        defendingTown.setCrusaders(destinationCrusaders - losses[1]);
        defendingTown.setAmazons(destinationAmazons - losses[2]);

        defendingTown.setCorpses(defendingTown.getCorpses() + sourceWarlocks + sourceCrusaders + sourceAmazons + losses[0] + losses[1] + losses[2]);
    }
    return false;

}

/**
 * Taken from Game.java
 *
 * Generate N random numbers when their SUM is known
 *
 * @author Deepak Azad
 */

public class RandomNumberGenerator  {

    public int[] genNumbers(int n, int sum){
        int[] nums = new int[n];
        int upperbound = Long.valueOf(Math.round(sum*1.0/n)).intValue();
        int offset = Long.valueOf(Math.round(0.5*upperbound)).intValue();

        int cursum = 0;
        Random random = new Random(new Random().nextInt());
        for(int i=0 ; i < n ; i++){
            int rand = random.nextInt(upperbound) + offset;
            if( cursum + rand > sum || i == n - 1) {
                rand = sum - cursum;
            }
            cursum += rand;
            nums[i]=rand;
            if(cursum == sum){
                break;
            }
        }
        return nums;
    }

    public int[] genNumberWithLimits(int sum, int[] limits) {

        int n = limits.length;
        int[] nums = new int[n];
        int total = 0;

        for (int l : limits) {
            total += l;
        }

        if (total <= sum)
            return limits;

        Random random = new Random(new Random().nextInt());
        while (sum > 0) { 
            int x = random.nextInt(n);
            if (nums[x] < limits[x]) {
                nums[x] += 1;
                sum--;
            }
        }
        return nums;
    }
}

// algorithm taken from Game.java
private int estimateProceedsOfTheft(Town theivingTown)
{
    int bestTownToTheiveProceedsAmount = -1;
    for (Town town : towns)
    {
        int goldStolen = estimateProceedsOfTheft(town,theivingTown);

        if (goldStolen > bestTownToTheiveProceedsAmount)
        {
            bestTownToTheiveProceedsAmount=goldStolen;
        }             
    }
    return bestTownToTheiveProceedsAmount;
}

// algorithm taken from Game.java
private int estimateProceedsOfTheft(Town victimTown,Town theivingTown)
{
    int goldStolen = 0;

    if (victimTown.getOwnerId()!= theivingTown.getOwnerId())
    {
        int goldReserve = victimTown.getGold() + GOLD_MAX_DEBT > 0 ? victimTown.getGold() + GOLD_MAX_DEBT : GOLD_MAX_DEBT - Math.abs(victimTown.getGold());
        int goldToSteal = theivingTown.getCorsairs() * GOLD_PER_STEAL;
        goldStolen = Math.min(goldReserve, goldToSteal);
    }

    return goldStolen;
}

// exactly as the method name states :)
private Town findStrongestTownThatCanDefeatGivenTown(Town defendingTown)
{
    int strongestSurvivingForce=-1;
    Town strongestTown=null;
    for (Town town : towns)
    {
        if (town.getOwnerId()!=defendingTown.getOwnerId() && town.getOwnerId()!=-1)
        {
            Town simulatedThisTown = new Town(defendingTown);
            Town simulatedOtherTown = new Town(town);

            // check to see if the other town could defeat this town
            if (battle(simulatedOtherTown,simulatedThisTown,simulatedOtherTown.getWarlocks(), simulatedOtherTown.getCrusaders(), simulatedOtherTown.getAmazons()))
            {
                //and if so, if it is the most overwhelming win, then that town is the target of conversion.
                int survivingForce=simulatedOtherTown.getAmazons()+simulatedOtherTown.getCrusaders()+simulatedOtherTown.getWarlocks()+
                                simulatedThisTown.getAmazons()+simulatedThisTown.getCrusaders()+simulatedThisTown.getWarlocks();
                if (survivingForce>strongestSurvivingForce)
                {
                    strongestSurvivingForce=survivingForce;
                    strongestTown = town;
                }
            }
        }
    }
    return strongestTown;
}
}

Для запуска: 1. Поместите в каталог moogiesoft 2. В родительском каталоге: java moogiesoft.Opportunist


Вот Это Да! Это очень хорошо!
TheNumberOne

Это, конечно, замечательно, но я думаю, что вы могли бы немного улучшить его: 1. Прекратить покупать епископов, если у вас больше епископов, чем у всех вместе взятых войск, 2. Атаковать города вне закона до хода 100, если они не защищены и других ботов нет. Должен сделать ваш окончательный счет намного выше.
durron597

Спасибо, это хорошие предложения. Я постараюсь включить их :)
Moogie

Отлично, стратегия Оппортуниста была действительно интересной!
Thrax

@ Thrax спасибо за вызов! Судя по моим экспериментам, случай повлиял на то, насколько хорошо играет оппортунист. Его легко можно затопить в начале раундов ближнего боя. Обычно фанат.
Муги

8

Эгида, Ява

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

import java.util.ArrayList;
import java.util.List;

public class Aegis {

    int round;
    int phase;
    int playerID;
    int thisTownID;

    final int PEONS_PER_BISHOPS = 50;
    final int GOLD_STOLEN_PER_CORSAIR = 10;
    final int AVERAGE_COST_PER_UNIT = 2;
    final int GOLD_SAFETY = 100;
    final int PEONS_SAFETY = 20;
    final int COST_CORSAIR = 12;
    final int COST_SOLDIER = 10;
    final int COST_ESTATE = 200;
    final int MAX_CORSAIRS = 30;

    List<Town> towns;
    List<Town> myTowns;
    List<Town> otherTowns;

    Town thisTown;

    public static void main(String[] args){
        if (args.length == 0) {
            System.out.println("10 10 10 10 1 1 3 55");
        } else {
            new Aegis().protect(args[0].split(";"));
        }
    }

    private void protect(String[] args) {

        round = Integer.parseInt(args[0]);
        phase = Integer.parseInt(args[1]);
        playerID = Integer.parseInt(args[2]);
        thisTownID = Integer.parseInt(args[3]);

        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();

        for (int i = 4; i < args.length; i++){
            towns.add(new Town(args[i]));
        }

        for (Town town : towns){
            if (town.isMine()){
                myTowns.add(town);
                if (town.isThisTown()){
                    thisTown = town;
                }
            } else {
                otherTowns.add(town);
            }
        }

        switch (phase) {
        case 2: steal(); break;
        case 3: recruit(); break;
        case 6: convert(); break;
        case 7: attack(); break;
        case 8: move(); break;
        case 9: resurrect(); break;
        case 11: build(); break;
        }
    }

    private void steal() {
        Town richestTown = otherTowns.stream().max((a,b) -> a.gold - b.gold).get();
        System.out.println("S " + richestTown.getId() + " " + thisTown.getCorsairs());
    }

    private void recruit() {
        Town richestTown = otherTowns.stream().max((a,b) -> a.gold - b.gold).get();
        Town soldierTown = otherTowns.stream().max((a,b) -> (a.amazons + a.warlocks + a.crusaders) - (b.amazons + b.warlocks + b.crusaders)).get();
        int requiredBishops = Math.max(0, Math.floorDiv(thisTown.getPeons(), PEONS_PER_BISHOPS) - thisTown.getBishops());
        int requiredNecromancers = Math.max(0, 1 - thisTown.getNecromancers());
        int requiredArchitects = Math.max(0, 5 - thisTown.getArchitects());
        int requiredCorsairs = Math.max(0, Math.min(MAX_CORSAIRS - thisTown.getCorsairs(), Math.floorDiv(richestTown.getGold(), GOLD_STOLEN_PER_CORSAIR)));
        int goldAvailable = thisTown.getGold() - (AVERAGE_COST_PER_UNIT * thisTown.getUnits()) - GOLD_SAFETY;
        int peonsAvailable = Math.max(0, thisTown.getPeons() - PEONS_SAFETY);
        int recruitedCorsairs = 0;
        int[] recruits = new int[3];
        int i = 0;
        while (peonsAvailable >= 5 && goldAvailable >= 50 && recruitedCorsairs < requiredCorsairs) {
            recruitedCorsairs++;
            peonsAvailable--;
            goldAvailable-=COST_CORSAIR;
        }
        while (peonsAvailable >= 5 && goldAvailable >= 50) {
            if (soldierTown.getSoldiers() > thisTown.getSoldiers()) {
                i = (i >= recruits.length - 1 ? 0 : i+1);
                recruits[i]++;
                peonsAvailable--;
                goldAvailable-=COST_SOLDIER;
            } else {
                break;
            }
        }
        if (recruits[0] + recruits[1] + recruits[2] + recruitedCorsairs + requiredBishops + requiredNecromancers + requiredArchitects > 0) {
            System.out.println("R " + recruits[0] + " " + recruits[1] + " " + recruits[2] + " " + recruitedCorsairs + " " + requiredBishops + " " +  requiredNecromancers + " " + requiredArchitects);
        } else {
            System.out.println("W");
        }
    }

    private void convert() { 
        System.out.print("W");
    }

    private void attack() {
        if (this.countOtherPlayers() <= 1) {
            Town richestTown = otherTowns.stream().max((a,b) -> a.getGold() - b.getGold()).get();
            int neededWarlocks =  thisTown.getWarlocks() - richestTown.getWarlocks();
            int neededCrusaders = thisTown.getCrusaders() - richestTown.getCrusaders();
            int neededAmazons = thisTown.getAmazons() - richestTown.getAmazons() ;

            if (neededWarlocks > 0 && neededCrusaders > 0 && neededAmazons > 0) {
                System.out.println("A " + richestTown.getId() + " " + (richestTown.getWarlocks() + 1) + " " + (richestTown.getCrusaders() + 1) + " " + (richestTown.getAmazons() + 1));  
            } else {
                System.out.println("W");
            }
        } else {
            System.out.println("W");
        }
    }

    private void move() {
        for (Town town : myTowns) {
            int goldBalance = town.getGold() - (AVERAGE_COST_PER_UNIT * thisTown.getUnits()) + GOLD_SAFETY;
            if (goldBalance <= 0) {
                System.out.println("T " + town.getId() + " " + (-goldBalance + GOLD_SAFETY));
                break;
            }
        }
        System.out.println("W");
    }

    private void resurrect() {
        if (thisTown.getCorpses() > 0) {
            int corpses = Math.min(5, thisTown.getCorpses());
            System.out.print("R " + corpses);
        } else {
            System.out.print("W");
        }
    }

    private void build() {
        int goldAvailable = thisTown.getGold() - (AVERAGE_COST_PER_UNIT * thisTown.getUnits()) - GOLD_SAFETY;
        if (goldAvailable >= (COST_ESTATE + 50)) {
            System.out.println("B E");
        } else {
            System.out.println("W");
        }
    }

    public int countOtherPlayers() {
        List<Integer>players = new ArrayList<>();
        for (Town town : otherTowns) {
            if (!players.contains(town.getOwnerId()) && town.getOwnerId() >= 0) players.add(town.getOwnerId());
        }
        return players.size();
    }

    private class Town {

        private final int ownerId;
        private final int id;
        private final int gold;
        private final int corpses;
        private final int warlocks;
        private final int crusaders;
        private final int amazons;
        private final int corsairs;
        private final int bishops;
        private final int necromancers;
        private final int architects;
        private final int peons;
        private final int temples;
        private final int barracks;
        private final int estates;
        private final int palaces;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            gold = Integer.parseInt(args[2]);
            corpses = Integer.parseInt(args[3]);
            warlocks = Integer.parseInt(args[4]);
            crusaders = Integer.parseInt(args[5]);
            amazons = Integer.parseInt(args[6]);
            corsairs = Integer.parseInt(args[7]);
            bishops = Integer.parseInt(args[8]);
            necromancers = Integer.parseInt(args[9]);
            architects = Integer.parseInt(args[10]);
            peons = Integer.parseInt(args[11]);
            String[] args2 = args[12].split("-");
            temples = Integer.parseInt(args2[0]);
            barracks = Integer.parseInt(args2[1]);
            estates = Integer.parseInt(args2[2]);
            palaces = Integer.parseInt(args2[3]);
        }
        public int getOwnerId() {
            return ownerId;
        }
        public int getId() {
            return id;
        }
        public int getGold() {
            return gold;
        }
        public int getCorpses() {
            return corpses;
        }
        public int getWarlocks() {
            return warlocks;
        }
        public int getCrusaders() {
            return crusaders;
        }
        public int getAmazons() {
            return amazons;
        }
        public int getCorsairs() {
            return corsairs;
        }
        public int getBishops() {
            return bishops;
        }
        public int getNecromancers() {
            return necromancers;
        }
        public int getArchitects() {
            return architects;
        }
        public int getPeons() {
            return peons;
        }
        public int getTemples() {
            return temples;
        }
        public int getBarracks() {
            return barracks;
        }
        public int getEstates() {
            return estates;
        }
        public int getPalaces() {
            return palaces;
        }
        public int getBuildings() {
            return getTemples() + getBarracks() + getEstates() + getPalaces();
        }
        public int getSoldiers() {
            return getWarlocks() + getCrusaders() + getAmazons();
        }
        public int getUnits() {
             return getSoldiers() + getCorsairs() + getBishops() + getNecromancers() + getArchitects();
        }
        public int getCitizens() {
            return getUnits() + getPeons();
        }
        public boolean isMine(){
            return getOwnerId() == playerID;
        }
        public boolean isThisTown(){
            return id == thisTownID;
        }
    }

}

Компилировать с javac Aegis.java

Бежать с java Aegis


8

Молодой Граф, Питон 2

версия 3.1

Обновить:

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

import sys, re
from random import *
from operator import itemgetter

(PLAYER, TOWN, GOLD, CORPSES, WARLOCKS, CRUSADERS, AMAZONS, 
CORSAIRS, BISHOPS, NECROMANCERS, ARCHITECTS, PEONS, 
TEMPLES, BARRACKS, ESTATES, PALACES) = range(16)
OUTLAW = -1

def seqalloc(seq, num):
    outseq = []
    totalw = float(sum(seq))
    for weight in seq:
        share = int(round(num * weight / totalw)) if weight else 0
        outseq.append(share)
        totalw -= weight
        num -= share
    return outseq

def getstrength(t): return sum(t[WARLOCKS:AMAZONS+1])
def calcprofit(t): return t[GOLD] + 20*t[PEONS] + 200*t[ESTATES]
def getincome(t): return 5*t[PEONS] + 2*(t[PEONS]+t[CORSAIRS])*t[ESTATES]

if len(sys.argv) < 2:
    print 5,20,5,   12,4,1,13,   40
else:
    try:
        output = 'W'

        parts = sys.argv[1].split(';')
        turn, phase, me, thistown = [int(parts.pop(0)) for i in range(4)]
        # Catagorize towns:
        towns = [map(int, re.split(r'_', town)) for town in parts]
        outlaws = [t for t in towns if t[PLAYER] == OUTLAW]
        mytowns = [t for t in towns if t[PLAYER] == me]
        enemy = [t for t in towns if t[PLAYER] not in (me, OUTLAW)]
        # Situation:
        here = [t for t in mytowns if t[TOWN] == thistown][0]
        strength = sorted(enemy, key=getstrength)
        strengthoutlaw = sorted(outlaws, key=getstrength)
        profenemy = sorted(enemy, key=calcprofit)
        profoutlaw = sorted(outlaws, key=calcprofit)
        rich = outlaws + sorted(enemy, key=itemgetter(GOLD))
        bandits = sum(sum(t[4:12]) for t in outlaws)
        # Planning:
        siblings = [t for t in mytowns if t != here]
        bodytowns = [t for t in mytowns if t[CORPSES] > 0]
        myincome = getincome(here)
        isrich = all(t[GOLD] < here[GOLD]*1.5 for t in enemy)
        wages = getstrength(here) + sum(here[CORSAIRS:ARCHITECTS+1]) * 2
        newpeons = (turn % 5 == 1) if turn > 1 else 0
        theft = 10 * max(0, bandits/len(enemy+mytowns) - here[CORSAIRS]*5)

        if phase == 2:
            output = 'S %u %u' % (rich[-1][TOWN], here[CORSAIRS])

        elif phase == 3:
            cash = max(0, here[GOLD] - wages)
            if theft < myincome:
                if here[ARCHITECTS] and cash > 200:
                    cash -= 200
                cash = max(0, cash - 150)
            # must haves:
            cors = (bandits/len(mytowns+enemy)) / 5 + 1
            cors = cors if cors < 25 else 0
            bish = here[PEONS]/50 + 1
            necro = here[CORPSES]/20 + 1
            require = [cors, bish, necro, 0]
            need = [0]*3 + [max(0, p-q) for p,q in zip(require, here[7:11])]
            if sum(need)*22 < cash:
                train = need
            else:
                train = seqalloc(need, cash/22)
            now = [p+q for p,q in zip(here[4:11], train)]
            cash -= sum(p*q for p,q in zip(train[3:], [12,20,20,15]))
            cash -= sum(train)*2   # new wages
            # nice to have:
            raises = min(here[CORPSES]/4+1, now[5]*5, cash/20)
            cash -= raises * 20
            archreq = max(0, 13 - here[ARCHITECTS])
            if theft < myincome and archreq * 17 < cash:
                train[6] += archreq
                cash -= archreq * 17
                if cash > 200:
                    cash -= 200
            newbish = max(0, cash/50 - now[4])
            if newpeons:
                bishreq = (myincome - 200 - wages)/50 * 12/10
                newbish += max(0, bishreq - (now[4]+newbish))
            newbish = min(newbish, cash/22)
            train[4] += newbish
            cash -= newbish * 22

            if sum(train) > 0:
                output = 'R %u %u %u %u %u %u %u' % tuple(train)

        elif phase == 6:
            cash = here[GOLD]
            if theft < myincome:
                if here[ARCHITECTS] and cash > 200:
                    cash -= 200
                cash = max(0, cash - 150)
            raises = min(here[CORPSES]/4+1, here[NECROMANCERS]*5, cash/20)
            cash -= raises * 20
            count = min(cash/50, here[BISHOPS])
            if count > 0:
                target = (strengthoutlaw + strength)[-1]
                count = min(count, sum(target[4:7]))
                ftrs = seqalloc(target[4:7], count)
                output = 'C %u %u %u %u' % tuple([target[TOWN]] + ftrs)

        elif phase == 7:
            force = getstrength(here)
            target = None
            if not enemy or force > getstrength(strength[-1])*2:
                for town in profenemy[::-1]+profoutlaw[::-1]:
                    if force > getstrength(town)*4:
                        target = town
                        break
            if target:
                raiders = seqalloc(here[4:7], force/2)
                output = 'A %u %u %u %u' % tuple([target[TOWN]] + raiders)

        elif phase == 8:
            cash = here[GOLD]
            if theft < myincome:
                if here[ARCHITECTS] and cash > 200:
                    cash -= 200
                cash = max(0, cash - 150)
            raises = min(here[CORPSES]/4+1, here[NECROMANCERS]*5, cash/20)
            if raises > 0:
                output = 'R %s' % raises

        elif phase == 9:
            if here[CORPSES] == 0 and bodytowns:
                dest = max(bodytowns, key=itemgetter(CORPSES))
                necro = min(here[NECROMANCERS], dest[CORPSES]/20+1)
                output = 'M %u 0 0 0 0 0 %u 0' % (dest[TOWN], necro)
            elif siblings and theft < 100 and isrich:
                given = min(here[GOLD]/33, here[CORSAIRS]*200)
                dest = max(siblings, key=getincome)
                output = 'T %u %u' % (dest[TOWN], given)

        elif phase == 11:
            if here[ARCHITECTS] and here[GOLD] >= 200:
                output = 'B E'
    except:
        pass
    print output

Анализ производительности

В игровом конкурсе последний граф отлично справился. В 2 играх из 10 он сумел выиграть у городов-игроков, но затем застыл, когда пришло время побеждать города-бандиты. Я исправил эту ошибку - я никогда не думал, что он зайдет так далеко ;-). Оглядываясь назад, я должен был загрузить контроллер и проверить графа.

Поздравляем @Moogie и @TheBestOne с лучшими записями. Обидно, победить может только один. Они оба очень хороши.

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



Я побежу еще 3 игры с новым графом, чтобы увидеть результаты. Я также постоянно обновляю git, если вы хотите проверить его самостоятельно. (и я почти закончил работу над следующей KOTH, очень скоро ожидаю новую!)
Thrax

Вот результаты: 1. Outlaw(12, 6671, 2233682) 2. YoungEarl(3, 6346, 208215) 3. Politician(1, 96, 0)тогда 1. YoungEarl(16, 2514, 72315)и наконец 1. Politician(16, 1562, 53467). YoungEarl действительно делает чертовски хорошую работу.
Thrax

Спасибо, Тракс. Граф, похоже, уже освоился. Лучше поздно, чем никогда, а?
Рыцарь логики

Так как Moogie & TheBestOne все еще находятся в бегах, я постараюсь запустить 100 игр для другой награды. (Мне немного не хватает репутации, мне нужно как минимум вдвое больше того, что я уже потратил, т.е. 300 представителей)
Thrax

6

TheLannisters (Java)

Я выбираю это имя, потому что это представление чертовски богато. Также предложение TheLannisters gave birth to 30 childrenзвучит смешно: D

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

import java.util.ArrayList;
import java.util.List;

public class TheLannisters {
    private static final int COST_PER_SOLDIER = 11;
    private static final int COST_PER_CORSAIR = 14;
    private static final int COST_PER_BISHOP = 22;
    private static final int COST_PER_CONVERTION = 50;
    private final int MIN_PEONS;
    private final int phase;
    private final int myId;
    private final int round;
    private final List<Town> myTowns = new ArrayList<>();
    private final List<Town> enemyTowns = new ArrayList<>();
    private final List<Town> enemyPlayerTowns = new ArrayList<>();
    private final List<Town> outlawTowns = new ArrayList<>();
    private Town thisTown = null;

    public static void main(String[] args){
        if (args.length == 0) {
            System.out.println("12 14 10 11 3 5 5 40");
        } else {
            new TheLannisters(args[0].split(";")).command();
        }
    }

    public TheLannisters(String[] args) {
        round = Integer.parseInt(args[0]);
        phase = Integer.parseInt(args[1]);
        myId = Integer.parseInt(args[2]);
        MIN_PEONS = 40 + round/2;
        int thisTownId = Integer.parseInt(args[3]);

        boolean hasAlreadyCommanded = false;
        for (int i = 4; i < args.length; i++){
            Town town = new Town(args[i], hasAlreadyCommanded);
            if (town.isMine()){
                myTowns.add(town);
                if (town.id == thisTownId){
                    thisTown = town;
                    hasAlreadyCommanded = true;
                }
            } else {
                enemyTowns.add(town);
                if (town.isOutlawTown()) {
                    outlawTowns.add(town);
                } else {
                    enemyPlayerTowns.add(town);
                }
            }
        }
    }

    private void command() {
        switch (phase) {
            case 2: steal(); break;
            case 3: recruit(); break;
            case 6: convert(); break;
            case 7: attack(); break;
            case 8: resurrect(); break;
            case 9: move(); break;
            case 11: build(); break;
        }
    }

    private void steal() {
        int goldToSteal = thisTown.corsairs * 10;

        int mostSoldiers = -1;
        Town richestTown = null;
        for (Town town : enemyPlayerTowns) {
            if (town.getSoldiers() > mostSoldiers && town.gold >= goldToSteal) {
                richestTown = town;
                mostSoldiers = town.getSoldiers();
            }
        }
        if (richestTown != null) {
            printCommand("S " + richestTown.id + " " + thisTown.corsairs);
        }

        // player with most gold (could be an outlaw)
        int mostGold = -1;
        for (Town town : enemyTowns) {
            if (town.gold > mostGold) {
                richestTown = town;
                mostGold = town.gold;
            }
        }
        printCommand("S " + richestTown.id + " " + thisTown.corsairs);
    }

    private void recruit() {
        int freePeons = (thisTown.peons - MIN_PEONS);
        if (!thisTown.isWeak()) {
            freePeons /= 2;
        }
        int freeGold = thisTown.gold - thisTown.getSoldiers() - thisTown.getCitizens() * 2;

        if (freePeons <= 0 || freeGold < COST_PER_SOLDIER) {
            printCommand("W");
        }

        int bishops = 0;
        if ((thisTown.bishops * 50 < thisTown.peons || thisTown.gold > 500) && freeGold >= COST_PER_BISHOP) {
            bishops = 1;
            freeGold -= COST_PER_BISHOP;
            freePeons--;
        }

        int necromancers = 0;
        if (thisTown.necromancers == 0 && freeGold >= COST_PER_BISHOP) {
            necromancers = 1;
            freeGold -= COST_PER_BISHOP;
            freePeons--;
        }

        int corsairs = 0;
        if (thisTown.getsRobbed() && freeGold >= COST_PER_CORSAIR) {
            corsairs = 1;
            freeGold -= COST_PER_CORSAIR;
            freePeons--;
        }

        int architects = 0;
        if (thisTown.architects == 0 && freeGold > 500) {
            architects = 1;
            freeGold -= COST_PER_BISHOP;
            freePeons--;
        }

        int producableSoldiers = Math.min(freePeons, freeGold / COST_PER_SOLDIER);
        int soldierPerType = producableSoldiers / 3;
        int crusaders = soldierPerType + (producableSoldiers % 3);
        printCommand("R " + soldierPerType + " " + crusaders + " " + soldierPerType + " " + corsairs + " " + bishops + " " + necromancers + " " + architects);
    }

    private void convert() {
        int freeGold = 0;
        if (thisTown.isWeak() || thisTown.corpses <= 0) {
            freeGold = thisTown.gold - 300;
        }
        if (freeGold < COST_PER_CONVERTION || thisTown.bishops == 0 || (round < 2 && thisTown.getSoldiers() > 35)) {
            printCommand("W");
        }
        int soldiersToConvert = freeGold / COST_PER_CONVERTION;
        int soldiersPerType = soldiersToConvert / 3;
        int amazons = soldiersPerType + (soldiersToConvert % 3);

        Town destination = null;        
        int mostSoldiers = -1;
        if (destination == null) {
            for (Town town : enemyPlayerTowns) {
                if (town.getSoldiers() > mostSoldiers) {
                    destination = town;
                    mostSoldiers = town.getSoldiers();
                }
            }
        }
        if (destination == null) {
            destination = outlawTowns.get(0);
        }
        printCommand("C " + destination.id + " " + soldiersPerType + " " + soldiersPerType + " " + amazons);
    }

    private void attack() {
        int leastSoldiers = Integer.MAX_VALUE;
        Town destination = null;

        if (thisTown.isWeak() || round < 21) {
            printCommand("W");
        }

        for (Town town : enemyTowns) {
            if (town.getSoldiers() < leastSoldiers) {
                destination = town;
                leastSoldiers = town.getSoldiers();
            }
        }

        boolean attackTogether = false;
        for (Town town : myTowns) {
            if (!town.hasAlreadyCommanded && !town.isWeak() && !town.equals(thisTown)) {
                attackTogether = true;
            }
        }

        if (thisTown.getSoldiers() / 3.5 > destination.getSoldiers() || (attackTogether && thisTown.getSoldiers() / 2 >= destination.getSoldiers())) {
            int warlocks = thisTown.warlocks/2;
            int crusaders = thisTown.crusaders/2;
            int amazons = thisTown.amazons/2;
            while (warlocks + crusaders + amazons > (destination.getSoldiers() + 3) * 3) {
                warlocks = Math.max(0, --warlocks);
                crusaders = Math.max(0, --crusaders);
                amazons = Math.max(0, --amazons);
            }
            if (enemyPlayerTowns.size() == 0) {
                // dont send too many soldiers => otherwise they revolt
                printCommand("A " + destination.id + " " + (destination.warlocks + 2) + " " + (destination.crusaders + 2) + " " + (destination.amazons + 2));
            }
            printCommand("A " + destination.id + " " + warlocks + " " + crusaders + " " + amazons);
        } else {
            printCommand("W");
        }
    }

    private void resurrect() {
        printCommand("R 999");      
    }

    private void move() {
        if (myTowns.size() == 1 || thisTown.corpses > 10) {
            printCommand("W");
        }
        int leastGold = thisTown.gold;
        Town destination = null;
        for (Town town : myTowns) {
            if (town.gold < leastGold) {
                leastGold = town.gold;
                destination = town;
            }
        }
        if (destination != null && (thisTown.hasMostGold() || (thisTown.gold > 100 && destination.gold - destination.getSoldiers() - destination.getCitizens() * 2 < 300) || (thisTown.gold > 300 && destination.getsRobbed()))) {
            printCommand("T " + destination.id + " " + Math.max(thisTown.gold / 10, 30));
        }
        for (Town town : myTowns) {
            if (town.isWeak()) {
                printCommand("M " + town.id + " " + (thisTown.warlocks / 4) + " "  + (thisTown.crusaders / 4) + " "  + (thisTown.amazons / 4) + " 0 0 0 0");
            }
        }
        printCommand("W");
    }

    private void build() {
        if (thisTown.gold >= 500) {
            printCommand("B P");
        } else if (thisTown.gold > 300) {
            if (round % 2 == 0) {
                printCommand("B E");
            }
            printCommand("B B");    
        }
    }

    private class Town {

        private final int ownerId;
        private final int id;
        private final int gold;
        private final int corpses;
        private final int warlocks;
        private final int crusaders;
        private final int amazons;
        private final int corsairs;
        private final int bishops;
        private final int necromancers;
        private final int architects;
        private final int peons;
        private final boolean hasAlreadyCommanded;

        public Town(String string, boolean hasAlreadyCommanded){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            gold = Integer.parseInt(args[2]);
            corpses = Integer.parseInt(args[3]);
            warlocks = Integer.parseInt(args[4]);
            crusaders = Integer.parseInt(args[5]);
            amazons = Integer.parseInt(args[6]);
            corsairs = Integer.parseInt(args[7]);
            bishops = Integer.parseInt(args[8]);
            necromancers = Integer.parseInt(args[9]);
            architects = Integer.parseInt(args[10]);
            peons = Integer.parseInt(args[11]);
            this.hasAlreadyCommanded = hasAlreadyCommanded;
        }

        public int getSoldiers() {
            return warlocks + crusaders + amazons;
        }

        public int getCitizens() {
            return corsairs + bishops + necromancers + architects;
        }

        public boolean isMine(){
            return ownerId == myId;
        }

        public boolean isOutlawTown() {
            return ownerId == -1;
        }

        public boolean isWeak() {
            return willBeWeak(1);
        }

        public boolean willBeWeak(double divisor) {
            if (enemyPlayerTowns.size() == 0) {
                return false;
            }
            int mySoldiers = (int) (getSoldiers() * divisor);
            int weakerTowns = 0;
            for (Town town : enemyTowns) {
                if (town.getSoldiers() < mySoldiers) {
                    weakerTowns++;
                }
            }
            for (Town town : myTowns) {
                if (town.getSoldiers() < mySoldiers) {
                    weakerTowns++;
                }
            }
            return weakerTowns <= 2;
        }

        public boolean getsRobbed() {
            int outlaws = 0;
            for (Town town : outlawTowns) {
                outlaws += town.getSoldiers() + town.getCitizens() + town.peons;
            }
            int notOutlawTowns = enemyTowns.size() + myTowns.size() - outlawTowns.size();
            int outlawsPerTown = outlaws / notOutlawTowns;
            return outlawsPerTown - corsairs * 5 > 0;
        }

        public boolean hasMostGold() {
            for (Town town : enemyTowns) {
                if (gold < town.gold) {
                    return false;
                }
            }
            return true;
        }
    }

    private void printCommand(String command) {
        System.out.println(command);
        System.exit(0);
    }
}

У вас есть NPE, когда вы сражаетесь только против Outlaws. Этот фрагмент: for (Town town : enemyPlayerTowns)ничего не получает, поэтому ваш Town richestTown = null;или его эквивалент остаются нулевыми.
Thrax

@Thrax Спасибо, должно быть исправлено сейчас :)
CommonGuy

6

Политик, Ява

v3

Обновление: добавлен раздражающий комментарий и улучшено планирование.

Обновление: набирает гораздо меньше поездов (корсары) и фокусируется на создании экономики (пеоны).

Обновление: подправлено пара параметров.

Обновление: гораздо чаще атакует. Слушает ученых больше.

У него две цели.

  1. Неограниченное количество золота.

  2. Неограниченные армии.

import java.util.ArrayList;
import java.util.List;

public class Politician {

    private static final int SOLDIER_COST = 11;
    private static final int AMBASSADOR_COST = 22;
    private static final int SCIENTIST_COST = 22;
    private static final int TRAIN_COST = 14;
    private static final int ARCHITECT_COST = 17;
    private static final int CONVERSION_COST = 50;
    private static final double MIN_SOLDIER_RATIO = .75;
    private static final int MIN_PEOPLE = 30;
    private static final int MIN_ARCHITECTS = 13;
    private static final int MAX_PEOPLE = 200;
    int round;
    int phase;
    int playerID;
    int thisTownID;

    List<State> states;
    List<State> myStates;
    List<State> otherStates;

    State thisState;

    public Politician(String... args) {
        args = args[0].split(";");

        round = Integer.parseInt(args[0]);
        phase = Integer.parseInt(args[1]);
        playerID = Integer.parseInt(args[2]);
        thisTownID = Integer.parseInt(args[3]);

        states = new ArrayList<>();
        myStates = new ArrayList<>();
        otherStates = new ArrayList<>();

        for (int i = 4; i < args.length; i++){
            states.add(new State(args[i]));
        }


        for (State state : states){
            if (state.isMine()){
                myStates.add(state);
                if (state.isThisTown()){
                    thisState = state;
                }
            } else {
                otherStates.add(state);
            }
        }
    }

    public static void main(String[] args){
        if (args.length == 0) {
            System.out.println("8 8 8 26 4 1 13 32");
        } else {
            try {
                System.out.println(new Politician(args).conquer());
            } catch (Exception e){
                System.out.println("We, the enslaved people, declare Politician the winner.");
            }
        }
    }

    private String conquer() {

        switch (phase){
            case 2:
                return steal();
            case 3:
                return conscript();
            case 6:
                return bribe();
            case 7:
                return orderAttack();
            case 8:
                return topSecret();
            case 9:
                return handouts();
            case 11:
                return roadConstruction();
            default:
                throw new IllegalStateException();//Civil war!!!
        }
    }

    private String steal() {
        State bestState = otherStates.stream().max((a, b) -> a.profit() - b.profit()).get();
        return "S " + bestState.getId() + " " + thisState.getTrains();
    }

    private String conscript() {
        int gold = thisState.getFreeGold();

        int neededTrains = Math.max(neededTrains() - thisState.getTrains(), 0);
        neededTrains = Math.min(neededTrains, thisState.getRegularPeople());
        neededTrains = Math.min(neededTrains, gold / TRAIN_COST);
        thisState.regularPeople -= neededTrains;
        gold -= neededTrains * TRAIN_COST;

        int neededSoldiers = soldiersNeeded();
        neededSoldiers = Math.min(gold / SOLDIER_COST, neededSoldiers);
        int neededAmbassadors = Math.min(neededSoldiers, (gold - 200 - 10 * thisState.getCorpses() -
                CONVERSION_COST * thisState.getAmbassadors()) / (CONVERSION_COST + AMBASSADOR_COST));
        neededAmbassadors = Math.min(maxSoldiers() - thisState.getAmbassadors(), neededAmbassadors);
        neededSoldiers -= neededAmbassadors;
        thisState.regularPeople -= neededSoldiers;
        gold -= neededSoldiers * SOLDIER_COST;

        neededAmbassadors += (int) Math.max(Math.round(Math.ceil(thisState.getRegularPeople() / 50.0) -
                thisState.getAmbassadors() - neededAmbassadors), 0);
        neededAmbassadors = Math.min(gold / AMBASSADOR_COST, neededAmbassadors);
        thisState.regularPeople -= neededAmbassadors;
        gold -= neededAmbassadors * AMBASSADOR_COST;

        int neededScientists = (int) Math.max(Math.round(Math.ceil(thisState.getCorpses() / 10.0) -
                thisState.getScientists()), 0);
        neededScientists = Math.min(gold / SCIENTIST_COST, neededScientists);
        thisState.regularPeople -= neededScientists;
        gold -= neededScientists * SCIENTIST_COST;

        int neededArchitects = 0;

        if (thisState.getRegularPeople() > MIN_PEOPLE){
            int freePeople = thisState.getRegularPeople() - MIN_PEOPLE;

            neededArchitects = Math.max(MIN_ARCHITECTS - thisState.getArchitects(), 0);
            neededArchitects = Math.min(neededArchitects, freePeople);
            neededArchitects = Math.min(neededArchitects, gold / ARCHITECT_COST);
            freePeople -= neededArchitects;
            gold -= neededArchitects * ARCHITECT_COST;

            if (freePeople + MIN_PEOPLE > MAX_PEOPLE){

                if (freePeople + MIN_PEOPLE > MAX_PEOPLE){
                    freePeople = freePeople + MIN_PEOPLE - MAX_PEOPLE;
                }

                neededAmbassadors += Math.min(gold / AMBASSADOR_COST, freePeople);
                neededAmbassadors = Math.min(neededAmbassadors, maxSoldiers() - thisState.getAmbassadors());
                gold -= neededAmbassadors * AMBASSADOR_COST;
                freePeople -= neededAmbassadors;

                neededSoldiers += Math.min(gold / SOLDIER_COST, freePeople);
            }

        }

        int neededAirmen = neededSoldiers / 3;
        int neededSailors = neededSoldiers / 3;
        int neededPrivates = neededSoldiers / 3;


        return "R " + neededAirmen + " " + neededSailors + " " + neededPrivates + " " + neededTrains + " " +
                neededAmbassadors + " " + neededScientists + " " + neededArchitects;
    }

    private int neededTrains() {
        int totalOutlaws = 0;
        int totalStates = myStates.size();
        for (State state : otherStates){
            if (state.isOutlaw()){
                totalOutlaws += state.getTotalCitizens();
            } else {
                totalStates++;
            }
        }
        return (int) Math.round(Math.ceil(.2 * totalOutlaws / totalStates));
    }

    private int soldiersNeeded(){
        int soldiers = (int) ((MIN_SOLDIER_RATIO * thisState.getRegularPeople() - thisState.getTotalSoldiers()) /
                        (MIN_SOLDIER_RATIO + 1));
        soldiers = Math.max(soldiers, minSoldiers() + 5 - thisState.getTotalSoldiers());
        soldiers = Math.max(soldiers, maxSoldiers() / 2 - thisState.getTotalSoldiers());
        soldiers = Math.max(soldiers, 0);
        return soldiers;
    }

    private String bribe() {
        int soldiersToConvert = Math.min(thisState.ambassadors, (thisState.getGold() - 200 - 10 *
                thisState.getCorpses()) / CONVERSION_COST);
        soldiersToConvert = Math.max(soldiersToConvert, 0);
        State toughest = otherStates.stream().max((a,b) -> a.getTotalSoldiers() - b.getTotalSoldiers()).get();
        soldiersToConvert = Math.min(soldiersToConvert, toughest.getTotalSoldiers());
        int airmen = (int) ((1.0 * toughest.getAirmen() / toughest.getTotalSoldiers()) * soldiersToConvert);
        soldiersToConvert -= airmen;
        int sailors = (int) ((1.0 * toughest.getSailors() / toughest.getTotalSoldiers()) * soldiersToConvert) * 3 / 2;
        soldiersToConvert -= sailors;
        int privates = soldiersToConvert;
        return "C " + toughest.getId() + " " + airmen + " " + sailors + " " + privates;
    }

    private String orderAttack() {
        if (round < 99 && otherTowns.size() < 2){
            return "W";
        }
        int soldiers = thisState.getFreeSoldiers();
        otherStates.sort((a,b) -> b.getRegularPeople() / Math.max(b.getTotalSoldiers(), 1) - a.getRegularPeople() / Math.max(a.getTotalSoldiers(), 1));
        if (otherStates.get(0).getTotalSoldiers() < soldiers){//Attack!!!!
            int airmen = (int) (((thisState.getAirmen()*1.0) / thisState.getTotalSoldiers()) * soldiers);
            int sailors = (int) (((thisState.getSailors()*1.0) / thisState.getTotalSoldiers()) * soldiers);
            int privates = (int) (((thisState.getPrivates()*1.0) / thisState.getTotalSoldiers()) * soldiers);
            return "A " + otherStates.get(0).getId() + " " + airmen + " " + sailors + " " + privates;
        }
        return getWaitString();
    }

    private String handouts() {

        State poorestState = null;
        int goldOfPoorestTown = Integer.MAX_VALUE;

        for (State state : myStates){
            if (state.getGold() < goldOfPoorestTown){
                poorestState = state;
                goldOfPoorestTown = state.getGold();
            }
        }
        if (thisState.getGold() <= goldOfPoorestTown){
            return getWaitString();
        }
        return "T " + poorestState.getId() + " " + (thisState.getGold() - poorestState.getGold())  / 2;
    }

    private String topSecret() {
        return "R " + thisState.getCorpses();
    }

    private String roadConstruction() {
        int airportPriority = thisState.getAirmen() + thisState.getAmbassadors() + thisState.getScientists();
        int highwayPriority = thisState.getSailors() + thisState.getPrivates();
        int railroadPriority = thisState.getTrains() + thisState.getRegularPeople();
        int palacePriority = 5;//Why would we build a palace???
        if (airportPriority > highwayPriority && airportPriority > railroadPriority && airportPriority >
                palacePriority && thisState.getGold() > 200){
            return "B T";
        } else if (highwayPriority > railroadPriority && highwayPriority > palacePriority && thisState.getGold() > 200){
            return "B B";
        } else if (railroadPriority > palacePriority && thisState.getGold() > 200){
            return "B E";
        } else if (thisState.getGold() > 500){
            return "B P";
        } else {
            return getWaitString();
        }
    }

    private int maxSoldiers(){
        int max = 0;
        for (State state : otherStates){
            if (state.getTotalSoldiers() > max){
                max = state.getTotalSoldiers();
            }
        }
        return max;
    }

    private int minSoldiers(){
        int min = Integer.MAX_VALUE;
        for (State state : otherStates){
            if (state.getTotalSoldiers() < min){
                min = state.getTotalSoldiers();
            }
        }
        return min;
    }

    private class State {

        private final int ownerId;
        private final int id;
        private final int gold;
        private final int corpses;
        private final int airmen;
        private final int sailors;
        private final int privates;
        private final int trains;
        private final int ambassadors;
        private final int scientists;
        private final int architects;
        private int regularPeople;
        private final int airports;
        private final int highways;
        private final int railroads;
        private final int palaces;

        public State(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            gold = Integer.parseInt(args[2]);
            corpses = Integer.parseInt(args[3]);
            airmen = Integer.parseInt(args[4]);
            sailors = Integer.parseInt(args[5]);
            privates = Integer.parseInt(args[6]);
            trains = Integer.parseInt(args[7]);
            ambassadors = Integer.parseInt(args[8]);
            scientists = Integer.parseInt(args[9]);
            architects = Integer.parseInt(args[10]);
            regularPeople = Integer.parseInt(args[11]);
            airports = Integer.parseInt(args[12]);
            highways = Integer.parseInt(args[13]);
            railroads = Integer.parseInt(args[14]);
            palaces = Integer.parseInt(args[15]);
        }
        public int getOwnerId() {
            return ownerId;
        }
        public int getId() {
            return id;
        }
        public int getGold() {
            return gold;
        }
        public int getCorpses() {
            return corpses;
        }
        public int getAirmen() {
            return airmen;
        }
        public int getSailors() {
            return sailors;
        }
        public int getPrivates() {
            return privates;
        }
        public int getTrains() {
            return trains;
        }
        public int getAmbassadors() {
            return ambassadors;
        }
        public int getScientists() {
            return scientists;
        }
        public int getArchitects() {
            return architects;
        }
        public int getRegularPeople() {
            return regularPeople;
        }
        public int getAirports() {
            return airports;
        }
        public int getHighways() {
            return highways;
        }
        public int getRailroads() {
            return railroads;
        }
        public int getPalaces() {
            return palaces;
        }
        public int getTotalBuildings() {
            return getAirports() + getHighways() + getRailroads() + getPalaces();
        }
        public int getTotalSoldiers() {
            return getAirmen() + getSailors() + getPrivates();
        }
        public int getTotalUnits() {
            return getTotalSoldiers() + getTrains() + getAmbassadors() + getScientists() + getArchitects();
        }
        public int getTotalCitizens() {
            return getTotalUnits() + getRegularPeople();
        }
        public boolean isMine(){
            return getOwnerId() == playerID;
        }
        public boolean isThisTown(){
            return id == thisTownID;
        }
        public int neededGold(){
            return 2 * getTotalUnits() - getTotalSoldiers();
        }
        public int getFreeGold(){
            return gold - neededGold();
        }

        public int getFreeSoldiers() {
            int soldiers = Math.max((int) (getTotalSoldiers() - regularPeople * MIN_SOLDIER_RATIO), 0);
            soldiers = Math.min(soldiers, getTotalSoldiers() - minSoldiers() - 5);
            soldiers = Math.min(soldiers, getTotalSoldiers() - maxSoldiers() / 2);
            soldiers = Math.max(soldiers, 0);
            return soldiers;
        }

        public boolean isOutlaw() {
            return ownerId == -1;
        }

        public int income() {
            return 5 * regularPeople + 10 * trains + 2 * (airmen + ambassadors + scientists) * airports + 2 * (sailors +
                    privates) * highways + 2 * (trains + regularPeople) * railroads + 10 * palaces;
        }

        public int wages() {
            return airmen + sailors + privates + 2 * (trains + ambassadors + scientists + architects);
        }

        public int profit() {
            return income() - wages();
        }
    }

    private static String getWaitString(){
        switch ((int) (Math.random() * 7)){
            case 0:
                return "We will win!";
            case 1:
                return "Winny the Pooh, Winny the Pooh";
            case 2:
                return "Who washed Washington's white woolen underwear when Washington's laundry woman, went west?";
            case 3:
                return "What's up doc?";
            case 4:
                return "Why is this taking so long?";
            case 5:
                return "Wool is better than cotton.";
            case 6:
                return "Will I win?";
            case 7:
                return "What's your favorite color?";
            default:
                return "What! This message should not be being printed.";
        }
    }

}

объяснение

У него две цели.

  1. Неограниченное количество золота.
  2. Неограниченные армии.

Как получить золото:

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

Как получить армии:

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


К сожалению, этот политик - как и любой политик - все пустые обещания и не может противостоять Sehtimianer. (Потерянный раунд 30, второй до последнего в живых)
Thrax

Теперь он правит миром, поздравляю!
Thrax

@Thrax И он все еще есть!
TheNumberOne

Я впечатлен ... как и все политики ... он его очень приспосабливается к изменениям :)
Moogie

Битва жестока, но Политик пока не победил!
Thrax

5

Спокойствие, Луа

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

function explode(d,p)
  local t, ll; t={}; ll=0
  if(#p == 1) then return {p} end
    while true do
      l=string.find(p,d,ll,true)
      if l~=nil then table.insert(t, string.sub(p,ll,l-1)); ll=l+1
      else table.insert(t, string.sub(p,ll)); break
      end
    end
  return t
end

function soldiers(t)
  local s
  s = t["WARLOCKS"] + t["CRUSADERS"] + t["AMAZONS"]
  return s
end

function reserve(t)
  local s
  s = t["GOLD"] - (3 * soldiers(t))
  return s
end

parameters = {"PLAYER", "TOWN", "GOLD", "CORPSES", "WARLOCKS", "CRUSADERS", "AMAZONS", 
"CORSAIRS", "BISHOPS", "NECROMANCERS", "ARCHITECTS", "PEONS", "TEMPLES", "BARRACKS", 
"ESTATES", "PALACES"}

if (#arg < 1) then
  print("5 5 5 10 10 1 3 59")  
else

  args = explode(";", arg[1])

  local round = tonumber(args[1])
  local phase = tonumber(args[2])
  local playerID = tonumber(args[3])
  local thisTownID = tonumber(args[4])
  local thisTown = {}
  local towns = {}
  local enemyTowns = {}
  local myTowns = {}
  local output = "W"
  local stock = 200
  local peons = 33
  local bishops = 20

  for i=5,#args,1 do
    local town = explode("_", args[i])
    towns[town[2]] = {}
    for key, value in pairs(town) do 
      towns[town[2]][parameters[key]] = tonumber(value)
    end
  end

  for i, town in pairs(towns) do 
    if town["PLAYER"] == playerID then
      if town["TOWN"] == thisTownID then thisTown = town end
      table.insert(myTowns, town)
    else
      table.insert(enemyTowns, town)
    end
  end

  if phase == 2 then
    local richestTown
    for i, town in pairs(myTowns) do
      if richestTown == nil then richestTown = town end
      if richestTown["GOLD"] > town["GOLD"] then richestTown = town end
    end
    if thisTown["CORSAIRS"] > 0 then output = "S "..richestTown["TOWN"].." "..thisTown["CORSAIRS"] end
  elseif phase == 3 then 
    local necromancers = 0
    local architects = 0
    if thisTown["NECROMANCERS"] < 1 then necromancers = 1 end
    if thisTown["ARCHITECTS"] < 1 then architects = 1 end
    if reserve(thisTown) > stock and thisTown["PEONS"] > peons then output = "R 0 0 0 0 "..math.max(0, math.min(thisTown["BISHOPS"] - bishops, math.min(thisTown["PEONS"] - peons, math.floor((reserve(thisTown) - stock) / 20)))).." "..necromancers.." "..architects end
  elseif phase == 6 then
    local biggestTown
    for i, town in pairs(enemyTowns) do
      if biggestTown == nil then biggestTown = town end
      if soldiers(biggestTown) > soldiers(town) then biggestTown = town end  
    end
    local units = math.min(thisTown["BISHOPS"], math.floor((reserve(thisTown) - stock) / 50))
    if (reserve(thisTown) > stock) then output = "C "..biggestTown["TOWN"].." "..math.floor(units/3).." "..math.floor(units/3).." "..math.floor(units/3) end
  elseif phase == 7 then 
    for i, town in pairs(enemyTowns) do
      if soldiers(town) <= 3 and soldiers(thisTown) >= 9 then output = "A "..town["TOWN"].." 3 3 3"; break end
    end
  elseif phase == 8 then
    if thisTown["CORPSES"] > 0 and thisTown["NECROMANCERS"] > 0 then output = "R "..math.min(thisTown["NECROMANCERS"] * 5, thisTown["CORPSES"]) end
  elseif phase == 9 then
    local smallestTown, poorestTown
    for i, town in pairs(myTowns) do
      if smallestTown == nil then smallestTown = town end
      if poorestTown == nil then poorestTown = town end
      if soldiers(smallestTown) < soldiers(town) then smallestTown = town end  
      if poorestTown["GOLD"] < town["GOLD"] then poorestTown = town end  
      if (soldiers(thisTown) - soldiers(smallestTown) >= 18) then output = "M "..thisTown["TOWN"].." 3 3 3" break end
      if (thisTown["GOLD"] - poorestTown["GOLD"] >= 600) then output = "T "..thisTown["TOWN"].." 300" break end
    end
  elseif phase == 11 then
     if reserve(thisTown) > (stock + 200) then output = "B T" end
  end

  print(output)

end

Бег с lua Serenity.lua(требуется Lua 5.2)


5

Зилоты (Питон)

(На основе кода CarpetPython.)

Постройте как можно меньше храмов! Воскрешать мертвых! Конвертируйте неверных!

import sys
from random import *
from operator import itemgetter

(PLAYER, TOWN, GOLD, CORPSES, WARLOCKS, CRUSADERS, AMAZONS, 
CORSAIRS, BISHOPS, NECROMANCERS, ARCHITECTS, PEONS, 
TEMPLES, BARRACKS, ESTATES, PALACES) = range(16)

def getstrength(t):
    return t[WARLOCKS]+t[CRUSADERS]*1.5+t[AMAZONS]/1.5

if len(sys.argv) < 2:
    print 20, 5, 5, 10, 8, 5, 7, 40
else:
    parts = sys.argv[1].split(';')
    turn, phase, me, thistown = [int(parts.pop(0)) for i in range(4)]
    towns = [[int(v) for v in town.split('_')] for town in parts]
    enemy = [t for t in towns if t[PLAYER] != me]
    mytowns = [t for t in towns if t[PLAYER] == me]
    here = [t for t in mytowns if t[TOWN] == thistown][0]
    otherids = [t[TOWN] for t in enemy]
    strength = sorted(enemy, key=getstrength)
    rich = sorted(enemy, key=itemgetter(GOLD))

    output = ''
    if phase == 2:
        output = 'S %s %s' % (rich[-1][TOWN], here[CORSAIRS])
    elif phase == 3:
        Warlocks=Crusaders=Amazons=Corsairs=Bishops=Necromancers=Architects=0
        if here[CORPSES] > 5*here[NECROMANCERS]:
            Necromancers = 1
        if here[PEONS] > 50*here[BISHOPS]:
            Bishops = 1
        if here[WARLOCKS] < strength[0][CRUSADERS]:
            Warlocks = 2
            Amazons = 2
        if here[WARLOCKS] < here[AMAZONS]:
            Warlocks += 1
        if here[GOLD] > 200:
            Architects = 1
        if rich[-1][GOLD] > 100+2*here[GOLD]:
            Corsairs = 1
        output = 'R %s %s %s %s %s %s %s' % (Warlocks,Crusaders,Amazons,Corsairs,Bishops,Necromancers,Architects)
    elif phase == 6:
        if here[GOLD] > 300:
            output = 'C %s %s %s %s' % (strength[0][TOWN],here[GOLD]/300,here[GOLD]/300,here[GOLD]/300)
    elif phase == 7:
        target = strength[0]
        if getstrength(target) < getstrength(here)*3/5:
            output = 'A %s %s %s 0' % (target[TOWN],here[WARLOCKS]*3/4,target[AMAZONS])
    elif phase == 8:
        if here[CORPSES] > 10:
            output = 'R %s' % (here[NECROMANCERS]*5)
    elif phase == 9:
        pass  # move people or gold here
    elif phase == 11 and here[GOLD] > 300:
        output = 'B T'   # Build a temple!

    print output if output else 'W'

6
Это не похоже на Java для меня.
Ypnypn

5
Я думаю, что вы имели в виду Python
soktinpk

@ Thrax ты имеешь в виду пропавший двоеточие
rorlork

@soktinpk: Да, это Python; Я не знаю, как я получил Java.
MegaTom

@TheBestOne Я исправил это.
MegaTom

4

Commander, Java

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

import java.util.ArrayList;
import java.util.List;

public class Commander {

    int round;
    int phase;
    int playerID;
    int thisTownID;

    List<Town> towns;
    List<Town> myTowns;
    List<Town> otherTowns;

    Town thisTown;

    public static void main(String[] args){
        if (args.length == 0) {
            System.out.println("15 10 12 10 7 5 1 40");
        } else {
            new Commander().conquer(args[0].split(";"));
        }
    }

    private void conquer(String[] args) {

        round = Integer.parseInt(args[0]);
        phase = Integer.parseInt(args[1]);
        playerID = Integer.parseInt(args[2]);
        thisTownID = Integer.parseInt(args[3]);

        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();

        for (int i = 4; i < args.length; i++){
            towns.add(new Town(args[i]));
        }

        for (Town town : towns){
            if (town.isMine()){
                myTowns.add(town);
                if (town.isThisTown()){
                    thisTown = town;
                }
            } else {
                otherTowns.add(town);
            }
        }

        if (phase == 2) {               // Steal
            //Command : S destinationId corsairs
            steal();
        } else if (phase == 3) {        // Recruit
            //Command : R warlocks crusaders amazons corsairs bishops necromancers architects
            recruit()   ;
        } else if (phase == 6) {        // Convert
            //Command : C destinationId warlocks crusaders amazons 
            convert();
        } else if (phase == 7) {        // Attack
            //Command : A destinationId warlocks crusaders amazons
            attack();   
        } else if (phase == 8) {        // Resurrect
            //Command : R corpses
            resurrect();    
        } else if (phase == 9) {        // Move
            //Command : M destinationId warlocks crusaders amazons corsairs bishops necromancers architects
            move();
        } else if (phase == 11) {       // Build
            //Command : B building building building... (T: Temple, B: Barracks, E: Estate, P: Palace)
            build();
        }
    }

    private void steal() {
        Town richestTown = otherTowns.stream().max((a,b) -> a.gold - b.gold).get();
        System.out.println("S " + richestTown.getId() + " " + thisTown.getCorsairs());
    }

    private void recruit() {

        int maxUnitsToRecruits = Math.floorDiv(thisTown.getPeons() - thisTown.getUnits(), 2);
        int goldAvailable = thisTown.getGold() - (thisTown.getUnits() * 5);
        int unitsRecruited = 0;
        int cost = 10;
        int[] recruits = new int[3];
        int i = 0;
        int necromancers = Math.max(0, 5 - thisTown.getNecromancers());
        while (goldAvailable >= 0 && unitsRecruited <= maxUnitsToRecruits) {
             i = (i >= recruits.length - 1 ? 0 : i+1);
             recruits[i]++;
             unitsRecruited++;
             goldAvailable-=cost;
        }
        if (unitsRecruited > 0) {
            System.out.println("R " + recruits[0] + " " + recruits[1] + " " + recruits[2] + " 0 0 " +  necromancers + " 0");
        } else {
            System.out.println("W");
        }
    }

    private void convert() {

        Town biggestTown = otherTowns.stream().max((a,b) -> a.getCitizens() - b.getCitizens()).get();
        int goldAvailable = thisTown.getGold() - (thisTown.getUnits() * 5);
        int bishopsAvailable = thisTown.getBishops();
        int unitsConverted = 0;
        int cost = 50;
        int[] converts = new int[3];
        int i = 0;
        while (goldAvailable >= 0 && unitsConverted <= bishopsAvailable) {
             i = (i >= converts.length - 1 ? 0 : i+1);
             converts[i]++;
             goldAvailable-=cost;
        }
        System.out.println("C " + biggestTown.getId() + " " + converts[0] + " " + converts[1] + " " + converts[2]);  
    }

    private void attack() {

        Town lessDefendedTown = otherTowns.stream().max((a,b) -> a.getSoldiers() - b.getSoldiers()).get();
        int neededWarlocks =  thisTown.getWarlocks() - lessDefendedTown.getWarlocks();
        int neededCrusaders = thisTown.getCrusaders() - lessDefendedTown.getCrusaders();
        int neededAmazons = thisTown.getAmazons() - lessDefendedTown.getAmazons() ;

        if (neededWarlocks > 0 && neededCrusaders > 0 && neededAmazons > 0) {
            System.out.println("A " + lessDefendedTown.getId() + " " + (lessDefendedTown.getWarlocks() + 1) + " " + (lessDefendedTown.getCrusaders() + 1) + " " + (lessDefendedTown.getAmazons() + 1));  
        } else {
            System.out.println("W");
        }

    }

    private void move() {
        System.out.println("W");
    }

    private void resurrect() {
        int goldAvailable = thisTown.getGold() - (thisTown.getUnits() * 5);
        int corpsesAvailable = thisTown.getCorpses();
        int availableNecromancers = thisTown.getNecromancers();
        int raiseCapacity = availableNecromancers * 5;
        int raisedCorpses = 0;
        while (corpsesAvailable >= 0 && raiseCapacity >= 0 && goldAvailable >= 0) {
            raisedCorpses++;
            corpsesAvailable--;
            goldAvailable -= 20;
            raiseCapacity--;
        }
        if (raisedCorpses > 0) {
            System.out.println("R " + raisedCorpses);
        } else {
            System.out.println("W");
        }
    }

    private void build() {
        int goldAvailable = thisTown.getGold() - (thisTown.getUnits() * 5);
        if (goldAvailable >= 400) {
            System.out.println("B B");
        } else {
            System.out.println("W");
        }
    }

    private class Town {

        private final int ownerId;
        private final int id;
        private final int gold;
        private final int corpses;
        private final int warlocks;
        private final int crusaders;
        private final int amazons;
        private final int corsairs;
        private final int bishops;
        private final int necromancers;
        private final int architects;
        private final int peons;
        private final int temples;
        private final int barracks;
        private final int estates;
        private final int palaces;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            gold = Integer.parseInt(args[2]);
            corpses = Integer.parseInt(args[3]);
            warlocks = Integer.parseInt(args[4]);
            crusaders = Integer.parseInt(args[5]);
            amazons = Integer.parseInt(args[6]);
            corsairs = Integer.parseInt(args[7]);
            bishops = Integer.parseInt(args[8]);
            necromancers = Integer.parseInt(args[9]);
            architects = Integer.parseInt(args[10]);
            peons = Integer.parseInt(args[11]);
            temples = Integer.parseInt(args[12]);
            barracks = Integer.parseInt(args[13]);
            estates = Integer.parseInt(args[14]);
            palaces = Integer.parseInt(args[15]);
        }
        public int getOwnerId() {
            return ownerId;
        }
        public int getId() {
            return id;
        }
        public int getGold() {
            return gold;
        }
        public int getCorpses() {
            return corpses;
        }
        public int getWarlocks() {
            return warlocks;
        }
        public int getCrusaders() {
            return crusaders;
        }
        public int getAmazons() {
            return amazons;
        }
        public int getCorsairs() {
            return corsairs;
        }
        public int getBishops() {
            return bishops;
        }
        public int getNecromancers() {
            return necromancers;
        }
        public int getArchitects() {
            return architects;
        }
        public int getPeons() {
            return peons;
        }
        public int getTemples() {
            return temples;
        }
        public int getBarracks() {
            return barracks;
        }
        public int getEstates() {
            return estates;
        }
        public int getPalaces() {
            return palaces;
        }
        public int getBuildings() {
            return getTemples() + getBarracks() + getEstates() + getPalaces();
        }
        public int getSoldiers() {
            return getWarlocks() + getCrusaders() + getAmazons();
        }
        public int getUnits() {
             return getSoldiers() + getCorsairs() + getBishops() + getNecromancers() + getArchitects();
        }
        public int getCitizens() {
            return getUnits() + getPeons();
        }
        public boolean isMine(){
            return getOwnerId() == playerID;
        }
        public boolean isThisTown(){
            return id == thisTownID;
        }

    }

}

4

Масло

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

import java.util.ArrayList;
import java.util.List;

public class Butter {

    int round;
    int phase;
    int playerID;
    int thisTownID;

    List<Town> towns;
    List<Town> myTowns;
    List<Town> otherTowns;

    Town thisTown;

    public Butter(String... args) {
        args = args[0].split(";");

        round = Integer.parseInt(args[0]);
        phase = Integer.parseInt(args[1]);
        playerID = Integer.parseInt(args[2]);
        thisTownID = Integer.parseInt(args[3]);

        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();

        for (int i = 4; i < args.length; i++){
            towns.add(new Town(args[i]));
        }

        for (Town town : towns){
            if (town.isMine()){
                myTowns.add(town);
                if (town.isThisTown()){
                    thisTown = town;
                }
            } else {
                otherTowns.add(town);
            }
        }
    }

    public static void main(String[] args){
        if (args.length == 0) {
            System.out.println("12 12 12 12 13 13 13 13");
        } else {
            System.out.println(new Butter(args[0]).spread());
        }
    }

    private String spread() {

        if (phase == 2) {               // Steal
            //Command : S destinationId corsairs
            return steal();
        } else if (phase == 3) {        // Recruit
            //Command : R warlocks crusaders amazons corsairs bishops necromancers architects
            return recruit()    ;
        } else if (phase == 6) {        // Convert
            //Command : C destinationId warlocks crusaders amazons
            return convert();
        } else if (phase == 7) {        // Attack
            //Command : A destinationId warlocks crusaders amazons
            return attack();
        } else if (phase == 8) {        // Resurrect
            //Command : R corpses
            return resurrect();
        } else if (phase == 9) {        // Move
            //Command : M destinationId warlocks crusaders amazons corsairs bishops necromancers architects
            return move();
        } else if (phase == 11) {       // Build
            //Command : B building building building... (T: Temple, B: Barracks, E: Estate, P: Palace)
            return build();
        }
        throw new IllegalStateException(phase + "");
    }

    private String steal() {
        if (thisTown.getCorsairs() <= 0){
            return "W";
        }
        int mostGold = Integer.MIN_VALUE;
        Town richestTown = null;
        for (Town town : otherTowns){
            if (town.getGold() > mostGold){
                mostGold = town.getGold();
                richestTown = town;
            }
        }
        return "S " + richestTown.getId() + " " + thisTown.getCorsairs();
    }

    private String recruit() {
        int gold = thisTown.getFreeGold();

        int peons = thisTown.getPeons();
        int warlocks = thisTown.getWarlocks();
        int crusaders = thisTown.getCrusaders();
        int amazons = thisTown.getAmazons();
        int corsairs = thisTown.getCorsairs();
        int bishops = thisTown.getBishops();
        int necromancers = thisTown.getNecromancers();
        int architects = thisTown.getArchitects();

        int totalPeople = peons+warlocks+crusaders+amazons+corsairs+bishops+necromancers+architects;
        int averagePeople = totalPeople / 8;
        int extraPeons = peons - averagePeople;
        if (extraPeons <= 0 || gold <= 0){
            return "W";
        }

        int warlocksToAdd = warlocks < averagePeople ? 0 : warlocks - averagePeople;
        int crusadersToAdd = crusaders < averagePeople ? 0 : crusaders - averagePeople;
        int amazonsToAdd = amazons < averagePeople ? 0 : amazons - averagePeople;
        int corsairsToAdd = corsairs < averagePeople ? 0 : corsairs - averagePeople;
        int bishopsToAdd = bishops < averagePeople ? 0 : bishops - averagePeople;
        int necromancersToAdd = necromancers < averagePeople ? 0 : necromancers - averagePeople;
        int architectsToAdd = architects < averagePeople ? 0 : architects - averagePeople;

        warlocksToAdd = warlocksToAdd * 11 > gold ? gold / 11 : warlocksToAdd;
        gold -= warlocksToAdd * 11;
        crusadersToAdd = crusadersToAdd * 11 > gold ? gold / 11 : crusadersToAdd;
        gold -= crusadersToAdd * 11;
        amazonsToAdd = amazonsToAdd * 11 > gold ? gold / 11 : amazonsToAdd;
        gold -= amazonsToAdd * 11;
        corsairsToAdd = corsairsToAdd * 14 > gold ? gold / 14 : corsairsToAdd;
        gold -= corsairsToAdd * 14;
        bishopsToAdd = bishopsToAdd * 22 > gold ? gold / 22 : bishopsToAdd;
        gold -= bishopsToAdd * 22;
        necromancersToAdd = necromancersToAdd * 22 > gold ? gold / 22: necromancersToAdd;
        gold -= necromancersToAdd * 22;
        architectsToAdd = architectsToAdd * 17 > gold ? gold / 17 : architectsToAdd;
        gold -= architectsToAdd * 17;

        warlocksToAdd = warlocksToAdd > extraPeons ? extraPeons : warlocksToAdd;
        extraPeons -= warlocksToAdd;
        crusadersToAdd = crusadersToAdd > extraPeons ? extraPeons : crusadersToAdd;
        extraPeons -= crusadersToAdd;
        amazonsToAdd = amazonsToAdd > extraPeons ? extraPeons : amazonsToAdd;
        extraPeons -= amazonsToAdd;
        corsairsToAdd = corsairsToAdd > extraPeons ? extraPeons : corsairsToAdd;
        extraPeons -= corsairsToAdd;
        bishopsToAdd = bishopsToAdd > extraPeons ? extraPeons : bishopsToAdd;
        extraPeons -= bishopsToAdd;
        necromancersToAdd = necromancersToAdd > extraPeons ? extraPeons : necromancersToAdd;
        extraPeons -= necromancersToAdd;
        architectsToAdd = architectsToAdd > extraPeons ? extraPeons : architectsToAdd;

        return "R " + warlocksToAdd + " " + crusadersToAdd + " " + amazonsToAdd + " " + corsairsToAdd + " " +
                bishopsToAdd + " " + necromancersToAdd + " " + architectsToAdd;
    }

    private String convert() {
        return "W";
    }

    private String attack() {
        for (Town town : otherTowns){
            if (town.getSoldiers() * 4 < thisTown.getSoldiers()){
                return "A " + town.getId() + " " + thisTown.getWarlocks() / 2 + " " + thisTown.getCrusaders() / 2 + " "
                        + thisTown.getAmazons() / 2;
            }
        }
        return "W";
    }

    private String move() {
        int totalWarlocks = 0;
        int totalCrusaders = 0;
        int totalAmazons = 0;
        int totalCorsairs = 0;
        int totalBishops = 0;
        int totalNecromancers = 0;
        int totalArchitects = 0;
        for (Town town : myTowns){
            totalWarlocks += town.getWarlocks();
            totalCrusaders += town.getCrusaders();
            totalAmazons += town.getAmazons();
            totalCorsairs += town.getCorsairs();
            totalBishops += town.getBishops();
            totalNecromancers += town.getNecromancers();
            totalArchitects += town.getArchitects();
        }
        int averageWarlocks = totalWarlocks / myTowns.size();
        int averageCrusaders = totalCrusaders / myTowns.size();
        int averageAmazons = totalAmazons / myTowns.size();
        int averageCorsairs = totalCorsairs / myTowns.size();
        int averageBishops = totalBishops / myTowns.size();
        int averageNecromancers = totalNecromancers / myTowns.size();
        int averageArchitects = totalArchitects / myTowns.size();

        Town worstTown = null;
        int biggestDifference = Integer.MIN_VALUE;
        for (Town town : myTowns){
            int difference = 0;
            difference += town.getWarlocks() < averageWarlocks ? averageWarlocks - town.getWarlocks() : 0;
            difference += town.getCrusaders() < averageCrusaders ? averageCrusaders - town.getCrusaders() : 0;
            difference += town.getAmazons() < averageAmazons ? averageAmazons - town.getAmazons() : 0;
            difference += town.getCorsairs() < averageCorsairs ? averageCorsairs - town.getCorsairs() : 0;
            difference += town.getBishops() < averageBishops ? averageBishops - town.getBishops() : 0;
            difference += town.getNecromancers() < averageNecromancers ? averageNecromancers - town.getNecromancers() :
                    0;
            difference += town.getArchitects() < averageArchitects ? averageArchitects - town.getArchitects() : 0;
            if (difference > biggestDifference){
                worstTown = town;
                biggestDifference = difference;
            }
        }
        int neededWarlocks = worstTown.getWarlocks() < averageWarlocks ? averageWarlocks - worstTown.getWarlocks() : 0;
        int neededCrusaders = worstTown.getCrusaders() < averageCrusaders ? averageCrusaders - worstTown.getCrusaders()
                : 0;
        int neededAmazons = worstTown.getAmazons() < averageAmazons ? averageAmazons - worstTown.getAmazons() : 0;
        int neededCorsairs = worstTown.getCorsairs() < averageCorsairs ? averageCorsairs - worstTown.getCorsairs() : 0;
        int neededBishops = worstTown.getBishops() < averageBishops ? averageBishops - worstTown.getBishops() : 0;
        int neededNecromancers = worstTown.getNecromancers() < averageNecromancers ? averageNecromancers - worstTown.
                getNecromancers() : 0;
        int neededArchitects = worstTown.getArchitects() < averageArchitects ? averageArchitects - worstTown.
                getArchitects() : 0;
        return "M " + worstTown.getId() + " " + neededWarlocks + " " + neededCrusaders + " " + neededAmazons + " " +
                neededCorsairs + " " + neededBishops + " " + neededNecromancers + " " + neededArchitects;
    }

    private String resurrect() {
        return "R " + thisTown.getCorpses();
    }

    private String build() {
        if (thisTown.getGold() > 500){
            return "B P";
        }
        if (thisTown.getGold() > 200){
            return "B T";
        }
        return "W";
    }

    private class Town {

        private final int ownerId;
        private final int id;
        private final int gold;
        private final int corpses;
        private final int warlocks;
        private final int crusaders;
        private final int amazons;
        private final int corsairs;
        private final int bishops;
        private final int necromancers;
        private final int architects;
        private final int peons;
        private final int temples;
        private final int barracks;
        private final int estates;
        private final int palaces;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            gold = Integer.parseInt(args[2]);
            corpses = Integer.parseInt(args[3]);
            warlocks = Integer.parseInt(args[4]);
            crusaders = Integer.parseInt(args[5]);
            amazons = Integer.parseInt(args[6]);
            corsairs = Integer.parseInt(args[7]);
            bishops = Integer.parseInt(args[8]);
            necromancers = Integer.parseInt(args[9]);
            architects = Integer.parseInt(args[10]);
            peons = Integer.parseInt(args[11]);
            temples = Integer.parseInt(args[12]);
            barracks = Integer.parseInt(args[13]);
            estates = Integer.parseInt(args[14]);
            palaces = Integer.parseInt(args[15]);
        }
        public int getOwnerId() {
            return ownerId;
        }
        public int getId() {
            return id;
        }
        public int getGold() {
            return gold;
        }
        public int getCorpses() {
            return corpses;
        }
        public int getWarlocks() {
            return warlocks;
        }
        public int getCrusaders() {
            return crusaders;
        }
        public int getAmazons() {
            return amazons;
        }
        public int getCorsairs() {
            return corsairs;
        }
        public int getBishops() {
            return bishops;
        }
        public int getNecromancers() {
            return necromancers;
        }
        public int getArchitects() {
            return architects;
        }
        public int getPeons() {
            return peons;
        }
        public int getTemples() {
            return temples;
        }
        public int getBarracks() {
            return barracks;
        }
        public int getEstates() {
            return estates;
        }
        public int getPalaces() {
            return palaces;
        }
        public int getBuildings() {
            return getTemples() + getBarracks() + getEstates() + getPalaces();
        }
        public int getSoldiers() {
            return getWarlocks() + getCrusaders() + getAmazons();
        }
        public int getUnits() {
            return getSoldiers() + getCorsairs() + getBishops() + getNecromancers() + getArchitects();
        }
        public int getCitizens() {
            return getUnits() + getPeons();
        }
        public boolean isMine(){
            return getOwnerId() == playerID;
        }
        public boolean isThisTown(){
            return id == thisTownID;
        }
        public int neededGold(){
            return 2 * getUnits() - getSoldiers();
        }
        public int getFreeGold(){
            return gold - neededGold();
        }

    }

}

4

Sehtimianer, Java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

public class Sehtimianer {
private static final int GOLD_MAX_DEBT = 200;
private static final int BIRTH_ROUND = 5;
private static final int ZOMBIE_WAKING_CHANCE = 10;
private static final int NECRO_RAISE_CAPACITY = 5;
private static final int DEMON_SUMMON_CHANCE = 10;
private static final int BISHOP_PRAYER_CAPACITY = 50;
private static final int CORSAIR_SURVEILLANCE_RATIO = 5;

public static final int GOLD_PER_WARLOCK = -1;
public static final int GOLD_PER_CRUSADER = -1;
public static final int GOLD_PER_AMAZON = -1;
public static final int GOLD_PER_CORSAIR = -2;
public static final int GOLD_PER_BISHOP = -2;
public static final int GOLD_PER_NECRO = -2;
public static final int GOLD_PER_ARCHITECT = -2;
public static final int GOLD_PER_PEON = 5;

public static final int GOLD_PER_RESURRECTION = 20;
public static final int GOLD_PER_CONVERSION = 50;
public static final int GOLD_PER_STEAL = 10;

public static final int GOLD_RECRUIT_WARLOCK = 10;
public static final int GOLD_RECRUIT_CRUSADER = 10;
public static final int GOLD_RECRUIT_AMAZON = 10;
public static final int GOLD_RECRUIT_CORSAIR = 12;
public static final int GOLD_RECRUIT_BISHOP = 20;
public static final int GOLD_RECRUIT_NECRO = 20;
public static final int GOLD_RECRUIT_ARCHITECT = 15;
public static final int GOLD_RECRUIT_DEFAULT = 20;

public static final int GOLD_PER_TEMPLE = 2;
public static final int GOLD_PER_BARRACKS = 2;
public static final int GOLD_PER_ESTATE = 2;
public static final int GOLD_PER_PALACE = 10;

public static final int GOLD_COST_BUILDING = 200;

public static final int COMPLETION_PER_ARCHITECT = 8;
public static final int COMPLETION_NEEDED = 100;
public static final int ARCHITECTS = (int) Math.ceil(1.0 * COMPLETION_NEEDED / COMPLETION_PER_ARCHITECT);

int round;
int phase;
int playerID;
int thisTownID;

List<Town> towns;
List<Town> myTowns;
List<Town> playerTowns;
List<Town> outlawTowns;

Town thisTown;

public static void main(String[] args) {
    if (args.length == 0) {
        System.out.println("9 9 9 24 5 2 13 29");
    } else {
        new Sehtimianer().actions(args[0].split(";"));
    }
}

private void actions(String[] args) {

    round = Integer.parseInt(args[0]);
    phase = Integer.parseInt(args[1]);
    playerID = Integer.parseInt(args[2]);
    thisTownID = Integer.parseInt(args[3]);

    towns = new ArrayList<Town>();
    myTowns = new ArrayList<Town>();
    playerTowns = new ArrayList<Town>();
    outlawTowns = new ArrayList<Town>();

    for (int i = 4; i < args.length; i++) {
        towns.add(new Town(args[i]));
    }

    for (Town town : towns) {
        if (town.isMine()) {
            myTowns.add(town);
            if (town.isThisTown()) {
                thisTown = town;
            }
        } else {
            if (town.getOwnerId() == -1) {
                outlawTowns.add(town);
            } else {
                playerTowns.add(town);
            }
        }
    }
    if (outlawTowns.size() == 0 && playerTowns.size() == 0) {
        System.out.print("WIN : D");
        return;
    }

    if (phase == 2) {
        steal();
    } else if (phase == 3) {
        recruit();
    } else if (phase == 6) {
        convert();
    } else if (phase == 7) {
        attack();
    } else if (phase == 8) {
        resurrect();
    } else if (phase == 9) {
        move();
    } else if (phase == 11) {
        build();
    }
}

private List<Town> calcStrongestPlayers() {
    if (playerTowns.size() == 0) {
        return outlawTowns;
    }

    Map<Integer, Integer> playerTownCount = new HashMap<Integer, Integer>();
    Integer count;
    int maxCount = 0;
    for (Town town : playerTowns) {
        count = playerTownCount.get(town.getOwnerId());
        if (count == null) {
            count = Integer.valueOf(1);
        } else {
            count = Integer.valueOf(count + 1);
        }
        playerTownCount.put(town.getOwnerId(), count);

        if (count > maxCount) {
            maxCount = count;
        }
    }
    Set<Integer> strongestPlayers = new HashSet<Integer>();
    for (Entry<Integer, Integer> entry : playerTownCount.entrySet()) {
        if (entry.getValue() == maxCount) {
            strongestPlayers.add(entry.getKey());
        }
    }

    return playerTowns.stream().filter(a -> strongestPlayers.contains(a.getOwnerId())).collect(Collectors.toList());
}

private void steal() {
    // S destinationId corsairs
    List<Town> afterFilter = calcStrongestPlayers().stream().filter(a -> a.getGold() > 0).collect(Collectors.toList());
    if (afterFilter.size() == 0) {
        afterFilter = calcStrongestPlayers();
    }
    Town poorestTown = afterFilter.stream().min((a, b) -> a.gold - b.gold).get();
    System.out.println("S " + poorestTown.getId() + " " + thisTown.getCorsairs());
}

private boolean willAttackSoon() {
    Town strongestTown;
    if (playerTowns.size() > 0) {
        strongestTown = playerTowns.stream().max((a, b) -> a.getSoldiers() - b.getSoldiers()).get();
        if ((thisTown.getSoldiers() + thisTown.getBishops()) / 3 <= strongestTown.getSoldiers()) {
            return false;
        }
    }

    strongestTown = calcStrongestPlayers().stream().max((a, b) -> a.getSoldiers() - b.getSoldiers()).get();

    int deltaWarlocks = thisTown.getWarlocks() - (strongestTown.getWarlocks() + strongestTown.getAmazons());
    int deltaCrusaders = thisTown.getCrusaders() - (strongestTown.getCrusaders() + strongestTown.getWarlocks());
    int deltaAmazons = thisTown.getAmazons() - (strongestTown.getAmazons() + strongestTown.getCrusaders());

    return (deltaWarlocks + deltaCrusaders + deltaAmazons) > 0;
}

private void recruit() {
    // R warlocks crusaders amazons corsairs bishops necros architects
    int peonsAvailable = Math.max(0, thisTown.getPeons() - round);

    int corsairNeed = calcCorsairsNeeded(thisTown);
    int goldForNecros = Math.min(thisTown.getCorpses(), thisTown.getNecros() * NECRO_RAISE_CAPACITY) * GOLD_PER_RESURRECTION;
    int goldAvailable = thisTown.getGold() - thisTown.getBishops() * GOLD_PER_CONVERSION - goldForNecros - GOLD_COST_BUILDING + calcWages(thisTown)
            - (calcCashflow(thisTown) < GOLD_MAX_DEBT ? (corsairNeed * CORSAIR_SURVEILLANCE_RATIO * GOLD_PER_STEAL) : 0);
    int corsairGoldAvailable = thisTown.getGold() + calcWages(thisTown) - goldForNecros;
    boolean onlyCorsair = false;
    if (goldAvailable < 0) {
        if (corsairGoldAvailable > 0) {
            onlyCorsair = true;
            goldAvailable = corsairGoldAvailable;
        } else {
            System.out.println("W");
            return;
        }
    }

    int necroNeed = Math.max(0, (int) Math.ceil(1.0 * thisTown.getCorpses() / NECRO_RAISE_CAPACITY) - thisTown.getNecros());
    necroNeed = Math.max(necroNeed, Math.min(peonsAvailable, calcOtherNecrosNeeded() / 3));
    int architectNeed = Math.max(0, ARCHITECTS - thisTown.getArchitects());

    int necros = 0;
    if (!onlyCorsair) {
        int necroCost = GOLD_RECRUIT_NECRO + GOLD_PER_RESURRECTION * NECRO_RAISE_CAPACITY - GOLD_PER_NECRO;
        necros = Math.min(necroNeed, goldAvailable / necroCost);
        goldAvailable -= necros * necroCost;
        peonsAvailable -= necros;
    }

    if (willAttackSoon()) {
        corsairNeed = calcCorsairSpread(thisTown) * 2 - thisTown.getCorsairs();
    }
    corsairNeed = (int) Math.max(corsairNeed, calcOtherCorsairsNeeded());

    int corsairCost = GOLD_RECRUIT_CORSAIR - GOLD_PER_CORSAIR;
    int corsairs = Math.min(corsairNeed, peonsAvailable);
    corsairs = Math.min(corsairs, goldAvailable / corsairCost);
    goldAvailable -= corsairs * corsairCost;
    peonsAvailable -= corsairs;

    int architects = 0;
    if (!onlyCorsair) {
        int architectCost = GOLD_RECRUIT_ARCHITECT - GOLD_PER_ARCHITECT;
        architects = Math.min(architectNeed, peonsAvailable);
        architects = Math.min(architects, goldAvailable / architectCost);
        goldAvailable -= architects * architectCost;
        peonsAvailable -= architects;
    }

    int bishops = 0;
    if (!onlyCorsair) {
        int peonParts;
        if (round <= 50) {
            peonParts = 20;
        } else if (round <= 70) {
            peonParts = 15;
        } else if (round <= 90) {
            peonParts = 10;
        } else if (round <= 95) {
            peonParts = 5;
        } else {
            peonParts = 3;
        }
        int peonsLeft = Math.max(0, thisTown.getPeons() - (necros + corsairs + architects));
        bishops = (int) Math.min(Math.min(peonsAvailable, peonsLeft / peonParts), goldAvailable / (GOLD_RECRUIT_BISHOP + GOLD_PER_CONVERSION - GOLD_PER_BISHOP));
    }

    if (corsairs > 0 || bishops > 0 || necros > 0 || architects > 0) {
        System.out.println("R 0 0 0 " + corsairs + " " + bishops + " " + necros + " " + architects);
    } else {
        System.out.println("W");
    }
}

private int calcCashflow(Town town) {
    int taxes = (town.getSurvivingPeons() * GOLD_PER_PEON);
    taxes += ((town.getWarlocks() + town.getBishops() + town.getNecros()) * (town.getTemple() * GOLD_PER_TEMPLE));
    taxes += ((town.getCrusaders() + town.getAmazons()) * (town.getBarracks() * GOLD_PER_BARRACKS));
    taxes += ((town.getSurvivingPeons() + town.getCorsairs()) * (town.getEstate() * GOLD_PER_ESTATE));
    taxes += (town.getPalace() * GOLD_PER_PALACE);

    int wages = calcWages(town);

    return taxes + wages;
}

private int calcWages(Town town) {
    int wages = (town.getWarlocks() * GOLD_PER_WARLOCK);
    wages += (town.getCrusaders() * GOLD_PER_CRUSADER);
    wages += (town.getAmazons() * GOLD_PER_AMAZON);
    wages += (town.getCorsairs() * GOLD_PER_CORSAIR);
    wages += (town.getBishops() * GOLD_PER_BISHOP);
    wages += (town.getNecros() * GOLD_PER_NECRO);
    wages += (town.getArchitects() * GOLD_PER_ARCHITECT);
    return wages;
}

private int calcCorsairSpread(Town calcTown) {
    int outlaws = 0;
    for (Town town : outlawTowns) {
        outlaws += town.getPopulation();
    }

    return (int) Math.ceil(1.0 * Math.floorDiv(outlaws, (playerTowns.size() + myTowns.size())) / CORSAIR_SURVEILLANCE_RATIO);
}

private int calcCorsairsNeeded(Town town) {
    return Math.max(0, calcCorsairSpread(town) - town.getCorsairs());
}

private int calcFreeCorsairs(Town town) {
    return Math.max(0, town.getCorsairs() - calcCorsairSpread(town));
}

private int calcOtherNecrosNeeded() {
    int necrosNeed = 0;
    for (Town town : myTowns) {
        if (town == thisTown) {
            continue;
        }
        necrosNeed += Math.max(0, (int) Math.ceil(1.0 * town.getCorpses() / NECRO_RAISE_CAPACITY) - town.getNecros());
    }
    int necrosAvailable = Math.max(0, thisTown.getNecros() - (int) Math.ceil(1.0 * thisTown.getCorpses() / NECRO_RAISE_CAPACITY));
    return Math.max(0, necrosNeed - necrosAvailable);
}

private int calcOtherCorsairsNeeded() {
    int corsairsNeed = 0;
    for (Town town : myTowns) {
        if (town == thisTown) {
            continue;
        }
        corsairsNeed += calcCorsairsNeeded(town);
    }
    return Math.max(0, corsairsNeed - calcFreeCorsairs(thisTown));
}

private void convert() {
    // C destinationId warlocks crusaders amazons
    final int MIN_CONVERT_PERCENTAGE = 10;

    int goldAvailable = thisTown.getGold() - thisTown.getCorpses() * GOLD_PER_RESURRECTION - GOLD_COST_BUILDING
            - (calcCashflow(thisTown) < GOLD_MAX_DEBT ? (calcCorsairsNeeded(thisTown) * CORSAIR_SURVEILLANCE_RATIO * GOLD_PER_STEAL) : 0);
    if (goldAvailable < 0) {
        System.out.println("W");
        return;
    }

    final int canConvert = Math.min(thisTown.getBishops(), goldAvailable / GOLD_PER_CONVERSION);
    if (canConvert == 0) {
        System.out.println("W");
        return;
    }

    List<Town> useTowns = calcStrongestPlayers();

    List<Town> afterFilter = useTowns.stream().filter(a -> a.getSoldiers() > canConvert / MIN_CONVERT_PERCENTAGE).collect(Collectors.toList());
    if (afterFilter.size() == 0) {
        if (playerTowns.size() > 0) {
            useTowns = playerTowns;
        } else {
            useTowns = outlawTowns;
        }
    }
    afterFilter = useTowns.stream().filter(a -> a.getSoldiers() > canConvert).collect(Collectors.toList());
    float getNear = 1.0f;
    while (afterFilter.size() == 0) {
        getNear -= 0.1f;
        final float toLower = getNear;
        afterFilter = useTowns.stream().filter(a -> a.getSoldiers() > canConvert * toLower).collect(Collectors.toList());
    }
    Town smallestTown = afterFilter.stream().min((a, b) -> a.getSoldiers() - b.getSoldiers()).get();

    Town convertTown;
    if (smallestTown.getSoldiers() < canConvert / MIN_CONVERT_PERCENTAGE) {
        convertTown = useTowns.stream().max((a, b) -> a.getSoldiers() - b.getSoldiers()).get();
    } else {
        convertTown = smallestTown;
    }

    int leftToConvert = canConvert;
    int warlocks = Math.min(leftToConvert, convertTown.getWarlocks());
    leftToConvert -= warlocks;
    int crusaders = Math.min(leftToConvert, convertTown.getCrusaders());
    leftToConvert -= crusaders;
    int amazons = Math.min(leftToConvert, convertTown.getAmazons());
    leftToConvert -= amazons;

    System.out.println("C " + convertTown.getId() + " " + warlocks + " " + crusaders + " " + amazons);
}

private void attack() {
    // A destinationId warlocks crusaders amazons

    Town strongestTown;
    if (playerTowns.size() > 0) {
        strongestTown = playerTowns.stream().max((a, b) -> a.getSoldiers() - b.getSoldiers()).get();
        if (thisTown.getSoldiers() / 3 <= strongestTown.getSoldiers()) {
            System.out.println("W");
            return;
        }
    }

    strongestTown = calcStrongestPlayers().stream().max((a, b) -> a.getSoldiers() - b.getSoldiers()).get();

    int warlockNeed = strongestTown.getWarlocks() + strongestTown.getAmazons();
    int crusaderNeed = strongestTown.getCrusaders() + strongestTown.getWarlocks();
    int amazonNeed = strongestTown.getAmazons() + strongestTown.getCrusaders();
    int deltaWarlocks = thisTown.getWarlocks() - warlockNeed;
    int deltaCrusaders = thisTown.getCrusaders() - crusaderNeed;
    int deltaAmazons = thisTown.getAmazons() - amazonNeed;

    if ((deltaWarlocks + deltaCrusaders + deltaAmazons) > 0) {
        // calc Needed Troops
        int warlocks = Math.min(thisTown.getWarlocks(), warlockNeed);
        int crusaders = Math.min(thisTown.getCrusaders(), crusaderNeed);
        int amazons = Math.min(thisTown.getAmazons(), amazonNeed);
        if ((warlocks + crusaders + amazons) == 0) {
            warlocks = 1;
            crusaders = 1;
            amazons = 1;
        } else {
            while (deltaWarlocks < 0 || deltaCrusaders < 0 || deltaAmazons < 0) {
                if (deltaWarlocks < 0) {
                    deltaCrusaders += deltaWarlocks;
                    crusaders -= deltaWarlocks;
                    deltaWarlocks = 0;
                }
                if (deltaCrusaders < 0) {
                    deltaAmazons += deltaCrusaders;
                    amazons -= deltaCrusaders;
                    deltaCrusaders = 0;
                }
                if (deltaAmazons < 0) {
                    deltaWarlocks += deltaAmazons;
                    warlocks -= deltaAmazons;
                    deltaAmazons = 0;
                }
            }
        }
        System.out.println("A " + strongestTown.getId() + " " + warlocks + " " + crusaders + " " + amazons);
    } else {
        System.out.println("W");
    }
}

private void resurrect() {
    // R corpses
    int goldAvailable = thisTown.getGold();
    if (goldAvailable < 0) {
        System.out.println("W");
        return;
    }

    int raise = Math.min(thisTown.getCorpses(), goldAvailable / GOLD_PER_RESURRECTION);
    if (raise > 0) {
        System.out.println("R " + raise);
    } else {
        System.out.println("W");
    }
}

private void move() {
    if (myTowns.size() == 1) {
        System.out.println("W");
        return;
    }

    // M destinationId warlocks crusaders amazons corsairs bishops necros architects
    // T DestinationId Gold

    int thisStolenGold = calcCorsairsNeeded(thisTown) * CORSAIR_SURVEILLANCE_RATIO * GOLD_PER_STEAL;
    int thisGoldAvailable = Math.max(-GOLD_MAX_DEBT, thisTown.getGold() - thisStolenGold);
    int thisCashFlow = calcCashflow(thisTown);

    if (thisGoldAvailable + thisCashFlow <= 0) {
        // Give up the town
        Town sendToTown = myTowns.stream().filter(a -> a.getId() != thisTown.getId()).max((a, b) -> a.getSoldiers() - b.getSoldiers()).get();
        System.out.print("M " + sendToTown.getId() + " " + thisTown.getWarlocks() + " " + thisTown.getCrusaders() + " " + thisTown.getAmazons() + " " + thisTown.getCorsairs() + " "
                + thisTown.getBishops() + " " + thisTown.getNecros() + " " + thisTown.getArchitects());
        return;
    }
    thisGoldAvailable += thisCashFlow;

    int thisCostOfBishop = thisTown.getTemple() * GOLD_PER_TEMPLE + GOLD_PER_BISHOP;
    int thisCostOfNecro = thisTown.getTemple() * GOLD_PER_TEMPLE + GOLD_PER_NECRO;
    int thisCostOfWarlock = thisTown.getTemple() * GOLD_PER_TEMPLE + GOLD_PER_WARLOCK;
    int thisCostOfCrusader = thisTown.getBarracks() * GOLD_PER_BARRACKS + GOLD_PER_CRUSADER;
    int thisCostOfAmazon = thisTown.getBarracks() * GOLD_PER_BARRACKS + GOLD_PER_AMAZON;
    int thisCostOfCorsair = thisTown.getEstate() * GOLD_PER_ESTATE + GOLD_PER_CORSAIR;

    int thisCorsairsAvailable = calcFreeCorsairs(thisTown);
    int thisNecrosAvailable = Math.max(0, thisTown.getNecros() - (int) Math.ceil(1.0 * thisTown.getCorpses() / NECRO_RAISE_CAPACITY));
    int thisBishopsAvailable = Math.max(0, thisTown.getBishops() - (int) Math.ceil(1.0 * thisTown.getPeons() / BISHOP_PRAYER_CAPACITY));
    int thisArchitectsAvailable = Math.max(0, thisTown.getArchitects() - ARCHITECTS);

    int strongestTownSoldiers = 0;
    if (playerTowns.size() > 0) {
        Town strongestTown = playerTowns.stream().max((a, b) -> a.getSoldiers() - b.getSoldiers()).get();
        strongestTownSoldiers = strongestTown.getSoldiers();
    }
    int thisSoldiersAvailable = Math.max(0, thisTown.getSoldiers() - strongestTownSoldiers);
    int thisWarlocksAvailable = thisSoldiersAvailable / 3;
    thisSoldiersAvailable -= thisWarlocksAvailable;
    int thisCrusadersAvailable = thisSoldiersAvailable / 2;
    thisSoldiersAvailable -= thisCrusadersAvailable;
    int thisAmazonsAvailable = thisSoldiersAvailable;
    int warlockDelta = thisWarlocksAvailable - thisTown.getWarlocks();
    int crusaderDelta = thisCrusadersAvailable - thisTown.getCrusaders();
    int amazonDelta = thisAmazonsAvailable - thisTown.getAmazons();
    while (warlockDelta > 0 || crusaderDelta > 0 || amazonDelta > 0) {
        if (warlockDelta > 0) {
            thisWarlocksAvailable -= warlockDelta;
            thisCrusadersAvailable += warlockDelta;
            crusaderDelta += warlockDelta;
            warlockDelta = 0;
        }
        if (crusaderDelta > 0) {
            thisCrusadersAvailable -= crusaderDelta;
            thisAmazonsAvailable += crusaderDelta;
            amazonDelta += crusaderDelta;
            crusaderDelta = 0;
        }
        if (amazonDelta > 0) {
            thisAmazonsAvailable -= amazonDelta;
            thisWarlocksAvailable += amazonDelta;
            warlockDelta += amazonDelta;
            amazonDelta = 0;
        }
    }

    // Calc loosing income for each x the town sends
    int tempThisGoldAvailable = thisGoldAvailable;
    if (thisCostOfCorsair > 0) {
        thisCorsairsAvailable = Math.min(thisCorsairsAvailable, tempThisGoldAvailable / thisCostOfCorsair);
        tempThisGoldAvailable -= thisCorsairsAvailable * thisCostOfCorsair;
    } // else dont plus the gold - would get too complicated
    if (thisCostOfWarlock > 0) {
        thisWarlocksAvailable = Math.min(thisWarlocksAvailable, tempThisGoldAvailable / thisCostOfWarlock);
        tempThisGoldAvailable -= thisWarlocksAvailable * thisCostOfWarlock;
    }
    if (thisCostOfCrusader > 0) {
        thisCrusadersAvailable = Math.min(thisCrusadersAvailable, tempThisGoldAvailable / thisCostOfCrusader);
        tempThisGoldAvailable -= thisCrusadersAvailable * thisCostOfCrusader;
    }
    if (thisCostOfAmazon > 0) {
        thisAmazonsAvailable = Math.min(thisAmazonsAvailable, tempThisGoldAvailable / thisCostOfAmazon);
        tempThisGoldAvailable -= thisAmazonsAvailable * thisCostOfAmazon;
    }
    if (thisCostOfNecro > 0) {
        thisNecrosAvailable = Math.min(thisNecrosAvailable, tempThisGoldAvailable / thisCostOfNecro);
        tempThisGoldAvailable -= thisNecrosAvailable * thisCostOfNecro;
    }
    if (thisCostOfBishop > 0) {
        thisBishopsAvailable = Math.min(thisBishopsAvailable, tempThisGoldAvailable / thisCostOfBishop);
        tempThisGoldAvailable -= thisBishopsAvailable * thisCostOfBishop;
    }

    boolean checkGoldNeed;
    boolean needsGold;
    for (int i = 0; i < 2; i++) {
        checkGoldNeed = i == 0;
        for (Town town : myTowns) {
            if (town == thisTown) {
                continue;
            }
            needsGold = false;

            int costOfBishop = town.getTemple() * GOLD_PER_TEMPLE + GOLD_PER_BISHOP;
            int costOfNecro = town.getTemple() * GOLD_PER_TEMPLE + GOLD_PER_NECRO;
            int costOfWarlock = town.getTemple() * GOLD_PER_TEMPLE + GOLD_PER_WARLOCK;
            int costOfCrusader = town.getBarracks() * GOLD_PER_BARRACKS + GOLD_PER_CRUSADER;
            int costOfAmazon = town.getBarracks() * GOLD_PER_BARRACKS + GOLD_PER_AMAZON;
            int costOfCorsair = town.getEstate() * GOLD_PER_ESTATE + GOLD_PER_CORSAIR;

            int corsairsNeed = calcCorsairsNeeded(town);
            int sendCorsairs = Math.min(corsairsNeed, thisCorsairsAvailable);
            int goldStolen = corsairsNeed * CORSAIR_SURVEILLANCE_RATIO * GOLD_PER_STEAL;
            int goldAvailable = town.getGold() - goldStolen;
            int goldAvailableWithCorsairs = Math.max(-GOLD_MAX_DEBT, goldAvailable + sendCorsairs * CORSAIR_SURVEILLANCE_RATIO * GOLD_PER_STEAL);
            goldAvailable = Math.max(-GOLD_MAX_DEBT, goldAvailable);
            int cashflow = calcCashflow(town);
            if (goldAvailable + cashflow < 0) {
                needsGold = true;
            }
            tryToSwim: if (goldAvailableWithCorsairs < 0) {
                int potentialCashflow = cashflow + sendCorsairs * costOfCorsair;
                if (goldAvailableWithCorsairs + potentialCashflow >= 0) {
                    break tryToSwim;
                } else {
                    int potentialGoldAvailable = goldAvailableWithCorsairs + potentialCashflow;
                    if (costOfWarlock > 0) {
                        potentialGoldAvailable += thisWarlocksAvailable * costOfWarlock;
                    }
                    if (costOfCrusader > 0) {
                        potentialGoldAvailable += thisCrusadersAvailable * costOfCrusader;
                    }
                    if (costOfAmazon > 0) {
                        potentialGoldAvailable += thisAmazonsAvailable * costOfAmazon;
                    }
                    if (costOfNecro > 0) {
                        potentialGoldAvailable += thisNecrosAvailable * costOfNecro;
                    }
                    if (costOfBishop > 0) {
                        potentialGoldAvailable += thisBishopsAvailable * costOfBishop;
                    }
                    if (potentialGoldAvailable >= 0) {
                        System.out.print("M " + town.getId() + " " + thisWarlocksAvailable + " " + thisCrusadersAvailable + " " + thisAmazonsAvailable + " " + sendCorsairs + " "
                                + thisBishopsAvailable + " " + thisNecrosAvailable + " 0");
                        return;
                    }
                }

                // Last hope, check if enough gold can rescue the town from revolt
                int goldNeeded = -(town.getGold() - goldStolen + cashflow);
                if (thisGoldAvailable >= goldNeeded) {
                    System.out.println("T " + town.getId() + " " + goldNeeded);
                    return;
                }
                System.out.println("W");
                continue;
            }

            if (checkGoldNeed && !needsGold) {
                continue;
            }

            goldAvailable = goldAvailableWithCorsairs;
            goldAvailable += cashflow + sendCorsairs * costOfCorsair;
            int sendNecros = 0;
            int sendBishops = 0;
            int sendWarlocks = 0;
            int sendCrusaders = 0;
            int sendAmazons = 0;
            int sendArchitects = 0;

            int soldiersNeed = Math.max(0, strongestTownSoldiers - town.getSoldiers());
            int lastNeededSoldiers = 0;
            while (soldiersNeed > 0 && (thisWarlocksAvailable > 0 || thisCrusadersAvailable > 0 || thisAmazonsAvailable > 0) && soldiersNeed != lastNeededSoldiers) {
                lastNeededSoldiers = soldiersNeed;
                if (thisWarlocksAvailable > 0) {
                    goldAvailable += costOfWarlock;
                    if (goldAvailable < 0) {
                        goldAvailable -= costOfWarlock;
                    } else {
                        soldiersNeed--;
                        thisWarlocksAvailable--;
                        sendWarlocks++;
                    }
                }
                if (thisCrusadersAvailable > 0) {
                    goldAvailable += costOfCrusader;
                    if (goldAvailable < 0) {
                        goldAvailable -= costOfCrusader;
                    } else {
                        soldiersNeed--;
                        thisCrusadersAvailable--;
                        sendCrusaders++;
                    }
                }
                if (thisAmazonsAvailable > 0) {
                    goldAvailable += costOfAmazon;
                    if (goldAvailable < 0) {
                        goldAvailable -= costOfAmazon;
                    } else {
                        soldiersNeed--;
                        thisAmazonsAvailable--;
                        sendAmazons++;
                    }
                }
            }

            int necrosNeed = Math.max(0, (int) Math.ceil(1.0 * town.getCorpses() / NECRO_RAISE_CAPACITY) - town.getNecros());
            int necrosCanAfford = costOfNecro < 0 ? Math.min(necrosNeed, goldAvailable / -costOfNecro) : necrosNeed;
            if (necrosCanAfford > 0) {
                sendNecros = Math.min(necrosCanAfford, thisNecrosAvailable);
                goldAvailable += sendNecros * costOfNecro;
            }

            int bishopsNeed = Math.max(0, (int) Math.ceil(1.0 * town.getPeons() / BISHOP_PRAYER_CAPACITY) - town.getBishops());
            int bishopsCanAfford = costOfBishop < 0 ? Math.min(bishopsNeed, goldAvailable / -costOfBishop) : bishopsNeed;
            if (bishopsCanAfford > 0) {
                sendBishops = Math.min(bishopsCanAfford, thisBishopsAvailable);
                goldAvailable += sendBishops * costOfBishop;
            }

            int architectsNeed = Math.max(0, (int) Math.ceil(1.0 * COMPLETION_NEEDED / COMPLETION_PER_ARCHITECT) - thisTown.getArchitects());
            int architectsCanAfford = Math.min(architectsNeed, goldAvailable / Math.abs(GOLD_PER_ARCHITECT));
            sendArchitects = Math.min(architectsCanAfford, thisArchitectsAvailable);

            if (sendWarlocks > 0 || sendCrusaders > 0 || sendAmazons > 0 || sendCorsairs > 0 || sendBishops > 0 || sendNecros > 0 || sendArchitects > 0) {
                System.out.print("M " + town.getId() + " " + sendWarlocks + " " + sendCrusaders + " " + sendAmazons + " " + sendCorsairs + " " + sendBishops + " " + sendNecros + " "
                        + sendArchitects);
                return;
            }
        }
    }

    System.out.println("W");
}

private void build() {
    // B building building building...
    // (T: Temple, B: Barracks, E: Estate, P: Palace)

    int goldAvailable = thisTown.getGold() - (calcCashflow(thisTown) < GOLD_MAX_DEBT ? (calcCorsairsNeeded(thisTown) * CORSAIR_SURVEILLANCE_RATIO * GOLD_PER_STEAL) : 0);
    if (goldAvailable >= GOLD_COST_BUILDING) {
        char building = 'E';
        int templeUnits = thisTown.getWarlocks() + thisTown.getBishops() + thisTown.getNecros();
        int barracksUnits = thisTown.getCrusaders() + thisTown.getAmazons();
        int estateUnits = thisTown.getCorsairs() + thisTown.getPeons();
        if (templeUnits > barracksUnits) {
            if (templeUnits > estateUnits) {
                building = 'T';
            }
        } else {
            if (barracksUnits > estateUnits) {
                building = 'B';
            }
        }
        System.out.println("B " + building);
    } else {
        System.out.println("W");
    }
}

private class Town {

    private final int ownerId;
    private final int id;
    private final int gold;
    private final int corpses;
    private final int warlocks;
    private final int crusaders;
    private final int amazons;
    private final int corsairs;
    private final int bishops;
    private final int necros;
    private final int architects;
    private final int peons;
    private final int temple;
    private final int barracks;
    private final int estate;
    private final int palace;

    public Town(String string) {
        String[] args = string.split("_");
        ownerId = Integer.parseInt(args[0]);
        id = Integer.parseInt(args[1]);
        gold = Integer.parseInt(args[2]);
        corpses = Integer.parseInt(args[3]);
        warlocks = Integer.parseInt(args[4]);
        crusaders = Integer.parseInt(args[5]);
        amazons = Integer.parseInt(args[6]);
        corsairs = Integer.parseInt(args[7]);
        bishops = Integer.parseInt(args[8]);
        necros = Integer.parseInt(args[9]);
        architects = Integer.parseInt(args[10]);
        peons = Integer.parseInt(args[11]);
        temple = Integer.parseInt(args[12]);
        barracks = Integer.parseInt(args[13]);
        estate = Integer.parseInt(args[14]);
        palace = Integer.parseInt(args[15]);
    }

    public int getOwnerId() {
        return ownerId;
    }

    public int getId() {
        return id;
    }

    public int getGold() {
        return gold;
    }

    public int getCorpses() {
        return corpses;
    }

    public int getWarlocks() {
        return warlocks;
    }

    public int getCrusaders() {
        return crusaders;
    }

    public int getAmazons() {
        return amazons;
    }

    public int getCorsairs() {
        return corsairs;
    }

    public int getBishops() {
        return bishops;
    }

    public int getNecros() {
        return necros;
    }

    public int getArchitects() {
        return architects;
    }

    public int getPeons() {
        return peons;
    }

    public int getSurvivingPeons() {
        int peons = this.peons;
        int zombies = Math.floorDiv(corpses, ZOMBIE_WAKING_CHANCE);
        peons = Math.max(0, peons - zombies);
        int demons = Math.floorDiv(peons - (bishops * BISHOP_PRAYER_CAPACITY), DEMON_SUMMON_CHANCE);
        peons = Math.max(0, peons - demons);
        if (round % BIRTH_ROUND == 0) {
            peons += Math.floorDiv(peons, 2);
        }
        return peons;
    }

    public int getTemple() {
        return temple;
    }

    public int getBarracks() {
        return barracks;
    }

    public int getEstate() {
        return estate;
    }

    public int getPalace() {
        return palace;
    }

    public int getSoldiers() {
        return getWarlocks() + getCrusaders() + getAmazons();
    }

    public int getUnits() {
        return getSoldiers() + getCorsairs() + getBishops() + getNecros() + getArchitects();
    }

    public int getPopulation() {
        return getUnits() + getPeons();
    }

    public boolean isMine() {
        return getOwnerId() == playerID;
    }

    public boolean isThisTown() {
        return id == thisTownID;
    }
}
}

Я работал над чем-то вроде этого. Правильно ли я сказал, что это становится безумно богатым?
TheNumberOne

Да, это действительно очень большой доход xD
Sehtim

3

Макиавелли, Питон 2

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

import sys, re
from random import *
from operator import itemgetter
import cPickle

(PLAYER, TOWN, GOLD, CORPSES, WARLOCKS, CRUSADERS, AMAZONS, 
CORSAIRS, BISHOPS, NECROMANCERS, ARCHITECTS, PEONS, 
TEMPLES, BARRACKS, ESTATES, PALACES) = range(16)

def getfighters(t): return sum(t[WARLOCKS:WARLOCKS+3])
def threat(t): return t[2] + sum(t[4:12])*12 + sum(t[12:16])*200
def spyon(t): return ( t[2] + min(30,t[3])*5 + t[11]*10 + 
    sum(t[12:16])*200 - getfighters(t)*20 )
def needs(t): return [bandits/5+1, t[PEONS]/50+1, t[CORPSES]/5+1, 7]
def wants(t): return [max(0, g-h) for g,h in zip(needs(t), t[7:11])]
def helpcheck(t): return sum(wants(t))

def choose(frequency, picks, span):
    'Return <picks> counts using samples from <frequency> in list <span>'
    choices = [choice(frequency) for i in range(picks)]
    return [choices.count(i) for i in range(span)]

if len(sys.argv) < 2:
    print 5, 15, 10, 20, 3, 4, 7, 36
else:
    parts = sys.argv[1].split(';')
    turn, phase, me, thistown = [int(parts.pop(0)) for i in range(4)]
    towns = [map(int, re.split(r'_', town)) for town in parts]
    # Analysis:
    enemy = [t for t in towns if t[PLAYER] != me]
    mytowns = [t for t in towns if t[PLAYER] == me]
    here = [t for t in mytowns if t[TOWN] == thistown][0]
    otherids = [t[TOWN] for t in enemy]
    fighters = sorted(enemy, key=getfighters)
    rich = sorted(enemy, key=itemgetter(GOLD))
    threats = sorted(enemy, key=threat)
    attractive = sorted(enemy, key=spyon)
    # Useful numbers:
    avgfighters = sum(map(getfighters, enemy)) / len(enemy)
    wages = getfighters(here) + sum(here[CORSAIRS:CORSAIRS+4]) * 2
    outlaws = sum(sum(t[4:12]) for t in towns if t[PLAYER] == -1)
    freetowns = len([t for t in towns if t[PLAYER] != -1])
    bandits = outlaws / freetowns
    # Depends on above
    needhelp = sorted(mytowns, key=helpcheck)
    needhelp.remove(here)

    try:
        plans = cPickle.load(open('Machiavelli.txt', 'rb'))
    except:
        plans = {}
    bribes, raises, gobuild = plans.get(thistown, (0,0,''))

    output = 'W'
    if phase == 2:
        output = 'S %s 100' % rich[-1][TOWN]  # take from the rich ...
    elif phase == 3:
        # Decide strategy here:
        cash = here[GOLD] - wages
        forces = getfighters(here)
        raises = min(here[NECROMANCERS]*5, here[CORPSES], cash/20)
        cash -= raises * 20
        bribes = trainftr = trainextra = 0
        gobuild = ''
        if forces < avgfighters:
            bribes = min(here[BISHOPS], cash/50)
            cash -= bribes * 50
            trainftr = min(max(0, here[PEONS]-30), cash/10)
            cash -= trainftr * 10
        if cash > 200 and turn % 2 == 0:
            gobuild = choice('EEB')
            cash -= 200
        bribes2 = min(here[BISHOPS] - bribes, cash/50)
        cash -= bribes2 * 50
        bribes += bribes2
        trainextra = min(max(0, here[PEONS]-30), cash/50)
        # Write plan to file:
        plans[thistown] = (bribes, raises, gobuild)
        cPickle.dump(plans, open('Machiavelli.txt', 'wb'), -1)

        # Output recruitment decision:
        if trainftr + trainextra:
            getutil = wants(here)
            if sum(getutil) > trainextra:
                utilbias = ( [0]*getutil[0]*3 + [1]*getutil[1]*3 + 
                            [2]*(getutil[2]) + [3]*(getutil[3]) )
                getutil = choose(utilbias, trainextra, 4)
            getftr = choose([0,1,1,2], trainftr, 3)
            getpers = getftr + getutil
            if sum(getutil) < trainextra:
                othernum = trainextra - sum(getutil)
                others = choose([0,1,1,2,3,4,6], othernum, 7)
                getpers = [p+q for p,q in zip(getpers, others)]
            output = 'R %u %u %u %u %u %u %u' % tuple(getpers)
    elif phase == 6:
        if bribes:
            soldiers = choose([0,1,2], bribes, 3)
            target = fighters[-1][TOWN]
            output = 'C %s %s %s %s' % tuple([target] + soldiers)
    elif phase == 7:
        if getfighters(here) > avgfighters * 1.3:
            myarmy = here[WARLOCKS : WARLOCKS+3]
            raiders = sum(myarmy) / 2
            for n in range(raiders):
                force = [min(myarmy[i], n) for i in (0,1,2)]
                if sum(force) >= raiders:
                    break
            for target in attractive[::-1]:
                if raiders > getfighters(target) * 2.5:
                    output = 'A %s %s %s %s' % tuple([target[TOWN]] + force)
                    break
    elif phase == 8:
        if raises:
            output = 'R %s' % raises
    elif phase == 9:
        if needhelp:
            town = needhelp[-1]
            excess = [max(0, g-h) for g,h in zip(here[7:11], needs(here))]
            send = [min(g, h) for g,h in zip(excess, wants(town))]
            if sum(send) > 0:
                output = 'M %u 0 0 0 %u %u %u %u' % tuple([town[TOWN]] + send)
    elif phase == 11:   
        if gobuild:
            output = 'B %s' % gobuild
    print output

2

Монарх (Рубин)

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

$BONUS = 1.5
class Town

  attr_accessor :player, :town, :gold, :corpses, :warlocks, :crusaders, :amazons, 
    :corsairs, :bishops, :necromancers, :architects, :peons, :temples, :barracks, 
    :estates, :palaces

  def initialize(arg)
    args = arg.split("_")
    @player = args[0].to_i
    @town = args[1].to_i
    @gold = args[2].to_i
    @corpses = args[3].to_i
    @warlocks = args[4].to_i
    @crusaders = args[5].to_i
    @amazons = args[6].to_i
    @corsairs = args[7].to_i
    @bishops = args[8].to_i
    @necromancers = args[9].to_i
    @architects = args[10].to_i
    @peons = args[11].to_i
    @temples = args[12].to_i
    @barracks = args[13].to_i
    @estates = args[14].to_i
    @palaces = args[15].to_i
  end  
  def soldiers
    @warlocks + @crusaders + @amazons
  end 
  def units
    self.soldiers + @corsairs + @bishops + @necromancers + @architects
  end  
  def citizens
    self.units + @peons
  end  
  def buildings
    @temples + @barracks + @estates + @palaces
  end
  def cash
    @gold - (self.units * 2) - 50
  end
  def flesh
    @peons - (self.units * 2 / 5)
  end
end

def stronger(aW, aC, aA, dW, dC, dA)
  aW - [[0, aW - dW].max, dA].min + ([[0, aW - dW].max, dA].min * $BONUS) + aC - [[0, aC - dC].max, dW].min + ([[0, aC - dC].max, dW].min * $BONUS) + aA - [[0, aA - dA].max, dC].min + ([[0, aA - dA].max, dC].min * $BONUS)  > dW - [[0, dW - aW].max, aA].min + ([[0, dW - aW].max, aA].min * $BONUS) + dC - [[0, dC - aC].max, aW].min + ([[0, dC - aC].max, aW].min * $BONUS) + dA - [[0, dA - aA].max, aC].min + ([[0, dA - aA].max, aC].min * $BONUS) 
end

if ARGV.size < 1 
  puts "12 12 12 8 2 2 2 50"
else
  args = ARGV[0].split(";")

  round = args[0].to_i
  phase = args[1].to_i
  thisPlayer = args[2].to_i
  thisTownId = args[3].to_i
  towns, myTowns, enemyTowns = Array.new, Array.new, Array.new

  args[4..-1].each {|arg|arg.split(";").each {|t|towns.push(Town.new(t))}}
  towns.each {|town|town.player == thisPlayer ? myTowns.push(town) : enemyTowns.push(town)}
  thisTown = towns[towns.index{|t|t.town == thisTownId}]
  strongestTown = enemyTowns.sort{|x,y|y.soldiers<=>x.soldiers}.fetch(0)  
  weakestTown = enemyTowns.sort{|x,y|x.soldiers<=>y.soldiers}.fetch(0)  
  baseTown = myTowns.sort{|x,y|y.peons<=>x.peons}.fetch(0)    

  case phase
  when 2
    puts "S " + strongestTown.town.to_s + " " + thisTown.corsairs.to_s
  when 3
    if (thisTown.cash > 90)
      recruits = [[(thisTown.cash - 90) / 10, thisTown.flesh].min / 5, 0].max
      puts "R " + recruits.to_s + " " + recruits.to_s + " " + (recruits*3).to_s + " " + [0, 2 - thisTown.corsairs].max.to_s + " " + [0, 2 - thisTown.bishops].max.to_s + " " + [0, 2 - thisTown.necromancers].max.to_s + " " + [0, 2 - thisTown.architects].max.to_s
    else
      puts "W"
    end
  when 6
    converts = [[thisTown.cash / 50, thisTown.bishops].min / 5, 0].max
    puts "C " + strongestTown.town.to_s + " " + (converts*3).to_s + " " + converts.to_s + " " + converts.to_s
  when 7
    if round > 10
      if stronger(thisTown.warlocks / 6, thisTown.crusaders / 6, thisTown.amazons / 6, strongestTown.warlocks, strongestTown.crusaders, strongestTown.amazons)
        puts "A " + strongestTown.town.to_s + " " +  (thisTown.warlocks/4).to_s + " " + (thisTown.crusaders/4).to_s + " " + (thisTown.amazons/4).to_s
      elsif stronger(thisTown.warlocks / 6, thisTown.crusaders / 6, thisTown.amazons / 6, weakestTown.warlocks, weakestTown.crusaders, weakestTown.amazons)
        puts "A " + weakestTown.town.to_s + " " +  (thisTown.warlocks/4).to_s + " " + (thisTown.crusaders/4).to_s + " " + (thisTown.amazons/4).to_s
      else
        puts "W"
      end
    else
      puts "W"
    end
  when 8
    puts "R 10"
  when 9
    if thisTown.town != baseTown.town
      if thisTown.soldiers > 0 
        puts "M " + baseTown.town.to_s + " " + thisTown.warlocks.to_s + " " + thisTown.crusaders.to_s + " " + thisTown.amazons.to_s
      else
        puts "T " + baseTown.town.to_s + " " + thisTown.cash
      end
    else
      puts "W"
    end
  when 11
    if thisTown.town == baseTown.town and thisTown.cash > 200 
      puts "B B" 
    else
      puts "W"
    end
  else
    puts "W"
  end
end

Чтобы запустить этот скрипт, вам нужен интерпретатор Ruby 1.9.3.

Бежать с : ruby Monarch.rb


1

Я могу написать только 30000 знаков в одном ответе xD. Вот мои ошибки, которые я нашел:

Муги уже сообщил об этом: int totalConvertible = (warlocksConvertible + crusadersConvertible + amazonsConvertible);

executeMovement: if (source.getCorsairs() >= corsairsCount) {

executeTheft: использовал источник вместо пункта назначения. Но не могли бы вы проверить, правильно ли рассчитан тогда? Моя рекомендация будет такой:int goldReserve = destination.getGold() + GOLD_MAX_DEBT > 0 ? destination.getGold() + GOLD_MAX_DEBT : GOLD_MAX_DEBT - Math.abs(destination.getGold());

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

private void executeRecruitment(Command support) {

    Town source = support.getSource();
    try {
        String[] args = support.getArgs();

        if (support.getCommand().equals("R") && args.length == 7) {
            int goldAvailable = source.getGold();
            if (goldAvailable <= 0) {
                return;
            }

            int warlocksCount = Math.max(0, Integer.parseInt(args[0]));
            int crusadersCount = Math.max(0, Integer.parseInt(args[1]));
            int amazonsCount = Math.max(0, Integer.parseInt(args[2]));
            int corsairsCount = Math.max(0, Integer.parseInt(args[3]));
            int bishopsCount = Math.max(0, Integer.parseInt(args[4]));
            int necromancersCount = Math.max(0, Integer.parseInt(args[5]));
            int architectsCount = Math.max(0, Integer.parseInt(args[6]));

            int originalWarlocksCount = warlocksCount;
            int originalCrusadersCount = crusadersCount;
            int originalAmazonsCount = amazonsCount;
            int originalCorsairsCount = corsairsCount;
            int originalBishopsCount = bishopsCount;
            int originalNecromancersCount = necromancersCount;
            int originalArchitectsCount = architectsCount;

            int unitsToRecruits = warlocksCount + crusadersCount + amazonsCount + corsairsCount + bishopsCount + necromancersCount + architectsCount;
            int peonsAvailable = source.getPeons();
            int recruitableUnits = Math.min(unitsToRecruits, peonsAvailable);
            if (recruitableUnits != unitsToRecruits) {
                RandomNumberGenerator random = new RandomNumberGenerator();
                int[] recruits = random.genNumberWithLimits(recruitableUnits, new int[] { warlocksCount, crusadersCount, amazonsCount, corsairsCount, bishopsCount, necromancersCount,
                        architectsCount });
                warlocksCount = recruits[0];
                crusadersCount = recruits[1];
                amazonsCount = recruits[2];
                corsairsCount = recruits[3];
                bishopsCount = recruits[4];
                necromancersCount = recruits[5];
                architectsCount = recruits[6];
            }

            int wouldCost;
            int index = 1;
            boolean tooExpensive = true;
            do {
                wouldCost = warlocksCount * GOLD_RECRUIT_WARLOCK + crusadersCount * GOLD_RECRUIT_CRUSADER + amazonsCount * GOLD_RECRUIT_AMAZON + corsairsCount * GOLD_RECRUIT_CORSAIR
                        + bishopsCount * GOLD_PER_BISHOP + necromancersCount * GOLD_RECRUIT_NECROMANCER + architectsCount * GOLD_RECRUIT_ARCHITECT;
                if (goldAvailable < wouldCost) {
                    RandomNumberGenerator random = new RandomNumberGenerator();
                    int[] recruits = random.genNumberWithLimits(recruitableUnits - index, new int[] { originalWarlocksCount, originalCrusadersCount, originalAmazonsCount, originalCorsairsCount,
                            originalBishopsCount, originalNecromancersCount, originalArchitectsCount });
                    warlocksCount = recruits[0];
                    crusadersCount = recruits[1];
                    amazonsCount = recruits[2];
                    corsairsCount = recruits[3];
                    bishopsCount = recruits[4];
                    necromancersCount = recruits[5];
                    architectsCount = recruits[6];
                } else {
                    tooExpensive = false;
                }
                index++;
            } while (tooExpensive);

            int recruted = warlocksCount + crusadersCount + amazonsCount + corsairsCount + bishopsCount + necromancersCount + architectsCount;
            if (recruted > 0) {
                source.setWarlocks(source.getWarlocks() + warlocksCount);
                source.setCrusaders(source.getCrusaders() + crusadersCount);
                source.setAmazons(source.getAmazons() + amazonsCount);
                source.setCorsairs(source.getCorsairs() + corsairsCount);
                source.setBishops(source.getBishops() + bishopsCount);
                source.setNecromancers(source.getNecromancers() + necromancersCount);
                source.setArchitects(source.getArchitects() + architectsCount);
                source.setPeons(source.getPeons() - recruted);
                source.setGold(source.getGold() - wouldCost);

                if (GAME_MESSAGES)
                    System.out.println(source.getOwner().getDisplayName() + " recruted " + recruted + " units (" + warlocksCount + " Wa / " + crusadersCount + " Cr / " + amazonsCount + " Am / "
                            + corsairsCount + " Co / " + bishopsCount + " Bi / " + necromancersCount + " Ne / " + architectsCount + " Ar)");
            }
        } else if (support.getCommand().equals("W")) {
            // Do nothing
        } else {
            if (DEBUG)
                System.out.println("Phase " + phase + " (Recruitment) : Invalid command by " + source.getOwner().getDisplayName() + "{" + source.getId() + "}");
        }
    } catch (Exception e) {
        if (DEBUG) {
            System.out.println("Exception in executeRecruitment() by " + source.getOwner().getDisplayName());
            e.printStackTrace();
        }
    }
}

Вау, большое спасибо, что нашли время проверить контроллер (спасибо @Moogie тоже). Я применил ваши исправления и через несколько часов проведу несколько тестовых игр.
Thrax
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.