KOTH: Hit and Sunk

12

pengantar

Untuk KOTH ke-5 saya, saya mempersembahkan sebuah tantangan berdasarkan game Battleship yang terkenal dengan beberapa putaran. Anda hanya akan memerintahkan satu kapal, yang tipenya Anda dapat memilih antara 5 kelas "tradisional", tetapi Anda akan dapat melakukan beberapa tindakan setiap belokan, termasuk bergerak! Ini dimainkan sebagai FFA (Gratis Untuk Semua) dan tujuan Anda adalah menjadi yang terakhir berdiri.

Prinsip

Permainan ini berbasis giliran. Di awal permainan, Anda harus memilih kelas kapal Anda. Kemudian setiap belokan, pemain akan dapat melakukan beberapa aksi tergantung pada kapalnya.

Permainan berlangsung di kisi 2D (X, Y) yang sisi-sisinya ditentukan dengan cara ini:
X = 30 + numberOfPlayer
Y = 30 + numberOfPlayer
Posisi awal setiap kapal adalah acak.

Urutan main diacak setiap belokan, dan Anda tidak akan tahu posisi Anda di "antrian" atau jumlah pemain. Permainan ini berlangsung selama 100 putaran atau sampai hanya ada satu kapal yang masih hidup.

Setiap kali Anda menabrak kapal musuh atau tertabrak, Anda akan mendapatkan atau kehilangan poin. Pemain dengan skor tertinggi menang. Hadiah akan diberikan kepada pemenang (nilainya tergantung pada jumlah peserta).

Kontroler memberi Anda input melalui argumen perintah, dan program Anda harus melakukan output melalui stdout.

Sintaksis

Belokan pertama

Program Anda akan dipanggil sekali tanpa argumen. Anda harus mengeluarkan bilangan bulat antara 1 dan 5 (inklusif) untuk memilih kapal Anda:

1: Penghancur [panjang: 2, gerakan / putaran: 3, tembakan / putaran: 1, kisaran: 9, ranjau: 4]
Keterampilan : Rotasi kapal gratis (tanpa cooldown)

2: Kapal selam [panjang: 3, bergerak / belok: 2, tembakan / belok: 1, kisaran: 5, ranjau: 4]
Keterampilan : Bisa Terjun / Permukaan (lihat output). Saat berada di bawah air, Anda hanya dapat menggunakan tindakan "Gerakan" dan hanya dapat dilihat dengan pemindaian. Anda tidak dapat terkena tembakan, tetapi dapat mengambil kerusakan dari ranjau.

3: Cruiser [panjang: 3, bergerak / belok: 1, tembakan / belok: 2, kisaran: 9, ranjau: 2]
Keterampilan : Dapat Memperbaiki (lihat keluaran)

4: Battleship [panjang: 4, gerakan / putaran: 1, tembakan / putaran: 3, kisaran: 7, ranjau: 1]
Keterampilan : Can Shield (lihat output)

5: Pengangkut [panjang: 5, gerakan / putaran: 1, tembakan / putaran: 1, kisaran: 7, ranjau: 3]
Keterampilan : Tembakan menangani kerusakan AOE (Area Efek) ke target (kerusakan kerusakan 1 jarak). Jika target memukul dengan tembakan, hingga 2 sel-sel ini kapal juga akan rusak.

Ternyata

Memasukkan

Setiap kali program Anda dipanggil, ia akan menerima argumen dalam format ini:

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

Babak 1-diindeks.

Contoh input

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

Di sini, ini ronde 1, Anda pemain 8.
Kapal Anda diposisikan di (X = 1, Y = 12) dan arah Anda mengarah ke atas (0 = Atas, 1 = Kanan, 2 = Bawah, 3 = Kiri ).
Lambung Anda tidak rusak (kapal Anda memiliki panjang 3, dan setiap bit benar [1 = OK, 0 = Rusak]). Anda dapat bergerak 1 kali, menembak 2 kali, memiliki 2 ranjau tersisa dan "skill" Anda tersedia (cooldown = 0).
Anda tidak menabrak apa pun, juga tidak menenggelamkan kapal apa pun dan Anda tidak tertabrak juga.
Anda tidak berada di bawah air, pelindung Anda (jika ada) tidak diaktifkan dan pemindaian Anda juga tidak.
Lebih banyak di peta nanti ...

Keluaran

Anda harus mengeluarkan String yang menjelaskan tindakan apa yang akan Anda lakukan pada giliran ini. Urutan karakter dalam String output Anda akan menentukan urutan tindakan. Anda dapat menampilkan tindakan yang sama beberapa kali jika tidak melebihi batas kapal Anda. Jika satu atau beberapa tindakan tidak valid, masing-masing akan secara terpisah dianggap sebagai W. Berikut daftar tindakan yang tersedia:

