Trận chiến định tuyến


22

LƯU Ý: Thử thách này hiện đã chết, vì tôi không thể cài đặt các ngôn ngữ cần thiết để chạy một trận đấu. Nếu ai đó có thời gian và sở thích để làm điều đó, tôi không phản đối.

Xem dưới cùng của bài viết cho một bảng thành tích.

Đây là một thử thách vua nửa hợp tác, nơi các bot xây dựng các đường dẫn thông qua biểu đồ lưới hai chiều. Bot kiểm soát các nút có lưu lượng truy cập nhiều nhất là người chiến thắng. Tuy nhiên, phải mất nhiều tài nguyên của một bot để thực sự xây dựng một đường dẫn kết nối, vì vậy các bot sẽ phải làm việc cùng nhau - ở một mức độ nào đó.

Trò chơi

Sau đây, hãy để N > 0 là số lượng bot đang chơi.

Cái lưới sắt

Trò chơi được chơi trên một lưới số nguyên hai chiều , có tọa độ phía dưới bên trái . Mỗi tọa độ với có các gờ đi với ba tọa độ , và ở trên nó, nơi -coordinates được lấy modulo . Điều này có nghĩa là lưới bao quanh ở rìa phía đông và phía tây. Mỗi tọa độ dưới cùng là một nguồn , và mọi tọa độ trên cùng là một bồn rửa .⌊4/3N2⌋ × ⌊4/3N2(0,0)(x,y)0 ≤ y < ⌊4/3N2⌋-1(x-1,y+1)(x,y+1)(x+1,y+1)x⌊4/3N2(x,0)(x,⌊4/3N2⌋-1)

Hình ảnh sau đây cho thấy một 8 × 8lưới.

Lưới 8 x 8.

Mỗi đỉnh của đồ thị không hoạt động , hoạt động hoặc bị hỏng . Tất cả các đỉnh bắt đầu không hoạt động và có thể được kích hoạt bởi các bot, sau đó sẽ là chủ sở hữu của chúng. Ngoài ra, các bot có thể phá vỡ các đỉnh và chúng không thể được sửa chữa.

Đặt hàng

Một lượt bao gồm một giai đoạn phá hủy và một giai đoạn kích hoạt . Trong giai đoạn phá hủy, mỗi bot có thể phá vỡ một đỉnh không hoạt động. Đỉnh đó bị phá vỡ từ đó trở đi, và có thể không được kích hoạt bởi bất cứ ai. Trong giai đoạn kích hoạt, mỗi bot có thể kích hoạt một đỉnh không hoạt động. Từ đó trở đi, họ sở hữu đỉnh đó và không ai có thể kích hoạt lại được. Một số bot có thể sở hữu một đỉnh duy nhất, nếu tất cả chúng đều kích hoạt nó trên cùng một lượt. Trong mỗi giai đoạn, các lựa chọn đỉnh được thực hiện đồng thời.

Chấm điểm

Một vòng kéo dài cho lượt chính xác . Sau này, vòng được tính như sau. Từ mỗi đỉnh nguồn hoạt động, chúng tôi thực hiệnN2N lần tìm kiếm theo chiều sâu ngẫu nhiên dọc theo các đỉnh hoạt động (có nghĩa là con của mỗi đỉnh được truy cập theo thứ tự ngẫu nhiên). Nếu một đường dẫn được tìm thấy từ nguồn đến một số chìm, thì đối với tất cả các đỉnh dọc theo đường dẫn đó, mọi chủ sở hữu của đỉnh sẽ có một điểm.

Toàn bộ trò chơi kéo dài trong 100 vòng, và bot có nhiều điểm nhất là người chiến thắng. Tôi có thể tăng con số này, nếu phương sai của điểm số quá cao.

Quy tắc bổ sung

  • Không gây rối với bộ điều khiển hoặc đệ trình khác.
  • Nhiều nhất một bài nộp cho mỗi thí sinh.
  • Không có tài nguyên bên ngoài, ngoại trừ một tệp văn bản riêng, bị xóa sạch khi bắt đầu trò chơi.
  • Không thiết kế bot của bạn để đánh bại hoặc hỗ trợ các đối thủ cụ thể.
  • Cung cấp các lệnh để biên dịch và chạy bot của bạn. Mọi trình biên dịch / trình thông dịch có sẵn miễn phí cho Debian Linux đều được chấp nhận.

Bộ điều khiển

Bộ điều khiển được viết bằng Python 3 và có thể được tìm thấy trong GitHub . Xem tệp README để được hướng dẫn chi tiết. Đây là một API để giúp bạn bắt đầu:

  • Bots được bắt đầu vào đầu mỗi vòng, và tồn tại cho đến cuối vòng. Giao tiếp với bộ điều khiển thông qua STDIN và STDOUT, sử dụng các tin nhắn kết thúc dòng mới.
  • BEGIN [num-of-bots] [num-of-turns] [side-length] là đầu vào lúc đầu.
  • DESTROY [turn]là đầu vào ở đầu của mỗi giai đoạn phá hủy. Bot của bạn sẽ trả lời với một trong hai VERTEX x,yđể chọn một đỉnh, hoặc NONE.
  • BROKEN [turn] [your-choice] [other-choices]là đầu vào ở cuối mỗi giai đoạn phá hủy. Thứ tự của các bot khác được chọn ngẫu nhiên vào đầu mỗi trò chơi, nhưng vẫn cố định trong suốt quá trình. Các lựa chọn được trình bày là x,yhoặc N.
  • ACTIVATE [turn]OWNED [turn] [your-choice] [other-choices]là tương đương của ở trên cho giai đoạn kích hoạt, và có cùng ngữ nghĩa.
  • SCORE [your-score] [other-scores] là đầu vào ở cuối trò chơi.
  • Bot của bạn có 1 giây để phân tích kết quả của một pha và chọn đỉnh tiếp theo và 1 giây để thoát sau khi cho điểm. Tôi sẽ kiểm tra các bài nộp trên máy tính xách tay tương đối cũ của mình, vì vậy tốt hơn là để lại một số lề ở đây.

