그리드 라우팅 전투


22

참고 : 이 도전은 경기를 실행하는 데 필요한 언어를 설치할 수 없으므로 현재 죽었습니다. 다른 사람이 할 시간과 관심이 있다면 반대하지 않습니다.

리더 보드는 게시물 하단을 참조하십시오.

이것은 봇이 2 차원 그리드 그래프를 통해 경로를 구성하는 반 협조적인 도전입니다. 트래픽이 가장 많은 노드를 제어하는 ​​봇이 승자입니다. 그러나 실제로 연결 경로를 구축하려면 둘 이상의 봇 리소스가 필요하므로 봇은 어느 정도 함께 작동해야합니다.

게임 플레이

다음 N > 0은 봇의 수입니다.

그리드

이 게임은 왼쪽 하단 좌표가 에있는 2 차원 정수 격자 크기로 재생됩니다 . 각 좌표 와는 세 개의 좌표 출사 가장자리가 , , 및 를 Where, 위 -coordinates 모듈이 촬영된다 . 이것은 그리드가 동쪽과 서쪽 가장자리를 둘러싸고 있음을 의미합니다. 모든 하단 좌표 는 소스 이고 모든 상단 좌표 는 싱크 입니다.⌊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)

다음 그림은 8 × 8격자를 보여줍니다 .

8x8 그리드.

그래프의 각 정점은 비활성 , 활성 또는 파손 입니다. 모든 정점이 비활성화되고 봇에 의해 활성화 될 수 있습니다. 또한 봇은 정점을 깰 수 있으며 복구 할 수 없습니다.

순서 전환

턴은 파괴 단계활성화 단계 로 구성됩니다 . 파괴 단계에서 각 봇은 하나의 비활성 정점을 파괴 할 수 있습니다. 그 정점은 그때부터 끊어졌으며 다른 사람에 의해 활성화되지 않을 수 있습니다. 활성화 단계에서, 각 봇은 하나의 비활성 버텍스를 활성화 할 수 있습니다. 그때부터, 그들은 그 정점을 소유하며, 다른 사람에 의해 재 활성화 될 수 없습니다. 여러 봇이 모두 같은 차례에 활성화하면 하나의 정점을 소유 할 수 있습니다. 각 단계에서 정점 선택이 동시에 수행됩니다.

채점

한 라운드는 정확히 회전합니다. 이후 라운드는 다음과 같이 점수가 매겨집니다. 각 활성 소스 정점 에서 활성 정점을 따라 무작위로 깊이 우선 검색을 수행합니다 (각 정점의 자식이 임의 순서로 방문됨을 의미). 소스에서 싱크까지의 경로가 발견되면 해당 경로를 따라 모든 정점에 대해 정점의 모든 소유자가 한 점을 얻습니다.N2N

전체 게임은 100 라운드 동안 지속되며 전체 점수가 가장 높은 봇이 승자입니다. 점수의 분산이 너무 높으면이 수를 늘릴 수 있습니다.

추가 규칙

  • 컨트롤러 또는 다른 제출물을 망칠 필요가 없습니다.
  • 참가자 당 최대 하나의 제출.
  • 게임 시작시 하나의 개인 텍스트 파일을 제외한 외부 리소스는 깨끗하게 지워지지 않았습니다.
  • 특정 상대를 이길 수 있도록 봇을 설계하지 마십시오.
  • 봇을 컴파일하고 실행하는 명령을 제공하십시오. 데비안 리눅스에서 자유롭게 사용할 수있는 모든 컴파일러 / 인터프리터가 허용됩니다.

컨트롤러

