KOTH: pueblos en guerra


22

Los resultados finales están aquí!

Introducción

El juego toma está fuertemente inspirado en Manu's Game of Town . Se lleva a cabo en un mundo de espadas y magia. El rey que gobernó todo el continente acaba de morir, y los señores de las muchas ciudades-estado ahora están luchando por el territorio. Usted es uno de estos señores y su objetivo es conquistar y gobernar cada ciudad.

Principio

Las personas se dividen en 8 clases :

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)

Cuando comienza el juego, gobiernas una ciudad. En cada pueblo hay 100 personas . Tienes que dividirlos entre esas 8 categorías.

Entonces comienza el juego real, que se basa en turnos. Un turno consta de 12 fases , 7 de las cuales son interactivas (solicitando un comando a los bots). La siguiente fase comienza cuando la fase anterior ha sido ejecutada por cada ciudad (Fase 1: Ciudad 1, Ciudad 2, Ciudad 3 ...; Fase 2: Ciudad 1, Ciudad 2, Ciudad 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

El controlador le proporciona entrada a través de argumentos de comando, su programa tiene que salir a través de stdout.

Sintaxis

Salida (preparación)
Antes de que comience el juego, el controlador invoca su presentación sin argumentos. Esto significa que debe distribuir a sus 100 personas en las 8 categorías.

Necesitas salida: Warlocks Crusaders Amazons Corsairs Bishops Necromancers Architects Peons

Por ejemplo: 15 10 12 10 7 5 1 40.

Cada ciudad también comienza con 500 de oro y 5 cadáveres.

Entrada
Cada vez que se llama a su programa, recibirá argumentos en este formato: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;...

Entrada de ejemplo 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;...

Aquí, ves que es la primera ronda, la segunda fase, eres el jugador 1 en la ciudad 1. Tienes 700 de oro, 5 cadáveres, 15 brujos, 10 cruzados, 12 amazonas, 10 corsarios, 7 obispos, 5 nigromantes, 1 arquitecto, 40 peones, 0 templos, 1 cuartel, 0 fincas y 2 palacios.

Salida

Ver jugabilidad.

Jugabilidad

Todas las fases

Comando W = ESPERAR

Comando no válido = ESPERAR

Fase 1: Aumento de impuestos

Los ingresos se generan de acuerdo con su población y sus edificios terminados:

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

Fase 2: robar dinero

Durante esta fase, puedes robar dinero de una ciudad enviando corsarios. Cada corsario puede robar hasta 10 de oro (es decir, 12 corsarios pueden robar hasta 120 de oro). Si la ciudad objetivo no tiene suficiente oro, tus corsarios robarán todo, hasta el monto máximo de la deuda: 200 de oro . Si intenta enviar más corsarios de los que posee, el programa utilizará todos sus corsarios disponibles.

Sintaxis del comando :S DestinationId Corsairs

Fase 3: reclutar tropas

Aquí puedes entrenar a tus peones gastando algo de oro. Puedes reclutar tantas unidades como quieras, siempre que tengas suficientes peones y oro disponibles. Si intentas reclutar más de lo que realmente puedes, el juego reclutará al azar hasta que se haya gastado todo. El programa respeta sus cuotas máximas (si intenta reclutar 10 cruzados y 5 amazonas con solo 8 peones, por ejemplo reclutará 6 cruzados y 2 amazonas, y no 8 amazonas u 8 brujos).

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

Sintaxis del comando :R Warlocks Crusaders Amazons Corsairs Bishops Necromancers Architects

Fase 4: Salarios salariales

Los salarios se cargan de acuerdo a su población:

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

Fase 5: Prueba Revuelta

Si su saldo es negativo, pierde el control de su ciudad a los Forajidos . Después de una revuelta, el oro de la ciudad se restablece al valor inicial: 500 de oro . La población se mantiene en sus niveles actuales.

Fase 6: Convertir soldados

Cada uno de tus obispos puede convertir 1 soldado enemigo (brujo, cruzado o amazona) de una ciudad elegida por una tarifa de 50 de oro por unidad. Las unidades convertidas se unen a las fuerzas estacionadas en tu ciudad. Al igual que con el reclutamiento, si no tiene suficiente oro u obispos disponibles, el programa se convertirá al azar y respetará las cuotas.

Sintaxis del comando :C DestinationId Warlocks Crusaders Amazons

Fase 7: Ciudad de ataque

Puedes enviar un ejército de brujos, cruzados y amazonas para conquistar una ciudad. Si intenta enviar más de lo que tiene, el programa enviará a todos.

Los soldados tienen una bonificación de combate de 1.5 siguiendo este patrón: Mage > Range > Melee > Mage(es decir, un brujo que lucha contra un Amazonas gana 1.5 de poder). Solo las unidades en exceso obtienen esta bonificación (es decir, un brujo que lucha contra un brujo y un amazona no obtiene esta bonificación). La bonificación se atribuye tanto a la ofensa como a la defensa.

Las pérdidas se distribuyen aleatoriamente entre las unidades del vencedor de acuerdo con el poder total más flojo (es decir. Poder ofensivo: 12 vs. Poder de defensa: 14, Defensa gana y pierde 12 unidades). El perdedor pierde todas sus unidades. Cada unidad muerta se agrega al recuento de cadáveres de la ciudad atacada. Si el delito gana, la ciudad es capturada y ahora es propiedad del atacante. También guarda el oro, los cadáveres y los peones que había en esta ciudad. Los corsarios, obispos, nigromantes y arquitectos huyen frente a la posible opresión.

La defensa no consigue nada.

Sintaxis del comando :A DestinationId Warlocks Crusaders Amazons

Fase 8: Levantar cadáveres

Cada uno de tus nigromantes puede resucitar hasta 5 peones al consumir cadáveres y gastar oro. Cada peón resucitado cuesta 1 cadáver y 20 de oro. Si intentas resucitar más de lo que puedes, el programa gastará todo lo que tienes.

Sintaxis del comando :R Corpses

Fase 9: mover ejército o tributo

Puedes enviar unidades a otra ciudad. Si intenta enviar más de lo que tiene, el programa enviará a todos.

Sintaxis del comando :M DestinationId Warlocks Crusaders Amazons Corsairs Bishops Necromancers Architects

O puedes enviar oro alquilando las naves de los corsarios. Cada corsario puede transportar hasta 200 de oro . Si intenta enviar más de lo que tiene, el programa le enviará lo que tiene.

Sintaxis del comando :T DestinationId Gold

Fase 10: defenderse de las amenazas

Varias amenazas de amenazas para dañar tu ciudad:

  • Zombis: los muertos no siempre están tan muertos como parecen. El 10% (con piso) de los cadáveres en tu ciudad despertará y comerá cerebros. Cada zombie se comerá 1 Peón y luego se adentrará en la nada (se consumen los cadáveres de los zombis y los peones comidos).
  • Demonios: Tus peones necesitan escuchar sermones o comenzarán a invocar a los Espíritus Oscuros. Cada uno de sus obispos cubre las necesidades de hasta 50 peones. El 10% (con piso) de tus herejes (peones en exceso) generarán demonios. Los demonios matan a 1 peón cada uno y regresan al infierno (los cuerpos de peones se agregan al conteo de la ciudad).
  • Bandidos: Los forajidos viven en el vecindario. La población total de forajidos se divide equitativamente entre las ciudades y se envía a robar riqueza. Tu única defensa son tus patrullas de corsarios. Cada corsario puede detener hasta 5 forajidos. Cada forajido que no se detiene roba 10 de oro de su ciudad (la deuda máxima de la ciudad es de 200 de oro)

Al menos 1 ciudad de Outlaws (100 habitantes) se genera al comienzo del juego, luego 1 más por cada 5 jugadores (es decir, 1-4 jugadores: 1 Outlaws, 5-9 jugadores: 2 Outlaws ...). Los forajidos pueden ser reconocidos conid = -1

Fase 11: Construcción del edificio

Al llegar a esta fase, la construcción de los edificios en su ciudad progresa según el número de arquitectos. Cada arquitecto aumenta la finalización de un solo edificio en un 8%. Cuando un Edificio alcanza el 100%, se completa y comienza a generar ingresos en la próxima Fase de "Impuestos". La cola de construcción se gestiona automáticamente (por orden de llegada).

Entonces también puede comenzar la construcción de otros Edificios (BuildingId = Letter entre paréntesis):

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

Puede comenzar la construcción de tantos edificios como desee, y si no tiene suficiente oro, se ignorará el edificio. La construcción de tus nuevos edificios solo comenzará la próxima ronda.

Sintaxis del comando :B BuildingId BuildingId BuildingId ...

Fase 12: Hacer niños

Cada cinco asaltos (asaltos 5, 10, 15 ...), nacerán nuevos Peones y estarán listos para pelear. Cada par de peones hará 1 peón (es decir, 23 peones generarán 11 peones nuevos).

Reglas

  • Los bots no deben escribirse para vencer o admitir otros bots específicos.
  • Se permite escribir en archivos. Escribe a "yoursubmissionname.txt", la carpeta se vaciará antes de que comience el juego. Otros recursos externos están prohibidos.
  • Su envío tiene 1 segundo para responder (por ciudad).
  • Proporcione comandos para compilar y ejecutar sus envíos.

Victorioso

El ganador es el que tiene más ciudades después de 100 rondas. Si un jugador captura todas las ciudades, el juego se detiene y gana. Si varios jugadores tienen la misma cantidad de ciudades, la población total contará, luego la cantidad de oro.

Controlador

Puedes encontrar el controlador en github. También contiene 2 samplebots, escritos en Java. Ábralo en Eclipse, coloque los bots compilados en la carpeta raíz y agregue una clase al programa de control (al igual que los robots de muestra).

Peleas

La fórmula de lucha es algo como esto:

Para cada clase de soldado (Warlock, Crusader, Amazon):

  • Calcular el equilibrio entre ataque y defensa (es decir, ¿quién tiene más de cada clase y cuántos más?)
  • Para el exceso de soldados (es decir, el valor del equilibrio positivo), vea cuántos "objetivos débiles" (vea el diagrama de la Fase 7) hay.
  • Multiplique la fuerza de combate de los soldados elegibles (es decir, "objetivos débiles" en comparación con "soldados en exceso") por la bonificación y agregue el resto con una fuerza de combate de 1.

Puedes probar un simulador aquí: http://ideone.com/ArJosE (solo cambia los valores de los soldados, obtendrás bonificaciones y fortalezas totales)

Aquí hay algunos casos de prueba:

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

Resultados finales

Promedio de 10 juegos. Sintaxis: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)