Hãy nhớ để xóa bộ đệm đầu ra của bạn. Không làm như vậy có thể treo bộ điều khiển trong một số môi trường.

Bảng xếp hạng

Cập nhật ngày 13/03/2015

Peacemaker đang hoạt động và Funnelweb cũng nhận được bản cập nhật. Điểm số tăng vọt bởi một thứ tự cường độ. Kết nối vượt quá giới hạn thời gian trong hai trò chơi.

Funnelweb: 30911
Connector: 18431
Watermelon: 3488
Annoyance: 1552
Explorer: 735
Checkpoint: 720
Random Builder: 535
FaucetBot: 236
Peacemaker: 80

Nhật ký đầy đủ với đồ họa nghệ thuật ASCII có thể được tìm thấy trong kho lưu trữ của bộ điều khiển graphical_log.txt.

Một số quan sát:

  • Trình kết nối có thể rất dễ dàng bị dừng bằng cách phá vỡ một đỉnh ở phía trước nó. Tôi nghi ngờ Annoyance thường xuyên làm điều này. Tuy nhiên, hiện tại nó không có ý nghĩa gì vì chỉ Trình kết nối mới có thể hình dung được một đường dẫn.
  • Dưa hấu có thể đạt được một số điểm kha khá bằng cách đơn giản là nằm trên đường nối (vì DFS rất có thể sử dụng các đỉnh của nó).
  • Explorer thích trồng dây leo từ dưa hấu.
  • Funnelweb được cập nhật đạt điểm thực sự tốt, vì Trình kết nối thường bám vào nó ở nửa dưới của lưới.
  • Các trò chơi đang trở nên khá dài, vòng trung bình mất khoảng 25 giây trên máy của tôi.

1
@Alex Tôi đã cố gắng thiết kế thử thách để các bot tự tử sẽ không làm mọi thứ rối tung lên. Ba bot được thiết kế tốt sẽ luôn có thể xây dựng một đường dẫn hợp lệ, nếu chúng hoạt động cùng nhau.
Zgarb

2
@Zgarb Tự tử không nên làm hỏng nó, nhưng một vài con troll-bot làm việc cùng nhau có lẽ cũng có thể chặn tất cả các con đường, phá hỏng trò chơi.
Geobits 20/2/2015

2
Các nút hoạt động @CarpetPython không thể bị hủy.
Zgarb

1
Có vẻ như chúng ta khó có thể thấy bất kỳ trò chơi thú vị nào với người chơi và quy tắc hiện tại. Tôi đề nghị bạn thay đổi các quy tắc một chút để tạo cơ hội cho các trò chơi thú vị. Thay đổi kích thước lưới thành 1,5 * N ^ 2 thay vì 2 * N ^ 2 sẽ tốt và không nhầm lẫn các robot hiện có quá nhiều.
Hiệp sĩ logic

1
@justhalf Đó là sự thật. Các trò chơi trong nhật ký thực sự được chơi với kích thước lưới giảm hơn nữa 4/3*N^2và thậm chí ở đó, các bot có vấn đề hình thành các đường dẫn hợp lệ. Tuy nhiên, Trình kết nối tạm thời bị loại do lỗi và bây giờ nó đã được sửa, tôi hy vọng các trò chơi sẽ thú vị hơn. Tôi sẽ chạy một đợt khác tối nay.
Zgarb

Câu trả lời:


7

Trình kết nối (Java)

Cố gắng tạo một con đường tại một vị trí ngẫu nhiên. Bởi vì nó không thể tự tạo một đường dẫn, nó tìm kiếm các ô đang hoạt động và sử dụng chúng. Tín dụng đến Geobits, từ đó tôi đã đánh cắp một số mã. Ngoài ra, bài nộp này chưa kết thúc, vì nó chỉ đơn giản dừng làm bất cứ điều gì ngay khi đường dẫn được xây dựng.

Chỉnh sửa: Nếu một đường dẫn được xây dựng, Trình kết nối sẽ cố gắng tạo nhiều đường dẫn dọc theo đường dẫn hiện có.

