Rủi ro, con đường chiến tranh


12

Giới thiệu

Trong trò chơi này, người chơi sử dụng đội quân của mình để chiến đấu với quân đội của người chơi khác, chiếm lãnh thổ và trở thành người đứng cuối cùng. Mỗi lượt, người chơi nhận được một số lượng quân đội cơ bản để sử dụng theo ý của họ. Tuy nhiên, bằng cách chiếm được các vùng lãnh thổ ở một số khu vực nhất định, người chơi có thể tăng con số này để mang lại cho họ lợi thế tiềm năng sau này trong trò chơi. (Điều này về cơ bản giống như Warlight ).

Tất cả các bot nên được viết bằng Java, C hoặc C ++ (Tôi sẽ bao gồm các ngôn ngữ khác nhưng không có phần mềm hoặc kinh nghiệm cho chúng). Việc gửi của bạn không cần thiết để mở rộng một lớp và bạn có thể tạo các hàm, lớp, giao diện hoặc bất cứ thứ gì khác là cần thiết và sử dụng bất kỳ gói hoặc lớp nào trong các API tiêu chuẩn . Nếu bạn đang dự định tạo một lớp hoặc giao diện, vui lòng xem xét sử dụng lớp bên trong hoặc giao diện bên trong.

Xin đừng cố gắng lập trình thay đổi bộ điều khiển hoặc các bài nộp khác trong cuộc thi này.

Trò chơi

Tổng quat

Mảng hai chiều 10x10 sẽ mô phỏng bảng, mỗi phần tử / ô đại diện cho một "lãnh thổ". Sẽ có 20 vòng và lên tới 1000 lượt mỗi vòng. Mỗi lượt, người chơi trước tiên sẽ triển khai quân đội mà họ có đến bất kỳ vùng lãnh thổ nào họ sở hữu và sau đó được trao cơ hội vận chuyển quân đội của mình đến các lãnh thổ gần đó trong nỗ lực đánh chiếm lãnh thổ của đối thủ bằng cách tấn công quân đội của họ. Người chơi phải triển khai tất cả các đội quân của mình, nhưng họ không phải di chuyển chúng nếu muốn.

Tấn công / chuyển quân

Nếu người chơi mong muốn, anh ta / cô ta có thể gửi quân đội từ một lãnh thổ đến bất kỳ trong số tám lãnh thổ lân cận. Bảng "bao bọc xung quanh", tức là nếu lãnh thổ của người chơi ở một bên, quân đội từ đó có thể được chuyển sang lãnh thổ liền kề ở phía bên kia. Khi di chuyển quân đội từ một lãnh thổ, vẫn còn ít nhất một đội quân còn lại trong lãnh thổ đó. Chẳng hạn, nếu một lãnh thổ chứa năm quân đội, không quá bốn người có thể được chuyển đến một lãnh thổ khác; nếu một lãnh thổ chứa một, quân đội đó không thể di chuyển.

Nếu người chơi gửi nquân đội từ lãnh thổ này sang lãnh thổ khác mà họ sở hữu, lãnh thổ đó sẽ nhận được nquân đội.

Giả sử một người chơi gửi nquân đội từ lãnh thổ của mình đến lãnh thổ đối địch có oquân đội trong đó. osẽ giảm bằng cách n * .6làm tròn đến số nguyên gần nhất; tuy nhiên, đồng thời, nsẽ giảm bằng cách o * .7làm tròn đến số nguyên gần nhất. Các quy tắc sau đây liên quan đến việc có chiếm được lãnh thổ đối lập hay không sẽ được áp dụng:

  • Nếu ođạt đến 0 VÀ nlớn hơn 0, người chơi sẽ chiếm lấy lãnh thổ, nơi sẽ có nquân đội trong đó.
  • Nếu cả hai notrở thành số không, osẽ tự động được đặt thành 1 và lãnh thổ sẽ không bị bắt.
  • Nếu ovẫn lớn hơn 0, số lượng quân đội trong lãnh thổ của người chơi sẽ tăng lên nvà lãnh thổ đối phương sẽ không bị bắt.

