КОТА: Вдар і затонув


12

Вступ

Для своєї 5-ї КОТІ я представляю вам виклик, заснований на відомій грі Battleship з кількома поворотами. Ви будете командувати лише одним кораблем, тип якого ви зможете вибирати між 5 «традиційними» класами, але ви зможете здійснювати кілька дій на кожному кроці, включаючи переміщення! Це грається як FFA (безкоштовно для всіх), і ваша мета буде стати останнім судном, що стоїть.

Принцип

Гра покрокова. На початку гри вам доведеться вибрати клас свого корабля. Після кожного повороту гравці зможуть виконати кілька дій залежно від свого корабля.

Гра відбувається по 2D сітці (X, Y), сторона якої визначена так:
X = 30 + numberOfPlayer
Y = 30 + numberOfPlayer
Вихідне положення кожного корабля є випадковим.

Порядок гри на рандомізованому етапі кожного кроку, і ви не дізнаєтесь ні своєї позиції в "черзі", ні кількості гравців. Гра триває 100 оборотів або поки залишився живий лише один корабель.

Кожен раз, коли ви потрапите на корабель противника або потрапите в нього, ви заробляєте або втрачаєте очки. Виграє гравець з найвищим балом. Переможцю буде присвоєно виграш (вартість залежить від кількості учасників).

Контролер надає вам введення через аргументи команд, і ваша програма повинна виводити через stdout.

Синтаксис

Перша черга

Ваша програма буде викликана один раз без жодних аргументів. Вам потрібно буде витіснити ціле число від 1 до 5 (включно), щоб вибрати свій корабель:

1: Destroyer [довжина: 2, хід / поворот: 3, постріли / поворот: 1, дальність дії: 9, міни: 4]
Майстерність : вільні обертання суден (без зависання)

2: Підводний човен [довжина: 3, ходи / повороти: 2, постріли / повороти: 1, дальність дії: 5, міни: 4]
Майстерність : Може поривати / повертати (див. Виходи). Перебуваючи під водою, ви можете використовувати лише дії "Рух" і їх можна побачити лише при скануванні. Ви не можете потрапити в постріл, але можете завдати шкоди від мін.

3: Крейсер [довжина: 3, ходи / повороти: 1, постріли / повороти: 2, дальність дії: 9, міни: 2]
Майстерність : Може відремонтувати (див. Виходи)

4: Бортовий корабель [довжина: 4, хід / поворот: 1, постріли / повороти: 3, дальність дії: 7, міни: 1]
Майстерність : Can Shield (див. Виходи)

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

Ось, це перший раунд, ви гравець 8.
Ваш корабель розміщений на (X = 1, Y = 12), а ваш напрямок у напрямку до верху (0 = верх, 1 = праворуч, 2 = знизу, 3 = ліворуч ).
Ваш корпус не пошкоджений (ваш корабель має довжину 3, і кожен біт справжній [1 = ОК, 0 = Пошкоджений]). Ви можете рухатись 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 комірку.

Ігровий процес

Сітка

Ось приклад сітки (33 х 13), де розміщуються 3 гравці:

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

Як ми бачимо, Mпоруч із гравцем 1 також є шахта .

Візьмемо гравця 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 отримує із скануванням та без нього (перерваються рядки для кращого розуміння, але не надсилаються гравцям):

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

Шахти

Міни спрацьовують, коли судно рухається до осередку, зайнятого шахтою, або коли в шахту наноситься постріл. Міни не можуть бути спровоковані дією "Баран".

Шахти завдають шкоди AOE (1 збиток від сплеску) кожному, навіть людині, яка розмістила шахту. Міни можуть викликати "ланцюгові" вибухи, якщо інша шахта знаходиться в радіусі вибуху.

Обертання

Обертання - це центральні симетрії, орієнтовані на «голову» корабля. Обертання запускають міну лише в тому випадку, якщо вона розміщена в "місці призначення" (ви не будете запускати міни в дузі.

Область дії

1 дальність ураження від вибуху (для мін та пострілів Перевозчика) визначається квадратом 3x3 (9 комірок), орієнтованим на початковий постріл / вибух (x, y). Він потрапляє на ці координати:[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кількість ударів по ворожному кораблю, або вибухом Рами, Пострілу або Міни (1 удар ураженої корабельної осередки пошкоджено, включаючи ланцюгові вибухи)
sunken: кількість "останнього удару" по ворожему кораблю, яке спричинило його затоплення
damage: кількість отримані удари (не зменшуються за допомогою "Ремонту", але запобігають "Щит")
alive: перевіряє, чи ваш корабель живий в кінці (принаймні 1 клітина корпусу непошкоджена)

Контролер

Ви можете знайти контролер на GitHub . Він також містить два зразки, написані на Java. Щоб запустити його, перегляньте проект та відкрийте його у вашій Java IDE. Точка входу в основний метод класу Гра. Потрібна Java 8.

Щоб додати ботів, спочатку вам потрібна або компільована версія для Java (файли .class), або джерела для інтерпретованих мов. Розмістіть їх у кореневій папці проекту. Потім створіть новий клас Java в пакеті гравців (ви можете взяти приклад для вже наявних ботів). Цей клас повинен реалізувати програвач Player, щоб замінити метод String getCmd (). Рядок, що повернувся - це команда оболонки для запуску ваших ботів. Наприклад, ви можете змусити роботу бота Ruby за допомогою цієї команди: повернути "C: \ Ruby \ bin \ ruby.exe MyBot.rb" ;. Нарешті, додайте бота в масив гравців у верхній частині Ігрового класу.

Правила

  • Ботів не слід писати, щоб бити або підтримувати конкретних інших ботів.
  • Запис у файли дозволяється. Будь ласка, напишіть на "tvojeubmissionname.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

Отже, чи підводний човен автоматично повертається? на якому повороті?
Руйнуючий лимон

також повороти приймаються одночасно?
Руйнуючий лимон

також, що корисне у здатності барана? (чому б просто не стріляти?)
Руйнуючий лимон

Відповіді:


3

RandomBot

Це приклад бота. Він вибирає корабель, дію та цільову клітинку (за потреби) випадковим чином.

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

}

PassiveBot

Це приклад бота. Це нічого не робить.

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.