import java.awt.Point;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Connector {
    private static final int INACTIVE = 0;
    private static final int ACTIVE   = 1;
    private static final int BROKEN   = 2;
    private static final int MINE     = 3;

    private int size = 0;
    private int[][] grid = new int[size][size];
    private Point previousCell = null;
    private final List<Point> path = new ArrayList<>();

    public static void main(String[] args) {
        new Connector().start();
    }

    private void start() {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while(true) {
            try {
                String input = reader.readLine();
                act(input);
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(0);
            }
        }
    }

    private void act(String input) throws Exception {
        String[] msg = input.split(" ");
        String output = "";
        int turn;
        switch(msg[0]){
        case "BEGIN":
            size = Integer.parseInt(msg[3]);
            grid = new int[size][size];
            break;
        case "DESTROY":
            output = "NONE";
            break;
        case "BROKEN":
            update(msg, true);
            break;
        case "ACTIVATE":
            turn = Integer.parseInt(msg[1]);
            output = activate(turn);
            break;
        case "OWNED":
            update(msg, false);
            break;
        case "SCORE":
            System.exit(0);
            break;
        }
        if (output.length() > 0) {
            System.out.println(output);
        }
    }

    private String activate(int turn) {
        if (turn == 0) {
            Random r = new Random();
            previousCell = new Point(r.nextInt(size), 0);
            return "VERTEX " + previousCell.x + "," + 0;
        }
        Point lastCell = findLastPathCell(previousCell.x, previousCell.y);
        if (lastCell.y == size-1) {
            //path is done
            Point extendingPathPoint = findExtendingPathPoint();
            if (extendingPathPoint == null) {
                return "NONE";
            }
            return "VERTEX " + extendingPathPoint.x + "," + extendingPathPoint.y;
        } else {
            int x = findBestX(lastCell.x, lastCell.y);
            return "VERTEX " + x + "," + (lastCell.y + 1);
        }
    }

    private int findBestX(int x, int y) {
        int bestScore = Integer.MIN_VALUE;
        int bestX = 0;
        for (int i = -1; i <= 1; i++) {
            int newY = y + 1;
            int newX = (x + i + size) % size;
            int score = calcCellScore(newX, newY, 10);
            if (score > bestScore) {
                bestScore = score;
                bestX = newX;
            } else if (score == bestScore && Math.random() < 0.3) {
                bestX = newX;
            }
        }
        return bestX;
    }

    private int calcCellScore(int x, int y, int depth) {
        int newY = y + 1;
        if (depth < 0) {
            return 1;
        }
        if (newY >= size)
            return 100;
        int cellScore = 0;
        for (int i = -1; i <= 1; i++) {
            int newX = (x + i + size) % size;
            if (grid[newX][newY] == ACTIVE || grid[newX][newY] == MINE) {
                cellScore += 5;
            } else if (grid[newX][newY] == INACTIVE) {
                cellScore += 1;             
            } else {
                cellScore -= 2;
            }
            cellScore += calcCellScore(newX, newY, depth -1);
        }
        return cellScore;
    }

    private Point findLastPathCell(int x, int y) {
        Point thisCell = new Point(x,y);
        int newY = y + 1;
        if (newY >= size) {
            return thisCell;
        }
        List<Point> endCells = new ArrayList<>();
        endCells.add(thisCell);
        path.add(thisCell);
        for (int i = -1; i <= 1; i++) {
            int newX = (x + i + size) % size;
            if (grid[newX][newY] == ACTIVE || grid[newX][newY] == MINE) {
                endCells.add(findLastPathCell(newX, newY));
            }
        }
        int bestY = -1;
        Point bestPoint = null;
        for (Point p : endCells) {
            if (p.y > bestY) {
                bestY = p.y;
                bestPoint = p;
            }
        }
        return bestPoint;
    }

    private Point findExtendingPathPoint() {
        if (path.size() == 0)
            return null;
        Random rand = new Random();
        for (int i = 0; i < size; i++) {
            Point cell = path.get(rand.nextInt(path.size()));
            for (int j = -1; j <= 1; j += 2) {
                Point newCellX = new Point((cell.x + j + size) % size, cell.y);
                if (grid[newCellX.x][newCellX.y] == INACTIVE)
                    return newCellX;

                Point newCellY = new Point(cell.x, cell.y + j);
                if (cell.y < 0 || cell.y >= size)
                    continue;
                if (grid[newCellY.x][newCellY.y] == INACTIVE)
                    return newCellY;
            }
        }
        return null;
    }

    private void update(String[] args, boolean destroyPhase) {
        for(int i = 2; i < args.length; i++) {
            String[] tokens = args[i].split(",");
            if(tokens.length > 1){
                int x = Integer.parseInt(tokens[0]);
                int y = Integer.parseInt(tokens[1]);
                if (grid[x][y] == INACTIVE) {
                    if (destroyPhase) {
                        grid[x][y] = BROKEN;
                    } else if (i == 2) {
                        grid[x][y] = MINE;
                        path.add(new Point(x,y));
                        previousCell = new Point(x,y);
                    } else {
                        grid[x][y] = ACTIVE;
                    }
                }
            }
        }
    }
}

@Zgarb Xin lỗi, tôi đã tạo một lỗi trong khi sửa lỗi khác. Nó hoạt động ngay bây giờ
CommonGuy 5/03/2015

@Manu, thật tốt khi bạn quay lại trò chơi. Có quá nhiều người khai thác và không đủ người xây dựng. Khi Trình kết nối đang chạy, các trò chơi có thể trở nên thú vị hơn (hơn 1 trò chơi trong 100 với số điểm).
Hiệp sĩ logic

Trình kết nối mất 28 giây để phản hồi trong một trong những trò chơi mới nhất (xem nhật ký). Có vẻ như nó đã chạy vào Dưa hấu và có một thời gian khó khăn để quyết định nơi tiếp theo.
Zgarb

Tôi đã chạy một số trò chơi một lần nữa với Công cụ cải tiến và Trình kết nối đã gặp lỗi : java.lang.ArrayIndexOutOfBoundsException: -1 at Connector.findExtendingPathPoint(Connector.java:166).
Zgarb

7

Phễu, Python 2

phiên bản 1.2 - Mã tham gia tốt hơn, thêm hình ảnh động mới

Được đặt theo tên một trong những con nhện kém thân thiện của Úc. Bot này trước tiên xây dựng một tổ hình phễu ở các hàng trên cùng, sau đó thu hút các bot khác vào xây dựng đường dẫn lưu lượng đến tổ.

Dưới đây là hình ảnh động mới của trò chơi 6 bot trên bảng 4 / 3N ^ 2 hiển thị phễu và một số bot đơn giản hơn:

bot6.gif

Mã Python của phễu:

from random import *
import sys
ME = 0
def pt(x,y): return '%u,%u' % (x % side_len, y)