Resultados de 10 juegos: http://pastebin.com/GdufEYjm

Registros completos de 2 juegos: http://pastebin.com/GQDZ0JdY y http://pastebin.com/m3UBTDuC

Bien jugado todos, la pelea ha sido muy estrecha entre político y Oppotunist.


Al aumentar el número de interacción del jugador, espero ver una diversificación en las estrategias. Sin embargo, se puede lograr un bot simple en muy pocas líneas.
Thrax

The total Outlaws population is divided equitably between towns and sent to steal wealth.¿Cuántos bandidos hay en total?
MegaTom

@MegaTorn Al comienzo, hay una ciudad de Outlaws para 5 jugadores (mínimo 1) y 100 personas dentro de cada uno de ellos. Luego, a medida que avanza el juego, los Outlaws pueden aparecer de revueltas o ser asesinados por otros jugadores.
Thrax

¿Cómo sabemos cuántos edificios tiene una ciudad oponente? el controlador no parece enviar esa información. Esto es necesario para determinar la cantidad de impuestos se elevó de manera de determinar si un ataque exitoso en realidad puede terminar en ser incapaz de salarios de pago y rápidamente soltar la ciudad para una revolución
Moogie

Cuando una ciudad cae en la fase 5, ¿pueden otras ciudades de jugadores hacerse cargo de esa ciudad? Si es así, ¿se mantienen los tipos de clase de población? es decir: si tenían 20/20/40 combatientes en Warlocks, Crusaders, Amazonas, ¿esto es lo que necesitas para luchar para tomar esa ciudad?
Caballero lógico