Tiền thưởng

Một nhóm các lãnh thổ sẽ được chọn để đại diện cho một phần thưởng; nếu một người chơi sở hữu tất cả các lãnh thổ là một phần của nhóm, người chơi đó sẽ nhận được thêm một lượng quân đội mỗi lượt.

Phần thưởng có số id để biểu thị các giá trị và giá trị khác nhau đại diện cho số lượng quân đội bổ sung mà người chơi có thể nhận được. Mỗi vòng, giá trị của phần thưởng sẽ là một số ngẫu nhiên trong khoảng từ 5 đến 10, bao gồm và mười phần thưởng sẽ có sẵn trên sân, mỗi phần có mười lãnh thổ được bao gồm trong phần thưởng.

Ví dụ: nếu người chơi nhận được 5 quân mỗi lượt sở hữu tất cả các lãnh thổ tạo thành phần thưởng có giá trị là 8, người chơi sẽ nhận được 13 quân trong lượt tiếp theo và lượt tiếp theo. Tuy nhiên, nếu người chơi mất một hoặc nhiều lãnh thổ tạo nên phần thưởng, anh ta hoặc cô ta sẽ chỉ nhận được 5 quân đội mỗi lượt.

Đầu ra đầu vào

Chương trình của bạn sẽ nhận đầu vào thông qua các đối số dòng lệnh, sẽ có định dạng sau:

[id] [armies] [territories (yours and all adjacent ones)] [bonuses] ["X" (if first turn)]
  • idarmieslà cả hai số nguyên. idlà id của bạn và armieslà số lượng quân đội bạn cần triển khai đến các lãnh thổ của mình. Bạn phải triển khai tất cả các đội quân được trao cho bạn - không hơn không kém.
  • territorieslà một chuỗi các chuỗi đại diện cho các lãnh thổ bạn sở hữu và các lãnh thổ mà bạn không sở hữu liền kề với các lãnh thổ của bạn. Các chuỗi có định dạng này:

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

    rowcolchỉ ra hàng và cột của bảng nơi có lãnh thổ, bonus idlà id của phần thưởng mà lãnh thổ này là một phần của, player idlà id của người chơi sở hữu lãnh thổ và armieslà số quân đội có trong lãnh thổ. Đây là tất cả các số.

  • bonuseslà một chuỗi các chuỗi đại diện cho các phần thưởng trên bảng mà bạn có thể tận dụng. Các chuỗi có định dạng này:

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

    idlà id của phần thưởng, armieslà số lượng quân đội bạn có thể nhận được bằng cách sở hữu tất cả các lãnh thổ trong phần thưởng này và territories leftlà số lượng lãnh thổ trong phần thưởng mà bạn cần nắm bắt để nhận thêm quân đội.

Xin lưu ý rằng một đối số thứ năm, "X", sẽ xuất hiện nếu đó là lượt đầu tiên của vòng và có thể được sử dụng vì lý do thuận tiện.

Một ví dụ về đầu vào ở lượt đầu tiên:

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

Chương trình của bạn phải xuất hai chuỗi được phân tách bằng một dòng mới, chuỗi đầu tiên liệt kê các hàng và cột của lãnh thổ mà bạn muốn thêm quân đội vào và số lượng quân đội bạn muốn thêm vào đó và chuỗi thứ hai liệt kê các hàng và các cột của lãnh thổ bạn muốn gửi quân đội đến và số lượng quân đội bạn muốn gửi. Đầu ra có thể chứa dấu cách.

Để chỉ định lãnh thổ bạn muốn thêm quân đội vào, đầu ra của bạn phải theo định dạng sau:

[row],[col],[armies]