while True:
    msg = raw_input().split()

    if msg[0] == 'BEGIN':
        turn = 0
        numbots, turns, side_len = map(int, msg[1:])
        R = range(side_len)
        top = side_len - 1
        grid = dict((pt(x, y), []) for x in R for y in R)
        mynodes = set()
        deadnodes = set()
        freenodes = set(grid.keys())
        mycol = choice(R)
        extra = sample([pt(x,top) for x in R], side_len)
        path = [(mycol, y) for y in range(top, top - side_len/6, -1)]
        moves = []
        fence = []
        for x,y in path:
            moves.append( [pt(x,y), pt(x+1,y), pt(x-1,y)] )
            fence.extend( [pt(x+1,y), pt(x-1,y)] )
        for dx in range(2, side_len):
            fence.extend( [pt(x+dx,y), pt(x-dx,y)] )
        for x,y in [(mycol, y) for y in 
                range(top - side_len/6, top - 3*side_len/4, -1)]:
            moves.append( [pt(x,y), pt(x+1,y), pt(x-1,y)] )

    elif msg[0] == 'DESTROY':
        target = 'NONE'
        while fence:
            loc = fence.pop(0)
            if loc in freenodes:
                target = 'VERTEX ' + loc
                break
        print target
        sys.stdout.flush()

    elif msg[0] == 'BROKEN':
        for rid, loc in enumerate(msg[2:]):
            if loc != 'N':
                grid[loc] = None
                deadnodes.add(loc)
                freenodes.discard(loc)
                if loc in extra: extra.remove(loc)

    elif msg[0] == 'ACTIVATE':
        target = 'NONE'
        while moves:
            loclist = moves.pop(0)
            goodlocs = [loc for loc in loclist if loc in freenodes]
            if goodlocs:
                target = 'VERTEX ' + goodlocs[0]
                break
        if target == 'NONE':
            if extra:
                target = 'VERTEX ' + extra.pop(0)
            else:
                target = 'VERTEX ' + pt(choice(R), choice(R))
        print target
        sys.stdout.flush()

    elif msg[0] == 'OWNED':
        for rid, loc in enumerate(msg[2:]):
            if loc != 'N':
                grid[loc].append(rid)
                if rid == ME:
                    mynodes.add(loc)
                freenodes.discard(loc)
                if loc in extra: extra.remove(loc)
        turn += 1

    elif msg[0] == 'SCORE':
        break

Con nhện được chạy với python funnelweb.py.


Thay đổi thuật toán và thử nghiệm nó. Nó nên chạy ngay bây giờ.
Logic Knight

Hoạt động tuyệt vời bây giờ!
Zgarb

6

Điểm kiểm tra, Java

Bot này cố gắng tạo các điểm kiểm tra để bất kỳ đường dẫn hợp lệ nào đi qua một trong các đỉnh của tôi. Vì có N 2 lượt và bảng có 2N 2 ngang, tôi có thể kích hoạt / ngắt mọi nút trên một đường ngang duy nhất (giả sử tôi ở đó trước). Làm điều này trong một mô hình xen kẽ ( xbị hỏng, olà của tôi):

xoxoxoxoxoxox...

Nếu bạn muốn tạo một đường dẫn, bạn cần phải đi qua các điểm kiểm tra của tôi :)

Bây giờ, có một số vấn đề này có thể phải đối mặt. Đầu tiên, nó sẽ không hoạt động tốt chút nào trừ khi có nhiều con đường. Vì anh ấy không tự mình thực hiện bất kỳ con đường sản xuất nào , anh ấy thực sự hoàn toàn phụ thuộc vào việc có một số đối thủ cạnh tranh. Ngay cả một vài đối thủ cạnh tranh kết hợp để tạo ra một con đường duy nhất sẽ không giúp được gì nhiều, vì anh ta chỉ ghi được một điểm cho mỗi con đường được tìm thấy. Những gì anh ta cần để tỏa sáng có lẽ là khá nhiều bot tạo ra khá nhiều con đường khác nhau. Thậm chí sau đó, nó có thể không ghi bàn rất cao, nhưng nó là một ý tưởng tôi đã có trong trò chuyện, vì vậy ...

Nếu một trong các khoảng trắng trên dòng đã bị chặn / yêu cầu, tôi chỉ cần tìm kiếm một vị trí gần đó mà tôi có thể sử dụng (tốt nhất là trên cùng một xdòng, chỉ cần thay đổi theo chiều dọc).


import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Checkpoint {
    public static void main(String[] args) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while(true)
            try {
                String input = reader.readLine();
                act(input);
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(0);
            }
    }

    static void act(String input) throws Exception{
        String[] msg = input.split(" ");
        String output = "";
        int turn;
        boolean found = false;
        switch(msg[0]){
        case "BEGIN":
            size = Integer.parseInt(msg[3]);
            grid = new int[size][size];
            target = size/2;
            break;
        case "DESTROY":
            turn = Integer.parseInt(msg[1]);
            for(int x=0;x<size;x+=2)
                for(int y=0;y<size&&!found;y++)
                    if(grid[(x+turn*2)%size][(y+target)%size]==INACTIVE){
                        output = "VERTEX " + ((x+turn*2)%size) + "," + ((y+target)%size);
                        found = true;
                    }
            if(output.length() < 1)
                output = "NONE";
            break;
        case "BROKEN":
            for(int i=2;i<msg.length;i++){
                String[] tokens = msg[i].split(",");
                if(tokens.length>1){
                    int x = Integer.parseInt(tokens[0]);
                    int y = Integer.parseInt(tokens[1]);                    
                    if(grid[x][y]==INACTIVE)
                        grid[x][y] = BROKEN;
                }
            }
            break;
        case "ACTIVATE":
            turn = Integer.parseInt(msg[1]);
            for(int x=1;x<size;x+=2)
                for(int y=0;y<size&&!found;y++)
                    if(grid[(x+turn*2)%size][(y+target)%size]==INACTIVE){
                        output = "VERTEX " + ((x+turn*2)%size) + "," + ((y+target)%size);
                        found = true;
                    }
            if(output.length() < 1)
                output = "NONE";
            break;
        case "OWNED":
            for(int i=2;i<msg.length;i++){
                String[] tokens = msg[i].split(",");
                if(tokens.length>1){
                    int x = Integer.parseInt(tokens[0]);
                    int y = Integer.parseInt(tokens[1]);
                    if(i==2){
                        if(grid[x][y]==INACTIVE)
                            grid[x][y] = MINE;
                    }else{
                        if(grid[x][y]==INACTIVE)
                            grid[x][y]=ACTIVE;
                    }
                }
            }
            break;
        case "SCORE":
            System.exit(0);
            break;
        }
        if(output.length()>0)
            System.out.println(output);
    }

    static int size = 2;
    static int target = size/2;
    static int[][] grid = new int[size][size];

    static final int INACTIVE = 0;
    static final int ACTIVE   = 1;
    static final int BROKEN   = 2;
    static final int MINE     = 3;
}

Để biên dịch, nó javac Checkpoint.java. Để chạy , java Checkpoint. Bạn sẽ muốn thêm / thay đổi đường dẫn để phản ánh mọi lúc mọi nơi.


