El juego de las ciudades

34

Introducción

El juego tiene lugar en un mundo pequeño con diferentes ciudades. Los gobernantes de las ciudades se odian y desean gobernar el mundo. La gente se divide en dos grupos, guerreros y nacidos bajos. Sin embargo, los nacidos bajos pueden elevarse a guerreros. Eres el gobernante de tres de estas ciudades.

Jugabilidad

Cuando comienza el juego, gobiernas tres ciudades. En cada pueblo hay 100 personas. Tienes que dividirlos en caballeros y nacidos bajos.

Entonces comienza el juego real, que se basa en turnos. Un turno se ve así: "Produce" knights=> execute command of first town=> execute command of next town(repetir para todas las ciudades) => try a rebellion.

  • Cada turno, se invocará su programa para cada ciudad que le pertenezca . Puedes atacar una ciudad , apoyar a una ciudad o simplemente esperar . Estas acciones se ejecutarán secuencialmente, no simultáneamente.
  • Cada tercer turno, obtienes un caballero por 2 nacidos bajos (23 nacidos bajos => 11 caballeros). La cantidad de nacidos bajos permanece igual.
  • Los caballeros dentro de una ciudad tienen una bonificación de defensa de 1.2. Si te atacan, tus caballeros se multiplicarán por este número (por ejemplo 78 knights, tienes, tendrás 93 knightsdurante el ataque). Después del ataque, se eliminarán los caballeros adicionales (si 82 knightssobrevives, aún tendrás 78 knights).
  • En un ataque, cada caballero mata a un enemigo antes de morir. Por ejemplo: 30 knightsataque 100 knights(sin bonificación de defensa) => 70 caballeros sobreviven.
  • Puedes capturar una ciudad matando a todos los caballeros dentro de ella . Todos los nacidos bajos te pertenecen ahora y tus caballeros sobrevivientes están estacionados en la ciudad. En la siguiente ronda, puedes gobernar esta ciudad además de todas tus otras ciudades .
  • Después de capturar una ciudad, no tendrá una bonificación de defensa durante 2 turnos completos (porque las puertas están rotas). En el tercer turno, las puertas serán reparadas.
  • Para evitar que los nacidos bajos se rebelen, necesitas al menos la mitad de los caballeros que los bajos (23 nacidos bajos en una ciudad necesitan al menos 12 caballeros en la misma ciudad). De lo contrario, los nacidos bajos matarán a todos los caballeros y la ciudad se volverá "neutral" (sin un líder, indicado por un ID de jugador -1).
  • Las ciudades neutrales "producirán" caballeros, pero no atacarán ni apoyarán a ninguna otra ciudad.

Sintaxis

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

Salida (preparación)
Antes de que comience el juego, el controlador invoca su presentación sin argumentos. Esto significa que tienes que distribuir a tus 100 personas (para cada ciudad) en caballeros y nacidos bajos. Necesita salida KnightCount KnightCount KnightCount, por ejemplo 95 80 95.

Entrada
Round;YourPlayerId;YourTownId;PlayerId_TownId_knights_lowborns;PlayerId_TownId_knights_lowborns;...
En la primera ronda, esto será algo así 1;2;2;0_0_100_0;1_1_50_50;2_2_80_20. Aquí, ves que es la primera ronda, eres el jugador 2 en la ciudad 2. Tienes 80 caballeros y 20 nacidos bajos.

Más adelante en el juego, podría ser algo así 20;2;1;0_0_100_0;2_1_30_50;2_2_40_20. Todavía eres el jugador 2 (esto nunca cambia), pero capturaste la ciudad 1 (que estás controlando en este momento).

Salida
A TownId NumberOfKnights o S TownId NumberOfKnightso W(para esperar).
Ejemplo: A 2 100(atacar la ciudad 2 con 100 caballeros) o S 3 2(apoyar la ciudad 3 con 2 caballeros).

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 cantidad de caballeros contará, luego la cantidad de nacidos bajos.

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).

Resultados

Para los resultados finales, corrí 10 juegos. Este es el promedio:

    Ciudades del jugador 
 1. Liberator 37.5
 2. Sehtimianer 8.2
 3. SuperProducer 5.4
 4. Sleeper 1.4
 5. Frankenstein 1.2
 6. Mantequilla 0.8 (más caballeros)
 7. TheKing 0.8 (menos caballeros)
 8. Éxodo 0.6
 9. Tortuga 0.5 (más caballeros)
10. AttackOn3 0.5 (menos caballeros)
11. Democracia 0.3
12. CalculatedFail 0.2
13. Revolucionario 0.1

Puedes leer un juego de muestra aquí: juego de muestra en github

CommonGuy
fuente
Supongo que cuando una ciudad Aapoya a otra ciudad B, el número dado de caballeros simplemente se transfiere de Aa B, después de lo cual son controlados por el propietario de B, ¿correcto?
Zgarb
@Zgarb Correcto :)
CommonGuy
¿Realizarás partidos y mostrarás una tabla de clasificación?
Logic Knight el
@CarpetPython Por supuesto, lo publico tan pronto como tengo tiempo
CommonGuy
1
@Manu, tengo que decir que amo a tus KOTHs. ESTE es mi tipo de preguntas Codegolf.SE. ¿Hasta cuándo aceptas los envíos? Empezaré a pensar en un algoritmo ahora. Además, creo que debería agregar otra regla: número máximo de envíos por usuario.
Mark Gabriel

Respuestas:

14

Python3, Libertador

from sys import argv
from math import ceil, floor

class OppressedTown:
    def __init__(self, owner_id, id, oppressors, oppressed):
        self.owner_id = owner_id
        self.id = id
        self.oppressors = oppressors
        self.oppressed = oppressed

    def get_free_oppressors(self):
        return self.oppressors - ceil(self.oppressed / 2)

    def get_needed_liberators(self):
        return ceil(self.oppressed / 2)

class LiberatedTown:
    def __init__(self, owner_id, id, liberators, liberated):
        self.owner_id = owner_id
        self.id = id
        self.liberators = liberators
        self.liberated = liberated

    def get_free_liberators(self):
        return self.liberators - ceil(self.liberated / 2)

    def get_needed_liberators(self):
        return ceil(self.liberated / 2)

    def is_safe(self):
        return self.liberators >= self.liberated * 2

    def get_unneeded_liberators(self):
        return self.liberators - self.liberated * 2

def safe_div(a, b):
    try:
        c = a / b
    except ZeroDivisionError:
        if a == 0:
            c = 0
        else:
            c = float("inf")
    return c

def main():
    if len(argv) == 1:
        print ("100 100 100")
    else:
        decision = decide()
        print (decision)