rowcollà hàng và cột của bảng nơi lãnh thổ bạn muốn thêm quân đội và armieslà số quân đội bạn muốn thêm vào lãnh thổ.

Để chỉ định vùng lãnh thổ bạn muốn gửi quân đội tới, đầu ra của bạn phải theo định dạng sau:

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

srowscollà hàng và cột của bảng nơi lãnh thổ bạn muốn vận chuyển quân đội từ đó, drowdcollà hàng và cột của bảng nơi lãnh thổ bạn muốn gửi quân đội đến và armieslà số quân bạn muốn gửi . Lưu ý rằng nếu bạn không muốn di chuyển bất kỳ quân đội nào, chương trình của bạn sẽ in một khoảng trắng.

Một đầu ra mẫu có thể là thế này:

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

Trong trường hợp này, người chơi triển khai năm đội quân đến lãnh thổ ở mức 0,0 và di chuyển ba đội quân từ 0,0 đến 0,1; ba từ 0,0 đến 1,0; và ba từ 0,0 đến 1,1.

Vòng và lượt

Khi bắt đầu mỗi vòng, tất cả người chơi sẽ được cung cấp một lãnh thổ nằm ở một vị trí ngẫu nhiên trên bảng (có thể hai hoặc nhiều người chơi bắt đầu cạnh nhau). Các lãnh thổ tạo nên một phần thưởng cũng có thể thay đổi.

Ở lượt đầu tiên, mỗi người chơi sẽ có một lãnh thổ chứa năm đội quân và họ sẽ nhận được năm đội quân họ có thể sử dụng (đây là mức tối thiểu mà họ có thể nhận được). Tất cả các lãnh thổ khác sẽ được sở hữu bởi các NPC không tấn công; mỗi cái đều chứa hai đội quân và có id -1.

Mỗi lượt chương trình của bạn sẽ được chạy và cả hai phần đầu ra sẽ được thu thập. Bộ điều khiển sẽ áp dụng phần đầu ra đầu tiên, thêm quân đội vào lãnh thổ, ngay lập tức; tuy nhiên, bộ điều khiển sẽ đợi cho đến khi tất cả người chơi đưa ra phần đầu ra thứ hai, các lệnh tấn công / chuyển giao của họ. Một khi điều này đã được hoàn thành, các lệnh sẽ được xáo trộn ngẫu nhiên và sau đó được thực thi. Chương trình của bạn phải cung cấp đầu ra và chấm dứt trong một giây hoặc ít hơn để tham gia vào lượt chơi.

Ghi điểm và chiến thắng

Đối với bất kỳ vòng nào, nếu một người chơi vẫn còn, người chơi đó sẽ kiếm được 100 điểm. Mặt khác, nếu 1000 lượt vượt qua và vẫn còn nhiều người chơi, 100 điểm sẽ được chia đều cho các người chơi còn lại (tức là 3 người chơi còn lại mang lại 33 điểm mỗi người). Người chơi nào có nhiều điểm nhất vào cuối 20 vòng sẽ giành chiến thắng.

Đệ trình

Bài đăng của bạn nên bao gồm tên cho bot, ngôn ngữ được viết, mô tả ngắn gọn về nó và mã được sử dụng để chạy nó. Một bot mẫu sẽ được đăng ở đây làm ví dụ và sẽ được sử dụng trong cuộc thi. Bạn có thể gửi nhiều như bạn muốn.

Khác

Chương trình của bạn có thể tạo, ghi và đọc từ một tệp miễn là tên tệp đó giống với tên bạn đã sử dụng để gửi. Những tập tin này sẽ bị xóa trước khi bắt đầu một giải đấu nhưng không phải ở giữa các vòng.