5

Dưa hấu, Java

Nỗ lực vẽ dưa hấu trên lưới.

import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Watermelon {

    private static int numberOfBots;
    private static int numberOfTurns;
    private static int sideLength;

    private static int turn = 0;

    private static int[][] theGrid;

    private static final int INACTIVE = -2;
    private static final int BROKEN   = -1;
    private static final int MINE     =  0;
    private static final int ACTIVE   =  1;

    private static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    private static PrintStream out = System.out;

    public static void main(String[] args) throws IOException {
        while (true){
            String[] input = in.readLine().trim().split(" ");
            String instruction = input[0];
            switch (instruction){
                case "BEGIN":
                    begin(input);
                    break;
                case "DESTROY":
                    destroy(input);
                    break;
                case "BROKEN":
                    broken(input);
                    break;
                case "ACTIVATE":
                    activate(input);
                    break;
                case "OWNED":
                    owned(input);
                    break;
                default:
                    return;
            }
            out.flush();
        }
    }

    private static void begin(String[] input) {
        numberOfBots = Integer.parseInt(input[1]);
        numberOfTurns = Integer.parseInt(input[2]);
        sideLength = Integer.parseInt(input[3]);
        theGrid = new int[sideLength][sideLength];
        for (int x = 0; x < sideLength; x++){
            for (int y = 0; y < sideLength; y++){
                theGrid[x][y] = INACTIVE;
            }
        }
    }

    private static void owned(String[] input) {
        turn = Integer.parseInt(input[1]);
        for (int i = input.length - 1; i >= 2; i--){
            if (input[i].equals("N")){
                continue;
            }
            String[] coordinates = input[i].split(",");
            int x = Integer.parseInt(coordinates[0]);
            int y = Integer.parseInt(coordinates[1]);
            int player = i - 2;
            if (player == 0){
                theGrid[x][y] = MINE;
            } else {
                theGrid[x][y] = ACTIVE;
            }
        }
    }

    private static void activate(String[] input) {
        turn = Integer.parseInt(input[1]);
        double[][] values = new double[sideLength][sideLength];
        List<Point> pointList = new ArrayList<>();
        for (int x = 0; x < sideLength; x++){
            for (int y = 0; y < sideLength; y++){
                if (theGrid[x][y] == MINE || theGrid[x][y] == ACTIVE){
                    for (int x1 = 0; x1 < sideLength; x1++){
                        for (int y1 = 0; y1 < sideLength; y1++){
                            double distance = Math.pow(x - x1, 2) + Math.pow(y - y1, 2);
                            values[x1][y1] += 1 / (distance + 1);
                        }
                    }
                }
                pointList.add(new Point(x, y));
            }
        }
        pointList.sort(Comparator.comparingDouble((Point a) -> values[a.x][a.y]).reversed());
        for (Point point : pointList){
            if (theGrid[point.x][point.y] == INACTIVE){
                out.println("VERTEX " + point.x + "," + point.y);
                return;
            }
        }
        out.println("NONE");
    }

    private static void broken(String[] input) {
        turn = Integer.parseInt(input[1]);
        for (int i = 2; i < input.length; i++){
            if (input[i].equals("N")){
                continue;
            }
            String[] coordinates = input[i].split(",");
            int x = Integer.parseInt(coordinates[0]);
            int y = Integer.parseInt(coordinates[1]);
            theGrid[x][y] = BROKEN;
        }
    }

    private static void destroy(String[] input) {
        turn = Integer.parseInt(input[1]);
        double[][] values = new double[sideLength][sideLength];
        List<Point> pointList = new ArrayList<>();
        for (int x = 0; x < sideLength; x++){
            for (int y = 0; y < sideLength; y++){
                if (theGrid[x][y] == MINE){
                    for (int x1 = 0; x1 < sideLength; x1++){
                        for (int y1 = 0; y1 < sideLength; y1++){
                            double distance = Math.pow(x - x1, 2) + Math.pow(y - y1, 2);
                            values[x1][y1] -= 1 / (distance + 1);
                        }
                    }
                }
                if (theGrid[x][y] == ACTIVE){
                    for (int x1 = 0; x1 < sideLength; x1++){
                        for (int y1 = 0; y1 < sideLength; y1++){
                            double distance = Math.pow(x - x1, 2) + Math.pow(y - y1, 2);
                            values[x1][y1] += 1 / (distance + 1) / (numberOfBots - 1);
                        }
                    }
                }
                pointList.add(new Point(x, y));
            }
        }
        pointList.sort(Comparator.comparingDouble((Point a) -> values[a.x][a.y]).reversed());
        for (Point point : pointList){
            if (theGrid[point.x][point.y] == INACTIVE){
                out.println("VERTEX " + point.x + "," + point.y);
                return;
            }
        }
        out.println("NONE");
    }
}

5

VòiBot (tính bằng R)

Tạo một nút cổ chai trên dòng thứ hai và kích hoạt các nút trên đường dẫn phía sau nó.