def decide():
    def needs_urgent_support(town):
        return town.get_needed_liberators() >= town.liberators and town.liberated > 0

    def can_beat(free_liberators, town):
        return free_liberators > town.oppressors * 1.2 + town.get_needed_liberators()

    def can_damage(free_liberators, town):
        return free_liberators > town.oppressors * 0.2

    args = argv[1].split(";")
    round = int(args[0])
    me = int(args[1])
    current_id = int(args[2])
    liberated_towns = []
    oppressed_towns = []

    for i in range(3, len(args)):
        infos = list(map(int, args[i].split("_")))
        if infos[0] != me:
            oppressed_towns.append(OppressedTown(infos[0], infos[1], infos[2], infos[3]))
        else:
            liberated_towns.append(LiberatedTown(infos[0], infos[1], infos[2], infos[3]))

    current_town = [town for town in liberated_towns if town.id == current_id][0]
    free_liberators = current_town.get_free_liberators()

    total_oppressors = sum(town.liberators for town in liberated_towns)
    total_oppressors = sum(town.oppressors for town in oppressed_towns)
    total_liberated = sum(town.liberated for town in liberated_towns)
    total_oppressed = sum(town.oppressed for town in oppressed_towns)

    oppressed_towns.sort(key=lambda town: safe_div(town.oppressed, town.oppressors), reverse=True)

    most_oppressed = oppressed_towns[-1]

    if free_liberators > 0:
        for town in liberated_towns:
            if town.id != current_id and needs_urgent_support(town):
                return "S {0} {1}".format(town.id, free_liberators // 2)

        if current_town.is_safe():
            free_liberators = current_town.get_unneeded_liberators()

            if free_liberators > 0:
                for town in oppressed_towns:
                    if can_beat(free_liberators, town):
                        if total_liberated <= total_oppressed or town.owner_id != -1 or not any(town.owner_id != -1 for town in oppressed_towns):
                            return "A {0} {1}".format(town.id, free_liberators)
                        else:
                            continue
                    else:
                        break

                for town in liberated_towns:
                    if not town.is_safe():
                        return "S {0} {1}".format(town.id, free_liberators)

                liberated_towns.sort(key=lambda town: (town.liberated, town.liberators), reverse=True)

##                if current_id == liberated_towns[0].id and total_oppressors > total_oppressors and can_damage(free_liberators, most_oppressed):
##                    return "A {0} {1}".format(most_oppressed.id, free_liberators)

                if current_id != liberated_towns[0].id:
                    return "S {0} {1}".format(liberated_towns[0].id, free_liberators)

    return "W"

main()

El único objetivo de este bot es liberar a las personas más comunes del yugo opresivo de la tiranía.


fuente
1
Debo decir que este Libertador es una plaga: fuerte, rápido y mortal. Ganó casi todas las simulaciones que corrí, incluso superando al jugador neutral ... Still Butter es un gran rival.
Thrax
Liberaste el pan de la tiranía de la mantequilla. :( Me gusta la mantequilla.
TheNumberOne
Dang! ¡El Libertador es difícil de superar! Tenía una entrada que iba a enviar antes de agregar participantes que no fueran Java al controlador ... ¡pero ahora esa entrada no puede ganar como el resto de los no liberadores! Tengo otra idea que probar para que no todo esté perdido ...: ¡P + 1 para el desafío!
Moogie
¡bien hecho! ¡la tuya fue una victoria bien merecida!
Moogie
11

Python 2, el rey

El Rey gobierna la ciudad con el mayor número de su imperio y exige que todos los caballeros en exceso le sean enviados desde otras ciudades bajo su control. Cuando tenga suficientes caballeros, atacará una ciudad enemiga. No es un rey muy inteligente, por lo que no ha estudiado historia ni comprende las consecuencias de sus acciones.

import sys
from random import *

PLAYER, TOWN, KNIGHTS, SERFS = range(4)

if len(sys.argv) < 2:
    print randint(20,100), randint(50,100), randint(70,100)
else:
    parts = sys.argv[1].split(';')
    turn, me, thistown = [int(parts.pop(0)) for i in range(3)]
    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]

    avgfree = sum(t[KNIGHTS]-t[SERFS]/2 for t in towns) / len(towns)
    free = here[KNIGHTS] - here[SERFS]/2
    last = mytowns[-1]
    if here == last:
        needed, target = min([(t[KNIGHTS]*1.2+t[SERFS]/2, t) for t in enemy])
        if free > needed+5:
            print 'A', target[TOWN], int(free+needed)/2 + 1
        else:
            print 'W'
    else:
        spare = max(0, free - avgfree)
        if spare:
            print 'S', last[TOWN], spare
        else:
            print 'W'

Esto no se ha probado con el controlador u otros bots.

Caballero Lógico
fuente
+1 paraHe is not a very smart King, so has not studied history or understands the consequences of his actions.
Mark Gabriel
8

Javascript (Nodo), Imperio

Comienza fuerte para asustar a otras ciudades. Las ciudades intentan trabajar juntas para capturar a otros. Prioriza la captura de ciudades con muchos nacidos bajos.

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

function startGame() {
  console.log('80 70 60');
}

function parseArgs(args) {
  var state = {
    players: [],
    towns: []
  };
  var argArray = args.split(';');
  state.currentTurn = parseInt(argArray.splice(0, 1)[0], 10);
  var myId = argArray.splice(0, 1)[0];
  var myTownId = parseInt(argArray.splice(0, 1)[0], 10);

  for(var townIndex = 0; townIndex < argArray.length; townIndex++) {
    var townArgs = argArray[townIndex].split('_');
    var playerId = townArgs[0];
    var townId = parseInt(townArgs[1], 10);
    var player = state.players[playerId];

    if(!player) {
      player = {
        towns: []
      };
      state.players[playerId] = player;
    }

    var town = {
      id: townId,
      knights: parseInt(townArgs[2], 10),
      lowborns: parseInt(townArgs[3], 10),
      player: player
    };

    state.towns[townId] = town;
    player.towns.push(town);
  }

  state.me = state.players[myId];
  state.currentTown = state.towns[myTownId];

  return state;
}

function getDefense(town) {
  return Math.floor(town.knights * 1.2) + Math.ceil(town.lowborns / 2) + 1;
}

function getAttackers(town) {
  return Math.max(town.knights - Math.ceil(town.lowborns / 2), 0);
}

function attackTown(town, strength) {
  console.log('A ' + town.id + ' ' + strength);
}

function supportTown(town, strength) {
  console.log('S ' + town.id + ' ' + strength);
}

function wait() {
  console.log('W');
}

function processTurn(gameState) {
  var attackers = getAttackers(gameState.currentTown);

  if(attackers > 0) {
    var totalAttackers = attackers;

    var helperIndex = (gameState.currentTown.id + 1) % gameState.towns.length;
    while(gameState.towns[helperIndex].player === gameState.me) {
      totalAttackers += getAttackers(gameState.towns[helperIndex]);
      helperIndex = (helperIndex + 1) % gameState.towns.length;
    }

    var bestTarget;

    for(var targetIndex = 0; targetIndex < gameState.towns.length; targetIndex++) {
      var targetTown = gameState.towns[targetIndex];
      if(targetTown.player !== gameState.me) {
        var defense = getDefense(targetTown);

        if(defense < totalAttackers) {
          if(!bestTarget) {
            bestTarget = targetTown;
          }
          else if(targetTown.lowborns > bestTarget.lowborns) {
            bestTarget = targetTown;
          }
          else if(getDefense(bestTarget) < defense) {
            bestTarget = targetTown;
          }
        }
      }
    }

    if(bestTarget) {
      return attackTown(bestTarget, Math.min(attackers, getDefense(bestTarget)));
    }

    var smallestTown;
    var smallestSize = gameState.currentTown.knights;

    for(var myTownIndex = 0; myTownIndex < gameState.me.towns.length; myTownIndex++) {
      var myTown = gameState.me.towns[myTownIndex];
      if(myTown.knights < smallestSize) {
        smallestTown = myTown;
        smallestSize = smallestTown.knights;
      }
    }

    if(smallestTown) {
      var supporters = Math.floor((smallestSize - gameState.currentTown.knights) / 2);
      supporters = Math.min(supporters, attackers);
      if(supporters > 0) {
        return supportTown(smallestTown, supporters);
      }
    }
  }

  wait();
}

if(process.argv.length <= 2) {
  startGame();
}
else {
  var gameState = parseArgs(process.argv[2]);  
  processTurn(gameState);
}

Ejecutar: nodo imperio

Spencer
fuente
1
Su presentación a veces envía más caballeros de los que hay en la ciudad y, por lo tanto, pierde en este momento ...
CommonGuy
@Manu oops, de alguna manera nunca me encontré (o al menos noté) eso en mis pruebas, posiblemente porque no tuve la oportunidad de configurar todos los bots oponentes para las pruebas. Ese error en particular debería repararse ahora.
Spencer
Todavía no está arreglado ... a veces atacas con 0 o con una cantidad negativa de caballeros ... Es porque calculas knights - lowborns/2, pero si tienes 30 caballeros y 90 nacidos bajos, esto no funciona. Por favor arregle su getAttackers()función.
CommonGuy
Además, a veces envías apoyos con una cantidad negativa de caballeros.
CommonGuy
@Manu, bueno, me siento tonto, finalmente noté la DEBUGbandera en el controlador que estaba causando que se tragara errores incluso con la GAME_MESSAGESbandera establecida en verdadero. Siento que todavía podía utilizar algún trabajo en mi estrategia, especialmente con Liberator ahora en la escena, pero con la última edición no veo ningún error cuando ejecuto mis pruebas con DEBUGel
Spencer
8

Java, Frankenstein

Al intentar encontrar una manera de destruir Liberator, un pequeño error se deslizó en mi código. El código luego comenzó a destruir la competencia. Después de agregar Democracia y reorganizar a los jugadores, comenzó a fallar. Estudiando el código intenté encontrar su estrategia. En consecuencia, se hizo el siguiente código. Tiende a atacar y destruir al mejor jugador. Después de que los mejores jugadores son destruidos, esto destruye fácilmente al resto.

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Frankenstein {

    int round;
    int playerID;
    int thisTownID;

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

    private static final boolean DEBUG = true;

    Town thisTown;

    int scariestPlayerId = -1;
    int scariestPlayerRecord = -1;

    private static final String LOG_FILE_NAME = "EmperorLog.txt";

    private static final String DATA_FILE_NAME = "Emperor.txt";

    public static void main(String[] args){
        try {
            if (args.length == 0) {
                System.out.println("100 100 100");
                return;
            }
            Frankenstein frankenstein = new Frankenstein();
            String result = frankenstein.destroy(args[0].split(";"));
            frankenstein.saveScariestPlayer();
            System.out.println(result);
            if (DEBUG) {
                new PrintStream(new FileOutputStream(LOG_FILE_NAME, true)).print(args[0] + "\n" + result + "\n");
            }
        } catch (Exception e){
            if (DEBUG) {
                try {
                    e.printStackTrace(new PrintStream(new FileOutputStream(LOG_FILE_NAME, true)));
                } catch (FileNotFoundException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    private void saveScariestPlayer() throws FileNotFoundException {
        PrintStream out = new PrintStream(DATA_FILE_NAME);
        out.println(round);
        out.println(scariestPlayerId);
        out.println(scariestPlayerRecord);
    }

    private static int divide(int a, int b){
        if (a == 0){
            return 0;
        }
        if (b == 0){
            return 1000;
        }
        return a/b;
    }

    private String destroy(String[] args) {

        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();


        for (int i = 3; 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);
            }
        }

        loadScariestPlayer();
        updateScariestPlayer();

        if (thisTown.getFreeKnights() > 0){

            for (Town town : myTowns){
                if (town.needsHelp() && town.getFreeKnights() + thisTown.getFreeKnights() >= 0){
                    return "S " + town.getId() + " " + thisTown.getFreeKnights();
                }
            }

            Town bestTown = otherTowns.stream().max((a, b) -> divide(a.lowbornCount() * (scariestPlayerId == -1 || scariestPlayerId == a.ownerId ? a.lowbornCount() : 1), a.knightCount()) -
                    divide(b.lowbornCount() * (scariestPlayerId == -1 || scariestPlayerId == b.ownerId ? b.lowbornCount() : 1), b.knightCount())).get();

            if (bestTown.numberOfKnightsToConquer() <= thisTown.getFreeKnights()){
                return "A " + bestTown.getId() + " " + thisTown.getFreeKnights();
            }

            myTowns.sort((a,b) -> b.knightCount() - a.knightCount());
            myTowns.sort((a,b) -> b.lowbornCount() - a.lowbornCount());
            if (!myTowns.get(0).isThisTown()){
                return "S " + myTowns.get(0).getId() + " " + thisTown.getFreeKnights();
            }

        }

        return "W";

    }

    private void updateScariestPlayer() {
        Map<Integer, Integer> playerMap = new HashMap<>();
        int biggestPlayerId = -1;
        for (Town town : otherTowns){
            if (playerMap.containsKey(town.ownerId)){
                playerMap.put(town.ownerId, town.lowbornCount() + playerMap.get(town.ownerId));
            } else {
                playerMap.put(town.ownerId, town.lowbornCount());
            }
            if (biggestPlayerId == -1 || playerMap.get(town.ownerId) > playerMap.get(biggestPlayerId)){
                biggestPlayerId = town.ownerId;
            }
        }
        if (scariestPlayerId == -1 || scariestPlayerRecord == -1 || !playerMap.containsKey(scariestPlayerId) || playerMap.get(biggestPlayerId) > scariestPlayerRecord){
            scariestPlayerId = biggestPlayerId;
            scariestPlayerRecord = playerMap.get(biggestPlayerId);
        }
    }

    private void loadScariestPlayer() {
        try {
            BufferedReader in = new BufferedReader(new FileReader(DATA_FILE_NAME));
            int turn = Integer.parseInt(in.readLine());
            if (turn != round || turn != round + 1){
                throw new Exception();
            }
            scariestPlayerId = Integer.parseInt(in.readLine());
            scariestPlayerRecord = Integer.parseInt(in.readLine());
        } catch (Exception e) {
            scariestPlayerId = -1;
            scariestPlayerRecord = -1;
        }
    }


    private class Town {
        final int ownerId;
        final int id;
        final int knights;
        final int lowborns;
        boolean defenseBonus;

        Town(String string) {
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
            defenseBonus = true;
        }

        int getId() {
            return id;
        }

        int knightCount() {
            return knights;
        }

        int lowbornCount() {
            return lowborns;
        }

        boolean isMine() {
            return ownerId == playerID;
        }

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

        int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }

        int numberOfKnightsToConquer() {
            if (defenseBonus) {
                return ((knights * 6) / 5) + (lowborns / 2) + 1;
            } else {
                return knights + lowborns/2 + 1;
            }
        }

        int numberOfKnightsToOverthrow(){
            if (defenseBonus) {
                return (((knights * 6) / 5) - (lowborns / 2)) + 1;
            } else {
                return knights - lowborns / 2 + 1;
            }
        }

        boolean needsHelp() {
            return getFreeKnights() < 0;
        }

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

Aquí está el jugador original:

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

public class Frankenstein {

    int round;
    int playerID;
    int thisTownID;

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

    Town thisTown;

    Player me;

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("100 100 100");
            return;
        }
        new Frankenstein().destroy(args[0].split(";"));
    }

    private static int divide(int a, int b){
        if (a == 0){
            return 0;
        }
        if (b == 0){
            return 1000000;
        }
        return a/b;
    }

    private void destroy(String[] args) {
        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();


        for (int i = 3; 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);
            }
        }

        players.stream().filter(player -> player.id == playerID).forEach(player -> me = player);

        if (thisTown.getFreeKnights() > 0){

            for (Town town : myTowns){
                if (town.needsHelp()){
                    System.out.println("S " + town.getId() + " " + thisTown.getFreeKnights() / 2);
                    return;
                }
            }

            Town richestTown = otherTowns.stream().max((a, b) -> divide(a.lowbornCount(), a.knightCount()) -
                    divide(b.lowbornCount(), b.knightCount())).get();

            if (richestTown.numberOfKnightsToConquer() < thisTown.getFreeKnights()){
                System.out.println("A " + richestTown.getId() + " " + thisTown.getFreeKnights());
                return;
            }

            otherTowns.sort((a,b) -> divide(b.lowbornCount() * b.owner.richness(), b.getFreeKnights()) -
                    divide(a.lowbornCount() * a.owner.richness(), a.getFreeKnights()));

            if (thisTown.getFreeKnights() >= otherTowns.get(0).numberOfKnightsToOverthrow() && !otherTowns.get(0).isNeutral()){
                System.out.println("A " + otherTowns.get(0).getId() + " " + otherTowns.get(0).numberOfKnightsToOverthrow());
                return;
            }

            myTowns.sort((a,b) -> b.knightCount() - a.knightCount());
            myTowns.sort((a,b) -> b.lowbornCount() - a.lowbornCount());
            if (!myTowns.get(0).isThisTown()){
                System.out.println("S " + myTowns.get(0).getId() + " " + thisTown.getFreeKnights());
                return;
            }

        }

        System.out.println("W");

    }


    private class Town {
        private final int ownerId;
        private final int id;
        private final int knights;
        private final int lowborns;
        private final Player owner;

        private Town(String string) {
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
            for (Player player : players){
                if (player.id == ownerId){
                    player.addTown(this);
                    owner = player;
                    return;
                }
            }
            owner = new Player(id);//This mistake makes my player perform really good for some reason.
            owner.towns.add(this);
        }

        private int getId() {
            return id;
        }

        private int knightCount() {
            return knights;
        }

        private int lowbornCount() {
            return lowborns;
        }

        private boolean isMine() {
            return ownerId == playerID;
        }

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

        private int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }

        private int numberOfKnightsToConquer() {
            return ((knights * 6) / 5) + (lowborns / 2) + 1;
        }

        private int numberOfKnightsToOverthrow(){
            return (((knights * 6) / 5) - (lowborns / 2)) + 1;
        }

        private boolean needsHelp() {
            return getFreeKnights() < 0;
        }

        private boolean isNeutral() {
            return owner.id == -1;
        }

    }

    List<Player> players = new ArrayList<>();

    private class Player{

        int id;

        List<Town> towns;

        int richness = 0;

        Player(int id){
            this.id = id;
            this.towns = new ArrayList<>();
            players.add(this);
        }

        void addTown(Town t){
            towns.add(t);
            richness += t.lowbornCount();
        }

        int richness(){
            return id == -1 ? (towns.size() > 0 ? 1 : 0) : richness;
        }

    }
}
El numero uno
fuente
Corrí 20 juegos, me entristece decir que Frankenstein ganó solo 2 veces, mientras que Liberator ganó 17 veces (sí, Revolutionnist logró que el jugador neutral ganara una vez mientras obtenía el 2do lugar).
Thrax
@Thrax fijo !!!!!
TheNumberOne
7

