КОТ: Хит и Потоплен

12

Вступление

Для моего 5-го КОТЯ я представляю вам вызов, основанный на известной игре « Морской бой» с несколькими поворотами. Вы будете командовать только одним кораблем, чей тип вы сможете выбрать между 5 «традиционными» классами, но вы сможете выполнять несколько действий каждый ход, включая перемещение! Это играется как FFA (Free For All), и вашей целью будет стать последним стоящим кораблем.

Принцип

Игра пошаговая. В начале игры вам нужно будет выбрать класс своего корабля. Затем каждый ход игроки смогут выполнять несколько действий в зависимости от своего корабля.

Действие игры происходит на двумерной сетке (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]
Умение : 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

Здесь 1-й раунд, вы - игрок 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 выстрел). Должны быть затем целенаправленные ячейки в этом формате ([+ -] Х [+ -]) Y / пример: F+2-3)
N: Место 1 шахта в клетку , примыкающей к вашему кораблю (потребляют все выстрелы и 1 мину). Должно быть затем целенаправленными ячейками в этом формате ([+ -] Х [+ -]) 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

копи

Мины срабатывают, когда корабль движется к клетке, занятой миной, или когда по мине стреляют. Мины не могут быть запущены с действием "Ram".

Мины наносят AOE-урон (1 урон по дальности) всем, даже человеку, который установил мины. Мины могут вызвать «цепные» взрывы, если в радиусе взрыва находится другая мина.

Повороты

Вращения - это центральные симметрии, центрированные на «голове» корабля. Вращения будут приводить в действие мины, только если они находятся в «месте назначения» (вы не будете запускать мины по дуге.

Область эффекта

1 урон от дальнего удара (для мин и выстрелов Перевозчика) определяется квадратом 3х3 (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. Точка входа в основной метод класса Game. Java 8 требуется.

Чтобы добавить ботов, сначала вам потребуется либо скомпилированная версия для Java (файлы .class), либо исходные тексты для интерпретируемых языков. Поместите их в корневую папку проекта. Затем создайте новый класс Java в пакете игроков (вы можете взять пример с уже существующими ботами). Этот класс должен реализовывать Player для переопределения метода String getCmd (). Возвращаемая строка - это команда оболочки для запуска ваших ботов. Например, вы можете заставить бот 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.

Thrax
источник
Интересно, что у меня есть несколько вопросов: можем ли мы написать несколько заявок (например, по одному для каждого типа корабля)? Когда вы говорите об AoE, это квадрат вокруг позиции вправо (он попадает в [x + 1; y + 1])?
Катенькио,
@ 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]
Аорта
Итак, подводная лодка автоматически всплывает на поверхность? на каком повороте?
Разрушаемый Лимон
также ходы принимаются одновременно?
лимон
также, что полезно в способности оперативной памяти? (почему бы просто не выстрелить?)
Разрушаемый лимон

Ответы:

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

}
Thrax
источник
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
Juin
источник
1
«Миротворец стреляет». Вы потеряли меня там.
Okx