infile <- file("stdin")
open(infile)
repeat{
    input <- readLines(infile,1)
    args <- strsplit(input," ")[[1]]
    if(args[1]=="BEGIN"){
        L <- as.integer(args[4])
        M <- N <- matrix(0,nrow=L,ncol=L)
        x0 <- sample(2:(L-1),1)
        }
    if(args[1]=="DESTROY"){
        if(args[2]==0){
            X <- x0
            Y <- 2
            }else{
                free <- which(M[,2] == 0)
                mine <- which(N[,2] == 1)
                X <- free[which.min(abs(free-mine))]
                Y <- 2
                }
        if(length(X)){cat(sprintf("VERTEX %s,%s\n",X-1,Y-1))}else{cat("NONE\n")}
        flush(stdout())
        }
    if(args[1]=="BROKEN"){
        b <- strsplit(args[args!="N"][-(1:2)],",")
        o <- strsplit(args[3],",")[[1]]
        b <- lapply(b,as.integer)
        if(o[1]!="N") N[as.integer(o[1])+1,as.integer(o[2])+1] <- -1
        for(i in seq_along(b)){M[b[[i]][1]+1,b[[i]][2]+1] <- -1}
        }
    if(args[1]=="ACTIVATE"){
        if(args[2]==0){
            broken <- which(M[,2] == -1)
            free <- which(M[,2] == 0)
            X <- free[which.min(abs(broken-free))]
            Y <- 2
            }else{
                y <- 3
                X <- NULL
                while(length(X)<1){
                    lastrow <- which(N[,y-1]==1)
                    newrow <- unlist(sapply(lastrow,function(x)which(M[,y]==0 & abs((1:L)-x)<2)))
                    if(length(newrow)){
                        X <- sample(newrow,1)
                        Y <- y
                        }
                    y <- y+1
                    if(y>L){X <- x0; Y <- 1}
                    }
                }
        cat(sprintf("VERTEX %s,%s\n",X-1,Y-1))
        flush(stdout())
        }
    if(args[1]=="OWNED"){
        b <- strsplit(args[args!="N"][-(1:2)],",")
        o <- strsplit(args[3],",")[[1]]
        b <- lapply(b,as.integer)
        if(o[1]!="N") N[as.integer(o[1])+1,as.integer(o[2])+1] <- 1
        for(i in seq_along(b)){M[b[[i]][1]+1,b[[i]][2]+1] <- 1}
        }
    if(args[1]=="SCORE") q(save="no")
    }

Nếu tôi không làm hỏng, cấu hình cuối cùng sẽ giống như:

........    .a..aa..
..aaa...    ..aaa...
.xxaxx..    xxxaxxx.    etc.
........    ........

Lệnh là Rscript FaucetBot.R.


5

Hòa giải, Java

Dựa trên mã của Manu.

Các khu vực xung đột tìm kiếm hòa giải (nghĩa là hầu hết nồng độ đỉnh MÔI GIỚI hoặc HOẠT ĐỘNG) và kích hoạt một đỉnh ngẫu nhiên gần đó.

import java.awt.Point;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

public class Peacemaker {
    private static final int INACTIVE = 0;
    private static final int ACTIVE   = 1;
    private static final int BROKEN   = 2;
    private static final int MINE     = 3;

    private int size = 0;
    private int[][] grid = new int[size][size];
    private int startingPoint = 0;

    public static void main(String[] args) {
        new Peacemaker().start();
    }

    private void start() {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while(true) {
            try {
                String input = reader.readLine();
                act(input);
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(0);
            }
        }
    }

    private void act(String input) throws Exception {
        String[] msg = input.split(" ");
        String output = "";
        int turn;
        switch(msg[0]){
        case "BEGIN":
            size = Integer.parseInt(msg[3]);
            grid = new int[size][size];
            break;
        case "DESTROY":
            output = "NONE";
            break;
        case "BROKEN":
            update(msg, true);
            break;
        case "ACTIVATE":
            turn = Integer.parseInt(msg[1]);
            output = activate(turn);
            break;
        case "OWNED":
            update(msg, false);
            break;
        case "SCORE":
            System.exit(0);
            break;
        }
        if (output.length() > 0) {
            System.out.println(output);
        }
    }

    private String activate(int turn) {
        Random r = new Random();
        if (turn == 0) {
            startingPoint = r.nextInt(size);
            return "VERTEX " + startingPoint + "," + 0;
        } else {

            Point point = searchConflicts();

            int posX = point.x;
            int posY = point.y;

            while (grid[posX][posY] != INACTIVE) {
                 int previousX = (posX - 1 < 0 ? size - 1 : posX - 1);
                 int nextX = (posX + 1 > size - 1 ? 0 : posX + 1);
                 int previousY = (posY - 1 < 0 ? size - 1 : posY - 1);
                 int nextY = (posY + 1 > size - 1 ? 0 : posY + 1);

                 int choice = r.nextInt(4);
                 switch (choice) {
                     case 0: posX = previousX; break;
                     case 1: posX = nextX; break;
                     case 2: posY = previousY; break;
                     case 3: posY = nextY; break;
                 }
            }

            return "VERTEX " + posX + "," + posY;
        }
    }

    private Point searchConflicts() {

        int previousCellScore = 0;
        int cellX = 0;
        int cellY = 0;
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j ++) {
                if (previousCellScore < adjacentCellsScore(i, j)) {
                    cellX = i; cellY = j;
                    previousCellScore = adjacentCellsScore(i, j);
                }
            }
        }
        return new Point(cellX, cellY);
    }

    /*  Format of adjacent cells :
     * 
     *   0 1 2
     *   3 . 4
     *   5 6 7
     */
    private int adjacentCellsScore(int x, int y) {

        int[] scores = new int[8];

        int previousX = (x - 1 < 0 ? size - 1 : x - 1);
        int nextX = (x + 1 > size - 1 ? 0 : x + 1);
        int previousY = (y - 1 < 0 ? size - 1 : y - 1);
        int nextY = (y + 1 > size - 1 ? 0 : y + 1);

        scores[0] = calcScore(previousX, nextY);
        scores[1] = calcScore(x, nextY);
        scores[2] = calcScore(nextX, nextY);
        scores[3] = calcScore(previousX, y);
        scores[4] = calcScore(nextX, y);
        scores[5] = calcScore(previousX, previousY);
        scores[6] = calcScore(x, previousY);
        scores[7] = calcScore(nextX, previousY);

        return IntStream.of(scores).reduce(0, (a, b) -> a + b);
    }

    private int calcScore(int x, int y) {
        int activeScore = 2;
        int mineScore = 1;
        int inactiveScore = 0;
        int brokenScore = 3;

        if (grid[x][y] == ACTIVE) 
            return activeScore;
        else if (grid[x][y] == MINE)
            return mineScore;
        else if (grid[x][y] == INACTIVE) 
            return inactiveScore;
        else if (grid[x][y] == BROKEN) 
            return brokenScore;
        else
            return 0;
    }


    private void update(String[] args, boolean destroyPhase) {
        for(int i = 2; i < args.length; i++) {
            String[] tokens = args[i].split(",");
            if(tokens.length > 1){
                int x = Integer.parseInt(tokens[0]);
                int y = Integer.parseInt(tokens[1]);
                if (grid[x][y] == INACTIVE) {
                    if (destroyPhase) {
                        grid[x][y] = BROKEN;
                    } else if (i == 2) {
                        grid[x][y] = MINE;
                    } else {
                        grid[x][y] = ACTIVE;
                    }
                }
            }
        }
    }       
}