Java, tortuga

Gracias a TheBestOne por los métodos principales, acabo de cambiar el algoritmo (espero que esté bien). Este bot básicamente mejora su ciudad mejor defendida para rivalizar con la ciudad enemiga más peligrosa, mientras mantiene suficientes caballeros para evitar la rebelión en sus otras ciudades.

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


public class Turtle {


    int round;
    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("34 34 34");
            return;
        }
        new Turtle().defend(args[0].split(";"));
    }

    private void defend(String[] args) {
        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();

        for (int i = 3; 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);
            }
        }

        Town bestDefendedTown = null;
        for (Town town : myTowns) {
            if (bestDefendedTown == null)
                bestDefendedTown = town;

            bestDefendedTown = bestDefendedTown.knightCount() >= town.knightCount() ? bestDefendedTown : town;
        }

        Town dangerousEnemyTown = null;
        for (Town town : otherTowns) {
            if (dangerousEnemyTown == null)
                dangerousEnemyTown = town;

            dangerousEnemyTown = dangerousEnemyTown.knightCount() >= town.knightCount() ? dangerousEnemyTown : town;
        }

        int missingKnights = dangerousEnemyTown.knightCount() - bestDefendedTown.knightCount() > 0 ? dangerousEnemyTown.knightCount() - bestDefendedTown.knightCount() : 0;
        int reinforcements = thisTown.getFreeKnights() - (missingKnights + 1) > 0 ? thisTown.getFreeKnights() - (missingKnights + 1) : thisTown.getFreeKnights(); 


        if (reinforcements > 0) {
            System.out.println("S " + bestDefendedTown.getId() + " " + reinforcements);
        } else {
            System.out.println("W");
        }
    }



    private class Town {
        private final int ownerId;
        private final int id;
        private final int knights;
        private final int lowborns;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
        }

        public int getId() {
            return id;
        }

        public int getOwner() {
            return ownerId;
        }

        public int knightCount() {
            return knights;
        }

        public int lowbornCount() {
            return lowborns;
        }

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

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

        private int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }
    }
}

Compilar: javac Turtle.java

Correr: java Turtle

Thrax
fuente
Creo que dangerousEnemyTown = dangerousEnemyTown.knightCount() >= town.knightCount() ? dangerousEnemyTown : town;dangerousEnemyTown = bestDefendedTown.knightCount() >= town.knightCount() ? bestDefendedTown : town;
querías
@TheBestOne ¡Gracias por señalarlo! Actualizando mi publicación.
Thrax
También corregí un NPE haciendo que mi tortuga esperara cada turno. De hecho, esta pequeña tortuga dormía hasta ahora ...
Thrax
7

Java 8, político

Actúa como un verdadero político. Lástima que Crasher todavía lo mate.

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

public class Politician {

    int round;
    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("34 34 34");
            return;
        }
        new Politician().bribe(args[0].split(";"));
    }

    private void bribe(String[] args) {
        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();


        for (int i = 3; 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);
            }
        }

        Town biggestTown = otherTowns.stream().max((a,b) -> a.knights - b.knights).get();

        if (thisTown.getFreeKnights() <= 0){//Out of knights.
            System.out.println("W");//Waiting for taxes so can hire more knights.
        }

        System.out.println("S " + biggestTown.getId() + " " + thisTown.getFreeKnights());
    }


    private class Town {
        private final int ownerId;
        private final int id;
        private final int knights;
        private final int lowborns;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
        }

        public int getId() {
            return id;
        }

        public int getOwner() {
            return ownerId;
        }

        public int knightCount() {
            return knights;
        }

        public int lowbornCount() {
            return lowborns;
        }

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

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

        private int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }

    }
}

Compilar: javac Politician.java

Correr: java Politician

El numero uno
fuente
1
+1 por soborno, pero creo que te perdiste el liemétodo demasiado común
globby
6

Java 8, mantequilla

Se extiende lo más uniformemente posible. Asfixia una ciudad si la ciudad es lo suficientemente pequeña.

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

public class Butter {

    int round;
    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("34 34 34");
            return;
        }
        new Butter().spread(args[0].split(";"));
    }

    private void spread(String[] args) {
        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();


        for (int i = 3; 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);
            }
        }

        Town mySmallestTown = myTowns.stream().min((a, b) -> a.getFreeKnights() - b.getFreeKnights()).get();

        Town smallestEnemyTown = otherTowns.stream().min((a,b) -> a.knights - b.knights).get();

        if ((thisTown.getFreeKnights() - mySmallestTown.getFreeKnights())/2 > 0) {
            System.out.println("S " + mySmallestTown.getId() + " " + (thisTown.getFreeKnights() - mySmallestTown.getFreeKnights()) / 2);
        } else if (thisTown.getFreeKnights() / 2 > smallestEnemyTown.numberOfKnightsToConquer()){
            System.out.println("A " + smallestEnemyTown.getId() + " " + smallestEnemyTown.numberOfKnightsToConquer());
        } else {
            System.out.println("W");
        }
    }


    private class Town {
        private final int ownerId;
        private final int id;
        private final int knights;
        private final int lowborns;

        private Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
        }

        private int getId() {
            return id;
        }

        private int getOwner() {
            return ownerId;
        }

        private int knightCount() {
            return knights;
        }

        private int lowbornCount() {
            return lowborns;
        }

        private boolean isMine(){
            return ownerId == playerID;
        }

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

        private int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }

        private int numberOfKnightsToConquer(){
            return ((knights * 6) / 5) + (lowborns / 2) + 1;
        }

    }
}

Compilar: javac Butter.java

Correr: java Butter

El numero uno
fuente
6

Java, revolucionario

Una última, todavía basada en los métodos básicos de TheBestOne. Este bot intenta incitar rebeliones en cada ciudad, ya que el jugador neutral es inofensivo, matando a una cierta cantidad de caballeros en relación con la población de bajo nacimiento. Por supuesto, no atacará al jugador neutral.

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


public class Revolutionist {


    int round;
    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("80 80 80");
            return;
        }
        new Revolutionist().inciteRebellion(args[0].split(";"));
    }

    private void inciteRebellion(String[] args) {
        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();

        for (int i = 3; 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);
            }
        }

        Town onEdgeTown = null;
        int edgeCounter = 100;
        for (Town town : otherTowns) {
            if (onEdgeTown == null)
                onEdgeTown = town;

            if (town.getFreeKnights() >= 0 && town.getFreeKnights() <= edgeCounter && town.getOwner() >= 0) {
                onEdgeTown = town;
                edgeCounter = town.getFreeKnights();
            }
        }

        int minimumRequiredKnights = (int) ((onEdgeTown.knightCount() * 1.2 - onEdgeTown.getMinimumKnights() + 2) * 1.2) ;


        if (thisTown.getFreeKnights() > minimumRequiredKnights && onEdgeTown.getOwner() >= 0)
            System.out.println("A " + onEdgeTown.getId() + " " + minimumRequiredKnights);
        else
            System.out.println("W");

    }



    private class Town {
        private final int ownerId;
        private final int id;
        private final int knights;
        private final int lowborns;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
        }

        public int getId() {
            return id;
        }

        public int getOwner() {
            return ownerId;
        }

        public int knightCount() {
            return knights;
        }

        public int lowbornCount() {
            return lowborns;
        }

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

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

        private int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }

        private int getMinimumKnights() {
            return lowborns / 2 + 1;
        }
    }
}

Compilar: javac Revolutionist.java

Correr: java Revolutionist

Thrax
fuente
6

JAVA, Sehtimianer

Gracias de nuevo a TheBestOne, también copié sus métodos principales; ) Esta es la primera vez que juego KingOfTheHill-CodeGame, así que espero haber hecho todo bien. Presento con orgullo a los Sehtimianers: D

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Sehtimianer {

private static final String FILENAME = "Sehtimianer.txt";
private static final int AGGRESSIVE_ROUND_BORDER = 80;

int round;
int playerID;
int thisTownID;

List<Town> towns = new ArrayList<Town>();
List<Town> myTowns = new ArrayList<Town>();
List<Town> playerTowns = new ArrayList<Town>();
List<Town> neutralTowns = new ArrayList<Town>();
Map<Integer, Integer> townToPlayerMapping = new HashMap<Integer, Integer>();
boolean isAllowedToWriteMapping = true;

Town thisTown;

public static void main(String[] args) {
    if (args.length == 0) {
        // new File(FILENAME).delete();
        System.out.println("100 100 100");
        return;
    }
    new Sehtimianer().decide(args[0].split(";"));
}

private void decide(String[] args) {
    // final long start = System.currentTimeMillis();

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

    for (int i = 3; 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.getOwner() == -1) {
                neutralTowns.add(town);
            } else {
                playerTowns.add(town);
            }
        }
    }

    if (new File(FILENAME).exists()) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(FILENAME));
            String inputLine;
            String[] ids;
            while ((inputLine = reader.readLine()) != null) {
                ids = inputLine.split(";");
                if (ids.length == 1) {
                    Integer writingTownID = Integer.valueOf(ids[0]);
                    boolean townIsLost = true;
                    for (Town town : myTowns) {
                        if (town.getId() == writingTownID) {
                            townIsLost = false;
                            break;
                        }
                    }
                    isAllowedToWriteMapping = townIsLost || thisTownID == writingTownID;
                    continue;
                }
                townToPlayerMapping.put(Integer.valueOf(ids[0]), Integer.valueOf(ids[1]));
            }
            reader.close();

            for (Town town : towns) {
                if (!townToPlayerMapping.get(town.getId()).equals(town.getOwner())) {
                    town.setDefenseBonus(false);
                }
            }
        } catch (IOException e) {
            // Dont worry : )
        }
    }

    if (round == 1) {
        int maxKnights = 0;
        int maxKnightTownID = thisTownID;
        for (Town town : myTowns) {
            if (town == thisTown) {
                continue;
            }
            if (town.knightCount() > maxKnights) {
                maxKnights = town.knightCount();
                maxKnightTownID = town.getId();
            }
        }
        if (maxKnightTownID != thisTownID) {
            System.out.println("S " + maxKnightTownID + " " + thisTown.knightCount());
        }
    } else if (round % 3 == 2) {
        int myKnightIncome = 0;
        for (Town town : myTowns) {
            myKnightIncome += town.lowbornCount() / 2;
        }

        Map<Integer, Integer> playerKnightIncomeMap = new HashMap<Integer, Integer>();
        Map<Integer, Integer> playerTownCountMap = new HashMap<Integer, Integer>();
        List<Integer> nextRoundKnights = new ArrayList<Integer>();
        Map<Integer, Town> nextRoundKnightsToTownMapping = new HashMap<Integer, Town>();

        for (Town town : playerTowns) {
            fillDescisionMaps(town, nextRoundKnights, nextRoundKnightsToTownMapping, playerKnightIncomeMap, playerTownCountMap);
        }
        for (Town town : neutralTowns) {
            fillDescisionMaps(town, nextRoundKnights, nextRoundKnightsToTownMapping, playerKnightIncomeMap, playerTownCountMap);
        }

        Integer maxEnemyKnightIncome = 0;
        for (Integer knightIncome : playerKnightIncomeMap.values()) {
            if (knightIncome > maxEnemyKnightIncome) {
                maxEnemyKnightIncome = knightIncome;
            }
        }
        Integer maxEnemyTownCount = 0;
        for (Integer townCount : playerTownCountMap.values()) {
            if (townCount > maxEnemyTownCount) {
                maxEnemyTownCount = townCount;
            }
        }

        if (maxEnemyKnightIncome > myKnightIncome || (round > AGGRESSIVE_ROUND_BORDER && maxEnemyTownCount >= myTowns.size())) {
            Collections.sort(nextRoundKnights);
            int possibleHighest = 0;
            Town enemyTown;
            int enemyTownUpkeep;
            for (int i = nextRoundKnights.size() - 1; i >= 0; i--) {
                possibleHighest = nextRoundKnights.get(i);
                enemyTown = nextRoundKnightsToTownMapping.get(possibleHighest);
                enemyTownUpkeep = enemyTown.lowbornCount() / 2;
                if (enemyTownUpkeep > (possibleHighest - enemyTownUpkeep)) { // Substract the calculated Income for the next Turn
                    // Town will be lost because of revolution after captured -> Bad target
                    possibleHighest = 0;
                    continue;
                }
                if (round > AGGRESSIVE_ROUND_BORDER || enemyTown.lowbornCount() > 0) {
                    break;
                }
            }
            if (possibleHighest > 0) {
                Town attackedTown = nextRoundKnightsToTownMapping.get(possibleHighest);
                System.out.println("A " + attackedTown.getId() + " " + calcHowMuchKnightsShouldAttack(attackedTown, possibleHighest));
            }
        }
    }

    if (isAllowedToWriteMapping) {
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(FILENAME));
            writer.write(thisTownID + "\n");
            for (Town town : towns) {
                writer.write(town.getId() + ";" + town.getOwner() + "\n");
            }
            writer.close();
        } catch (IOException e) {
            // Dont worry : )
        }
    }

    System.out.println("W");

    // long duration = System.currentTimeMillis() - start;
    // if (duration > 1000) {
    // throw new RuntimeException();
    // }
}

