위험, 전쟁의 길


12

소개

이 게임에서 플레이어는 자신의 군대를 사용하여 다른 플레이어의 군대와 싸우고 영토를 점령하며 마지막으로 서있는 사람이됩니다. 매 턴마다 플레이어는 자신의 처분에 사용할 기본 군대를받습니다. 그러나 특정 지역에서 영토를 점령하면 플레이어가이 숫자를 늘려 나중에 게임에서 잠재적 이점을 얻을 수 있습니다. (이것은 기본적으로 Warlight 와 동일합니다 ).

모든 봇은 Java, C 또는 C ++로 작성해야합니다 (다른 언어는 포함하지만 소프트웨어 나 경험이없는 경우). 제출물이 클래스를 확장 할 필요는 없으며 함수, 클래스, 인터페이스 또는 기타 필요한 것을 작성하고 표준 API 에서 패키지 또는 클래스를 사용할 수 있습니다. 클래스 또는 인터페이스를 만들 계획이라면 내부 클래스 또는 내부 인터페이스 사용을 고려하십시오.

이 경쟁에서 컨트롤러 또는 다른 제출물을 프로그래밍 방식으로 변경하려고 시도하지 마십시오.

게임 플레이

개요

10x10 2 차원 배열은 보드를 시뮬레이션하며 각 요소 / 셀은 "영역"을 나타냅니다. 라운드 당 20 라운드와 최대 1000 턴이 있습니다. 매 턴마다 플레이어는 먼저 자신이 소유 한 영토를 자신이 소유 한 영토에 배치 한 다음 군대를 공격하여 상대방의 영토를 점령하려는 시도로 인근 영토로 군대를 옮길 수 있습니다. 플레이어 모든 군대 배치 해야 하지만 원하는 경우 이동할 필요는 없습니다.

공격 / 이동 군대

플레이어가 원하면 한 지역에서 8 개의 인접 지역으로 군대를 보낼 수 있습니다. 보드는 "랩핑"됩니다. 즉, 플레이어의 영토가 한쪽에 있다면, 그 군대를 다른 쪽의 인접한 영토로 옮길 수 있습니다. 영토에서 군대를 옮길 때에도 그 영토에 군대가 적어도 하나는 남아 있어야합니다. 예를 들어, 영토에 5 개의 군대가있는 경우 4 개 이하 만 다른 영토로 이동할 수 있습니다. 영토에 하나가 포함되어 있으면 해당 군대는 이동할 수 없습니다.

플레이어 n가 한 영토에서 다른 영토 로 군대를 보내면 해당 영토가 n군대 를받습니다 .

플레이어 n가 자신의 영토에서 o군대 가있는 상대 영토로 군대를 보냅니다 . 가장 가까운 정수 on * .6반올림하여 감소 합니다. 그러나 동시에 가장 가까운 정수 no * .7반올림하여 감소 합니다. 상대방 영토의 체포 여부를 다루는 다음 규칙이 적용됩니다.

  • 경우 o0에 도달과 n0보다 큰 경우, 플레이어는 것 영토, 이상 걸릴 것입니다 n거기에 군대를.
  • 두 경우 no이 될 제로, o자동으로 1로 설정되고 영토 캡처되지 않습니다.
  • 경우 o유골 0보다 큰, 플레이어의 영토에서 군대의 수는 증가 할 n과 반대 영토 캡처되지 않습니다.

보너스

보너스를 나타 내기 위해 지역 그룹이 선택됩니다. 한 플레이어가 그룹의 일부인 모든 영토를 소유 한 경우 해당 플레이어는 턴당 추가 량의 군대를받습니다.

보너스는 플레이어가받을 수있는 여분의 군대 수를 나타내는 다른 숫자와 값을 나타내는 id 번호를 가지고 있습니다. 각 라운드에서 보너스의 가치는 5에서 10 사이의 임의의 숫자이며, 보너스에는 10 개의 영토가 포함 된 10 개의 보너스가 현장에서 제공됩니다.

예를 들어, 턴당 5 개의 군대를받는 플레이어가 8의 가치를 가진 보너스를 구성하는 모든 영토를 소유 한 경우, 플레이어는 다음 차례에 13 개의 군대를받습니다. 그러나 플레이어가 보너스를 구성하는 하나 이상의 영토를 잃는 경우 한 턴에 5 개의 군대 만 받게됩니다.

입출력

프로그램은 다음 형식의 명령 줄 인수를 통해 입력을 받아야합니다.

[id] [armies] [territories (yours and all adjacent ones)] [bonuses] ["X" (if first turn)]
  • id그리고 armies모두 정수이다. id은 신분이며 armies영토에 배치해야하는 군대의 수입니다. 당신은 당신에게 주어진 모든 군대를 더 이상 배치하지 않아야합니다.
  • territories는 소유 한 영토와 소유하지 않은 영토를 나타내는 일련의 문자열입니다. 문자열은 다음 형식으로되어 있습니다 :

    [row],[col],[bonus id],[player id],[armies]
    

    rowcol행과 영토는 보드의 열이, 표시 bonus id이 영토의 일부임을 보너스의 ID입니다 player id영토를 소유 한 플레이어의 ID이며, armies군대의 수는 영토에 포함되어 있습니다. 이들은 모두 숫자입니다.

  • bonuses보드에서 사용할 수있는 보너스를 나타내는 일련의 문자열입니다. 문자열은 다음 형식으로되어 있습니다 :

    [id],[armies],[territories left]
    

    id는 보너스의 id이고,이 보너스의 armies모든 영토를 소유함으로써받을 수있는 추가 군대 territories left의 수이며, 추가 군대를 받기 위해 캡처해야하는 보너스의 영역의 수입니다.

라운드의 첫 번째 턴이고 편의상 사용할 수있는 경우 다섯 번째 인수 인 "X"가 나타납니다.

첫 번째 턴에서의 입력 예 :

0 5 "7,6,7,-1,2 8,7,7,-1,2 7,7,7,0,5 6,6,7,-1,2 8,8,9,-1,2 6,7,7,-1,2 7,8,9,-1,2 6,8,9,-1,2 8,6,7,-1,2" "0,5,10 1,5,10 2,9,10 3,9,10 4,9,10 5,5,10 6,5,10 7,6,9 8,7,10 9,7,10" X

프로그램은 줄 바꿈으로 구분 된 두 개의 문자열을 출력해야합니다. 첫 번째 문자열은 군대를 추가하려는 영토의 행과 열을 나열하고 추가하려는 군대 수와 열을 나열합니다. 군대를 보내려는 지역의 열과 보내려는 군대의 수. 출력에는 후행 공백이 포함될 수 있습니다.

군대를 추가하려는 지역을 지정하려면 출력이 다음 형식을 따라야합니다.

[row],[col],[armies]

rowcol영토하면되는 군대를 추가 할 보드의 행과 열, 그리고 armies당신이 영역에 추가 할 군대의 수입니다.

군대를 보낼 영토를 지정하려면 출력이 다음 형식을 따라야합니다.

[srow],[scol],[drow],[dcol],[armies]

srowscol이다에서 영토 당신이 전송 군대에 원하는 행과 보드의 열입니다, drow그리고 dcol영토 당신이에 군대를 보낼 보드의 행과 열이 있고, armies당신이 보낼 군대의 수입니다 . 군대를 옮기고 싶지 않다면 프로그램은 공백을 인쇄해야합니다.

샘플 출력은 다음과 같습니다.

0,0,5
0,0,0,1,3 0,0,1,0,3 0,0,1,1,3

이 경우 플레이어는 5의 군대를 0,0의 영토에 배치하고 3 개의 군대를 0,0에서 0.1로 이동합니다. 0,0 내지 1,0의 3; 0,0에서 1,1 사이의 3 개.

라운드와 턴

각 라운드가 시작될 때, 모든 플레이어는 보드의 무작위 지점에 하나의 영토를 부여받습니다 (두 명 이상의 플레이어가 서로 옆에서 시작할 수 있습니다). 보너스를 구성하는 지역도 변경 될 수 있습니다.