Đến lượt bạn sẽ bị bỏ qua nếu:

  • bạn bị loại (không có lãnh thổ);
  • chương trình của bạn không in bất cứ điều gì;
  • chương trình của bạn không chấm dứt trong vòng một giây;
  • bạn triển khai quá ít quân đội đến các lãnh thổ của mình (triển khai quân đội đến các lãnh thổ mà bạn không sở hữu sẽ được tính vào điều này) hoặc quá nhiều quân đội; hoặc là
  • đầu ra của bạn làm cho bộ điều khiển ném một ngoại lệ.

Lệnh tấn công / chuyển của bạn sẽ không được thực thi nếu:

  • chương trình của bạn không cung cấp đầu ra chính xác;
  • bạn chọn một lãnh thổ để di chuyển quân đội từ đó không phải là của bạn;
  • bạn di chuyển bằng không hoặc một số lượng quân đội âm từ lãnh thổ của bạn;
  • bạn di chuyển quá nhiều quân đội từ lãnh thổ của bạn; hoặc là
  • bạn chọn một lãnh thổ để gửi quân đội đến đó không liền kề với lãnh thổ mà bạn đã chọn để di chuyển quân đội từ đó.

Bạn có thể tìm thấy bộ điều khiển và bot mẫu ở đây . Bot sẽ tham gia vào trò chơi, nhưng có lẽ nó sẽ không thắng được vòng nào (trừ khi nó thực sự may mắn).

Các kết quả

Chạy bộ điều khiển sau khi đẩy một bản sửa lỗi cho nó, WeSwarm tiếp tục là một lực lượng được tính toán. Nó sẽ lấy một bot với một chiến lược tuyệt vời để có cơ hội chống lại nó.

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

Để ý!

Một lỗi được phát hiện bởi Zsw khiến các vùng lãnh thổ triển khai quân đội của họ sau khi những người khác có lợi thế tiềm năng trong trò chơi đã được sửa. Một chỉnh sửa đã được đẩy đến bộ điều khiển, vì vậy vui lòng sử dụng phiên bản hiện có được tìm thấy bằng liên kết ở trên.


JavaScript? Nó có thể được chạy trong bất kỳ bảng điều khiển trình duyệt nào
Downgoat

Xin lỗi nhưng không; Tôi muốn bài dự thi thuộc bất kỳ ngôn ngữ nào trong ba ngôn ngữ trên.
TNT

Không chắc đó là lỗi trong trình điều khiển hay bot trình phát của bạn, nhưng nếu tôi tự đặt ba phiên bản bot của mình vào mô phỏng thì giao diện điều khiển xuất ra: Lệnh không hợp lệ của java Player: không có đầu ra
Moogie 16/07/2015

@Moogie Điều này có xảy ra với mỗi bot không? Nó có đầu ra nhất quán (mỗi lượt) hoặc định kỳ (cứ sau vài lượt) không? Và bạn có đang sử dụng "java Player" trong mảng ba lần hay bạn đã tạo các lớp riêng biệt?
TNT

@TNT ok đó là vấn đề của tôi ... chúng tôi thực sự là vấn đề của IDE: P đã thay đổi lệnh thành "java -cp bin Player" và tất cả đều tốt. xin lỗi vì điều đó.
Moogie 16/07/2015

Câu trả lời:


6

Castler - Java 8

Anh ta chỉ muốn làm một lâu đài vuông ... và nếu để các thiết bị của mình sẽ làm điều đó. Mặc dù anh ta đã chán với một lâu đài nhỏ nên làm cho nó ngày càng lớn hơn. Điều này chắc chắn sẽ có nghĩa là xung đột với những người chơi khác và do đó, trận chiến xảy ra. Tuy nhiên, anh không bao giờ quên hình dạng mong muốn nhất của mình ... hình vuông.

[

Nhấp vào hình ảnh cho gif hoạt hình (15 meg) của mô phỏng lần lượt 20x 1000 đầy đủ. Castler ghi được 1700 và những người chơi khác ghi được 100 điểm.

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

Hermit - Java

Chỉ cần tiếp tục thêm quân đội của mình vào cùng một thị trấn. Tôi không nghĩ rằng nó có thể bị gỡ xuống mà không nhận được quân đội tiền thưởng.

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

Sự đơn giản là hiệu quả đáng ngạc nhiên! :) hoàn thành rất tốt.
Moogie 20/07/2015