private void fillDescisionMaps(Town town, List<Integer> nextRoundKnights, Map<Integer, Town> nextRoundKnightsToTownMapping, Map<Integer, Integer> playerKnightIncomeMap,
        Map<Integer, Integer> playerTownCountMap) {
    int calculatedKnights = calcKnightsInNextRound(town);
    nextRoundKnights.add(calculatedKnights);
    nextRoundKnightsToTownMapping.put(calculatedKnights, town);

    Integer enemyKnightIncome = playerKnightIncomeMap.get(town.getOwner());
    if (enemyKnightIncome == null) {
        enemyKnightIncome = town.lowbornCount() / 2;
    } else {
        enemyKnightIncome = enemyKnightIncome + (town.lowbornCount() / 2);
    }
    playerKnightIncomeMap.put(town.getOwner(), enemyKnightIncome);

    Integer enemyTownCount = playerTownCountMap.get(town.getOwner());
    if (enemyTownCount == null) {
        enemyTownCount = Integer.valueOf(1);
    } else {
        enemyTownCount = enemyTownCount + 1;
    }
    playerTownCountMap.put(town.getOwner(), enemyTownCount);
}

private int calcKnightsInNextRound(Town enemyTown) {
    int knights = (int) ((double) enemyTown.knightCount() * (enemyTown.isDefenseBonus() ? 1.2 : 1));
    knights = thisTown.getFreeKnights() - knights;
    if (knights > 0) {
        knights += enemyTown.lowbornCount() / 2;
    } else {
        knights = 0;
    }
    return knights;
}

private int calcHowMuchKnightsShouldAttack(Town enemyTown, int possibleHighest) {
    if (round < AGGRESSIVE_ROUND_BORDER && thisTown.lowbornCount() == 0) {
        return thisTown.knightCount();
    }

    int spareKnights = possibleHighest - enemyTown.lowbornCount(); // Correct -> div 2 and mul 2
    int minShouldSend = thisTown.getFreeKnights() - (spareKnights / 2);

    return Math.max(minShouldSend, thisTown.knightCount() / 2);
}

private class Town {
    private final int ownerId;
    private final int id;
    private final int knights;
    private final int lowborns;
    private boolean defenseBonus;

    public Town(String string) {
        String[] args = string.split("_");
        ownerId = Integer.parseInt(args[0]);
        id = Integer.parseInt(args[1]);
        knights = Integer.parseInt(args[2]);
        lowborns = Integer.parseInt(args[3]);
        defenseBonus = true;
    }

    public boolean isDefenseBonus() {
        return defenseBonus;
    }

    public void setDefenseBonus(boolean defenseBonus) {
        this.defenseBonus = defenseBonus;
    }

    public int getId() {
        return id;
    }

    public int getOwner() {
        return ownerId;
    }

    public int knightCount() {
        return knights;
    }

    public int lowbornCount() {
        return lowborns;
    }

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

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

    private int getFreeKnights() {
        return knights - lowborns / 2 - 1;
    }
}
}

Los Sehtimianers intentan ser superiores en todo el juego y terminarlo al final. Espero que mi bot no lo haga tan mal :)

Sehtim
fuente
5

Java, éxodo

Una vez más, basado en los métodos principales de TheBestOne. Este bot migra de pueblo en pueblo una vez que ha alcanzado un cierto nivel de población de caballeros, indiscriminadamente de su dueño, y repite este proceso hasta que haya convertido el mundo entero.

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


public class Exodus {


    int round;
    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("100 100 100");
            return;
        }
        new Exodus().migrate(args[0].split(";"));
    }

    private void migrate(String[] args) {
        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();

        for (int i = 3; 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 (thisTown.knightCount() >= 100) {
           int nextTownId = thisTown.getId() + 1 > towns.size() - 1 ? 0 : thisTown.getId() + 1;
           Town nextTown = towns.get(nextTownId);
          if (nextTown.isMine()){
              System.out.println("S " + nextTown.getId() + " " + thisTown.knightCount()) ;
          } else {
              System.out.println("A " + nextTown.getId() + " " + thisTown.knightCount()) ;
          }
       } else {
           System.out.println("W") ;
       }
    }



    private class Town {
        private final int ownerId;
        private final int id;
        private final int knights;
        private final int lowborns;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
        }

        public int getId() {
            return id;
        }

        public int getOwner() {
            return ownerId;
        }

        public int knightCount() {
            return knights;
        }

        public int lowbornCount() {
            return lowborns;
        }

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

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

        private int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }
    }
}

Compilar: javac Exodus.java

Correr: java Exodus

Thrax
fuente
5

Pitón 2, Democracia

Este rey no es rey. Es algo moderno. Es el rey de las personas . Es democracia. Es lento, poco eficiente, y cuando hace algo, lo hace mal.

import sys
from math import sqrt, ceil

class Town:
    def __init__(self, owner, ID, military, civilian):
        self.owner=owner
        self.id=ID
        self.isEnemy=(self.owner!=PlayerId)
        self.isCurrent=(self.id!=TownId)
        self.mil=military
        self.civ=civilian
        self.freeK=self.mil-self.civ/2
    def canBeat(self, other):
        otherPower    = int(ceil(other.mil*1.2))
        otherMinPower = int(ceil(other.freeK*1.2))
        selfPower     = self.freeK
        if selfPower<otherMinPower:
            return 0
        elif selfPower<otherPower or (selfPower-otherPower)*2-1<other.civ:
            return 1
        else:
            return 2
    def canMove(self, other):
        otherPower    = int(ceil(other.mil*1.2))
        otherMinPower = int(ceil(other.freeK*1.2))
        if otherPower<self.mil:
            return 2
        elif otherMinPower<=self.mil:
            return 1
        else:
            return 0

    def canDefend(self, other):
        return self.freeK>other.mil

def attack_weak():

    for town in EnemyTowns:
        if curr.canMove(town)==2:
            print "A", town.id, curr.mil
            exit()
    for town in EnemyTowns:
        if curr.canMove(town)==1:
            print "A", town.id, curr.mil
            exit()

    target=EnemyTowns[0]
    for et in EnemyTowns:
        if et.mil<target.mil and et.id!=-1:
            target=et
    print "A", target.id, curr.mil-1
    exit()


if len(sys.argv) < 2:
    print 96, 96, 96
else:
    Round, PlayerId, TownId, Towns = sys.argv[1].split(";", 3)
    Round=int(Round)
    PlayerId=int(PlayerId)
    TownId=int(TownId)
    Towns=[[int(i) for i in town.split("_")] for town in Towns.split(";")]
    Towns=[Town(i[0], i[1], i[2], i[3]) for i in Towns]
    MyTowns=[t for t in Towns if t.isEnemy==False]
    EnemyTowns=[t for t in Towns if t.isEnemy]
    GameStateEnd = [t for t in EnemyTowns if t.id!=-1]==[]
    curr=[town for town in MyTowns if town.isCurrent][0]

    support=[town for town in MyTowns if town.freeK<1]
    if support!=[]:
        for town in support:
            if town.id==curr.id:
                missing=town.freeK-int(ceil(town.civ/2))
                if town.civ<5:
                    attack_weak()
                elif town.freeK<-10:
                    attack_weak()
                else:
                    print "W"
                    exit()
        for town in support:
            if abs(town.freeK-2)<curr.freeK-2:
                print "S", town.id, abs(town.freeK-2)
                exit()
            else:
                if curr.freeK>10:
                    print "S", town.id, int(abs(town.freeK-2)*0.2)
                    exit()
    if GameStateEnd:
        attack_end()
    else:
        selection=EnemyTowns[:]
        selection.sort(key=(lambda x: (x.mil-x.civ) if x.civ>3 else x.mil/4))
        for s in selection:
            if curr.canBeat(s)==2 and s.civ>s.mil/2:
                NF=(int(ceil(s.mil*1.2))+s.civ/2+1)
                if curr.mil>NF:
                    print "A", s.id, NF+(curr.mil-NF)/3
                    exit()
    if curr.freeK>10:
        MyTowns.sort(key=lambda x: x.mil)
        print "S", MyTowns[-1].id, (curr.freeK-5)/5*3
        exit()
    print "W"
    exit()

Ejecutar python2 democracy.py. Tenga en cuenta que la democracia requiere Python 2 .

Editar: se corrigió un error sobre la impresión del objeto de la ciudad

Hannes Karppila
fuente
Esto a veces da salida <__main__.Town.
TheNumberOne
Tengo que arreglarlo ...
Hannes Karppila
4

C ++ 11, CalculatedFail

Después de probar algunas cosas con el pequeño Java que conozco y no pude lograr lo que quería, elijo volver a escribirlo en C ++ y agregar el manejo de archivos. El problema era que mi C ++ está bastante oxidado y no mucho mejor, por lo que algunas partes están unidas y son la primera solución en Google, por lo que no es un código de calidad ...

Aún así, pude obtener un resultado que al menos funciona que no es tan malo, gana al menos ocasionalmente, pero no puedo probarlo perfectamente porque no puedo ejecutar todas las otras presentaciones en esta PC. Probablemente volveré a escribir la orientación por completo y la agregaré como otra respuesta más tarde hoy o mañana.

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cmath>
#include <ratio>
#include <fstream>
#include <algorithm>