첫 번째 턴에서 각 플레이어는 5 개의 군대를 포함하는 1 개의 영토를 갖게되며, 사용할 수있는 5 개의 군대를받습니다 (이것은 그들이받을 수있는 최소치입니다). 다른 모든 영토는 공격하지 않는 NPC가 소유합니다. 이들 각각은 두 군대를 포함하고 id는 -1입니다.

매 턴마다 프로그램이 실행되고 두 출력이 모두 수집됩니다. 컨트롤러는 첫 번째 출력을 적용하여 군대를 지역에 즉시 추가합니다. 그러나 컨트롤러는 모든 플레이어가 두 번째 출력 인 공격 / 전송 명령을 내릴 때까지 기다립니다. 이 작업이 완료되면 명령이 무작위로 섞여 실행됩니다. 턴에 참여하려면 프로그램이 1 초 이내에 출력을 제공하고 종료해야합니다.

득점과 승리

주어진 라운드에서 한 선수가 남으면 그 플레이어는 100 점을 얻습니다. 그렇지 않으면, 1000 턴이 지나도 여전히 다수의 플레이어가 있다면, 100 점은 나머지 플레이어들 사이에 균등하게 분배됩니다 (즉, 3 명의 플레이어는 각각 33 포인트를 산출합니다). 20 라운드 끝에서 가장 많은 점수를 얻은 플레이어가 승리합니다.

제출물

게시물에는 봇 이름, 작성된 언어, 간단한 설명 및 실행에 사용 된 코드가 포함되어야합니다. 여기에 샘플 봇이 게시되어 컨테스트에 사용됩니다. 원하는만큼 제출할 수 있습니다.

다른

파일 이름이 제출에 사용한 이름과 동일한 한 프로그램에서 파일을 작성하고 파일에서 읽고 읽을 수 있습니다. 이 파일들은 토너먼트 시작 전에 삭제되지만 라운드 사이에는 삭제되지 않습니다.

다음과 같은 경우 차례를 건너 뜁니다.

  • 당신은 제거됩니다 (영토가 없음);
  • 프로그램이 아무것도 인쇄하지 않습니다.
  • 귀하의 프로그램은 1 초 이내에 종료되지 않습니다.
  • 귀하의 영토에 군대를 너무 적게 배치하거나 (귀하가 소유하지 않은 영토에 군대를 배치하면 이에 해당됩니다) 또는 너무 많은 군대; 또는
  • 출력으로 인해 컨트롤러에서 예외가 발생합니다.

다음과 같은 경우 공격 / 전송 명령이 실행되지 않습니다.

  • 프로그램이 올바른 결과를 제공하지 않습니다.
  • 당신은 당신이 아닌 군대를 이동할 영토를 선택합니다.
  • 당신은 영토에서 제로 또는 마이너스 수의 군대를 움직입니다.
  • 당신은 당신의 영토에서 너무 많은 군대를 옮깁니다. 또는
  • 군대를 이동 시키려고 선택한 지역과 인접하지 않은 지역으로 군대를 보낼 지역을 선택합니다.

여기 에서 컨트롤러와 샘플 봇을 찾을 수 있습니다 . 봇은 게임에 참여할 것이지만, 실제로는 좋지 않은 경우에는 이기지 못할 것입니다 .

결과

버그 수정을 실행 한 후 컨트롤러를 실행하면 WeSwarm은 계속해서 고려해야 할 힘이되고 있습니다. 대항 할 수있는 좋은 전략을 가진 봇이 필요합니다.

As of 25-08-15, 04:40 UTC

1: WeSwarm           1420
2: java Player        120
   java LandGrab      120
   java Hermit        120
   java Castler       120
6: java RandomHalver   80

주의!

Zsw가 발견 한 버그로 인해 다른 지역에 군대를 배치 한 지역이 게임에서 잠재적 인 이점을 갖게되었습니다. 수정 사항이 컨트롤러로 푸시되었으므로 위의 링크를 사용하여 찾은 기존 버전을 사용하십시오.


자바 스크립트? 모든 브라우저 콘솔에서 실행 가능
Downgoat

죄송합니다. 제출물이 위의 세 가지 언어 중 하나로 작성되기를 원합니다.
TNT

컨트롤러 또는 플레이어 봇의 버그인지 확실하지 않지만, 봇의 3 가지 인스턴스를 시뮬레이션에 직접 넣으면 콘솔이 출력됩니다. java 플레이어의 잘못된 명령 : 출력 없음
Moogie

@Moogie 각 봇에서 발생합니까? 일관되게 (각 턴) 또는 주기적으로 (몇 턴마다) 출력합니까? 그리고 배열에서 "자바 플레이어"를 세 번 사용합니까, 아니면 별도의 클래스를 만들었습니까?
TNT

@TNT ok 그것은 내 문제입니다 ... 우리는 실제로 IDE의 문제입니다 : P는 명령을 "java -cp bin Player"로 변경했으며 모두 좋습니다. 그 죄송합니다.
Moogie

답변:


6

Castler-Java 8

그는 단지 광장 성을 만들고 싶어합니다 ... 그리고 자신의 장치에 남겨두면 그렇게 할 것입니다. 그는 작은 성으로 지루해지기 때문에 더 크고 크게 만듭니다. 이것은 필연적으로 다른 플레이어와의 충돌을 의미하므로 전투가 계속됩니다. 그러나 그는 자신이 가장 원하는 모양, 즉 사각형을 잊지 않습니다.