컨트롤러는 Python 3으로 작성 되었으며 GitHub에서 찾을 수 있습니다 . 자세한 지시 사항은 README 파일을 참조하십시오. 시작하는 API는 다음과 같습니다.

  • 봇은 각 라운드가 시작될 때 시작되며 라운드가 끝날 때까지 지속됩니다. 줄 바꿈 종료 메시지를 사용하여 STDIN 및 STDOUT을 통해 컨트롤러와 통신합니다.
  • BEGIN [num-of-bots] [num-of-turns] [side-length] 처음에 입력됩니다.
  • DESTROY [turn]각 파괴 단계의 시작 부분에 입력됩니다. 봇 VERTEX x,y은 정점을 선택 하거나 으로 응답해야 합니다 NONE.
  • BROKEN [turn] [your-choice] [other-choices]각 파괴 단계의 끝에 입력됩니다. 다른 봇의 순서는 각 게임이 시작될 때 무작위로 결정되지만 그 동안 고정되어 있습니다. 선택 사항은 x,y또는 로 표시됩니다 N.
  • ACTIVATE [turn]OWNED [turn] [your-choice] [other-choices]상기 활성화 단계 용의 당량은, 동일한 의미를 갖는다.
  • SCORE [your-score] [other-scores] 게임이 끝나면 입력됩니다.
  • 봇은 1 초 동안 단계 결과를 분석하고 다음 정점을 선택하고 1 초 후에 점수를 매 깁니다. 비교적 오래된 랩톱에서 제출 한 내용을 테스트하므로 여기에 약간의 여유를 두는 것이 좋습니다.

출력 버퍼를 플러시해야합니다. 그렇지 않으면 일부 환경에서 컨트롤러가 정지 될 수 있습니다.

리더 보드

2015 년 3 월 13 일 업데이트

Peacemaker가 시작되었고 Funnelweb도 업데이트를 받았습니다. 점수가 한 단계 올라갔습니다. 두 게임에서 커넥터가 시간 제한을 초과했습니다.

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

ASCII 아트 그래픽이 포함 된 전체 로그는 컨트롤러의 저장소에 graphical_log.txt있습니다.

일부 관찰 :

  • 커넥터는 하나의 정점을 끊어 아주 쉽게 멈출 수 있습니다. 나는 성가심이 자주하는 것으로 생각합니다. 그러나 커넥터 만 경로를 구성 할 수 있기 때문에 현재는 의미가 없습니다.
  • 수박은 단순히 연결 경로에 있기 때문에 적절한 점수를 얻을 수 있습니다 (DFS가 정점을 사용할 가능성이 높기 때문에).
  • 탐험가는 수박에서 포도를 재배하는 것을 좋아합니다.
  • 커넥터는 일반적으로 그리드의 아래쪽 절반에 걸러지기 때문에 업데이트 된 Funnelweb은 정말 좋은 점수를받습니다.
  • 게임이 꽤 길어지고 있으며 평균 라운드는 내 컴퓨터에서 약 25 초가 걸립니다.

1
@Alex 자살 봇이 모든 것을 망칠 수 없도록 도전을 설계하려고했습니다. 잘 설계된 3 개의 봇은 함께 작동하는 경우 항상 올바른 경로를 구성 할 수 있어야합니다.
Zgarb 2019

2
@Zgarb Suicide는 그것을 망쳐서는 안되지만, 함께 작동하는 몇 트롤 로봇은 아마도 모든 경로를 차단 하여 게임을 망칠 수 있습니다.
Geobits

2
@CarpetPython 활성 노드는 삭제할 수 없습니다.
Zgarb 2019

1
현재 플레이어 및 규칙과 함께 재미있는 게임을 볼 수 없을 것 같습니다. 재미있는 게임을위한 기회를 만들기 위해 규칙을 약간 변경하는 것이 좋습니다. 그리드 크기를 2 * N ^ 2 대신 1.5 * N ^ 2로 변경하면 좋으며 기존 로봇을 너무 혼동하지 않아야합니다.
논리 기사

1
@justhalf 사실입니다. 로그에있는 게임은 실제로 그리드 크기가 더 줄어든 상태에서 플레이 4/3*N^2되었으며 심지어 봇은 유효한 경로를 형성하는 데 문제가있었습니다. 그러나 오류로 인해 커넥터가 일시적으로 실격 처리되었으며 이제 수정되었으므로 게임이 더 흥미로울 것으로 기대합니다. 오늘 밤 또 다른 배치를 실행하겠습니다.
Zgarb