using namespace std;


class Town {
public:
    Town(int owner, int townId, int knights, int population, int roundToDefBonus);
    int getOwner();
    int getId();
    int getKnights();
    int getPopulation();

    int getFreeKnights();
    int neededConquer();
    int getKnightsStable();
    int getRoundToDef();

    bool operator< (const Town &other) const  {
        return townId < other.townId;
    }
private:
    int owner;
    int townId;
    int knights;
    int population;
    int roundToDefBonus;
    double defBonus;
};

Town::Town(int inOwner, int inTownId, int inKnights, int inPopulation, int inRoundToDefBonus) {
    owner = inOwner;
    townId = inTownId;
    knights = inKnights;
    population = inPopulation;
    roundToDefBonus = inRoundToDefBonus;
    if(roundToDefBonus > 0) {
        defBonus = 1;
    }
    else{
        defBonus = 1.2;
    }
}

int Town::getOwner() {
    return owner;
}
int Town::getId() {
    return townId;
}
int Town::getKnights() {
    return knights;
}
int Town::getPopulation() {
    return population;
}
int Town::getFreeKnights() {
    return knights - population / 2;
}
int Town::neededConquer() {
    return max(static_cast<int>(ceil(knights * defBonus + population / 2)), 1);
}
int Town::getKnightsStable() {
    return population / 2;
}
int Town::getRoundToDef() {
    return roundToDefBonus;
}


int gameRound;
int myId;
int thisTownId;
Town* thisTown;

vector <Town> myTowns;
vector <Town> enemyTowns;

vector <Town> lastTime;

string turn();
Town* bestTarget(int knights);
Town* bestSafe(int knights);
Town* biggestTarget(int knights);
Town* biggestSafe(int knights);


string out(string, int, int);
string attack(Town*);
string safe(Town*);

bool sortTowns(const Town & t1, const Town & t2);

vector <string> stringSplit(string input, string delimeter);

int main(int argc, char* argv[]) {
    if(argc < 2){
        cout << "100 100 100";
        ofstream myFile;
        myFile.open("CalculatedFail.txt");
        myFile << "0\n";
        myFile.close();
    }
    else{
        if(argc == 2){

            string input = argv[1];
            vector <string> params = stringSplit(input, ";");

            gameRound = atoi(params.at(0).c_str());
            myId = atoi((params.at(1)).c_str());
            thisTownId = atoi(params.at(2).c_str());

            ifstream myfile("CalculatedFail.txt");
            if(myfile.is_open()){
                string line;

                getline(myfile, line);
                bool newRound = false;
                if(atoi(line.c_str()) > gameRound) {
                    newRound = true;
                }

                vector <string> oldVals;
                if(!newRound) {
                    while (getline(myfile, line)) {
                        oldVals = stringSplit(line, "_");

                        int playerId = atoi(oldVals.at(0).c_str());
                        int townId = atoi(oldVals.at(1).c_str());
                        int knights = atoi(oldVals.at(2).c_str());
                        int population = atoi(oldVals.at(3).c_str());
                        int roundToDefBonus = atoi(oldVals.at(4).c_str());

                        lastTime.push_back(Town(playerId, townId, knights, population, roundToDefBonus));
                        oldVals.clear();
                    }
                }
                else {
                    while (getline(myfile, line)) {
                        oldVals = stringSplit(line, "_");

                        int playerId = atoi(oldVals.at(0).c_str());
                        int townId = atoi(oldVals.at(1).c_str());
                        int knights = atoi(oldVals.at(2).c_str());
                        int population = atoi(oldVals.at(3).c_str());
                        int roundToDefBonus = atoi(oldVals.at(4).c_str());
                        if(roundToDefBonus) {   //if round def bonus > 0, decrement because new round
                            roundToDefBonus --;
                        }

                        lastTime.push_back(Town(playerId, townId, knights, population, roundToDefBonus));
                        oldVals.clear();
                    }

                }
                std::sort(lastTime.begin(), lastTime.end());
            }

            if(lastTime.size() > 0) {
                vector <string> values;
                for(int i = 3; i < params.size(); i++) {

                    values = stringSplit(params.at(i), "_");

                    int playerId = atoi(values.at(0).c_str());
                    int townId = atoi(values.at(1).c_str());
                    int knights = atoi(values.at(2).c_str());
                    int population = atoi(values.at(3).c_str());

                    int roundsToDef = lastTime.at(townId).getRoundToDef();
                    if(playerId != lastTime.at(townId).getOwner()) {
                        roundsToDef = 2;
                    }
                    if(playerId == myId){
                        if(thisTownId != townId)
                            myTowns.push_back(Town(playerId, townId, knights, population, roundsToDef));
                        else{
                            thisTown = new Town(playerId, townId, knights, population, roundsToDef);
                        }
                    }
                    else{
                        enemyTowns.push_back(Town(playerId, townId, knights, population, roundsToDef));
                    }
                    values.clear();
                }
            }
            else {
                vector <string> values;
                for(int i = 3; i < params.size(); i++) {

                    values = stringSplit(params.at(i), "_");

                    int playerId = atoi(values.at(0).c_str());
                    int townId = atoi(values.at(1).c_str());
                    int knights = atoi(values.at(2).c_str());
                    int population = atoi(values.at(3).c_str());

                    if(playerId == myId){
                        if(thisTownId != townId)
                            myTowns.push_back(Town(playerId, townId, knights, population, 0));
                        else{
                            thisTown = new Town(playerId, townId, knights, population, 0);
                        }
                    }
                    else{
                        enemyTowns.push_back(Town(playerId, townId, knights, population, 0));
                    }
                    values.clear();
                }
            }

            string tmp = turn();
            cout << tmp;

            ofstream writeFile("CalculatedFail.txt");
            if(writeFile.is_open()) {
                writeFile << gameRound <<"\n";

                writeFile << thisTown->getOwner() <<"_"<<thisTown->getId()<<"_"<<thisTown->getKnights()<<"_"<< thisTown->getPopulation()<<"_"<<thisTown->getRoundToDef()<<"\n";

                for(vector<Town>::size_type i = 0; i != myTowns.size(); i++) {
                    writeFile << myTowns[i].getOwner() <<"_"<<myTowns[i].getId()<<"_"<<myTowns[i].getKnights()<<"_"<< myTowns[i].getPopulation()<<"_"<<myTowns[i].getRoundToDef()<<"\n";
                }
                for(vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
                    writeFile << enemyTowns[i].getOwner() <<"_"<<enemyTowns[i].getId()<<"_"<<enemyTowns[i].getKnights()<<"_"<< enemyTowns[i].getPopulation()<<"_"<<enemyTowns[i].getRoundToDef()<<"\n";
                }
            }

        }
        else{
            cout<<"error, wrong parameter";
        }

    }

    delete thisTown;

    return 0;
}




string turn() {
    Town* safeTarget;
    Town* attackTarget;
    if(thisTown->getFreeKnights() < 0) {    //evacuate
        safeTarget = biggestSafe(thisTown->getKnights());
        attackTarget = biggestTarget(thisTown->getKnights());

        if(safeTarget != nullptr && attackTarget != nullptr){
            if(safeTarget->getPopulation() > attackTarget->getPopulation()) {
                return out("S", safeTarget->getId(), thisTown->getKnights());
            }
            else {
                return out("A", attackTarget->getId(), thisTown->getKnights());
            }
        }
        if(safeTarget){
            return out("S", safeTarget->getId(), thisTown->getKnights());
        }
        if(attackTarget){
            return out("A", attackTarget->getId(), thisTown->getKnights());
        }
        Town* target = &myTowns.at(0);
        for(vector<Town>::size_type i = 1; i != myTowns.size(); i++) {
            if(target->getPopulation() < myTowns[i].getPopulation())
                target = &myTowns[i];
        }
        return out("S", target->getId(), thisTown->getKnights());

    }

    safeTarget = biggestSafe(thisTown->getFreeKnights());
    attackTarget = bestTarget(thisTown->getFreeKnights());


    if(safeTarget != nullptr && attackTarget != nullptr){
        if(safeTarget->getPopulation() > attackTarget->getPopulation()) {
            return safe(safeTarget);
        }
        else {
            return attack(attackTarget);
        }
    }
    if(safeTarget){
        return safe(safeTarget);
    }
    if(attackTarget){
        return attack(attackTarget);
    }

    return "W";
}

Town* bestTarget(int knights) {
    Town* target = nullptr;
    double ratio = -1;
    for(vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
        if(enemyTowns[i].neededConquer() < knights) {
            if(enemyTowns[i].getPopulation() / enemyTowns[i].neededConquer() > ratio) {
                target = &enemyTowns[i];
                ratio = enemyTowns[i].getPopulation() / enemyTowns[i].neededConquer();
            }
        }
    }
    return target;
}

Town* biggestTarget(int knights) {
    Town* target = nullptr;
    int population = -1;
    for(vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
        if(enemyTowns[i].neededConquer() < knights) {
            if(enemyTowns[i].getPopulation() > population) {
                target = &enemyTowns[i];
                population = target->getPopulation();
            }
        }
    }
    return target;
}

Town* biggestSafe(int knights) {
    Town* target = nullptr;
    int population = -1;
    for(vector<Town>::size_type i = 0; i != myTowns.size(); i++) {
        if(myTowns[i].getFreeKnights() < 0 && myTowns[i].getFreeKnights() + knights >= 0){
            if(myTowns[i].getPopulation() > population) {
                target = &myTowns[i];
                population = target->getPopulation();
            }
        }
    }
    return target;
}

string attack(Town* target){
    int knights;
    if(thisTown->getPopulation() > target->getPopulation()) {
        knights = target->neededConquer();
    }
    else{
        knights = thisTown->getFreeKnights();
    }
    return out("A", target->getId(), knights);
}
string safe(Town* target){
    int knights;
    if(thisTown->getPopulation() > target->getPopulation()) {
        knights = target->getFreeKnights() * -1;
    }
    else{
        knights = thisTown->getFreeKnights();
    }
    return out("S", target->getId(), knights);
}
string out(string order, int targedId, int knights) {
    stringstream tmp;
    tmp << order << " " << targedId << " " << knights;
    return tmp.str();
}

vector <string> stringSplit(string input, string delimeter) {
    stringstream tmp(input);
    vector <string> splitted;
    string pushThis;
    while (getline(tmp, pushThis, delimeter.at(0))){
        splitted.push_back(pushThis);
    }

    return splitted;
}

compilar con: g++ -std=c++11 CalculatedFail.cpp -o CalculatedFail.exe

google dice en linux que es CalculatedFail.out en lugar del .exe, pero no puedo probarlo.

y correr CalculatedFail.exe

Como utiliza un archivo para verificar la bonificación de definición, ejecutar el juego simultáneamente varias veces puede provocar errores ...

espero que funcione correctamente sin demasiados problemas

sthrandom
fuente
Estoy bastante seguro de que en Linux no tendría una extensión de archivo.
TheNumberOne
No puedo hacer que esto se ejecute desde el Controlador Java en Windows. Lo compilé como dijiste. Funciona correctamente desde la línea de comando.
TheNumberOne
ok, ese era yo siendo estúpido, olvidé cambiar el nombre del archivo de texto al comienzo del juego, creo que debería funcionar ahora
sthrandom
Creo que es un problema con el controlador.
TheNumberOne
mh, ¿intentaste la versión actualizada? ayer tuve 2 nombres de archivo diferentes por accidente. la versión attackOn3 rara vez tiene errores de giro si ya ha ganado básicamente, pero ambos funcionan perfectamente bien con el controlador de mi sistema.
sthrandom
3

Java, Illuminati