4

WeSwarm - C ++ 11 [v2.2]

Cập nhật lên v2.2 kể từ ngày 25 tháng 8 năm 2015.

v2.2 - được điều chỉnh do thay đổi cách thức bộ điều khiển báo cáo quân đội.

v2.1 - TNT gặp sự cố khi biên dịch mã của tôi, vì vậy tôi đã ngừng sử dụng stoi .

v2.0 - một bộ tái cấu trúc mã cùng với một vài sửa lỗi.


Chào mừng đến với bầy đàn. Sức mạnh của chúng tôi là số lượng. Ý chí vĩnh cửu của chúng tôi là thu thập tất cả tiền thưởng của bạn để tối đa hóa sinh sản của chúng tôi. Đừng cản đường chúng ta, kẻo bạn muốn bị choáng ngợp. Đừng cố gắng đánh bại chúng tôi, cứ mỗi một người bạn giết, sẽ có thêm ba người nữa. Bạn có thể buộc chúng tôi phải hy sinh, nhưng bạn sẽ không bao giờ buộc chúng tôi đầu hàng!

#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 hoạt hình

GIF hoạt hình cho v2.2

Lưu trữ:

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

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


Cảm ơn! Thật không may, tôi không thể biên dịch chương trình của bạn do stoikhông được giải quyết mặc dù có C ++ 11. Đã có những vấn đề nhất quán với việc giải quyết mà tôi vẫn chưa biết phải làm thế nào, vì vậy bạn có thể cung cấp một giải pháp thay thế không sử dụng stoikhông?
TNT

@TNT Ahh mà hút. Tôi vẫn chưa quen với C ++, nhưng tôi chắc chắn mình có thể tìm ra thứ gì đó.
Zsw

@TNT Vui lòng xem nếu bạn có thể biên dịch nó ngay bây giờ.
Zsw

Nó biên dịch và chạy tốt. Cảm ơn!
TNT

@Zsw WeSwarm rất mạnh. làm tốt lắm! Tôi sẽ phải xem liệu tôi có thể đưa ra một chiến lược phản công không: P
Moogie

3

LandGrab - Java

Càng nhiều đất càng tốt. Nhắm mục tiêu vào các lãnh thổ tự do nếu có, sau đó với các đội quân còn sót lại bắt đầu xây dựng và tiêu diệt từng kẻ thù một.

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

Tôi đã thêm một hiệu chỉnh vào bot của bạn để bảo vệ chống lại chỉ số ngoài giới hạn. Xin vui lòng chấp nhận hoặc bỏ qua sự điều chỉnh
Moogie 16/07/2015

Hey, cảm ơn bạn đã quan tâm, nhưng trong thử nghiệm của tôi là một vấn đề. y không bao giờ nên vô giá trị, bởi vì các lãnh thổ duy nhất mà nó được thông qua là những lãnh thổ liền kề với một lãnh thổ mà tôi sở hữu, do đó, bất kỳ lãnh thổ đối phương nào cũng có ít nhất một hàng xóm trong myTerraries.
Cain

Kiên cường! Bot của bạn có thể phục hồi sau khi mất lãnh thổ một cách thành thạo. làm tốt lắm.
Moogie 20/07/2015

3

Halver ngẫu nhiên - Java 8

Một bot rất đơn giản chỉ cần di chuyển một nửa quân đội của mình trong mỗi lãnh thổ sang một lãnh thổ lân cận ngẫu nhiên. Không quan trọng nếu hàng xóm là bạn hay thù ...

Mặc dù nó không thể cạnh tranh với Castler, nhưng nó lại gây bất ngờ tốt với Người chơi và các bot khác.

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

    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.