Respuestas:


8

Oportunista, Java v2

Intenta aprovechar las oportunidades a medida que se presentan ... pero si ninguno se presenta (y todavía está en disputa) al final del juego, entonces hará todo lo posible.

UDPATE:

Incorporado algunas de las ideas de durron597. Ahora deja de reclutar obispos cuando puede convertir por completo la fuerza del oponente más fuerte y, en cambio, se concentra en comprar soldados.

También v1 tenía una desventaja inicial donde la propagación de la población inicial no sumaba 100 ... ¡solo 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;
}
}

Para ejecutar: 1. Coloque en el directorio moogiesoft 2. En el directorio padre: java moogiesoft.Opportunist


¡Guauu! Esto hace bastante bien!
TheNumberOne

Obviamente, esto es genial, pero creo que podrías mejorarlo marginalmente 1. dejando de comprar obispos si tienes más obispos que todos los demás tienen tropas combinadas, 2. atacando pueblos fuera de la ley antes del turno 100 si están indefensos y no hay otros bots. Debería hacer que su puntaje final sea mucho más alto.
durron597

Gracias, son buenas sugerencias. Me esforzaré por incorporarlos :)
Moogie

Bien hecho, ¡la estrategia de Opportunist fue realmente interesante!
Thrax

@Thrax gracias por el desafío! Según mis experimentos, el azar tiene un gran factor sobre qué tan bien juega el Oportunista. Se puede inundar fácilmente en los primeros asaltos cuerpo a cuerpo. Normalmente por Zealot.
Moogie