@Zgarb Cảm ơn, tôi đã giải quyết vấn đề này ngay bây giờ.
Thrax

Peacemaker hoạt động ngay bây giờ, và được bao gồm trong bảng thành tích. Tuy nhiên, nó dường như không làm được gì nhiều, vì vậy có lẽ vẫn còn một số lỗi.
Zgarb

Trên thực tế, nhìn vào mã của bạn, tôi nghĩ rằng vấn đề là trong whilevòng lặp của activatephương thức. Bạn dừng tìm kiếm một khi bạn tìm thấy một đỉnh không phải của bạn và không bị phá vỡ - nhưng nó có thể thuộc sở hữu của người khác, vì vậy bạn không thể kích hoạt nó.
Zgarb

@Zgarb Tôi đã đọc sai thông số kỹ thuật và nghĩ rằng nhiều người chơi có thể kích hoạt cùng một đỉnh bất cứ lúc nào. Tôi đoán tôi chỉ phải thay đổi tìm kiếm của mình và tìm kiếm đỉnh không hoạt động mà thôi.
Thrax

2

Trình tạo ngẫu nhiên, Python 3

Đây là một bot ví dụ ngu ngốc không bao giờ phá hủy bất cứ thứ gì và cố gắng kích hoạt một đỉnh ngẫu nhiên mỗi lượt. Lưu ý rằng không cần kiểm tra xem đỉnh có hoạt động không; Bộ điều khiển đảm nhận việc đó.

import random as r

while True:
    msg = input().split()
    if msg[0] == "BEGIN":
        side_len = int(msg[3])
    elif msg[0] == "DESTROY":
        print("NONE")
    elif msg[0] == "ACTIVATE":
        print("VERTEX %d,%d"%(r.randrange(side_len), r.randrange(side_len)), flush=True)
    elif msg[0] == "SCORE":
        break

Chạy với lệnh

python3 random_builder.py

Bạn có thể cần phải thay thế python3bằng cách pythontùy thuộc vào cài đặt Python của bạn. Để làm điều này, chỉ cần chỉnh sửa các bots.txttập tin. Tôi đã cập nhật bộ điều khiển và không cần phải lộn xộn với đường dẫn tệp nữa.


Kể từ khi bạn sử dụng python 3, thay vì sys.stdout.flush()bạn chỉ có thể làm flush=Truenhư một đối số print.
matjoyce 23/2/2015

@matsjoyce Cảm ơn, tôi không biết điều đó. Tôi sẽ chỉnh sửa phiên bản kho lưu trữ sau.
Zgarb 24/2/2015

2

Nhà thám hiểm, Python 3

Chiến lược kích hoạt:

Tạo một bản đồ nhiệt dựa trên trạng thái của mỗi nút (hoạt động / không hoạt động / bị hỏng) và chọn nút có giá trị nhiệt dự kiến ​​lớn nhất cho mỗi người nếu họ chọn nút đó.

Chiến lược hủy diệt:

Không bao giờ phá hủy bất cứ điều gì vì điều đó không giúp bot nhiều.

import sys

class bd:

    def __init__(s, l):

        s.l=l
        s.b=[]
        s.v=[]
        s.m=[]
        s.bm=[]
        s.utd=False #up_to_date
        s.bmc=1

        for i in range(s.l):
            s.b+=[[]]
            s.v+=[[]]
            s.m+=[[]]
            s.bm+=[[]]
            for k in range(s.l):
                s.b[i]+=[0]
                s.v[i]+=[0]
                s.m[i]+=[0]
                s.bm[i]+=[s.bmc]

    def update(s):
        s.utd=True

        vu=[]
        vd=[]
        for i in range(s.l):
            vu+=[[]]
            vd+=[[]]
            for k in range(s.l):
                vu[i]+=[1]
                vd[i]+=[1]

        #spread up
        for i in range(s.l):
            vu[i][0]*=s.bm[i][0]

        for k in range(1,s.l):
            for i in range(s.l):
                sumv=vu[(i-1)%s.l][k-1]+vu[(i)%s.l][k-1]+vu[(i+1)%s.l][k-1]  
                vu[i][k]*=sumv*s.bm[i][k]/3

        #spread down
        t=s.l-1
        for i in range(s.l):
            vd[i][t]*=s.bm[i][t]

        for k in range(s.l-2,-1,-1):
            for i in range(s.l):
                sumv=vd[(i-1)%s.l][k+1]+vd[(i)%s.l][k+1]+vd[(i+1)%s.l][k+1]  
                vd[i][k]*=sumv*s.bm[i][k]/3

        #mult
        for i in range(s.l):
            for k in range(s.l):
                if s.b[i][k]==-1 or s.m[i][k]==1:
                    s.v[i][k]=float(-1)
                else:
                    s.v[i][k]=vu[i][k]*vd[i][k]/(s.b[i][k]+1)

    def add_act(s,al):
        s.utd=False

        for ind, ap in enumerate(al):
            i,k=ap
            s.b[i][k]+=1            
            s.bm[i][k]=2*s.bmc            
            #doesn't work alone WHY???
            if ind==0: s.m[i][k]=1

    def add_ina(s,il):
        s.utd=False

        for ind, ip in enumerate(il):
            i,k=ip
            s.b[i][k]=-1
            s.bm[i][k]=0                    

    def get_newact(s):
        s.update()
        vm=-28
        pm=None
        for i in range(s.l):
            for k in range(s.l):
                if s.v[i][k]>vm:
                    vm=s.v[i][k]
                    pm=(i,k)
        #doesn't work alone WHY???
        s.m[pm[0]][pm[1]]=1
        return pm


