KOTH : 명중 및 침몰


12

소개

제 5 회 KOTH에서는 잘 알려진 게임 Battleship 을 기반으로 도전 과제를 제시합니다 . 5 개의 "전통"클래스 중에서 선택할 수있는 우주선 하나만 지휘 할 수 있지만, 매 차례마다 이동을 포함하여 여러 가지 행동을 취할 수 있습니다! 이것은 FFA (Free For All)로 플레이되며 목표는 마지막 배입니다.

원리

게임은 턴제입니다. 게임을 시작할 때 배의 클래스를 선택해야합니다. 그런 다음 매 턴마다 플레이어는 배에 따라 몇 가지 행동을 수행 할 수 있습니다.

게임은 측면이 다음과 같이 정의 된 2D 그리드 (X, Y)에서 발생
X = 30 + numberOfPlayer
Y = 30 + numberOfPlayer
합니다. 각 선박의 시작 위치는 무작위입니다.

플레이 순서는 매 차례 무작위로 지정되며 "대기열"에서의 위치 나 플레이어 수를 알 수 없습니다. 게임은 100 턴 동안 또는 한 배만 살아남을 때까지 지속됩니다 .

적의 함선에 부딪 히거나 맞을 때마다 점수를 얻거나 잃습니다. 가장 높은 점수를받은 플레이어가 승리합니다. 현상금이 수상자에게 수여됩니다 (참가자 수에 따른 가치).

컨트롤러는 명령 인수를 통한 입력을 제공하며 프로그램은 stdout을 통해 출력해야합니다.

통사론

첫번째 차례

당신의 프로그램은 논쟁없이 한 번 불려질 것 입니다 선박을 선택하려면 1에서 5 사이의 정수를 입력해야합니다.

1: 구축함 [길이 : 2, 이동 / 회전 : 3, 샷 / 턴 : 1, 범위 : 9, 지뢰 : 4]
스킬 : 자유 배 회전 (쿨 타임 없음)

2: 잠수함 [길이 : 3, 이동 / 턴 : 2, 샷 / 턴 : 1, 범위 : 5, 광산 : 4]
기술 : 뛰어들 수 / 표면 (출력 참조). 수중에서는 "이동"작업 만 사용할 수 있으며 스캔으로 만 볼 수 있습니다. 한방에 맞을 수는 없지만 광산에서 피해를 입을 수 있습니다.

3: 크루저 [길이 : 3, 이동 / 회전 : 1, 샷 / 턴 : 2, 범위 : 9, 광산 : 2]
기술 : 수리 가능 (출력 참조)

4: 전함 [길이 : 4, 이동 / 턴 : 1, 샷 / 턴 : 3, 범위 : 7, 광산 : 1]
기술 : 방패 막기 (출력 참조)

5: 캐리어 [길이 : 5, 이동 / 턴 : 1, 샷 / 턴 : 1, 범위 : 7, 지뢰 : 3]
스킬 : 샷은 대상에게 AOE (효과 영역) 피해를 입 힙니다 (1 범위 스플래시 피해). 목표물에 명중하면 함선 의 최대 2 개의 세포 도 손상됩니다.

회전

입력

프로그램이 호출 될 때마다 다음 형식으로 인수를받습니다.

Round;YourPlayerId;X,Y,Direction;Hull;Moves,Shots,Mines,Cooldown;Hits,Sunken,Damage;Underwater,Shield,Scan;Map

라운드는 1 인덱스입니다.

입력 예

1;8;1,12,0;111;1,2,2,0;0,0,0;0,0,0;UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.O.....UUUUUUUUXXXX.O.....UUUUUUUUXXXX.O.....UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU

여기는 1 라운드입니다. 플레이어는 8입니다.
당신의 함선은 (X = 1, Y = 12)에 위치하고 방향은 상단 (0 = 위, 1 = 오른쪽, 2 = 아래쪽, 3 = 왼쪽)입니다 ).
선체는 손상되지 않습니다 (선박의 길이는 3이며 각 비트는 참입니다 [1 = OK, 0 = Damaged]). 당신은 1 번 움직일 수 있고, 2 번 쏘고, 2 개의 지뢰가 남아 있고 "스킬"이 가능합니다 (쿨 타임 = 0).
당신은 아무것도 쳤거나, 배를 가라 앉 히지 않았으며, 타격도받지 않았습니다.
수중에 있지 않고 방패 (있는 경우)가 활성화되지 않았으며 스캔도 수행되지 않았습니다.
나중에지도에서 더보기 ...