[

전체 20x 1000 회전 시뮬레이션의 애니메이션 GIF (15 메가)를 보려면 이미지를 클릭하십시오. Castler는 1700 점을, 다른 선수들은 각각 100 점을 얻었습니다.

import java.util.*;
import java.util.stream.Collectors;

/**
 * Wants to make an expanding square castle... however if opponents interfere then will reluctantly make an odd-shaped castle   
 */
public class Castler {
    private static final int MAP_SIZE = 10;
    private int ownId;
    private int deployableArmyCount;
    private List<Territory> territories;
    private Territory[][] map;
    private Map<Territory,Territory> territoryHashMap;
    List<Territory> ownedTerritories;
    public int minRow;
    public int minCol;

    public static void main(String[] args)
    {
        new Castler(args);
    }

    Castler(String[] args)
    {
        ownId = Integer.parseInt(args[0]);
        deployableArmyCount = Integer.parseInt(args[1]);

        territories = new ArrayList<Territory>();
        map = new Territory[MAP_SIZE][MAP_SIZE]; 

        territoryHashMap = new HashMap<Territory,Territory>();

        for (String s : args[2].split(" ")) {
            Territory territory = new Territory(s.split(","));
               territories.add(territory);
            territoryHashMap.put(territory, territory);
            map[territory.col][territory.row]=territory;
        }

        ownedTerritories = territories.stream().filter(t->t.id==ownId).collect(Collectors.toList());

        minRow=Integer.MAX_VALUE;
        minCol=Integer.MAX_VALUE;

        //find top left territory that is the corner of our castle :)
        int largestArea=0;
        for (Territory territory : ownedTerritories)
        {
            int area=countRightDownConnected(territory,new int[MAP_SIZE][MAP_SIZE]);
            if (area>largestArea)
            {
                largestArea=area;
                minRow=territory.row;
                minCol=territory.col;
            }
        }

        // the average army size per owned territory
           int meanArmySize=0;
           for (Territory territory : ownedTerritories)
           {
               meanArmySize+=territory.armies;
           }
           meanArmySize/=ownedTerritories.size();


        int squareSideLength = (int) Math.ceil(Math.sqrt(ownedTerritories.size()));

        // if we own all territories inside the square of our castle, or we have stalled but have the numbers to expand... make the length of side of the square larger to allow expansion
        if (squareSideLength*squareSideLength == ownedTerritories.size() || meanArmySize>squareSideLength)
        {
            squareSideLength++;
        }

        // lets collate all the enemy territories within the area of our desired castle square and marke them as candidates to be attacked.
        List<Territory> attackCandidates = new ArrayList<>();
        for (int y=minRow;y<minRow+squareSideLength;y++)
        {
            for (int x=minCol;x<minCol+squareSideLength;x++)
            {
                Territory territory = map[x%MAP_SIZE][y%MAP_SIZE];
                if (territory!=null && territory.id!=ownId)
                {
                    attackCandidates.add(territory); 
                }
            }
        }


        // sort in ascending defensive army size.
        attackCandidates.sort((a,b)->a.armies-b.armies);

        List<Territory> unCommandedTerritories = new ArrayList<>(ownedTerritories);
        List<Move> moves = new ArrayList<>();
        Set<Territory> suicideAttackCandidate = new HashSet<>();

        // command owned territories to attack any territories within the area of the prescribed square if able to win. 
        for (int i=0;i<unCommandedTerritories.size();i++)
        {
            Territory commandPendingTerritory =unCommandedTerritories.get(i);
            List<Territory> neighbours = getNeighbours(commandPendingTerritory,map);
            List<Territory> attackCandidatesCopy = new ArrayList<>(attackCandidates);

            // remove non-neighbour attackCandidates
            attackCandidatesCopy.removeIf(t->!neighbours.contains(t));

            for (Territory attackCandidate : attackCandidatesCopy)
            {
                Battle battle = battle(commandPendingTerritory,attackCandidate);
                if (battle.attackerWon)
                {
                    attackCandidates.remove(attackCandidate);
                    suicideAttackCandidate.remove(attackCandidate);
                    unCommandedTerritories.remove(i--);

                    Territory[][] futureMap = cloneMap(map);
                    futureMap[attackCandidate.col][attackCandidate.row].id=ownId;

                    // default to sending the required armies to win + half the difference of the remainder
                    int armiesToSend = battle.minArmiesRequired + (commandPendingTerritory.armies-battle.minArmiesRequired)/2;

                    // but if after winning, there is no threat to the current territory then we shall send most of the armies to attack
                    if (!underThreat(commandPendingTerritory, futureMap))
                    {
                        armiesToSend = commandPendingTerritory.armies-1;
                    }
                    moves.add(new Move(commandPendingTerritory,attackCandidate,armiesToSend));

                    break;
                }
                else
                {
                    // we can't win outright, add it to a list to attack kamikaze style later if needed.
                    suicideAttackCandidate.add(attackCandidate);
                }
            }
        }


        // Find edge territories.
        // A territory is deemed an edge if at least one of its neighbours are not owned by us.
        List<Territory> edgeTerritories = new ArrayList<>();
        ownedTerritories.forEach(owned->
            getNeighbours(owned,map).stream().filter(neighbour->
                neighbour.id!=ownId).findFirst().ifPresent(t->
                edgeTerritories.add(owned)));

        // All edge territories that have not yet had orders this turn...
        List<Territory> uncommandedEdgeTerritories = edgeTerritories.stream().filter(t->unCommandedTerritories.contains(t)).collect(Collectors.toList());

        // Find edges that are under threat by hostile neighbours
        List<Territory> threatenedEdges = edgeTerritories.stream().filter(edge->underThreat(edge,map)).collect(Collectors.toList());

        // All threatened edge territories that have not yet had orders this turn...
        List<Territory> uncommandedThreatenedEdges = threatenedEdges.stream().filter(t->unCommandedTerritories.contains(t)).collect(Collectors.toList());

        // unthreatened edges
        List<Territory> unThreatenedEdges = edgeTerritories.stream().filter(edge->!threatenedEdges.contains(edge)).collect(Collectors.toList());
        List<Territory> uncommandedUnThreatenedEdges = unThreatenedEdges.stream().filter(t->unCommandedTerritories.contains(t)).collect(Collectors.toList());

        // map that describes the effect of moves. Ensures that we do not over commit on one territory and neglect others
        Territory[][] futureMap = cloneMap(map);

        //sort the threatened edges in ascending order of defense
        threatenedEdges.sort((a,b)->a.armies-b.armies); 

        int meanThreatenedEdgeArmySize = Integer.MAX_VALUE;
        if (!threatenedEdges.isEmpty())
        {
            // calculate the average defense of the threatened edges
            int[] total = new int[1];
            threatenedEdges.stream().forEach(t->total[0]+=t.armies);
            meanThreatenedEdgeArmySize = total[0]/threatenedEdges.size(); 

            // command any unthreatened edges to bolster weak threatened edges. 
            out:
            for (int i=0;i<uncommandedUnThreatenedEdges.size();i++)
            {
                Territory commandPendingTerritory = uncommandedUnThreatenedEdges.get(i);

                // the unthreatened edge has spare armies
                if (commandPendingTerritory.armies>1)
                {
                    for (int x=MAP_SIZE-1;x<=MAP_SIZE+1;x++)
                    {
                        for (int y=MAP_SIZE-1;y<=MAP_SIZE+1;y++)
                        {
                            if (!(x==MAP_SIZE && y==MAP_SIZE))
                            {
                                int xx=commandPendingTerritory.col+x;
                                int yy=commandPendingTerritory.row+y;
                                Territory territory = futureMap[xx%MAP_SIZE][yy%MAP_SIZE];

                                // if the current threatened edge has less than average defensive army then send all spare troops to from the uncommanded unthreatened edge. 
                                if (territory!=null && territory.armies<meanThreatenedEdgeArmySize && threatenedEdges.contains(territory))
                                {
                                    // update future map
                                    Territory clonedTerritory = (Territory) territory.clone();
                                    clonedTerritory.armies+=commandPendingTerritory.armies-1;
                                    futureMap[xx%MAP_SIZE][yy%MAP_SIZE]=clonedTerritory;

                                    moves.add(new Move(commandPendingTerritory,territory,commandPendingTerritory.armies-1));

                                    unCommandedTerritories.remove(commandPendingTerritory);
                                    uncommandedUnThreatenedEdges.remove(i--);
                                    uncommandedEdgeTerritories.remove(commandPendingTerritory);
                                    continue out;
                                }
                            }
                        }
                    }
                }
            }

            // command any stronger threatened edges to bolster weak threatened edges. 
            out:

            for (int i=0;i<uncommandedThreatenedEdges.size();i++)
            {
                Territory commandPendingTerritory = uncommandedThreatenedEdges.get(i);

                // the threatened edge has more than average edge armies
                if (commandPendingTerritory.armies>meanThreatenedEdgeArmySize)
                {
                    for (int x=MAP_SIZE-1;x<=MAP_SIZE+1;x++)
                    {
                        for (int y=MAP_SIZE-1;y<=MAP_SIZE+1;y++)
                        {
                            if (!(x==MAP_SIZE && y==MAP_SIZE))
                            {
                                int xx=commandPendingTerritory.col+x;
                                int yy=commandPendingTerritory.row+y;
                                Territory territory = futureMap[xx%MAP_SIZE][yy%MAP_SIZE];

                                // if the current threatened edge has less than average defensive army then send the excess troops larger than the average edge armies amount from the uncommanded threatened edge. 
                                if (territory!=null && territory.armies<meanThreatenedEdgeArmySize && threatenedEdges.contains(territory))
                                {
                                    // update future map
                                    Territory clonedTerritory = (Territory) territory.clone();
                                    clonedTerritory.armies+=commandPendingTerritory.armies-meanThreatenedEdgeArmySize;
                                    futureMap[xx%MAP_SIZE][yy%MAP_SIZE]=clonedTerritory;
                                    moves.add(new Move(commandPendingTerritory,territory,commandPendingTerritory.armies-meanThreatenedEdgeArmySize));

                                    unCommandedTerritories.remove(commandPendingTerritory);
                                    uncommandedThreatenedEdges.remove(i--);
                                    uncommandedEdgeTerritories.remove(commandPendingTerritory);
                                    continue out;
                                }
                            }
                        }
                    }
                }
            }
        }

        // for any uncommanded non-edge territories, just move excess armies to the right or down
           unCommandedTerritories.stream().filter(t->
               t.armies>1 && !edgeTerritories.contains(t)).forEach(t->
                   moves.add(new Random().nextFloat()>0.5? (new Move(t,map[(t.col+1)%MAP_SIZE][t.row],t.armies-1)):(new Move(t,map[t.col][(t.row+1)%MAP_SIZE],t.armies-1))));



           // lets perform suicide attacks if we are in a good position to do so... hopefully will whittle down turtling enemies.
        for (Territory target : suicideAttackCandidate)
        {
            List<Territory> ownedNeighbours = getNeighbours(target, map).stream().filter(neighbour->neighbour.id==ownId).collect(Collectors.toList());

            for (Territory ownedTerritory : ownedNeighbours)
            {
                // if the edge has yet to be commanded and the territory has more than three times the average armies then it is likely that we are in a power struggle so just suicide attack!
                if (uncommandedEdgeTerritories.contains(ownedTerritory) && ((ownedTerritory.armies)/3-1)>meanArmySize)
                {
                    uncommandedEdgeTerritories.remove(ownedTerritory);
                    unCommandedTerritories.remove(ownedTerritory);
                    moves.add(new Move(ownedTerritory,target,ownedTerritory.armies-meanArmySize));
                }
            }
        }


        // deploy troops to the weakest threatened edges
        int armiesToDeploy =deployableArmyCount;

        Map<Territory,Integer> deployTerritories = new HashMap<>();
        while (armiesToDeploy>0 && threatenedEdges.size()>0)
        {
            for (Territory threatenedEdge : threatenedEdges)
            {
                Integer deployAmount = deployTerritories.get(threatenedEdge);
                if (deployAmount==null)
                {
                    deployAmount=0;
                }
                deployAmount++;
                deployTerritories.put(threatenedEdge,deployAmount);
                armiesToDeploy--;
                if (armiesToDeploy==0) break;
            }
        }

        // no threatened edges needing deployment, so just add them to the "first" edge
        if (armiesToDeploy>0)
        {
            deployTerritories.put(edgeTerritories.get(new Random().nextInt(edgeTerritories.size())),armiesToDeploy);
        }

        // send deploy command
        StringBuilder sb = new StringBuilder();
        deployTerritories.entrySet().stream().forEach(entry-> sb.append(entry.getKey().row + "," + entry.getKey().col + "," + entry.getValue()+" "));
        sb.append(" ");
        System.out.println(sb);

        StringBuilder sb1 = new StringBuilder();

        // send move command
        moves.stream().forEach(move-> sb1.append(move.startTerritory.row + "," + move.startTerritory.col + "," + move.endTerritory.row + "," + move.endTerritory.col + "," + move.armies+" "));
        sb1.append(" ");
        System.out.println(sb1);

    }

    /**
     *    Recursive method that attempts to count area the territories in the square with the given territory as the top left corner  
     */
    private int countRightDownConnected(Territory territory,int[][] visited) {

        int count=0;
        if (visited[territory.col][territory.row]>0) return visited[territory.col][territory.row];
        if (visited[territory.col][territory.row]<0) return 0;
        visited[territory.col][territory.row]=-1;


        if (territory!=null && territory.id==ownId)
        {
            if (visited[territory.col][territory.row]>0) return visited[territory.col][territory.row];

            count++;
            count+=countRightDownConnected(map[territory.col][(territory.row+1)%MAP_SIZE],visited);
            count+=countRightDownConnected(map[(territory.col+1)%MAP_SIZE][territory.row],visited);
            visited[territory.col][territory.row]=count;
        }
        return count;
    }

    /**
     *    Performs a deep clone of the provided map  
     */
    private Territory[][] cloneMap(Territory[][] map)
    {
        Territory[][] clone = new Territory[MAP_SIZE][MAP_SIZE];
        for (int x=0;x<MAP_SIZE;x++)
        {
            for (int y=0;y<MAP_SIZE;y++)
            {
                Territory territory = map[x][y];
                clone[x][y] = territory==null?null:territory.clone();
            }
        }
        return clone;
    }

    /**
     * Simulates a battle between an attacker and a defending territory
     */
    private Battle battle(Territory attacker, Territory defender) 
    {
        Battle battle = new Battle();
        battle.attackerWon=false;
        battle.loser=attacker;
        battle.winner=defender;

        for (int i=0;i<attacker.armies;i++)
        {
            int attackerArmies = i;
            int defenderArmies = defender.armies;
            defenderArmies -= (int) Math.round(attackerArmies * .6);
            attackerArmies -= (int) Math.round(defenderArmies * .7);
            if (defenderArmies <= 0) {
                if (attackerArmies > 0) {
                    defenderArmies = attackerArmies;
                    battle.attackerWon=true;
                    battle.loser=defender;
                    battle.winner=attacker;
                    battle.minArmiesRequired=i;
                    break;
                }
            }
        }
        return battle;
    }

    /**
     * returns true if the provided territory is threatened by any hostile neighbours using the provided map 
     */
    private boolean underThreat(Territory territory,Territory[][] map)
    {
        return !getNeighbours(territory,map).stream().filter(neighbour->neighbour.id!=ownId && neighbour.id!=-1).collect(Collectors.toList()).isEmpty();
    }

    /**
     * returns the neighbours of the provided territory using the provided map 
     */
    private List<Territory> getNeighbours(Territory territory,Territory[][] map) {

        List<Territory> neighbours = new ArrayList<>();
        for (int x=MAP_SIZE-1;x<=MAP_SIZE+1;x++)
        {
            for (int y=MAP_SIZE-1;y<=MAP_SIZE+1;y++)
            {
                if (!(x==MAP_SIZE && y==MAP_SIZE))
                {
                    Territory t = map[(x+territory.col)%MAP_SIZE][(y+territory.row)%MAP_SIZE];
                    if (t!=null) neighbours.add(t);
                }
            }
        }
        return neighbours;
    }

    static class Battle {
        public int minArmiesRequired;
        Territory winner;
        Territory loser;
        boolean attackerWon;
    }

    static class Move
    {
        public Move(Territory startTerritory, Territory endTerritory, int armiesToSend) 
        {
            this.endTerritory=endTerritory;
            this.startTerritory=startTerritory;
            this.armies=armiesToSend;
        }
        Territory startTerritory;
        Territory endTerritory;
        int armies;
    }

    static class Territory implements Cloneable
    {
        public int id, row, col, armies;

        public Territory clone()
        {
            try {
                return (Territory) super.clone();
            } catch (CloneNotSupportedException e) {
                throw new RuntimeException(e);
            }
        }

        public Territory(String[] data) {
            id = Integer.parseInt(data[3]);
            row = Integer.parseInt(data[0]);
            col = Integer.parseInt(data[1]);
            armies = Integer.parseInt(data[4]);
        }

        void add(Territory territory)
        {
            row+=(territory.row);
            col+=(territory.col);
        }

        @Override
        public int hashCode()
        {
            return row*MAP_SIZE+col;
        }

        @Override
        public boolean equals(Object other)
        {
            Territory otherTerritory = (Territory) other;
            return row == otherTerritory.row && col == otherTerritory.col;
        }

    }
}

4

은자-자바

같은 도시에 군대를 계속 추가하십시오. 나는 보너스 군대를 얻지 않고 쓰러 질 수 있다고 생각하지 않습니다.

public class Hermit {
    public static void main(String[] args) {
        int myId = Integer.parseInt(args[0]);

        for (String s : args[2].split(" ")) {
            String[] data = s.split(",");
            int id = Integer.parseInt(data[3]);
            int row = Integer.parseInt(data[0]);
            int col = Integer.parseInt(data[1]);

            if (id == myId) {
                System.out.println(row + "," + col + "," + args[1]);
                break;
            }
        }
        System.out.println();
    }
}

단순성이 놀랍도록 효과적입니다! :) 아주 잘 했어요.
Moogie