답변:


7

커넥터 (자바)

임의의 위치에 경로를 만들려고합니다. 자체 경로를 만들 수 없으므로 활성 셀을 검색하여 사용합니다. 크레딧은 Geobits에게갑니다. 또한이 제출은 경로가 구축되는 즉시 아무것도하지 않기 때문에 아직 완료되지 않았습니다.

편집 : 경로가 작성되면 커넥터는 기존 경로를 따라 여러 경로를 작성하려고합니다.

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 죄송합니다. 다른 버그를 수정하는 동안 버그가 발생했습니다. 그것은 지금 작동
CommonGuy

@Manu, 다시 게임에 복귀하는 것이 좋습니다. 착취자가 너무 많고 빌더가 충분하지 않습니다. Connector가 실행되면 게임이 더 흥미로워 질 수 있습니다 (100 점 중 1 게임 이상).
논리 기사

최신 게임 중 하나에서 커넥터가 응답하는 데 28 초가 걸렸습니다 (로그 참조). 수박에 빠져 다음에 갈 곳을 결정하는 데 어려움을 겪었던 것 같습니다.
Zgarb

개선 된 Peacemaker를 사용하여 일부 게임을 다시 실행했으며 커넥터에서 오류가 발생했습니다 java.lang.ArrayIndexOutOfBoundsException: -1 at Connector.findExtendingPathPoint(Connector.java:166).
Zgarb

7

퍼널 웹, 파이썬 2

버전 1.2-코드 결합 개선, 새로운 애니메이션 추가

호주의 덜 친절한 거미 중 하나의 이름을 따서 명명되었습니다. 이 봇은 먼저 맨 윗줄에 깔때기 모양의 둥지를 만든 다음 다른 봇을 둥지로가는 통로로 끌어들입니다.

다음은 깔때기 웹과 몇 가지 간단한 봇을 보여주는 4 / 3N ^ 2 보드의 6 봇 게임의 새로운 애니메이션입니다.

bots6.gif

깔때기 웹의 파이썬 코드 :

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

거미는로 실행됩니다 python funnelweb.py.


알고리즘을 변경하고 테스트했습니다. 지금 실행해야합니다.
논리 기사

지금 잘 작동합니다!
Zgarb

6

체크 포인트, 자바

이 봇은 유효한 경로가 내 정점 중 하나를 통과하도록 체크 포인트를 만들려고합니다. N 2 턴이 있고 보드가 2N 2 이기 때문에 단일 수평선에서 모든 노드를 활성화 / 차단 할 수 있습니다 (먼저 있다고 가정). (대체 패턴에서이 작업을 수행 x, 고장 o내 꺼야) :

xoxoxoxoxoxox...

경로를 만들고 싶다면 내 체크 포인트를 거쳐야합니다. :)

이제 몇 가지 문제가 발생할 수 있습니다. 첫째, 경로가 많지 않으면 전혀 효과가 없을 것입니다. 그가하지 않기 때문에 어떤 생산적인 경로 자신을, 그는 정말 어떤 경쟁 거기에 전적으로 의존하고있다. 단일 경로를 만들기 위해 결합한 두 경쟁자조차도별로 도움이되지 않습니다. 그가 빛나야 할 것은 아마도 몇 가지 다른 길을 만드는 꽤 많은 봇 일 것입니다. 그렇다하더라도, 그것은 득점하지 않을 수 있습니다 매우 높은,하지만 그래서 내가 채팅에 가지고 있던 생각했다 ...

줄의 공백 중 하나가 이미 차단 / 청구 된 경우 사용할 수있는 근처 지점을 검색하면됩니다 (바람직하게는 같은 x줄에서 세로로 이동 한 경우에만).


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

컴파일하려면 javac Checkpoint.java입니다. 실행하려면 java Checkpoint. 어디에 있든지 경로를 추가 / 변경할 수 있습니다.


5