8

Aegis, Java

Aegis trata de ir a lo seguro y espera a que otros jugadores luchen entre ellos mientras construye un bonito bloque residencial, lleno de propiedades lujosas. Dado que el oro es un recurso precioso, Aegis recluta suficientes corsarios para robar a sus vecinos y proteger su dinero ganado con tanto esfuerzo.

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;
        }
    }

}

Compilar con javac Aegis.java

Corre con java Aegis


8

El joven conde, Python 2

versión 3.1

Actualizar:

La madre del joven conde no aguantará más su guerra. Él debe participar en la construcción de la ciudad en su lugar. El conde ahora tiene asesores económicos y muchas hojas de cálculo. Desea una vida más simple en la que pueda perseguir a las camareras.

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

Análisis de rendimiento

En la competencia del juego, el último Earl lo hizo bien. En 2 juegos de los 10, logró ganar contra las ciudades de jugadores, pero luego se congeló cuando llegó el momento de conquistar las ciudades de los bandidos. He solucionado ese error, nunca pensé que llegaría tan lejos ;-). En retrospectiva, debería haber descargado el controlador y probado el Earl.

Felicitaciones a @Moogie y @TheBestOne por las mejores entradas. Es una pena que solo uno pueda ganar. Ambos son muy buenos.

Si hay más juegos, me gustaría ver cómo el Earl reparado sobrevive contra los dos campeones. Espero que @Thrax tenga algo de tiempo libre para esto.



Ejecutaré 3 juegos más con el nuevo Earl para ver los resultados. También mantengo el git actualizado si quieres probarlo tú mismo. (y casi termino de trabajar en el próximo KOTH, ¡espero uno nuevo muy pronto!)
Thrax

Aquí están los resultados: 1. Outlaw(12, 6671, 2233682) 2. YoungEarl(3, 6346, 208215) 3. Politician(1, 96, 0)entonces 1. YoungEarl(16, 2514, 72315)y finalmente 1. Politician(16, 1562, 53467). YoungEarl está haciendo un trabajo bastante bueno.
Thrax

Gracias Thrax Parece que el conde se está acostumbrando. ¿Mejor tarde que nunca, eh?
Logic Knight

Dado que Moogie y TheBestOne todavía están en la carrera también, intentaré ejecutar 100 juegos por otra recompensa. (Aunque tengo un poco de reputación, necesito al menos el doble de lo que ya gasté, es decir, 300 repeticiones)
Thrax

6

TheLannisters (Java)

Elijo este nombre porque esta presentación se enriquece como el infierno. Además, la oración TheLannisters gave birth to 30 childrensuena graciosa: D

Editar: ahora espera con ataques durante mucho tiempo y molesta a los jugadores robando a sus soldados. También puede reclutar todo tipo de unidad.

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);
    }
}

Tienes un NPE cuando luchas solo contra forajidos. Este fragmento: for (Town town : enemyPlayerTowns)no está obteniendo nada, por lo que su Town richestTown = null;o equivalente permanece nulo.
Thrax

@Thrax Gracias, ya debería estar arreglado :)
CommonGuy

6

Político, Java

v3

Actualización: Se agregaron comentarios molestos y una mejor planificación.

Actualización: recluta mucho menos trenes (corsarios) y se centra en la construcción de la economía (peones).

Actualización: Ajustamos un par de parámetros.

Actualización: ataca con mucha más frecuencia. Escucha más a los científicos.

Él tiene dos goles.

  1. Oro ilimitado

  2. Ejércitos ilimitados.

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.";
        }
    }

}

Explicación

Él tiene dos goles.

  1. Oro ilimitado
  2. Ejércitos ilimitados.

Cómo obtener oro:

El político simplemente contrata a arquitectos para construir aeropuertos, carreteras y ferrocarriles. Montones de dinero comienzan a llegar con bastante rapidez. Después de aumentar los impuestos, el Político tiene dinero ilimitado.

Cómo conseguir ejércitos:

Esto es un poco más difícil. Con personas limitadas, solo puedes obtener un pequeño ejército. Con los embajadores, puede contratar ejércitos aún más grandes, pero aún no son lo suficientemente grandes. Después de cierta contemplación, el Político descubrió que conquistar otras naciones y luego esclavizar a la gente le da ejércitos bastante grandes. Pero todavía no son lo suficientemente grandes. Después de contratar a algunos científicos, le dicen que han descubierto el secreto para resucitar a los muertos, desafortunadamente, ya no son soldados después de la resurrección. Después de una profunda contemplación, el Político se da cuenta de que esto es una ventaja para él y contrata a los muertos resucitados como embajadores que contratan aún más soldados, hasta el infinito.


Desafortunadamente, este político, como todos los políticos, tiene promesas vacías y no puede enfrentarse a Sehtimianer. (Perdido en la ronda 30, penúltimo vivo)
Thrax

Ahora está gobernando el mundo, ¡felicidades!
Thrax

@Thrax ¡Y todavía lo es!
TheNumberOne

Estoy impresionado ... como todos los políticos ... él es muy adaptable al cambio :)
Moogie

¡La batalla es feroz, pero el político no llegó a la cima por ahora!
Thrax

5

Serenity, Lua

Se enfoca en alcanzar la serenidad a través de la religión. Intenta convertir a los infieles y esperar a que las ciudades alcancen un estado crítico antes de expandir su fe construyendo nuevos templos.

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

Ejecutar con lua Serenity.lua(requiere Lua 5.2)


5

Los zelotes (pitón)

(Basado en el código de CarpetPython).

¡Construye templos tan malos como sea posible! ¡Resucita a los muertos! ¡Convierte al infiel!

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'

66
Esto no me parece Java.
Ypnypn

55
Creo que te referías a Python
soktinpk

@ Thrax te refieres a la falta de colon
rorlork

@soktinpk: Sí, esto es python; No sé cómo llegué a Java.
MegaTom

@TheBestOne lo arreglé.
MegaTom

4

Comandante, Java

Commander es uno de los 2 bots predeterminados que creé junto con el controlador (el otro es Sleeper que no hace nada). El comandante es un conquistador e intentará usar cada uno de sus recursos para alcanzar la dominación completa.

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

Mantequilla

Esta mantequilla actúa de manera muy similar a la mantequilla anterior. A diferencia de la mantequilla anterior, esta se enriquece de manera extraordinariamente rápida. Desafortunadamente, los Young Earls, junto con los Lannisters, les gusta la mantequilla en sus waffles. Por lo tanto, la mantequilla se consume rápidamente.

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;
    }
}
}

Estaba trabajando en algo como esto. ¿Estoy en lo cierto al decir que esto se vuelve rico?
TheNumberOne

Sí, realmente recibe muchos ingresos xD
Sehtim

3

Maquiavelo, Python 2

Lord Maquiavelo tiene experiencia en los dominios políticos y militares necesarios para tener éxito. Ha desarrollado una lógica compleja que dirige su estrategia astuta, ahora observa desde las sombras mientras se desarrolla su plan ...

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

Monarca (Ruby)

Monarch es más que un simple Rey, por lo que no luchará contra otros hasta que esté seguro de que su ejército puede aplastar a sus oponentes y mostrar su poder abrumador. Mientras tanto, se pone cómodo en su base y pide tributos a los insectos insignificantes. Y, por supuesto, le gustan los rubíes y los rubíes.

$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

Para ejecutar este script, necesita un intérprete Ruby 1.9.3.

Corre con : ruby Monarch.rb


1

Solo puedo escribir 30000 signos en una respuesta xD Así que aquí están mis errores que encontré:

Moogie ya informó esto: int totalConvertible = (warlocksConvertible + crusadersConvertible + amazonsConvertible);

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

executeTheft: fuente utilizada en lugar de destino. Pero, ¿podría verificar si el cálculo es correcto? Mi recomendación sería:int goldReserve = destination.getGold() + GOLD_MAX_DEBT > 0 ? destination.getGold() + GOLD_MAX_DEBT : GOLD_MAX_DEBT - Math.abs(destination.getGold());

Y ejecutarReclutamiento tenía un error, que si la ciudad no tenía suficientes peones, podrían reclutar más de lo que tenían peones, si podían permitirse el reclutamiento. Así que reescribí el método que se refiere a peones y oro disponibles:

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();
        }
    }
}

Wow, muchas gracias por tomarse el tiempo de revisar el controlador (Gracias @Moogie también). He aplicado tus correcciones y ejecutaré varios juegos de prueba en unas pocas horas.
Thrax
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.