4

WeSwarm-C ++ 11 [v2.2]

2015 년 8 월 25 일자로 v2.2로 업데이트되었습니다.

v2.2-컨트롤러가 군대를보고하는 방식이 변경되어 조정되었습니다.

v2.1-TNT에서 코드를 컴파일하는 데 문제가 발생하여 사용을 중단했습니다 stoi.

v2.0-몇 가지 버그 수정과 함께 코드 리 팩터


떼에 오신 것을 환영합니다. 우리의 힘은 숫자입니다. 우리의 영원한 의지는 스폰을 극대화하기 위해 모든 보너스를 모으는 것입니다. 당신이 압도되기를 원하지 않도록 우리의 길에 서 있지 마십시오. 우리를 물리 치려고하지 마십시오. 당신이 죽일 때마다 3 명이 더 일어날 것입니다. 당신은 우리에게 희생을하도록 강요 할 수는 있지만, 절대 항복하도록 강요하지는 않을 것입니다!

#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <algorithm>
#include <map>

using namespace std;

/// http://stackoverflow.com/questions/236129/split-a-string-in-c
vector<string> &split(const string &s, char delim, vector<string> &elems) 
{
    stringstream ss(s);
    string item;
    while (getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

/// http://stackoverflow.com/questions/236129/split-a-string-in-c
vector<string> split(const string &s, char delim)
{
    vector<string> elems;
    split(s, delim, elems);
    return elems;
}

enum Allegiance { MINE, ENEMY, HOSTILE, NPC, ANY };

class Bonus
{
public:
    Bonus(int id, int armies, int territoriesLeft)
    {
        this->id = id;
        this->armies = armies;
        this->territoriesLeft = territoriesLeft;
    }

    int getId()
    {
        return id;
    }

    int getArmies()
    {
        return armies;
    }

    int getTerritoriesLeft()
    {
        return territoriesLeft;
    }

private:
    /// id of the bonus.
    int id;

    /// number of extra armies that this bonus gives.
    int armies;

    /// number of territories in the bonus that still needs to be captured.
    int territoriesLeft;
};

class Territory
{
public:
    Territory(int row, int col, Bonus* bonus, int playerId, int armies, Allegiance allegiance)
    {
        this->row = row;
        this->col = col;
        this->bonus = bonus;
        this->armies = armies;
        this->allegiance = allegiance;
        this->toAdd = 0;
        this->toRemove = 0;
    }

    Territory(Territory *territory)
    {
        this->row = territory->getRow();
        this->col = territory->getCol();
        this->bonus = territory->getBonusPtr();
        this->armies = territory->getArmies();
        this->allegiance = ANY;
        this->toAdd = 0;
        this->toRemove = 0;
    }

    /// Ensures uniqueness
    bool operator<(const Territory& other) const
    {
        return row < other.row && + col < other.col;
    }

    /// Return the minimum number of armies needed to conquer this territory.
    int conquerNeeded()
    {
        /*
        Say a player sends n armies from his/her territory to an opposing territory with o armies in it. 
        o will decrease by n * .6 rounded to the nearest integer; 
        however, at the same time, n will decrease by o * .7 rounded to the nearest integer. 
        The following rules dealing with whether or not the opposing territory has been captured will apply:

        If o reaches zero AND n is greater than 0, the player will take over the territory, which will have n armies in it.
        If both n and o become zero, o will automatically be set to 1 and the territory will not be captured.
        If o remains greater than 0, the number of armies in the player's territory will increase by n and the opposing territory will not be captured.
        */

        int o = this->armies; // Given o.
        int n; // Solve for n.
        int n1;
        int n2;

        if (this->allegiance != NPC) {
            o = o + 5; // To account for potential reinforcement.
        }

        // resulto = o - 0.6n
        // resultn = n - 0.7o
        //
        // We want a result of o = 0 and n = 1.
        // 0 = o - 0.6n
        // 1 = n - 0.7o
        // 
        // Isolate n
        // 0.6n = o
        // n = o / 0.6
        n1 = (int)ceil(o / 0.6);
        // 0.7o = n - 1
        // 0.7o + 1 = n
        n2 = (int)ceil(0.7 * o + 1);

        // Take the bigger of the two to guarantee o <= 0 and n >= 1
        n = max(n1, n2);
        return n;
    }

    /// Returns the minimum number of armies that must be added to this territory
    /// to ensure that the territory cannot be taken over by an attack with n armies.
    int reinforceNeeded(int n)
    {
        int o = this->armies; // Number of armies we already have.
        int add = 0; // Solve for number of armies we need to add.

        // resulto = o - 0.6n
        // resultn = n - 0.7o
        //
        // We want a result of o = 1 at the very least.
        // 1 = o - 0.6n
        // 1 + 0.6n = o

        int needed = (int)ceil(1 + 0.6 * n);

        // We only need to reinforce if we don't have enough.
        if (o < needed) {
            add = needed - o;
        }

        return add;
    }

    void add(int toAdd)
    {
        if (toAdd > 0) {
            this->toAdd = this->toAdd + toAdd;
        }
    }

    void remove(int toRemove)
    {
        if (toRemove > 0) {
            this->toRemove = this->toRemove + toRemove;
        }
    }

    void deploy()
    {
        this->armies = this->armies + this->toAdd - this->toRemove;
        this->toAdd = 0;
        this->toRemove = 0;
    }

    int getRow() 
    {
        return row;
    }

    int getCol() 
    {
        return col;
    }

    int getArmies()
    {
        return armies;
    }

    int getAvaliableArmies()
    {
        return armies - 1 - toRemove;
    }

    int getToAdd()
    {
        return toAdd;
    }

    bool isToBeDefended()
    {
        return toAdd > 0;
    }

    Bonus getBonus()
    {
        if (bonus != nullptr) {
            return *bonus;
        }

        return Bonus(-1, 1, 100);
    }

    Bonus *getBonusPtr()
    {
        return bonus;
    }

    bool isMine()
    {
        return allegiance == MINE;
    }

    bool isNPC()
    {
        return allegiance == NPC;
    }

private:
    /// Row number of this territory.
    int row;

    /// Column number of this territory.
    int col;

    /// The bonus that this territory is a part of.
    Bonus* bonus;

    /// number of armies contained in the territory.
    int armies;

    /// number of armies to add or send to the territory.
    int toAdd;

    /// number of armies to remove from this territory.
    int toRemove;

    /// Who this territory belongs to.
    Allegiance allegiance;

};

/// Return whether Territory a is a neighbour of Territory b.
bool isNeighbour(Territory *a, Territory *b)
{
    /*
    n n n
    n x n
    n n n
    */

    // A neighbouring territory is where either:
    // row - 1 , col - 1
    // row - 1 , col + 0
    // row - 1 , col + 1
    // row + 0 , col - 1
    // row + 0 , col + 1
    // row + 1 , col - 1
    // row + 1 , col + 0
    // row + 1 , col + 1

    int rowA = a->getRow();
    int colA = a->getCol();
    int rowB = b->getRow();
    int colB = b->getCol();

    // The row and column is the same, so they're the same territory, but not neighbours.
    if (rowA == rowB && colA == colB) {
        return false;
    }

    // The difference of row : row and column : column is no more than 1.
    // e.g. a territory at row 7 will have neighbour at row 6 and 8.
    if (abs(rowA - rowB) <= 1 && abs(colA - colB) <= 1) {
        return true;
    }

    // Special case for wrapping.

    int checkRow = -1;
    int checkCol = -1;

    // Row is at 0. We need to check for 9 and 1.
    // 1 is already covered by 0 - 1. Explicitly check the 0 - 9 case.
    if (rowB == 0) {
        checkRow = 9;
    }

    // Row is at 9. We need to check for 0 and 8.
    // 8 is already covered by 9 - 9. Explicitly check the 9 - 0 case;
    if (rowB == 9) {
        checkRow = 0;
    }

    // Same thing for column
    if (colB == 0) {
        checkCol = 9;
    }


    if (colB == 9) {
        checkCol = 0;
    }

    if ((rowA == checkRow && abs(colA - colB) <= 1) ||
        (abs(rowA - rowB) <= 1 && colA == checkCol) ||
        (rowA == checkRow && colA == checkCol)) {
        return true;
    }

    return false;
}

/// Verify that territory has the correct allegiance.
bool isOfAllegiance(Territory *territory, Allegiance allegiance)
{
    if (allegiance == MINE && territory->isMine()) {
        return true;
    }
    else if (allegiance == ENEMY && !territory->isMine()) {
        // Enemy means NOT mine, which includes NPCs.
        return true;
    }
    else if (allegiance == HOSTILE && !territory->isMine() && !territory->isNPC()) {
        // Specifically enemy PLAYERS.
        return true;
    }
    else if (allegiance == NPC && territory->isNPC()) {
        return true;
    }
    else if (allegiance == ANY) {
        return true;
    }

    return false;
}

/// Return all neighbouring territories of a particular territory,
/// where the neighbouring territories fits the given allegiance.
set<Territory *> getNeighbours(Territory *territory, Allegiance allegiance, set<Territory *> territories)
{
    set<Territory *> neighbours;

    for (Territory *neighbour : territories) {

        if (isNeighbour(neighbour, territory) && isOfAllegiance(neighbour, allegiance)) {
            neighbours.insert(neighbour);
        }

    }

    return neighbours;
}

/// Return the total number of armies near a particular territory that can be mobilized.
int getAvaliableArmiesNear(Territory *territory, Allegiance allegiance, set<Territory *> territories)
{
    int armies = 0;

    set<Territory *> neighbour = getNeighbours(territory, allegiance, territories);

    for (Territory *near : neighbour) {
        armies = armies + near->getAvaliableArmies();
    }

    return armies;
}

/// Return a set of all territories of a particular allegiance.
set<Territory *> getAllTerritories(Allegiance allegiance, set<Territory *> territories)
{
    set<Territory *> t;

    for (Territory *territory : territories) {
        if (isOfAllegiance(territory, allegiance)) {
            t.insert(territory);
        }
    }

    return t;
}

/// Returns the priority of attacking this particular territory.
/// The lower the priority, the better. It is calculated based on
/// the number of territories left to claim a bonus, the number
/// of armies required to take it over, and the number of armies
/// getting this bonus will give us.
int calculateAttackPriority(Territory *territory)
{
    Bonus bonus = territory->getBonus();
    int territoriesLeft = bonus.getTerritoriesLeft();
    int armiesNeeded = territory->conquerNeeded();
    int armiesGiven = bonus.getArmies();
    return (int)round(territoriesLeft * armiesNeeded / armiesGiven);
}

/// Return a map of int, Territories where int represent priority 
/// and Territory is the territory to be attacked.
///
/// Higher priority = LESS important.
///
/// ALL territories that can be attacked will appear in the set.
map<int, Territory *> getAttackCandidates(set<Territory *> territories)
{
    map<int, Territory *> attack;

    set<Territory *> opponents = getAllTerritories(ENEMY, territories);

    for (Territory *territory : opponents) {
        int priority = calculateAttackPriority(territory);

        // Check if the territory is already inserted.
        auto findTerritory = attack.find(priority);
        bool inserted = findTerritory != attack.end();

        // Already inserted, so we decrease the priority until we can insert it.
        while (inserted) {
            priority = priority + 1;
            findTerritory = attack.find(priority);
            inserted = findTerritory != attack.end();
        }

        attack.insert({ priority, territory });

    }

    return attack;
}

/// Returns the priority of defending this particular territory.
/// The lower the priority, the better. It is calculated based on
/// whether or not we have this bonus, number of armies that can
/// potentially take it over, and the number of armies
/// getting this bonus will give us.
int calculateDefendPriority(Territory *territory, set<Territory *> territories)
{
    Bonus bonus = territory->getBonus();
    set<Territory *> enemies = getNeighbours(territory, ENEMY, territories);

    int territoriesLeft = bonus.getTerritoriesLeft();
    int armiesNeeded = territory->reinforceNeeded(getAvaliableArmiesNear(territory, HOSTILE, territories));
    int armiesGiven = bonus.getArmies();

    return (int)round((1 + territoriesLeft) * armiesNeeded / armiesGiven);
}

/// Return a map of int, pair<int, Territory> where int represent priority 
/// and Territory is the territory to be defended.
/// 
/// Again, the higher the priority, the LESS important it is.
///
/// ALL territories that can be defended will appear in the set.
map<int, Territory *> getDefendCandidates(set<Territory *> territories)
{
    map<int, Territory *> defend;

    set<Territory *> mine = getAllTerritories(MINE, territories);

    for (Territory *territory : mine) {
        int priority = calculateDefendPriority(territory, territories);

        // Check if the territory is already inserted.
        auto findTerritory = defend.find(priority);
        bool inserted = findTerritory != defend.end();

        // Already inserted, so we decrease the priority until we can insert it.
        while (inserted) {
            priority = priority + 1;
            findTerritory = defend.find(priority);
            inserted = findTerritory != defend.end();
        }


        defend.insert({ priority, territory });

    }

    return defend;
}


/// Determine which territories to add armies to, and add to them accordingly.
/// Return a set which specifically lists the Territories that will have armies
/// added to them.
///
/// set<Territory> territories is a set of territories that are visible to us.
/// int armies is the number of armies we can add.
set<Territory *> getAdd(set<Territory *> territories, int armies)
{
    set<Territory *> add;

    // First we check whether there are any territories worth defending - i.e. we have bonus.
    map<int, Territory *> defend = getDefendCandidates(territories);

    for (auto pairs : defend) {

        if (armies <= 0) {
            break;
        }

        Territory *territory = pairs.second;

        Bonus bonus = territory->getBonus();

        int need = territory->reinforceNeeded(getAvaliableArmiesNear(territory, HOSTILE, territories));

        // Make sure that we actually need to defend this, and it actually can be defended.
        if (need > 0 && need <= armies + getAvaliableArmiesNear(territory, MINE, territories) + territory->getArmies()) {

            if (need < armies) {
                armies = armies - need;
                territory->add(need);
                add.insert(territory);
            }
            else {
                // Do we really want to use up all our armies
                // if it doen't even give us a bonus?
                if (bonus.getTerritoriesLeft() != 0) {
                    continue;
                }
                territory->add(armies);
                armies = 0;
                add.insert(territory);
            }

        }


    }

    // Attacking is much easier. We simply allocate all the armies
    // to a place beside where we wish to attack. 
    map<int, Territory *> attack = getAttackCandidates(territories);

    for (auto pairs : attack) {

        if (armies <= 0) {
            break;
        }

        Territory *territory = pairs.second;

        // Determine where to allocate.
        set<Territory *> neighbours = getNeighbours(territory, MINE, territories);

        // We'll just arbitrarily pick the first one that is an ally, though any one will work.
        for (Territory *my : neighbours) {

            // I am almost certain I messed up my logic somewhere around here.
            // I'm supposed to initiate an attack if I got a good surround near a territory.
            // However, it isn't working so I removed it and opted for a simpler logic.
            // So far, it is doing well as is. If I start loosing I'll reimplement this ;)
            //int need = territory->conquerNeeded() - getAvaliableArmiesNear(territory, MINE, territories);
            int need = territory->conquerNeeded();
            int a = territory->conquerNeeded();
            int b = getAvaliableArmiesNear(territory, MINE, territories);
            int c = my->getAvaliableArmies();

            if (need <= 0) {
                continue;
            }

            if (need < armies) {
                armies = armies - need;
                my->add(need);
                add.insert(my);
            }
            else {
                my->add(armies);
                armies = 0;
                add.insert(my);
            }
            break;
        }
    }

    // Check if there are any armies left over,
    // because we must add all our armies.
    if (armies > 0) {

        // This means that we are in a perfect position and it doesn't matter where we add it.
        // So we'll just pick a random territory and put it there.
        if (add.size() < 1) {
            set<Territory *> mine = getAllTerritories(MINE, territories);
            auto first = mine.begin();
            Territory *random = *first;
            random->add(armies);
            add.insert(random);
        }
        else {
            // In this case, we just throw it to the highest priority.
            auto first = add.begin();
            Territory *t = *first;
            t->add(armies);
        }

    }

    return add;
}


/// Return a set of set of Territories.
/// Each set have [0] as source and [1] as destination.
/// Number of armies to send will be in destination.
/// add is a list of territories with armies added to them.
set<pair<Territory *, Territory *>> getSend(set<Territory *> territories)
{
    set<pair<Territory *, Territory *>> send;

    // Attacking is much easier. We simply allocate all the armies
    // to a place beside where we wish to attack. 
    map<int, Territory *> attack = getAttackCandidates(territories);

    for (auto pairs : attack) {

        Territory *territory = pairs.second;

        int needed = territory->conquerNeeded();
        set<Territory *> mine = getNeighbours(territory, MINE, territories);

        // Find all our territories avaliable for attack.
        for (Territory *my : mine) {

            // We need to make sure we actually have enough!
            int avaliable = my->getAvaliableArmies();

            // We send all our attacking army from a single territory,
            // So this one territory must have enough.
            if (needed > 0 && avaliable >= needed) {
                // Attack!
                territory->add(needed); // represents number of armies to send.
                my->remove(needed);

                pair<Territory *, Territory *> attackOrder(my, territory); // src -> dst.
                send.insert(attackOrder);   
                break;
            }
        }
    }

    // First we check whether there are any territories worth defending - i.e. we have bonus.
    map<int, Territory *> defend = getDefendCandidates(territories);

    for (auto pairs : defend) {

        Territory *territory = pairs.second;

        // Number of armies that will potentially attack.
        int threat = getAvaliableArmiesNear(territory, HOSTILE, territories);

        // The number of armies needed to reinforce this attack.
        int needed = territory->reinforceNeeded(threat);

        if (needed <= 0) {
            continue;
        }

        // Check that we have enough to actually defend.
        int avaliable = getAvaliableArmiesNear(territory, MINE, territories);
        set<Territory *> neighbours = getNeighbours(territory, MINE, territories);

        if (avaliable < needed) {
            // Not enough, retreat!
            for (Territory *my : neighbours) {

                int retreat = territory->getAvaliableArmies();
                if (retreat > 0) {
                    // Retreat!

                    // Remove from the territory in defense candidate.
                    territory->remove(retreat);

                    // Add to territory else where.
                    my->add(retreat);

                    pair<Territory *, Territory *> defendOrder(territory, my); // src -> dst.
                    send.insert(defendOrder);
                }
                // We retreat to a single territory.
                // So we break as soon as we find a territory.
                // If there is no territory, this loop won't run.
                break;
            }
        }
        else {

            // Track how many we still need to add.
            int stillneed = needed;

            // Reinforce!
            for (Territory *my : neighbours) {

                // Do we need more?
                if (stillneed <= 0) {
                    break;
                }

                // Check that it's not about to be reinforced.
                // Otherwise, it is senseless to take armies away from a
                // territory we intend to defend!
                if (!my->isToBeDefended()) {
                    int canSend = my->getAvaliableArmies(); 
                    if (canSend > 0) {
                        // Reinforce!

                        // We create a copy of the territory when adding.
                        // Why? Because in this case, the destination Territory
                        // is only meant as a place holder territory simply
                        // for the purpose of having the toAdd value read.
                        Territory *territoryAdd = new Territory(territory);
                        territoryAdd->add(canSend);

                        // Remove from the territory we are sending from.
                        my->remove(canSend);

                        stillneed = stillneed - canSend;

                        pair<Territory *, Territory *> defendOrder(my, territoryAdd); // src -> dst.
                        send.insert(defendOrder);
                    }                   
                }
            }
        }



    }

    return send;
}

/// Rules of Engagement:
/// 1. Collect Bonuses.
/// 2. Attack Weak Territories whenever possible.
///
/// Rules of Defense:
/// 1. Reinforce if possible.
/// 2. Otherwise, retreat and live to fight another day
///
/// For a given territory, we will prioritze attacking over 
/// defending if we do not have the bonus yet for that territory. 
/// If we have the bonus, we will prioritze defending over attacking.
int main(int argc, char* argv[])
{
    // Note: cannot use stoi because of compilation problems.

    int id = atoi(argv[1]);
    int armies = atoi(argv[2]);
    string territoriesIn = argv[3];
    string bonusesIn = argv[4]; 

    // First seperate by space, then seperate by comma.
    vector<string> territoriesData = split(territoriesIn, ' ');
    vector<string> bonusesData = split(bonusesIn, ' ');

    set<Territory *> territories;
    map<int, Bonus *> bonuses;

    for (string data : bonusesData) {
        // [id],[armies],[territories left]
        vector<string> bonus = split(data, ',');
        int id = atoi(bonus[0].c_str());
        int armies = atoi(bonus[1].c_str());
        int territoriesLeft = atoi(bonus[2].c_str());

        Bonus *b = new Bonus(id, armies, territoriesLeft);

        bonuses.insert({ id, b });
    }

    for (string data : territoriesData) {
        // [row],[col],[bonus id],[player id],[armies]
        vector<string> territory = split(data, ',');

        int row = atoi(territory[0].c_str());
        int col = atoi(territory[1].c_str());
        int bonusId = atoi(territory[2].c_str());
        int playerId = atoi(territory[3].c_str());
        int armies = atoi(territory[4].c_str());

        // We can assume that each territory always belongs to a bonus.
        auto findBonus = bonuses.find(bonusId);
        Bonus *bonus;

        if (findBonus != bonuses.end()) {
            bonus = findBonus->second;
        }
        else {
            bonus = nullptr;
        }

        Allegiance allegiance = ENEMY;
        if (playerId == id) {
            allegiance = MINE;
        }
        else if (playerId == -1) {
            allegiance = NPC;
        }

        Territory *t = new Territory(row, col, bonus, playerId, armies, allegiance);

        territories.insert(t);

    }



    // Here we output our desire to add armies.
    set<Territory *> add = getAdd(territories, armies);

    string delimiter = "";
    for (Territory *t : add) {
        cout << delimiter << t->getRow() << "," << t->getCol() << "," << t->getToAdd();
        delimiter = " ";

        // Move added army to actual army.
        t->deploy();
    }

    cout << endl;

    // Here we output our desire to send armies.
    set<pair<Territory *, Territory *>> send = getSend(territories);

    delimiter = "";

    // Note that if you do not want to move any armies, your program should print a space.
    if (send.size() == 0) {
        cout << " ";
    }
    else {
        for (auto location : send) {
            Territory *source = location.first;
            Territory *destination = location.second;

            cout << delimiter << source->getRow() << "," << source->getCol() << "," << destination->getRow() << "," << destination->getCol() << "," << destination->getToAdd();
            delimiter = " ";
        }
    }

    cout << endl;

    return 0;
}

애니메이션 GIF

v2.2 용 애니메이션 GIF

보관 :

v2.1 : https://drive.google.com/uc?export=download&id=0B-BtKdd4FDDEU3lkNzVoTUpRTG8

v1.0 : https://drive.google.com/uc?export=download&id=0B-BtKdd4FDDEVzZUUlFydXo2T00


감사! 불행히도 stoiC ++ 11에도 불구하고 해결되지 않아서 프로그램을 컴파일 할 수 없습니다 . 일치가 있었다 문제 해결 그것은 그래서 당신이 사용하지 않는 대체 솔루션을 제공 할 수있는, 내가하는 방법을 알아낼 아직 stoi?
TNT

@TNT Ahh 짜증나. 나는 여전히 C ++을 처음 사용하지만 무언가를 알아낼 수 있다고 확신합니다.
Zsw

@TNT 지금 컴파일 할 수 있는지 확인하십시오.
Zsw

컴파일하고 잘 작동합니다. 감사!
TNT

@ Zsw WeSwarm은 매우 강력합니다. 잘 했어! 나는 반 전략을 생각 해낼 수 있는지를보아야 할 것이다. : P
Moogie

3

LandGrab-자바

땅이 많을수록 좋습니다. 존재하는 경우 독점적으로 자유 영토를 목표로 삼고 남은 군대와 함께 한 번에 하나의 타일을 쌓아 내기 시작합니다.

import java.util.Arrays;
import java.util.LinkedList;



public class LandGrab {
    public static void main(String[] args) {

        //Init
        int id = Integer.parseInt(args[0]);
        int armies = Integer.parseInt(args[1]);
        LinkedList<Territory> myTerritories = new LinkedList<Territory>();
        LinkedList<Territory> enemyTerritories = new LinkedList<Territory>();
        LinkedList<Territory> freeTerritories = new LinkedList<Territory>();
        for (String s : args[2].split(" ")) {
            Territory t = new Territory(s.split(","));
            if (t.id == id)
                myTerritories.add(t);
            else if(t.id == -1)
                freeTerritories.add(t);
            else
                enemyTerritories.add(t);
        }

        LinkedList<int[]> deploy = new LinkedList<int[]>();
        LinkedList<int[]> move = new LinkedList<int[]>();

        //Boost up territories next to free ones
        for(Territory mine : myTerritories){
            if(armies <= 0) break;
            LinkedList<Territory> neighbors = getNeighbors(mine, freeTerritories);
            int depArm = 0;
            while(neighbors.peek() != null && armies * 0.6 >= neighbors.peek().armies){
                Territory x = neighbors.pop();
                int needed = x.armies * 2;
                depArm += needed;
                mine.armies += needed;
                armies -= needed;
                int[] temp = {mine.row, mine.col, x.row, x.col, needed};
                move.add(temp);
            }
            int[] temp = {mine.row, mine.col, depArm};
            if(depArm > 0) deploy.add(temp); 
        }

     /* //Take any freebies we can
        for(Territory mine : myTerritories){
            LinkedList<Territory> neighbors = getNeighbors(mine, freeTerritories);
            while(neighbors.peek() != null){
                Territory x = neighbors.pop();
                if((mine.armies - 1) > x.armies * 2){
                    int needed = x.armies * 2;
                    move += mine.row + "," + mine.col + "," + x.row + "," + x.col + "," + (needed) + " ";
                    mine.armies -= needed;
                }
            }
        }
       */ 
        //Choose a single enemy army and crush it
        if(enemyTerritories.size() > 0 && armies > 0){
            Territory x = enemyTerritories.pop();
            Territory y = largest(getNeighbors(x, myTerritories));
            int[] temp = {y.row, y.col, armies};
            deploy.add(temp);
            int armSize = y.armies + armies - 1;
            if(armSize * 0.6 > x.armies){
                int[] attack = {y.row, y.col, x.row, x.col, armSize};
                move.add(attack);
            }
            armies = 0;
        }

        //Deploy leftover armies wherever
        if(armies > 0){
            Territory rand = myTerritories.getFirst();
            int[] temp = {rand.row, rand.col, armies};
            deploy.add(temp); 
        }

        //Consolidate
        String deployString = consolidate(deploy);
        String moveString = "";
        for(int[] command : move){
            moveString += Arrays.toString(command).replace(" ", "").replace("[", "").replace("]", "") + " ";
        }
        if(moveString == "") moveString = " ";

        //Return
        System.out.println(deployString);
        System.out.println(moveString);





    }


    private static Territory largest(LinkedList<Territory> l){
        Territory largest = l.getFirst();
        for(Territory t : l){
            if(t.armies > largest.armies) largest = t;
        }
        return largest;
    }

    public static String consolidate(LinkedList<int[]> list){
        LinkedList<int[]> combined = new LinkedList<int[]>();
        for(int[] t : list){
            boolean dup = false;
            for(int[] existing : combined){
                if(t[0] == existing[0] && t[1] == existing[1]){
                    existing[2] += t[2];
                    dup = true;
                }

            }
            if(!dup) combined.add(t);
        }

        String result = "";
        for(int[] dep : combined){
            result += Arrays.toString(dep).replace(" ", "").replace("[", "").replace("]", "") + " ";

        }
        return result;
    }

    private static LinkedList<Territory> getNeighbors(Territory t, LinkedList<Territory> possibles){
        LinkedList<Territory> neighbors = new LinkedList<Territory>();
        for(Territory x : possibles){
            if(Math.abs(x.row - t.row) <= 1 && Math.abs(x.col - t.col) <= 1){
                neighbors.add(x);
            }
        }
        return neighbors;
    }

    static class Territory {
        int id, row, col, armies;

        public Territory(String[] data) {
            id = Integer.parseInt(data[3]);
            row = Integer.parseInt(data[0]);
            col = Integer.parseInt(data[1]);
            armies = Integer.parseInt(data[4]);
        }
    }
}

범위를 벗어난 색인 예외로부터 보호하기 위해 봇에 수정 사항을 추가했습니다. 수정을 수락하거나 무시하십시오
Moogie

걱정 해줘서 고맙지 만 내 테스트에서 문제가되었습니다. 통과하는 유일한 영토는 내가 소유 한 영토와 인접한 영토이기 때문에 y는 절대 null이 아니어야합니다.
가인

끈기 있는! 봇은 영토의 손실을 능숙하게 복구 할 수 있습니다. 잘 했어.
Moogie

3

임의의 Halver-Java 8

각 지역의 군대 절반을 무작위로 인접한 지역으로 옮기는 매우 간단한 봇. 이웃이 친구인지 적이든 상관 없습니다.

캐슬 러와 경쟁 할 수는 없지만 놀랍게도 플레이어와 다른 봇과는 잘 맞습니다.

import java.util.*;
import java.util.stream.Collectors;


/**
 * Sends half its force to a random territory around itself.   
 */
public class RandomHalver {
    private static final int MAP_SIZE = 10;
    private int ownId;
    private int deployableArmyCount;
    private List<Territory> territories;
    private Territory[][] map;
    private Map<Territory,Territory> territoryHashMap;
    List<Territory> ownedTerritories;
    public int minRow;
    public int minCol;

    public static void main(String[] args)
    {
        new RandomHalver(args);
    }

    RandomHalver(String[] args)
    {
        ownId = Integer.parseInt(args[0]);
        deployableArmyCount = Integer.parseInt(args[1]);

        territories = new ArrayList<Territory>();
        map = new Territory[MAP_SIZE][MAP_SIZE]; 

        territoryHashMap = new HashMap<Territory,Territory>();

        for (String s : args[2].split(" ")) {
            Territory territory = new Territory(s.split(","));
            territories.add(territory);
            territoryHashMap.put(territory, territory);
            map[territory.col][territory.row]=territory;
        }

        ownedTerritories = territories.stream().filter(t->t.id==ownId).collect(Collectors.toList());

        List<Move> moves = new ArrayList<>();

        ownedTerritories.stream().forEach(t->moves.add(new Move(t, getNeighbours(t,map).get(new Random().nextInt(getNeighbours(t,map).size())),t.armies/2)));
        Map<Territory,Integer> deployTerritories = new HashMap<>();
        deployTerritories.put(ownedTerritories.get(new Random().nextInt(ownedTerritories.size())),deployableArmyCount);


        // send deploy command
        StringBuilder sb = new StringBuilder();
        deployTerritories.entrySet().stream().forEach(entry-> sb.append(entry.getKey().row + "," + entry.getKey().col + "," + entry.getValue()+" "));
        sb.append(" ");
        System.out.println(sb);

        StringBuilder sb1 = new StringBuilder();

        // send move command
        moves.stream().filter(m->m.armies>0).forEach(move-> sb1.append(move.startTerritory.row + "," + move.startTerritory.col + "," + move.endTerritory.row + "," + move.endTerritory.col + "," + move.armies+" "));
        sb1.append(" ");
        System.out.println(sb1);

    }


    /**
     * returns the neighbours of the provided territory using the provided map 
     */
    private List<Territory> getNeighbours(Territory territory,Territory[][] map) {

        List<Territory> neighbours = new ArrayList<>();
        for (int x=MAP_SIZE-1;x<=MAP_SIZE+1;x++)
        {
            for (int y=MAP_SIZE-1;y<=MAP_SIZE+1;y++)
            {
                if (!(x==MAP_SIZE && y==MAP_SIZE))
                {
                    Territory t = map[(x+territory.col)%MAP_SIZE][(y+territory.row)%MAP_SIZE];
                    if (t!=null) neighbours.add(t);
                }
            }
        }
        return neighbours;
    }

    static class Battle {
        public int minArmiesRequired;
        Territory winner;
        Territory loser;
        boolean attackerWon;
    }

    static class Move
    {
        public Move(Territory startTerritory, Territory endTerritory, int armiesToSend) 
        {
            this.endTerritory=endTerritory;
            this.startTerritory=startTerritory;
            this.armies=armiesToSend;
        }
        Territory startTerritory;
        Territory endTerritory;
        int armies;
    }

    static class Territory implements Cloneable
    {
        public int id, row, col, armies;

        public Territory clone()
        {
            try {
                return (Territory) super.clone();
            } catch (CloneNotSupportedException e) {
                throw new RuntimeException(e);
            }
        }

        public Territory(String[] data) {
            id = Integer.parseInt(data[3]);
            row = Integer.parseInt(data[0]);
            col = Integer.parseInt(data[1]);
            armies = Integer.parseInt(data[4]);
        }

        void add(Territory territory)
        {
            row+=(territory.row);
            col+=(territory.col);
        }

        @Override
        public int hashCode()
        {
            return row*MAP_SIZE+col;
        }

        @Override
        public boolean equals(Object other)
        {
            Territory otherTerritory = (Territory) other;
            return row == otherTerritory.row && col == otherTerritory.col;
        }

    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.