수박, 자바

격자에 수박을 그리려고 시도합니다.

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

수도꼭지 (R)

두 번째 줄에 병목 현상을 만들고 그 뒤에있는 경로에서 노드를 활성화합니다.

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

내가 망쳐 놓지 않으면 최종 구성은 다음과 같아야합니다.

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

명령은 Rscript FaucetBot.R입니다.


5

피스 메이커, 자바

Manu의 코드를 기반으로합니다.

Peacemaker 검색 충돌 영역 (예 : 대부분의 BROKEN 또는 ACTIVE 정점 집중)은 근처에 임의의 정점을 활성화합니다.

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 감사합니다. 지금이 문제를 해결해야합니다.
Thrax

피스 메이커는 현재 일하고 있으며 리더 보드에 포함되어 있습니다. 그러나 많은 작업을 수행하지 않는 것 같으므로 여전히 몇 가지 버그가 남아있을 수 있습니다.
Zgarb

실제로 코드를 보면 문제가 메소드 의 while루프에 있다고 생각합니다 activate. 본인이 아니고 깨지지 않은 정점을 찾으면 검색을 중지하지만 다른 사람이 소유 할 수 있으므로 활성화 할 수 없습니다.
Zgarb

@ Zgarb 나는 사양을 잘못 읽고 여러 플레이어가 언제든지 같은 정점을 활성화 할 수 있다고 생각했습니다. 검색을 변경하고 비활성 정점 만 찾아야한다고 생각합니다.
Thrax

2

랜덤 빌더, 파이썬 3

이것은 아무것도 파괴하지 않는 어리석은 예제 봇이며, 매 턴마다 임의의 정점을 활성화하려고 시도합니다. 꼭짓점이 비활성인지 여부를 확인할 필요는 없습니다. 컨트롤러가 처리합니다.

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

명령으로 실행

python3 random_builder.py

Python 설치 python3python따라 교체해야 할 수도 있습니다 . 이렇게하려면 bots.txt파일을 편집 하십시오. 컨트롤러를 업데이트했으며 더 이상 파일 경로를 엉망으로 만들 필요가 없습니다.


파이썬 3을 사용하기 때문에 대신에 인수로 sys.stdout.flush()할 수 있습니다 . flush=Trueprint
matsjoyce

@ matsjoyce 감사합니다, 나는 그것을 몰랐습니다. 나중에 리포지토리 버전을 편집하겠습니다.
Zgarb

2

익스플로러, Python 3

활성화 전략 :

모든 노드의 상태 (활성 / 비활성 / 브로큰)를 기반으로 히트 맵을 생성하고 해당 노드를 선택할 경우 1 인당 예상 최대 히트 맵 값을 갖는 노드를 선택합니다.

파괴 전략 :

봇에게 큰 도움이되지 않는 것을 파괴하지 마십시오.

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

성가심, 배쉬

#!/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

결과가 더 재미있어 보이도록 노력했습니다.

로 실행하십시오 bash annoyance.sh.


1
봇은 모든 입력을 STDERR에 인쇄합니다. 금지되어 있지 않으며 성가신 것입니다.
Zgarb

@Zgarb 죄송합니다. 잘못된 버전을 붙여 넣었습니다. 결정된.
jimmy23013

1

중년 남자

일부 봇은 상단에서, 일부는 하단에서 빌드되는 것을 보았습니다. 이것은 중간에서 시작하여 위아래로 작동하는 첫 번째 것입니다.

(컨트롤러로 테스트되지 않았으므로 용량이 작동하지 않으면 알려주십시오.)

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

제출해 주셔서 감사합니다! 불행히도이 도전은 거의 반년 동안 휴면 상태였으며 언어를 설치할 수있는 컴퓨터에 액세스 할 수 없기 때문에 현재 대부분의 봇을 실행할 수 없습니다.
Zgarb

1
@ Zgarb 이해합니다. 아마 언젠가 나는 합리적인 시간 안에 도전에 대답 할 것이다 ...
MegaTom
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.