M: Pindahkan 1 sel ke arah yang Anda hadapi (konsumsi 1 gerakan)
B: Kembali 1 sel dari arah yang Anda hadapi (konsumsi 1 gerakan)
C: Putar kapal Anda searah jarum jam (konsumsi 1 gerakan / gratis untuk Destroyer)
K: Putar kapal Anda berlawanan arah jarum jam (konsumsi 1 gerakan / gratis untuk Destroyer)
A: Ram kapal Anda ke arah yang Anda hadapi (hanya bekerja jika kapal lain menempati sel ke arah yang Anda hadapi / tidak memindahkan kapal Anda / konsumsi semua gerakan)
F: Menembak 1 tembakan ke sel dalam jangkauan (mengonsumsi 1 tembakan). Harus diikuti oleh sel ditargetkan dalam format ini ([+ -] X [+ -]) Y / Contoh: F+2-3)
N: Tempat 1 tambang ke sel yang berdekatan untuk kapal Anda (mengkonsumsi semua tembakan dan 1 saya). Harus diikuti oleh sel yang ditargetkan dalam format ini ([+ -] X [+ -]) Y / contoh N+0+1:)
S: Aktifkan pemindaian Anda untuk belokan berikutnya (konsumsi semua tembakan)
R: Perbaiki lambung yang rusak paling dekat dengan "kepala" kapal Anda (konsumsi semua tembakan, cooldown = 3 belokan / Cruiser saja)
P: Terjun / Permukaan (konsumsi semua tembakan, cooldown = 3 belokan, durasi maks = 5 belokan / Submarine saja)
D: Aktifkan perisai Anda untuk mencegah kerusakan berikutnya pada belokan berikutnya (konsumsi semua tembakan, cooldown = 3 / Kapal perang saja)
W: Tunggu (tidak melakukan apa-apa)

Klarifikasi : "Mengkonsumsi semua gerakan / tembakan" berarti Anda hanya dapat menggunakan tindakan ini jika Anda belum pernah menggunakan gerakan / tembakan apa pun sebelumnya selama giliran ini.

Contoh output

MF+9-8CM : Memindahkan 1 sel, lalu menembakkan sel yang posisinya relatif ke "kepala" kapal Anda (targetX = X + 9, targetY = Y - 8), berputar searah jarum jam dan akhirnya memindahkan 1 sel lagi.

Gameplay

Grid

Berikut ini contoh kotak (33 x 13) tempat 3 pemain ditempatkan:

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

Seperti yang bisa kita lihat, ada juga Tambang Mtepat di sebelah pemain 1.

Mari kita ambil pemain 2 untuk memahami posisi dan arah:

Posisi pemain 2 adalah X = 3, Y = 4, Arah = 3. Karena arahnya adalah "Bawah", sisa "sel kapal" -nya diposisikan "di atas" kepalanya "(X = 3, Y = 3) & (X = 3, Y = 2)

Peta pemain

Argumen terakhir yang diterima masing-masing pemain adalah peta "milik mereka". Secara default, sebuah kapal mendeteksi semuanya dalam kisaran 5 sel , tetapi dapat mengaktifkan Pemindaian untuk meningkatkan kisaran ini menjadi 9 .

Argumen selalu sepanjang 361 (19 x 19) karakter. Ini mewakili kotak yang berpusat di sekitar "kepala" kapal Anda, di mana setiap karakter sesuai dengan elemen yang didefinisikan dengan cara ini:

.: Sel kosong
O: Kapal Anda
M: Tambang
X: Dinding (sel di luar peta)
U: Tidak dikenal (akan diungkapkan oleh pemindaian)
A: Musuh mengirimkan sel yang tidak rusak
B: Musuh mengirimkan sel yang rusak
C: Musuh mengirimkan sel yang tidak rusak di bawah air (hanya terlihat dengan pemindaian)
D: Musuh mengirim sel yang rusak di bawah air (hanya terlihat dengan pemindaian)
W: Wreckage (dead ship)

String ini terdiri dari 19 karakter dari baris pertama, diikuti oleh 19 karakter dari baris kedua ... hingga baris ke-19.

Mari kita lihat apa yang diterima pemain 2 dengan dan tanpa pemindaian (jeda baris untuk pemahaman yang lebih baik, tetapi tidak mengirim ke pemain):

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

Tambang

Tambang dipicu ketika sebuah kapal bergerak ke sel yang ditempati oleh tambang atau ketika tembakan ditembakkan ke tambang. Tambang tidak dapat dipicu dengan aksi "Ram".