Leí esto y sabía que nunca sería capaz de idear una estrategia viable, así que decidí interpretar a los lagartos lamentablemente subrepresentados que pueden o no gobernarnos. En lugar de pelear con los otros bots, este los obliga a cooperar, solo para abandonarlos al final. Este bot, de hecho, no deja ningún daño permanente.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class Illuminati
{
    private static final String template = 
            "import java.io.File;import java.util.Scanner;import java.io.IOException;\n" +
            "public class <<NAME>> \n" +
            "{public static void main(String[] args) throws IOException {if(args.length == 0) {\n" +
            "System.out.println(\"35 35 35\");} else { File ill_data = new File(\"Illuminati.txt\");\n" + 
            "String order = new String();Scanner sc = new Scanner(ill_data);\n" +
            "while(sc.hasNextLine()){order = sc.nextLine();} sc.close(); int city = Integer.parseInt(order);" +
            "Illuminati.TurnDescriptor desc = new Illuminati.TurnDescriptor(args[0]);" +
            "int amt = desc.thistown.getFreeKnights(); System.out.println(\"S \" + city + \" \" + amt); }}}";

    private static final File datafile = new File("Illuminati.txt");

    private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    public static void main(String[] args) throws IOException
    {
        if(args.length == 0)
        {
            if(compiler != null)
            {
                if(!datafile.exists())
                {
                    datafile.createNewFile();
                }

                File parentdir = datafile.getAbsoluteFile().getParentFile();
                List<File> torecompile = new ArrayList<File>();

                for(File f : parentdir.listFiles())
                {
                    if(!f.isDirectory())
                    {
                        if(f.getName().endsWith(".class") && !f.getName().contains("$") && !f.getName().equals("Illuminati.class"))
                        {
                            torecompile.add(f);
                        }
                    }
                }

                for(File f : torecompile)
                {
                    File newfile = new File(f.getName() + ".temp");
                    FileInputStream fis = new FileInputStream(f);
                    FileOutputStream fos = new FileOutputStream(newfile);
                    int val;
                    while((val = fis.read()) != -1)
                    {
                        fos.write(val);
                    }
                    fis.close();
                    fos.close();
                }

                List<File> tocompile = new ArrayList<File>();

                for(File f : torecompile)
                {
                    String classname = f.getName().substring(0, f.getName().length() - 6);
                    String code = template.replace("<<NAME>>", classname);
                    File temp = new File(classname + ".java");
                    FileOutputStream fos = new FileOutputStream(temp);
                    fos.write(code.getBytes());
                    fos.close();
                    tocompile.add(temp);
                }

                StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
                compiler.getTask(null, manager, null, null, null, manager.getJavaFileObjectsFromFiles(tocompile)).call();

                tocompile.forEach(file -> file.delete());

                System.out.println("34 34 34");
            }
            else
            {
                System.out.println("85 85 85");
            }
        }
        else
        {
            if(datafile.exists())
            {
                TurnDescriptor descriptor = new TurnDescriptor(args[0]);
                int knights = descriptor.thistown.getFreeKnights();
                int stockpile = descriptor.towns.stream()
                .filter(town -> town.owner == descriptor.thistown.owner)
                .mapToInt(town -> town.id)
                .max().getAsInt();
                PrintWriter pw = new PrintWriter(datafile);
                pw.println("" + stockpile);
                pw.close();
                if(descriptor.thistown.id != stockpile)
                {
                    System.out.println("S " + stockpile + " " + knights);
                }
                if(descriptor.round > 80 && (descriptor.round & 1) == 1) //If the round is greater than 80 and is odd
                {
                    if(descriptor.thistown.id == stockpile)
                    {
                        Town target = descriptor.towns.stream()
                        .filter(town -> town.owner != descriptor.playerid)
                        .findAny().get();

                        System.out.println("A " + target.id + " " + descriptor.thistown.getFreeKnights());
                    }
                }
                if(descriptor.round == 99) //Resume normal AI practices
                {
                    resetClassesFromCache();
                }
            }
            else //Man, now we have to actually do stuff
            {
                System.out.println("W"); //Just kidding! Suicide!
            }
        }
    }

    private static void resetClassesFromCache() throws IOException
    {
        File parentdir = datafile.getAbsoluteFile().getParentFile();

        for(File f : parentdir.listFiles())
        {
            if(!f.isDirectory())
            {
                if(f.getName().endsWith(".class.temp") && !f.getName().contains("$"))
                {
                    FileInputStream fis = new FileInputStream(f);
                    File out = new File(f.getName().substring(0, f.getName().length() - 5));
                    FileOutputStream fos = new FileOutputStream(out, false);

                    int val;
                    while((val = fis.read()) != -1)
                    {
                        fos.write(val);
                    }

                    fis.close();
                    fos.close();
                    f.delete();
                }
            }
        }
    }

    public static class Town
    {
        public final int owner;
        public final int id;
        public final int knights;
        public final int lowborns;

        public Town(String chunk)
        {
            String[] vals = chunk.split("_");
            owner = Integer.parseInt(vals[0]);
            id = Integer.parseInt(vals[1]);
            knights = Integer.parseInt(vals[2]);
            lowborns = Integer.parseInt(vals[3]);
        }

        public int getFreeKnights()
        {
            return knights - (lowborns/2) - 1;
        }
    }

    public static class TurnDescriptor
    {
        public final List<Town> towns;
        public final int round;
        public final int playerid;
        public final Town thistown;

        public TurnDescriptor(String s)
        {
            String[] info = s.split(";");
            round = Integer.parseInt(info[0]);
            playerid = Integer.parseInt(info[1]);
            final int townid = Integer.parseInt(info[2]);

            towns = new ArrayList<Town>();
            for(int i = 3; i < info.length; i++)
            {
                Town t = new Town(info[i]);
                towns.add(t);
            }

            thistown = towns.stream()
            .filter(town -> {return town.id == townid;})
            .findFirst().get();
        }
    }
}
Hola llama
fuente
2
Si bien esta es una respuesta interesante, " Otros recursos externos no están permitidos ". Por lo tanto, su envío está excluido de las pruebas, pero lo votaré de todos modos;)
CommonGuy
3

Java, Superproductor

Es tarde en mi parte del mundo, así que no tengo tiempo suficiente para elaborar mi presentación. Lo haré, planearé explicar cómo funciona más adelante.

El rendimiento del bot parece altamente dependiente del orden de inicio que gana algunas veces ...

Tenía algunas ideas para ayudar a aumentar las rondas ganadoras ... pero fuera de tiempo: P

package moogiesoft;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;



public class SuperProducer implements Serializable
{
    private static final int MAX_POSSIBLE_LOWBORNS_IN_TOWN = 50;
    /**
     * 
     */
    private static final long serialVersionUID = 8652887937499233654L;
    public final String FILE = this.getClass().getSimpleName()+".txt";
    int round;
    int playerID;
    int thisTownID;

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

    Map<Integer, Conquest> townOwnerShipMap = new HashMap<Integer, Conquest>();

    Town thisTown;
    private int targetOpponent = -1; // the id of the opponent that out towns will endevour to direct their attacks 
    private int maxOpponentTownSize; // the number of knights of the opponent town with the most knights
    private int avgOpponentTownSize; // the average number of knights in an opponent town
    private int midAvgMaxOpponentTownSize; // value 1/2 between average and max knights in an opponent town

    public static void main(String[] args){
        if (args.length == 0){
            new SuperProducer().sendStartingKnights();
        }
        else
        {
            new SuperProducer().letsDoIt(args[0].split(";"));
        }
    }

    private void sendStartingKnights()
    {
        // delete any stale state information
        File file = new File(FILE);
        file.delete();

        System.out.println("100 100 0");
    }

    private void letsDoIt(String[] args)
    {
        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);
        thisTownID = Integer.parseInt(args[2]);
        towns = new ArrayList<>();
        myTowns = new ArrayList<>();
        otherTowns = new ArrayList<>();

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