b=None

while True:
    inp=input()
    msg = inp.split()
    if msg[0] == "BEGIN":        
        b = bd(int(msg[3]))
    elif msg[0] == "DESTROY":
        print("NONE")
    elif msg[0] == "BROKEN":
        pl=[]
        for m in msg[2:]:
            if m!='N':
                pl+=[tuple(map(int,m.split(',')))]
        b.add_ina(pl)
    elif msg[0] == "ACTIVATE":
        at=b.get_newact()
        print("VERTEX %d,%d"%(at[0], at[1]))
    elif msg[0] == "OWNED":
        pl=[]
        for m in msg[2:]:
            if m!='N':
                pl+=[tuple(map(int,m.split(',')))]        
        b.add_act(pl)
    elif msg[0] == "SCORE":
        break       

    sys.stdout.flush()

1

Bực mình, Bash

#!/bin/bash

declare -A avail
broken=
owned=

while read c p
    case "$c" in
        ACTIVATE|BROKEN) v=broken;;
        *) v=owned
    esac
    case "$c" in
        BEGIN)
            read b t n <<<"$p"
            list=$(
                eval "echo {0..$((n-1))},{0..$((n-1))}\$'\\n'" |
                shuf
            )
            for i in $list; do
                avail[$i]=1
            done;;
        DESTROY|ACTIVATE)
            for t in $(
                for i in ${!v}; do
                    [ "$i" != N ] &&
                    if [ "$c" = ACTIVATE ]; then
                        echo $(((${i%,*}+2)%n)),${i#*,}
                        echo $(((${i%,*}-2+n)%n)),${i#*,}
                    else
                        echo ${i%,*},$(((${i#*,}+1)%n))
                        echo ${i%,*},$(((${i#*,}-1+n)%n))
                    fi
                done |
                shuf
            ) $list; do
                [ "${avail[$t]}" ] && echo VERTEX $t && break
            done ||
            echo NONE;;
        BROKEN|OWNED)
            read x m $v <<<"$p";
            for i in $m ${!v}; do
                unset avail[$i]
            done;;
        SCORE)! :
    esac
do :;done

Đã cố gắng để làm cho kết quả trông thú vị hơn.

Chạy với bash annoyance.sh.


1
Bot của bạn in tất cả các đầu vào của nó thành STDERR. Nó không bị cấm hay bất cứ điều gì, chỉ là một sự phiền toái (ý định chơi chữ).
Zgarb 24/2/2015

@Zgarb Xin lỗi, tôi đã dán phiên bản sai. Đã sửa.
jimmy23013

1

Người trung

Tôi thấy rằng một số bot được xây dựng từ đầu, và một số từ phía dưới. Đây là lần đầu tiên (tôi nghĩ) bắt đầu ở giữa và làm việc lên xuống.

(nó không được thử nghiệm với bộ điều khiển, vì vậy nếu nó không hoạt động, hãy cho tôi biết.)

class Node

  def self.set_size s
    @@grid = Array.new(s,Array.new(s,0))
  end

  def initialize x,y
    @x=x
    @y=y
  end

  def offset dx,dy
    return Node.new @x+dx,@y+dy
  end

  def state
    return -1 if @x<0 || @y<0 || @x>=@@grid.length || @y>=@@grid.length
    @@grid[@x][@y]
  end

  def state= n
    return -1 if @x<0 || @y<0 || @x>=@@grid.length || @y>=@@grid.length
     @@grid[@x][@y]=n
  end

  def active?
    state > 0
  end

  def open?
    state == 0
  end
  attr_reader :x,:y

  def to_s
    "VERTEX #{@x},#{@y}"
  end


  def scan_down
    ans = nil
    [0,-1,1].each do|offset|
      n = Node.new @x+offset,@y-1
      ans = (ans||n) if n.open?
      ans = (n.scan_down||ans) if n.active?
    end
    return ans
  end

  def scan_up
    ans = nil
    [0,-1,1].each do|offset|
      n = Node.new @x+offset,@y+1
      ans = (ans||n) if n.open?
      ans = (n.scan_up||ans) if n.active?
    end
    return ans
  end

end

input = gets.split
input.shift

BotCount = input.shift.to_i
Turns = input.shift.to_i
GridSize = input.shift.to_i

Node.set_size GridSize

midRow = GridSize/2

toDestroy = (0...GridSize).map{|i|Node.new i,midRow}
toDestroy.reject!{|n| n.x==midRow}

chain = []
Turns.times do
  gets;
  toDestroy.each{|x|
    if x.active?
      toDestroy.push x.offset 0,1
      toDestroy.push x.offset 1,1
      toDestroy.push x.offset -1,1
    end
  }
  toDestroy.reject!{|x|!x.open?}
  puts toDestroy.sample
  input = gets.split
  input.shift;input.shift
  input.each{|str|
    a,b = str.split ','
    (Node.new a.to_i,b.to_i).state=1
  }
  gets;

  if chain.length == 0
    n = Node.new midRow,midRow
    until n.open?
      n = Node.new n.x+1,midRow
    end
    puts chain[0]=n
  elsif rand>0.5
    n=nil
    loop do
      h=chain[0]
      n = h.scan_down
     break if !n
      chain.shift
    end
    h.unshift n
    puts n
  else
    loop do
      h=chain[-1]
      n = h.scan_up
      h.pop if !n
      brake if n
    end
    chain.push n
    puts n
  end

  input = gets.split
  input.shift;input.shift
  input.each{|str|
    a,b = str.split ','
    (Node.new a,b).state=-1
  }

end
gets
exit

Cảm ơn bạn đã gửi! Thật không may, thử thách này đã không hoạt động được gần nửa năm và hiện tại tôi không thể chạy hầu hết các bot, vì tôi không có quyền truy cập vào máy tính nơi tôi có thể cài đặt ngôn ngữ.
Zgarb

1
@Zgarb Tôi hiểu. có thể một ngày nào đó tôi sẽ trả lời một thử thách trong khung thời gian hợp lý ...
MegaTom
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.