Tambang menangani kerusakan AOE (kerusakan 1 tingkat percikan) untuk semua orang, bahkan untuk orang yang menempatkan tambang. Tambang dapat memicu "rantai" ledakan jika tambang lain berada dalam radius ledakan.

Rotasi

Rotasi adalah simetri sentral yang berpusat pada "kepala" kapal. Rotasi hanya akan memicu tambang jika ditempatkan pada "posisi tujuan" (Anda tidak akan memicu ranjau di busur.

Area efek

Kerusakan splash 1 kisaran (untuk ranjau dan tembakan Carrier) ditentukan oleh kotak 3x3 (9 sel) yang berpusat pada tembakan / ledakan awal (x, y). Itu mengenai koordinat tersebut:[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]

Mencetak gol

Skor ditentukan oleh rumus ini:
Score = Hits + (Sunken x 5) - Damage taken - (Alive ? 0 : 10)

dimana::
hitsjumlah hit pada kapal musuh, baik oleh Ram, Shot atau ledakan Mine (1 hit oleh sel kapal musuh rusak, termasuk ledakan rantai)
sunken: jumlah "hit terakhir" pada kapal musuh yang menyebabkannya tenggelam
damage: jumlah hit diterima (tidak dikurangi oleh Perbaikan, tetapi dicegah oleh Shield)
alive: memeriksa apakah kapal Anda masih hidup di akhir (setidaknya 1 sel hull tidak rusak)

Pengendali

Anda dapat menemukan pengontrol di GitHub . Ini juga mengandung dua samplebot, ditulis dalam Java. Untuk membuatnya berjalan, periksa proyek dan buka di Java IDE Anda. Titik masuk dalam metode utama Game kelas. Diperlukan Java 8.

Untuk menambahkan bot, pertama-tama Anda perlu versi kompilasi untuk Java (file .class) atau sumber untuk bahasa yang ditafsirkan. Tempatkan mereka di folder root proyek. Kemudian, buat kelas Java baru dalam paket pemain (Anda dapat mengambil contoh pada bot yang sudah ada). Kelas ini harus mengimplementasikan Player untuk mengganti metode String getCmd (). String yang dikembalikan adalah perintah shell untuk menjalankan bot Anda. Misalnya Anda dapat membuat bot Ruby berfungsi dengan perintah ini: mengembalikan "C: \ Ruby \ bin \ ruby.exe MyBot.rb" ;. Terakhir, tambahkan bot di larik pemain di bagian atas kelas Game.

Aturan

  • Bot tidak boleh ditulis untuk mengalahkan atau mendukung bot tertentu lainnya.
  • Menulis ke file diperbolehkan. Silakan menulis ke "milikmu pengirimanmu.txt", folder akan dikosongkan sebelum permainan dimulai. Sumber daya eksternal lainnya tidak diizinkan.
  • Kiriman Anda memiliki 1 detik untuk merespons.
  • Berikan perintah untuk mengkompilasi dan menjalankan kiriman Anda.
  • Anda dapat menulis banyak pengiriman

Bahasa yang didukung

Saya akan mencoba dan mendukung setiap bahasa, tetapi harus tersedia online secara gratis. Harap berikan instruksi untuk pemasangan jika Anda tidak menggunakan bahasa "arus utama".

Sampai sekarang, saya dapat menjalankan: Java 6-7-8, PHP, Ruby, Perl, Python 2-3, Lua, R, node.js, Haskell, Kotlin, C ++ 11.

Thrax
sumber
KotH yang menarik, saya hanya punya beberapa pertanyaan: bisakah kita menulis banyak pengiriman (satu untuk setiap jenis kapal misalnya)? Ketika Anda berbicara tentang AoE, itu adalah bujur sangkar di sekitar posisi yang benar (itu mengenai [x +1; y +1])?
Katenkyo
@Katenkyo Ya, Anda dapat menulis beberapa pengiriman. Ya, hits 9 sel:[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
Jadi, apakah kapal selam itu muncul secara otomatis? di belokan mana?
Lemon Destructible
juga belokan diambil secara bersamaan?
Destructible Lemon
juga apa yang berguna tentang kemampuan ram? (mengapa tidak menembak saja?)
Destructible Lemon

Jawaban:

3

RandomBot

Ini adalah contoh bot. Ia memilih kapal, aksi, dan sel target (jika perlu) secara acak.

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

Ini adalah contoh bot. Tidak melakukan apa-apa.

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
sumber
3

PeaceMaker, Python 2 (Battleship)

PeaceMaker menembak 3 kali pada musuh terdekat (jarak spiral) dan bergerak bolak-balik dalam satu baris sementara tinggal setidaknya 2 sel dari tambang.

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
sumber
1
'PeaceMaker shoots'. Anda kehilangan saya di sana.
Okx