        // load in stored state information
        File file = new File(FILE);
        if (file.exists())
        {
            try
            {
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
                townOwnerShipMap = (Map<Integer, Conquest>) ois.readObject();
                targetOpponent  = ois.readInt();
                ois.close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        for (Town town : towns)
        {

            // update town conquest map
            Conquest conquest = townOwnerShipMap.remove(town.getId());
            if (conquest==null)
            {
                conquest = new Conquest(town.ownerId, -1);
                townOwnerShipMap.put(town.getId(),conquest);
            }
            else if (town.getOwner()!=conquest.getOwner())
            {
                conquest.setOwner(town.ownerId);
                conquest.setConquestRound(round-1);
            }
            town.setDefenceBonus(round-conquest.getConquestRound()>2);

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

        String response = "W";

        // this town has some knights to potentially command...
        if (thisTown.getKnightCount()>0)
        {
            // first round... consolidate into 1 super town
            if (round==1)
            {
                int thisTownIndex=myTowns.indexOf(thisTown);
                switch (thisTownIndex)
                {
                    case 1:
                    case 0:
                        // if we are the first town then move all knights into second town
                        if (myTowns.size()>1 && thisTown.getKnightCount()<200)
                        {
                            response = "S " + myTowns.get(thisTownIndex+1).getId() + " " + thisTown.getKnightCount();
                            break;
                        }
                    default:
                        // the third town does nothing!
                }
            }
            else 
            {
                // second round... go find some good starting towns to conquer
                if (round==2)
                {
                    // this town is a town able to attack
                    if (thisTown.getKnightCount()>100)
                    {
                        // If by some miracle we still own the town with no knights then re-inforce it.
                        Town superTown = myTowns.stream().filter(a->a.getKnightCount()==200).findFirst().get();
                        if (superTown!=null && superTown.getId()!=thisTown.getId())
                        {
                            response = "S " + superTown.getId() + " " + thisTown.getKnightCount();
                        }
                        else
                        {
                            // find the next most productive Town...
                            Town townToAttack = otherTowns.get(0);
                            for (Town town : otherTowns)
                            {
                                if (town.getLowbornCount()>townToAttack.getLowbornCount())
                                {
                                    townToAttack=town;
                                    if (townToAttack.getOwner()!=playerID)
                                    {
                                        targetOpponent=townToAttack.getOwner();
                                    }
                                }
                            }

                            // the town to attack is most likely the own we lost due to having no knights to begin with...
                            response = "A " + townToAttack.getId() + " " + thisTown.getKnightCount();
                        }
                    }
                    // else this is a conquered town so lets not do anything!
                }
                else if (round>97)
                {
                    int attackForce = thisTown.getFreeKnights()/4;
                    if (thisTown.getFreeKnights()>attackForce && attackForce>0)
                    {

                        boolean goFlag=false;
                        Town townToAttack = null;
                        for (Town town : towns)
                        {
                            // 
                            if (town==thisTown) goFlag=true;
                            else if (goFlag && town.getOwner()!=thisTown.getOwner())
                            {
                                if (town.getLowbornCount()==0)
                                {
                                    townToAttack=town;
                                    break;
                                }
                            }
                        }

                        if (townToAttack==null)
                        {
                            for (Town town : otherTowns)
                            {
                                if (town.getLowbornCount()==0)
                                {
                                    townToAttack=town;
                                    break;
                                }
                            }
                        }

                        if (round > 98 && townToAttack==null)
                        {
                            for (Town town : otherTowns)
                            {
                                attackForce = thisTown.getKnightCount()-town.getKnightCount()-town.getMinimumKnights()-1-thisTown.getMinimumKnights()-1;
                                if (attackForce>0)
                                {
                                    townToAttack=town;
                                    break;
                                }
                            }
                        }

                        if (townToAttack!=null)
                        {
                            response = "A " + townToAttack.getId() + " " + attackForce;
                        }
                        else
                        {
                            int thisTownIndex = myTowns.indexOf(thisTown);
                            int supportSize = Math.min(thisTown.getKnightCount()/4, thisTown.getFreeKnights());

                            if (supportSize>thisTown.getMinimumKnights() && thisTownIndex<myTowns.size()-1)
                            {
                                Town townToSupport = myTowns.get(thisTownIndex+1);
                                response = "S " + townToSupport.getId() + " " + (thisTown.getKnightCount()-thisTown.getKnightCount()/4);
                            }
                        }
                    }

                }

                // we are on non-beginning non-ending round...
                else
                {
                    // calculate statistics
                    IntSummaryStatistics statistics = otherTowns.stream().collect(Collectors.summarizingInt(Town::getKnightCount));
                    maxOpponentTownSize = statistics.getMax();
                    avgOpponentTownSize = (int) statistics.getAverage();
                    midAvgMaxOpponentTownSize = (maxOpponentTownSize+avgOpponentTownSize)/2;

                    if ((round-1)%3==1)
                    {
                        // find the next strongest town of our target Opponent that produces knights...
                        Town townToAttack = null;
                        for (Town town : otherTowns)
                        {
                            if (town.getLowbornCount() > 0 && town.getOwner() == targetOpponent && (townToAttack == null || town.getKnightCount()>townToAttack.getKnightCount()))
                            {
                                townToAttack=town;
                            }
                        } 


                        // target opponent cannot grow so choose another opponent...
                        // favour the weakest opponent that has has some towns that produces towns..
                        // otherwise favour the weakest opponent
                        if (townToAttack==null)
                        {
                            townToAttack=chooseNewOpponentToAttack();
                        }
                        targetOpponent=townToAttack.getOwner();

                        int minKnightsToLeaveAtThisTown = calculateDesiredKnightsAtTown(thisTown);
                        int minKnightsToLeftAtAttackedTownAfterBattle = calculateDesiredKnightsAtTown(townToAttack);

                        double defenceBonus = townToAttack.hasDefenceBonus()?1.2:1;
                        double defenderAttackStrength = townToAttack.getKnightCount() * defenceBonus;
                        int knightsNeededToWinAndEnsureNotAttackedNextRound =  minKnightsToLeftAtAttackedTownAfterBattle + (int) (defenderAttackStrength);
                        knightsNeededToWinAndEnsureNotAttackedNextRound = knightsNeededToWinAndEnsureNotAttackedNextRound + ((knightsNeededToWinAndEnsureNotAttackedNextRound-defenderAttackStrength - townToAttack.getMinimumKnights() < 0) ?townToAttack.getMinimumKnights():0);
                        int knightsLeftAtSortieingTownAfterAttacking = thisTown.getKnightCount()-knightsNeededToWinAndEnsureNotAttackedNextRound;

                        // if the sortieing town is sufficiently safe from another attack after it attempts to attack the other town will it try to attack  
                        if (knightsLeftAtSortieingTownAfterAttacking > thisTown.getMinimumKnights()*2 &&
                            knightsLeftAtSortieingTownAfterAttacking>minKnightsToLeaveAtThisTown &&
                            thisTown.getFreeKnights()>knightsNeededToWinAndEnsureNotAttackedNextRound)
                        {
                            response = "A " + townToAttack.getId() + " " + knightsNeededToWinAndEnsureNotAttackedNextRound;
                        }
                        // not safe... so lets support our other towns
                        else
                        {
                            int surplusKnights = thisTown.getKnightCount()-minKnightsToLeaveAtThisTown;

                            // this town has surplusKnights
                            if (surplusKnights>0)
                            {
                                int knightsAvailable = Math.min(surplusKnights, thisTown.getFreeKnights());

                                // find our weakest and strongest towns
                                Town myWeakestTown=null;
                                Town myStrongestTown=null;
                                for (Town town : myTowns)
                                {
                                    if (!(town.getKnightCount()==0 && round<50) && (myWeakestTown == null || town.getKnightCount()<myWeakestTown.getKnightCount()))
                                    {
                                        myWeakestTown=town;
                                    }
                                    if (!(town.getKnightCount()==0 && round<50) && ( myStrongestTown == null || town.getKnightCount()>myStrongestTown.getKnightCount()))
                                    {
                                        myStrongestTown=town;
                                    }
                                }

                                // see if my Weakest Town needs support
                                Town townToSupport = null;
                                int knightsToSend=0;
                                if (thisTown!=myWeakestTown)
                                {
                                    int desiredKnightsAtTown = calculateDesiredKnightsAtTown(myWeakestTown);

                                    if (myWeakestTown.getKnightCount()<desiredKnightsAtTown)
                                    {
                                        int deltaDesiredKnights = desiredKnightsAtTown-myWeakestTown.getKnightCount();
                                        knightsToSend = Math.min(knightsAvailable, deltaDesiredKnights);
                                        townToSupport=myWeakestTown;
                                    }
                                }

                                // no towns needed support so we will attempt to support the strongest town
                                if (townToSupport == null)
                                {
                                    if (thisTown!=myStrongestTown)
                                    {
                                        int desiredKnightsAtTown = calculateDesiredKnightsAtTown(myStrongestTown);
                                        if (myStrongestTown.getKnightCount()<desiredKnightsAtTown)
                                        {
                                            int deltaDesiredKnights = desiredKnightsAtTown-myStrongestTown.getKnightCount();
                                            knightsToSend = Math.min(knightsAvailable, deltaDesiredKnights);

                                            knightsToSend = knightsAvailable;
                                            townToSupport=myStrongestTown;
                                        }
                                    }
                                }

                                // support the chosen town if possible
                                if (townToSupport != null)
                                {
                                    response = "S " + townToSupport.getId() + " " + knightsToSend;
                                }
                            }
                        }
                    }
                }
            }
        }

        // save state information
        try
        {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
            oos.writeObject(townOwnerShipMap);
            oos.writeInt(targetOpponent);
            oos.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        System.out.println(response);
    }

    // returns a town of the opponent that is deemed to be the most worthy
    private final Town chooseNewOpponentToAttack()
    {
        Town townToAttack=null;

        // calculate opponent sizes
        HashMap<Integer,Opponent> opponentMap = new HashMap<Integer, Opponent>();
        for (Town town : otherTowns)
        {
            Opponent opponent = opponentMap.get(town.getOwner());
            if (opponent == null)
            {
                opponent = new Opponent(town.getOwner());
                opponentMap.put(town.getOwner(), opponent);
            }
            opponent.addTown(town);
        }


        // create sorted list of opponents based on strength. 
        List<Integer> opponentsByStrength = new ArrayList<Integer>(opponentMap.keySet());
        opponentsByStrength.sort(new Comparator<Integer>()
        {
            public int compare(Integer o1, Integer o2)
            {
                Opponent left = opponentMap.get(o1);
                Opponent right = opponentMap.get(o2);

                return left.getTotalKnights()-right.getTotalKnights();
            }
        });

        // attempt to choose the weakest opponent's weakest town that has some ability to generate knights...
        out:
        for (Integer opponent : opponentsByStrength)
        {
            for (Town town : opponentMap.get(opponent).getTowns())
            {
                if (town.getOwner() !=-1 && town.getLowbornCount() > 0 && (townToAttack == null || town.getKnightCount()<townToAttack.getKnightCount()))
                {
                    townToAttack=town;
                    break out;
                }
            } 
        }

        // no opponents left with knights producing towns... just go for the weakest town.
        if (townToAttack == null)
        {
            for (Town town : otherTowns)
            {
                if (townToAttack == null || town.getKnightCount()<townToAttack.getKnightCount())
                {
                    townToAttack=town;
                }
            } 
        }

        return townToAttack;
    }

    // returns the number of knights that should make this town safe from attack
    final private int calculateDesiredKnightsAtTown(Town town)
    {
        int minimumKnightsWeWantInATown = avgOpponentTownSize;
        return minimumKnightsWeWantInATown + town.getLowbornCount()==0?0:(minimumKnightsWeWantInATown +(int) (((double) town.getLowbornCount() / MAX_POSSIBLE_LOWBORNS_IN_TOWN) * (midAvgMaxOpponentTownSize-minimumKnightsWeWantInATown)));
    }

    /** represents a conquest of a Town by a player */
    class Conquest implements Serializable
    {
        private static final long serialVersionUID = -1120109012356785962L;
        private int owner;
        private int conquestRound;
        public int getOwner()
        {
            return owner;
        }
        public void setOwner(int owner)
        {
            this.owner = owner;
        }
        public int getConquestRound()
        {
            return conquestRound;
        }
        public void setConquestRound(int conquestRound)
        {
            this.conquestRound = conquestRound;
        }
        public Conquest(int owner, int conquestRound)
        {
            super();
            this.owner = owner;
            this.conquestRound = conquestRound;
        }

    }

    /** represents an opponent in the simulation */
     private class Opponent implements Serializable
     {
         private int ownerId;
         private int totalKnights;
         private List<Town> towns = new ArrayList<SuperProducer.Town>();

         public void addTown(Town town)
         {
             totalKnights+=town.getKnightCount();
             towns.add(town);
         }

        public int getOwnerId()
        {
            return ownerId;
        }

        public int getTotalKnights()
        {
            return totalKnights;
        }

        public List<Town> getTowns()
        {
            return towns;
        }

        public Opponent(int ownerId)
        {
            super();
            this.ownerId = ownerId;
        }
     }

     /** represents a Town in the simulation */
     private class Town implements Serializable
    {
        private static final long serialVersionUID = 5011668142883502165L;
        private final int ownerId;
        private final int id;
        private final int knights;
        private final int lowborns;
        private boolean defenceFlag =true;

        public Town(String string){
            String[] args = string.split("_");
            ownerId = Integer.parseInt(args[0]);
            id = Integer.parseInt(args[1]);
            knights = Integer.parseInt(args[2]);
            lowborns = Integer.parseInt(args[3]);
        }

        public boolean hasDefenceBonus()
        {
            return defenceFlag;
        }

        public void setDefenceBonus(boolean defenceFlag)
        {
            this.defenceFlag = defenceFlag;
        }

        public int getId() {
            return id;
        }

        public int getOwner() {
            return ownerId;
        }

        public int getKnightCount() {
            return knights;
        }

        public int getLowbornCount() {
            return lowborns;
        }

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

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

        private int getFreeKnights() {
            return knights - lowborns / 2 - 1;
        }

        private int getMinimumKnights() {
            return lowborns / 2 + 1;
        }
    }
 }

Compilar: javac SuperProducer.java

Ejecutar: java moogiesoft.SuperProducer

Moogie
fuente
2

C ++ 11, attackOn3

el código en sí no se volvió mucho más bonito, pero ahora utilizo otra forma de apuntar, posiblemente agregaré comentarios al código más adelante.

parece estar bien con los bots que estoy ejecutando, aunque todavía es difícil contra frankenstein y liberator y no puede ganar de manera consistente.

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cmath>
#include <ratio>
#include <fstream>
#include <algorithm>

using namespace std;


class Town {
public:
    Town(int owner, int townId, int knights, int population, int roundToDefBonus);

    int getOwner();

    int getId();

    int getKnights();

    int getPopulation();

    int getFreeKnights();

    int neededConquer();

    int needRevolt();

    int getRoundToDef();

    bool operator<(const Town &other) const {
        return townId < other.townId;
    }

private:
    int owner;
    int townId;
    int knights;
    int population;
    int roundToDefBonus;
    double defBonus;
};

Town::Town(int inOwner, int inTownId, int inKnights, int inPopulation, int inRoundToDefBonus) {
    owner = inOwner;
    townId = inTownId;
    knights = inKnights;
    population = inPopulation;
    roundToDefBonus = inRoundToDefBonus;
    if (roundToDefBonus > 0) {
        defBonus = 1;
    }
    else {
        defBonus = 1.2;
    }
}

int Town::getOwner() {
    return owner;
}

int Town::getId() {
    return townId;
}

int Town::getKnights() {
    return knights;
}

int Town::getPopulation() {
    return population;
}

int Town::getFreeKnights() {
    return knights - population / 2;
}

int Town::neededConquer() {
    return max(static_cast<int>(ceil(knights * defBonus + population / 2)), 1);
}

int Town::needRevolt() {
    return knights * defBonus - population / 2;
}

int Town::getRoundToDef() {
    return roundToDefBonus;
}

#define maxRounds 100
#define newKnights 3

const int attackround = newKnights - 1;
const int getEmptyTowns = maxRounds - 5;

int gameRound;
int myId;
int thisTownId;
Town *thisTown;

vector<Town> myTowns;
vector<Town> enemyTowns;

vector<Town> lastTime;

string turn();

Town *bestGainTarget(int knights);

Town *bestSafe(int knights);

Town *biggestTarget(int knights);

Town *biggestSafe(int knights);

Town *weakTarget(int knights);


string out(string, int, int);

string attack(Town *);

string safe(Town *);

bool sortTowns(const Town &t1, const Town &t2);

vector<string> stringSplit(string input, string delimeter);

int getBiggestEnemyId();

int main(int argc, char *argv[]) {
    if (argc < 2) {
        cout << "100 100 100";
        ofstream myFile;
        myFile.open("attackOn3.txt");
        myFile << "0\n";
        myFile.close();
    }
    else {
        if (argc == 2) {

            string input = argv[1];
            vector<string> params = stringSplit(input, ";");

            gameRound = atoi(params.at(0).c_str());
            myId = atoi((params.at(1)).c_str());
            thisTownId = atoi(params.at(2).c_str());

            ifstream myfile("attackOn3.txt");
            if (myfile.is_open()) {
                string line;

                getline(myfile, line);
                bool newRound = false;
                if (atoi(line.c_str()) > gameRound) {
                    newRound = true;
                }

                vector<string> oldVals;
                if (!newRound) {
                    while (getline(myfile, line)) {
                        oldVals = stringSplit(line, "_");

                        int playerId = atoi(oldVals.at(0).c_str());
                        int townId = atoi(oldVals.at(1).c_str());
                        int knights = atoi(oldVals.at(2).c_str());
                        int population = atoi(oldVals.at(3).c_str());
                        int roundToDefBonus = atoi(oldVals.at(4).c_str());

                        lastTime.push_back(Town(playerId, townId, knights, population, roundToDefBonus));
                        oldVals.clear();
                    }
                }
                else {
                    while (getline(myfile, line)) {
                        oldVals = stringSplit(line, "_");

                        int playerId = atoi(oldVals.at(0).c_str());
                        int townId = atoi(oldVals.at(1).c_str());
                        int knights = atoi(oldVals.at(2).c_str());
                        int population = atoi(oldVals.at(3).c_str());
                        int roundToDefBonus = atoi(oldVals.at(4).c_str());
                        if (roundToDefBonus) {   //if round def bonus > 0, decrement because new round
                            roundToDefBonus--;
                        }

                        lastTime.push_back(Town(playerId, townId, knights, population, roundToDefBonus));
                        oldVals.clear();
                    }

                }
                std::sort(lastTime.begin(), lastTime.end());
            }

            if (lastTime.size() > 0) {
                vector<string> values;
                for (int i = 3; i < params.size(); i++) {

                    values = stringSplit(params.at(i), "_");

                    int playerId = atoi(values.at(0).c_str());
                    int townId = atoi(values.at(1).c_str());
                    int knights = atoi(values.at(2).c_str());
                    int population = atoi(values.at(3).c_str());

                    int roundsToDef = lastTime.at(townId).getRoundToDef();
                    if (playerId != lastTime.at(townId).getOwner()) {
                        roundsToDef = 2;
                    }
                    if (playerId == myId) {
                        if (thisTownId != townId)
                            myTowns.push_back(Town(playerId, townId, knights, population, roundsToDef));
                        else {
                            thisTown = new Town(playerId, townId, knights, population, roundsToDef);
                        }
                    }
                    else {
                        enemyTowns.push_back(Town(playerId, townId, knights, population, roundsToDef));
                    }
                    values.clear();
                }
            }
            else {
                vector<string> values;
                for (int i = 3; i < params.size(); i++) {

                    values = stringSplit(params.at(i), "_");

                    int playerId = atoi(values.at(0).c_str());
                    int townId = atoi(values.at(1).c_str());
                    int knights = atoi(values.at(2).c_str());
                    int population = atoi(values.at(3).c_str());

                    if (playerId == myId) {
                        if (thisTownId != townId)
                            myTowns.push_back(Town(playerId, townId, knights, population, 0));
                        else {
                            thisTown = new Town(playerId, townId, knights, population, 0);
                        }
                    }
                    else {
                        enemyTowns.push_back(Town(playerId, townId, knights, population, 0));
                    }
                    values.clear();
                }
            }

            string tmp = turn();
            cout << tmp;

            ofstream writeFile("attackOn3.txt");
            if (writeFile.is_open()) {
                writeFile << gameRound << "\n";

                writeFile << thisTown->getOwner() << "_" << thisTown->getId() << "_" << thisTown->getKnights() << "_" << thisTown->getPopulation() << "_" << thisTown->getRoundToDef() << "\n";

                for (vector<Town>::size_type i = 0; i != myTowns.size(); i++) {
                    writeFile << myTowns[i].getOwner() << "_" << myTowns[i].getId() << "_" << myTowns[i].getKnights() << "_" << myTowns[i].getPopulation() << "_" << myTowns[i].getRoundToDef() << "\n";
                }
                for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
                    writeFile << enemyTowns[i].getOwner() << "_" << enemyTowns[i].getId() << "_" << enemyTowns[i].getKnights() << "_" << enemyTowns[i].getPopulation() << "_" << enemyTowns[i].getRoundToDef() << "\n";
                }
            }
        }
        else {
            cout << "error, wrong parameter";
        }
    }

    delete thisTown;

    return 0;
}


string turn() {
    Town *safeTarget;
    Town *attackTarget;
    if (thisTown->getFreeKnights() < 0) {    //evacuate
        safeTarget = biggestSafe(thisTown->getKnights());
        attackTarget = biggestTarget(thisTown->getKnights());

        if (safeTarget != nullptr && attackTarget != nullptr) {
            if (safeTarget->getPopulation() > attackTarget->getPopulation()) {
                return out("S", safeTarget->getId(), thisTown->getKnights());
            }
            else {
                return out("A", attackTarget->getId(), thisTown->getKnights());
            }
        }
        if (safeTarget) {
            return out("S", safeTarget->getId(), thisTown->getKnights());
        }
        if (attackTarget) {
            return out("A", attackTarget->getId(), thisTown->getKnights());
        }
        Town *target = &myTowns.at(0);
        for (vector<Town>::size_type i = 1; i != myTowns.size(); i++) {
            if (target->getPopulation() < myTowns[i].getPopulation())
                target = &myTowns[i];
        }
        return out("S", target->getId(), thisTown->getKnights());

    }

    safeTarget = biggestSafe(thisTown->getFreeKnights());
    if (gameRound % newKnights == attackround) {      //knights only get produced every 3 town, i want to conquer the best towns just before that so i get more reinforments and dont need to fight quite that much
        attackTarget = bestGainTarget(thisTown->getFreeKnights());
    }
    else {       //but if a town is easy to aquiere i still want it, e. g. because of revolution or someone weakened it so that it will revolte
        attackTarget = weakTarget(thisTown->getFreeKnights());
    }

    if (safeTarget != nullptr && attackTarget != nullptr) {
        if (safeTarget->getPopulation() > attackTarget->getPopulation()) {
            return safe(safeTarget);
        }
        else {
            return attack(attackTarget);
        }
    }
    if (safeTarget) {
        return safe(safeTarget);
    }
    if (attackTarget) {
        return attack(attackTarget);
    }

    if (gameRound > getEmptyTowns) {     //empty towns dont matter early on but still count to win score
        for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
            if (enemyTowns[i].getPopulation() < 2) {
                if (enemyTowns[i].neededConquer() < thisTown->getFreeKnights()) {
                    return attack(&enemyTowns[i]);
                }
            }
        }
    }

    int biggestEnemy = getBiggestEnemyId();
    //if last round attack possible biggest other guy
    if (gameRound == maxRounds) {
        int targetKnights = -1;
        Town *target;
        for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
            if (enemyTowns[i].getOwner() == biggestEnemy) {
                if (enemyTowns[i].neededConquer() < thisTown->getFreeKnights()) {
                    if (enemyTowns[i].getFreeKnights() > targetKnights) {
                        target = &enemyTowns[i];
                        targetKnights = target->getFreeKnights();
                    }
                }
            }
        }
        if (targetKnights > -1) {
            attack(target);
        }
    }
    //revolt from biggest other guy
    if (gameRound > 10) {        //most bots need a bit of time
        int targetPop = 0;
        Town *target;
        for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
            if (enemyTowns[i].getOwner() == biggestEnemy) {
                if (enemyTowns[i].needRevolt() < thisTown->getFreeKnights()) {
                    if (enemyTowns[i].getPopulation() > targetPop) {
                        target = &enemyTowns[i];
                        targetPop = target->getPopulation();
                    }
                }
            }
        }
        if (targetPop != 0) {
            return attack(target);
        }
    }

    return "W";
}