산출

이번 턴에 어떤 행동을할지 설명하는 문자열을 출력해야합니다. 출력 문자열의 문자 순서에 따라 동작 순서가 정의됩니다. 선박 한도를 초과하지 않으면 동일한 작업을 여러 번 출력 할 수 있습니다. 하나 이상의 작업이 유효하지 않은 경우 각 작업은 개별적으로로 간주됩니다 W. 사용 가능한 작업 목록은 다음과 같습니다.

M: 당신이 향하고있는 방향으로 1 셀 이동 (1 이동 이동)
B: 당신이 향하고있는 방향에서 1 셀 뒤로 이동 (1 이동 이동)
C: 배를 시계 방향으로 회전 (파괴자를 위해 1 이동 / 자유 소비)
K: 선박 회전 시계 반대 방향 (소멸자를 위해 1 회 이동 / 자유 소비)
A: 당신이 향하고있는 방향으로 당신의 함선을 램핑하십시오 (다른 함선이 당신이 향하고있는 방향으로 셀을 점유하고 있거나 / 이동하지 않거나 모든 이동을 소비하지 않는 경우에만 작동합니다)
F범위 내 셀에 1 발 사격 (1 발 사격). 이 포맷으로 타겟팅 된 세포에 의해 (- X [+ -] [+]) 따라야 Y / 예 : F+2-3)
N: 우주선 장소에 인접하는 셀 (1) 내 () 모든 샷 1 개 광산을 소비한다. 이 포맷으로 타겟팅 된 세포 와야 ([+ -] X [+ -]) Y / 예 : N+0+1)
S: 다음 턴을위한 스캔 활성화 (모든 샷 소비)
R: 선박의 "헤드"에 가장 가까운 손상된 선체 수리 (모든 샷 소비, 쿨 다운 = 3 턴 / 크루저 만 해당)
P: 플 런지 / 표면 (모든 샷 소비, 쿨 다운 = 3 턴, 최대 지속 시간 = 5 턴 / 잠수함 만 해당
D: 다음 턴 동안 다음 피해를 막기 위해 방패를 활성화하십시오 (모든 샷을 소비하고 쿨 다운 = 3 / 전함 만 해당)
W: 대기 (아무것도하지 않음)

설명 : "모든 움직임 / 샷 소비"는이 턴 동안 이전에 움직임 / 샷을 사용하지 않은 경우에만이 조치를 사용할 수 있음을 의미합니다.

출력 예

MF+9-8CM : 1 셀 이동 한 다음, 선박의 "헤드"에 대한 상대 위치가 (targetX = X + 9, targetY = Y-8) 인 셀에서 발사되고 시계 방향으로 돌아가 마지막으로 1 셀이 다시 이동합니다.

게임 플레이

그리드

다음은 3 명의 플레이어가 배치 된 그리드 (33 x 13)의 예입니다.

███████████████████████████████████
█                                 █
█       00                        █
█   2                             █
█   2                             █
█   2                             █
█                                 █
█       11111                     █
█        M                        █
█                                 █
█                                 █
█                                 █
█                                 █
█                                 █
███████████████████████████████████

우리가 볼 수 있듯이, M플레이어 1 옆에 광산도 있습니다 .

위치 2와 방향을 이해하기 위해 플레이어 2를 보자.

플레이어 2의 위치는 X = 3, Y = 4, 방향 = 3입니다. 방향이 "하단"이므로 나머지 "선박 셀"은 "헤드"(X = 3, Y = 3) 위에 있습니다. & (X = 3, Y = 2)

선수의지도

각 플레이어가받는 마지막 주장은 "자신의"맵입니다. 기본적으로 선박은 5 셀 범위의 모든 항목을 감지 하지만 스캔 을 활성화 하여이 범위를 9 로 늘릴 수 있습니다 .

인수는 항상 361 자 (19 x 19) 자입니다. 배의 "머리"를 중심으로 사각형을 나타냅니다. 각 문자는 다음과 같이 정의 된 요소에 해당합니다.

.: 빈 세포
O: 당신의 배
M: 광산
X: 벽 (지도에서 세포)
U: 알 수 없음 (스캔으로 표시)
A: 적의 선박 손상되지 않은 세포
B: 적의 선박 손상된 세포
C: 적의 수중 손상되지 않은 세포 (검사로 만 볼 수 있음)
D: 적의 수중 손상된 세포 (스캔 만 볼 수 있음)
W: 잔해 (죽은 배)

문자열은 첫 번째 줄의 19 자, 두 번째 줄의 19 문자로 구성됩니다 ... 19 번째 줄까지.

스캔 2의 유무에 관계없이 플레이어 2가받는 것을 살펴볼 수 있습니다 (더 나은 이해를 위해 줄 바꿈하지만 플레이어에게 보내지는 않음).

XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXX.............
XXXXXX.......AA....
XXXXXX...O.........
XXXXXX...O.........
XXXXXX...O.........
XXXXXX.............
XXXXXX.......AAAAA.
XXXXXX........M....
XXXXXX.............
XXXXXX.............
XXXXXX.............
XXXXXX.............
XXXXXX.............
XXXXXXXXXXXXXXXXXXX

UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUXXXXXXXXXXXUUUU
UUUUXX.........UUUU
UUUUXX.......AAUUUU
UUUUXX...O.....UUUU
UUUUXX...O.....UUUU
UUUUXX...O.....UUUU
UUUUXX.........UUUU
UUUUXX.......AAUUUU
UUUUXX........MUUUU
UUUUXX.........UUUU
UUUUXX.........UUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU

광산

광산은 배가 광산에 의해 점유 된 셀로 이동할 때 또는 광산에서 총성이 발사 될 때 트리거됩니다. "Ram"조치로 광산을 트리거 할 수 없습니다.

광산은 모든 사람에게, 심지어 광산을 배치 한 사람에게도 AOE 피해 (1 범위의 스플래시 피해)를줍니다. 다른 광산이 폭발 반경에 있으면 광산은 "사슬"폭발을 일으킬 수 있습니다.

회전

회전은 선박의 "헤드"를 중심으로하는 중앙 대칭입니다. 회전은 "목적지 위치"에 배치 된 경우에만 광산을 트리거합니다 (아크에서 광산을 트리거하지 않음).

효과 영역

1 범위 스플래시 데미지 (광산 및 캐리어 샷)는 초기 샷 / 폭발 (x, y)을 중심으로 3x3 (9 셀) 정사각형으로 정의됩니다. 그것은 그 좌표를 명중합니다 :[x - 1; y - 1],[x - 1; y],[x - 1; y + 1],[x; y - 1],[x; y],[x; y + 1],[x + 1; y - 1],[x + 1; y],[x + 1; y + 1]

채점

점수는 다음 공식으로 정의됩니다.
Score = Hits + (Sunken x 5) - Damage taken - (Alive ? 0 : 10)

여기서 :
hits: Ram, Shot 또는 Mine 폭발에 의한 적 선박의 적중 횟수 (연쇄 폭발을 포함하여 적의 적군 세포에 의해 발생한 적중
sunken횟수 ) : 적 선박의 "최종 적중"
damage횟수 적중 횟수 (수리로 감소되지 않지만 쉴드로 방지 됨)
alive: 선박이 마지막에 살아 있는지 확인합니다 (최소한 1 개의 선체 세포가 손상되지 않음)

제어 장치

컨트롤러는 GitHub 에서 찾을 수 있습니다 . 또한 Java로 작성된 두 개의 샘플 봇이 포함되어 있습니다. 실행하려면 프로젝트를 확인하고 Java IDE에서 엽니 다. Game 클래스의 주요 메소드의 진입 점입니다. Java 8이 필요합니다.

봇을 추가하려면 먼저 컴파일 된 Java 버전 (.class 파일) 또는 해석 된 언어의 소스가 필요합니다. 프로젝트의 루트 폴더에 배치하십시오. 그런 다음 플레이어 패키지에서 새 Java 클래스를 작성하십시오 (기존 봇에서 예를 들어 볼 수 있음). 이 클래스는 String getCmd () 메소드를 대체하기 위해 Player를 구현해야합니다. 반환 된 문자열은 봇을 실행하기위한 쉘 명령입니다. 예를 들어, 다음 명령으로 Ruby 봇을 작동시킬 수 있습니다. return "C : \ Ruby \ bin \ ruby.exe MyBot.rb";. 마지막으로, Game 클래스 맨 위에있는 플레이어 배열에 봇을 추가하십시오.

규칙

  • 봇은 다른 특정 봇을 이길 수 있도록 작성해서는 안됩니다.
  • 파일 쓰기가 허용됩니다. "yoursubmissionname.txt"에 쓰면 게임이 시작되기 전에 폴더가 비워집니다. 다른 외부 리소스는 허용되지 않습니다.
  • 제출 한 내용에 1 초의 응답 시간이 있습니다.
  • 제출물을 컴파일하고 실행하는 명령을 제공하십시오.
  • 여러 제출물을 작성할 수 있습니다

지원되는 언어

모든 언어를 지원하려고하지만 온라인에서 무료로 사용할 수 있어야합니다. "주류"언어를 사용하지 않는 경우 설치 지침을 제공하십시오.

현재 Java 6-7-8, PHP, Ruby, Perl, Python 2-3, Lua, R, node.js, Haskell, Kotlin, C ++ 11을 실행할 수 있습니다.


흥미로운 KotH, 나는 몇 가지 질문이 있습니다 : 우리는 여러 제출물을 작성할 수 있습니까 (예를 들어 각 유형의 선박에 대해 하나씩)? AoE에 대해 이야기 할 때 오른쪽 위치 주위에 사각형이 나타납니다 ([x + 1; y + 1]에 해당)?
Katenkyo

@Katenkyo 예, 여러 개의 제출물을 작성할 수 있습니다. 그렇습니다, 그것은 9 개의 세포를 명중합니다 :[x - 1; y - 1],[x - 1; y],[x - 1; y + 1],[x; y - 1],[x; y],[x; y + 1],[x + 1; y - 1],[x + 1; y],[x + 1; y + 1]
Thrax

그러면 잠수함이 자동으로 표면에 나타 납니까? 어느 차례에?
Destructible Lemon

회전도 동시에 이루어 지나요?
Destructible Lemon

또한 램 능력에 유용한 것은 무엇입니까? (왜 쏘지 않겠습니까?)
Destructible Lemon

답변:


3

랜덤 봇

이것은 예제 봇입니다. 배, 액션 및 대상 셀 (필요한 경우)을 임의로 선택합니다.

import java.util.Random;

public class RandomBot {

    int round;
    int playerID;

    public static void main(String[] args) {

        if (args.length == 0) {
            Random random = new Random();
            int ship = random.nextInt(5);
            String[] ships = { "1", "2", "3", "4", "5" };
            System.out.println(ships[ship]);
        } else {
            new RandomBot().play(args[0].split(";"));
        }
    }

    private void play(String[] args) {

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

        String[] actions = { "M", "B", "C", "K", "F", "S", "N", "A" };
        Random random = new Random();
        int action = random.nextInt(8);

        int rangeX = random.nextInt(5);
        int rangeY = random.nextInt(5);
        int mineX = random.nextInt(1);
        int mineY = random.nextInt(1);

        String signX = random.nextInt(1) == 1 ? "+" : "-";
        String signY = random.nextInt(1) == 1 ? "+" : "-";

        System.out.println(actions[action] + (action == 4 ? signX + rangeX + signY + rangeY : "") + (action == 6 ? signX + mineX + signY + mineY : ""));
    }

}

패시브 봇

이것은 예제 봇입니다. 아무것도하지 않습니다.

public class PassiveBot {

    int round;
    int playerID;

    public static void main(String[] args) {

        if (args.length == 0) {
            System.out.println("5");
        } else {
            new PassiveBot().play(args[0].split(";"));
        }
    }

    private void play(String[] args) {

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

        System.out.println("W");
    }

}

3

PeaceMaker, Python 2 (전함)

PeaceMaker는 가장 가까운 적 (나선 거리)을 3 번 쏘고 최소 2 개의 셀을 광산에서 멀리두고 줄을 따라 앞뒤로 움직입니다.

from os import sys

def reversedSpiralOrder(length):

    #Initialize our four indexes
    top = 0
    down = length - 1
    left = 0
    right = length - 1
    result = ""

    while 1:

        # Print top row
        for j in range(left, right + 1):
            result += str(top * length + j) + ";"
        top += 1
        if top > down or left > right:
            break

        # Print the rightmost column
        for i in range(top, down + 1):
            result += str(i * length + right) + ";"
        right -= 1
        if top > down or left > right:
            break

        # Print the bottom row
        for j in range(right, left + 1, -1):
            result += str(down * length + j) + ";"
        down -= 1
        if top > down or left > right:
            break

        # Print the leftmost column
        for i in range(down, top + 1, -1):
            result += str(i * length + left) + ";"
        left += 1
        if top > down or left > right:
            break

    result = result.split(";")
    del result[-1]
    return result[::-1]

def canMove(x, y, direction, hull, map):

    # M = 1, B = 2
    moves = 0

    if direction == 0:
        y1 = -1
        y2 = -2
        hx1 = hx2 = x1 = x2 = 0
        hy1 = -y1 + hull
        hy2 = -y2 + hull
    elif direction == 1:
        x1 = 1
        x2 = 2
        hy1 = hy2 = y1 = y2 = 0
        hx1 = -x1 - hull
        hx2 = -x2 - hull
    elif direction == 2:
        y1 = 1
        y2 = 2
        hx1 = hx2 = x1 = x2 = 0
        hy1 = -y1 - hull
        hy2 = -y2 - hull
    elif direction == 3:
        x1 = -1
        x2 = -2
        hy1 = hy2 = y1 = y2 = 0
        hx1 = -x1 + hull
        hx2 = -x2 + hull

    if map[y + y1][x + x1] == "." and map[y + y2][x + x2] != "M":
        moves += 1

    if map[y + hy1][x + hx1] == "." and map[y + hy2][x + hx2] != "M":
        moves += 2

    return moves

if len(sys.argv) <= 1:
    f = open("PeaceMaker.txt","w")
    f.write("")
    print "4"
else:
    arguments = sys.argv[1].split(";")
    sight = 19

    round = int(arguments[0])
    playerID = int(arguments[1])
    x = int(arguments[2].split(",")[0])
    y = int(arguments[2].split(",")[1])
    direction = int(arguments[2].split(",")[2])
    hull = arguments[3]
    moves = int(arguments[4].split(",")[0])
    shots = int(arguments[4].split(",")[1])
    mines = int(arguments[4].split(",")[2])
    cooldown = int(arguments[4].split(",")[3])
    hits = int(arguments[5].split(",")[0])
    kills = int(arguments[5].split(",")[0])
    taken = int(arguments[5].split(",")[0])
    underwater = int(arguments[6].split(",")[0])
    shield = int(arguments[6].split(",")[1])
    scan = int(arguments[6].split(",")[2])
    map = [[list(arguments[7])[j * sight + i] for i in xrange(sight)] for j in xrange(sight)]

    initialShots = shots


    priorities = reversedSpiralOrder(sight)

    actions = ""
    sighted = 0
    for priority in priorities:
        pX = int(priority) % sight
        pY = int(priority) / sight

        if map[pY][pX] == "A":
            sighted += 1
            if shots > 0:
                shots -= 1
                actions += "F" + ("+" if pX - 9 >= 0 else "") + str(pX - 9)  + ("+" if pY - 9 >= 0 else "") + str(pY - 9)

    if shots == initialShots and sighted > 0:
        actions += "D"
    elif shots == initialShots and sighted <= 0:
        actions += "S"
    else:
        actions += ""

    f = open("PeaceMaker.txt","r")
    fC = f.read(1)
    lastDirection = int("1" if fC == "" else fC)

    y = 9
    x = 9

    if lastDirection == 1:
        if canMove(x, y, direction, len(hull), map) == 1 or canMove(x, y, direction, len(hull), map) == 3:
            actions += "M"
        elif canMove(x, y, direction, len(hull), map) == 2:
            actions += "B"
            lastDirection = 0
    elif lastDirection == 0:
        if canMove(x, y, direction, len(hull), map) == 2 or canMove(x, y, direction, len(hull), map) == 3:
            actions += "B"
        elif canMove(x, y, direction, len(hull), map) == 1:
            actions += "M"
            lastDirection = 1

    f = open("PeaceMaker.txt","w")
    f.write(str(lastDirection))

    print actions

1
'PeaceMaker 촬영'. 넌 날 잃었 어
Okx
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.