Town *bestGainTarget(int knights) {
    Town *target = nullptr;
    int gain = -thisTown->getFreeKnights();
    int now = -thisTown->getFreeKnights();
    //int loses = thisTown->getFreeKnights();
    for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
        int conquer = enemyTowns[i].neededConquer();
        if (conquer < knights && enemyTowns[i].getPopulation() > 0) {
            if (enemyTowns[i].getPopulation() * 2 *1.2 - conquer > gain) {
                if(enemyTowns[i].getPopulation() - conquer > now){
                    target = &enemyTowns[i];
                    now = target->getPopulation() - conquer;
                    gain = target->getPopulation() * 2 - conquer;
                }
            }
        }
    }
    return target;
}

Town *weakTarget(int knights) {     //maybe change it that it prefers targets with 0/40 over 24/50
    Town *target = nullptr;
    double population = 1;
    for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
        if (enemyTowns[i].neededConquer() < knights) {
            if (enemyTowns[i].getKnights() < enemyTowns[i].getPopulation() / 2) {
                if (enemyTowns[i].getPopulation() > population) {
                    target = &enemyTowns[i];
                    population = target->getPopulation();
                }
            }
        }
    }
    return target;
}

Town *biggestTarget(int knights) {
    Town *target = nullptr;
    int population = -1;
    for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
        if (enemyTowns[i].neededConquer() < knights) {
            if (enemyTowns[i].getPopulation() > population) {
                target = &enemyTowns[i];
                population = target->getPopulation();
            }
        }
    }
    return target;
}

Town *biggestSafe(int knights) {
    Town *target = nullptr;
    int population = -1;
    for (vector<Town>::size_type i = 0; i != myTowns.size(); i++) {
        if (myTowns[i].getFreeKnights() < 0 && myTowns[i].getFreeKnights() + knights >= 0) {
            if (myTowns[i].getPopulation() > population) {
                target = &myTowns[i];
                population = target->getPopulation();
            }
        }
    }
    return target;
}

int getBiggestEnemyId() {
    int players[enemyTowns.size() / 3 + 1];
    for (vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) {
        if (enemyTowns[i].getOwner() != -1) {
            players[enemyTowns[i].getOwner()] = enemyTowns[i].getPopulation();
        }
    }
    int max = 0;
    for (int i = 1; i < enemyTowns.size() / 3 + 1; i++) {
        if (players[i] > players[max]) {
            max = i;
        }
    }
}

string attack(Town *target) {
    int knights;
    if (thisTown->getPopulation() > target->getPopulation()) {
        knights = target->neededConquer();
    }
    else {
        knights = thisTown->getFreeKnights();
    }
    return out("A", target->getId(), knights);
}

string safe(Town *target) {
    int knights;
    if (thisTown->getPopulation() > target->getPopulation()) {
        knights = target->getFreeKnights() * -1;
    }
    else {
        knights = thisTown->getFreeKnights();
    }
    return out("S", target->getId(), knights);
}

string out(string order, int targedId, int knights) {
    stringstream tmp;
    tmp << order << " " << targedId << " " << knights;
    return tmp.str();
}

vector<string> stringSplit(string input, string delimeter) {
    stringstream tmp(input);
    vector<string> splitted;
    string pushThis;
    while (getline(tmp, pushThis, delimeter.at(0))) {
        splitted.push_back(pushThis);
    }
    return splitted;
}

compilar con: g++ -std=c++11 attackOn3.cpp -o attackOn3.exe
y ejecutarattackOn3.exe

sthrandom
fuente