KOTH: Vur ve Batır


12

Giriş

5. KOTH'm için, size birkaç bükülme ile tanınmış Battleship oyununa dayanan bir meydan okuma sunuyorum . Sadece 5 "traditionnal" sınıfı arasında seçim yapabileceğiniz bir gemiye komuta edeceksiniz, ancak her turda birden fazla eylem gerçekleştirebileceksiniz. Bu bir FFA (Herkes İçin Ücretsiz) olarak oynanır ve hedefiniz son gemi ayakta olmak olacaktır.

Prensip

Oyun sıra tabanlı. Oyunun başlangıcında, geminizin sınıfını seçmeniz gerekecek. Daha sonra oyuncular her gemiye bağlı olarak birkaç işlem gerçekleştirebilecekler.

Oyun, tarafı şu şekilde tanımlanan bir 2D ızgarada (X, Y) gerçekleşir:
X = 30 + numberOfPlayer
Y = 30 + numberOfPlayer
Her geminin başlangıç ​​pozisyonu rastgele.

Oyun sırası her turda rastgele seçilir ve "sıradaki" pozisyonunuzu veya oyuncu sayısını bilmezsiniz. Oyun 100 tur ya da sadece bir gemi hayatta kalana kadar sürer .

Bir düşman gemisine her vurduğunuzda veya vurduğunuzda puan kazanacak veya kaybedeceksiniz. En yüksek puana sahip oyuncu kazanır. Kazanana bir ödül verilecektir (katılımcı sayısına bağlı olarak değer).

Kontrolör size komut argümanları yoluyla giriş sağlar ve programınızın stdout aracılığıyla çıkış yapması gerekir.

Sözdizimi

İlk Dönüş

Programınız herhangi bir argüman olmadan bir kez çağrılacaktır . Geminizi seçmek için 1 ile 5 (dahil) arasında bir tam sayı çıkarmanız gerekir:

1: Destroyer [uzunluk: 2, hamle / dönüş: 3, çekim / dönüş: 1, aralık: 9, mayın: 4]
Beceri : Ücretsiz gemi rotasyonu (bekleme süresi yok)

2: Denizaltı [uzunluk: 3, hareket / dönüş: 2, atış / dönüş: 1, aralık: 5, mayın: 4]
Beceri : Can Dalma / Yüzey (çıkışlara bakın). Sualtıdayken yalnızca "Hareket" eylemlerini kullanabilirsiniz ve yalnızca tarama ile görülebilir. Bir vuruşla vurulamazsınız, ancak mayınlardan hasar alabilirsiniz.

3: Kruvazör [uzunluk: 3, hareket / dönüş: 1, atış / dönüş: 2, aralık: 9, mayın: 2]
Beceri : Tamir edebilir (çıkışlara bakın)

4: Savaş gemisi [uzunluk: 4, hareket / dönüş: 1, atış / dönüş: 3, aralık: 7, mayın: 1]
Beceri : Kalkan Olabilir (çıkışlara bakın)

5: Taşıyıcı [uzunluk: 5, hareket / dönüş: 1, atış / dönüş: 1, aralık: 7, mayın: 3]
Beceri : Şutlar hedefe (1 aralık sıçrama hasarı) AOE (Etki Alanı) hasarı verir. Hedefe atışla vurulursa, bu geminin en fazla 2 hücresi de hasar görür.

Dönüşler

Giriş

Programınız her çağrıldığında, şu biçimde bağımsız değişkenler alır:

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

Turlar 1 dizinli.

Örnek giriş

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

Burada 1. tur, oyuncu 8'iniz.
Geminiz konumlandırılmış (X = 1, Y = 12) ve yönünüz yukarı doğru (0 = Üst, 1 = Sağ, 2 = Alt, 3 = Sol) ).
Tekneniz hasar görmemiştir (geminizin uzunluğu 3'tür ve her bit doğrudur [1 = Tamam, 0 = Hasarlı]). 1 kez hareket edebilir, 2 kez ateş edebilir, 2 mayın kaldırabilir ve "becerin" kullanılabilir (bekleme süresi = 0).
Hiçbir şeye vurmadınız, gemiyi batırmadınız ve vurulmadınız.
Su altında değilsiniz, kalkanlarınız (varsa) etkinleştirilmemiştir ve taramanız da değildir.
Daha sonra haritada daha fazlası ...

Çıktı

Bu dönüşü gerçekleştireceğiniz işlemleri açıklayan bir Dize çıkarmanız gerekir. Çıktı Dizenizdeki karakterlerin sırası, işlemlerin sırasını tanımlar. Geminizin sınırlarını aşmıyorsa aynı işlemleri birden çok kez gerçekleştirebilirsiniz. Bir veya birden fazla eylem geçersizse, her biri ayrı ayrı olarak değerlendirilir W. Kullanılabilir işlemlerin listesi:

M : 1 hücreyi baktığınız yönde hareket ettirin (1 hareket tüket)
B : 1 hücreyi baktığınız yönden geri (1 hamle tüket)
C: Geminizi saat yönünde döndürün (Muhripler için 1 hamle / serbest
Kbırakın ) : Geminizi döndürün saat yönünün tersine (Muhripler için 1 hamle / serbest) tüketme
A: Geminizi baktığınız yöne çevirin (yalnızca başka bir gemi hücreyi baktığınız yönde işgal ediyorsa / geminizi hareket ettirmiyorsa / tüm hareketleri tüketmiyorsa çalışır)
F: Menzil içindeki bir hücreye 1 atış yapın (1 atış tüketin). Bu biçimde hedeflenen hücre tarafından (X - [+ -] [+]) takip edilmesi gereken E / örnek: F+2-3)
N: yer gemi bitişik bir hücreye 1 madeni () her çekim ve 1 madeni tüketir. Bu biçimde hedeflenen hücre tarafından takip edilmelidir ([+ -] x [+ -]) E / örnek: N+0+1)
S: Taramanızı bir sonraki dönüş için etkinleştirin (tüm atışları tüketin)
R: Hasarlı gövdeyi geminizin "kafasına" en yakın olanı onarın (tüm atışları tüketin, bekleme süresi = sadece 3 dönüş / Kruvazör)
P: Dalma / Yüzey (tüm atışları, bekleme süresi = 3 dönüş, maksimum süre = 5 dönüş / yalnızca Denizaltı)
D: Bir sonraki dönüşünüzde bir sonraki hasarı önlemek için kalkanınızı etkinleştirin (tüm atışları tüket, bekleme süresi = 3 / Yalnızca savaş gemisi)
W: Bekleyin (hiçbir şey yapmaz)

Açıklama : "Tüm hamleleri / atışları tüket", bu eylemi yalnızca bu dönüş sırasında daha önce hamlelerinizi / atışlarınızı kullanmadıysanız kullanabileceğiniz anlamına gelir.

Örnek çıktı

MF+9-8CM : 1 hücreyi hareket ettirir, ardından geminizin "başına" göreceli konumu (targetX = X + 9, targetY = Y - 8) olan hücreye ateş eder, saat yönünde döner ve sonunda 1 hücreyi tekrar hareket ettirir.

Oynanış

Izgara

İşte 3 oyuncunun yerleştirildiği örnek bir tablo (33 x 13):

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

Gördüğümüz gibi M, oyuncunun hemen yanında bir Maden var 1.

Konum 2'yi ve yönü anlamak için 2. oyuncuyu alalım:

Oyuncu 2'nin pozisyonu X = 3, Y = 4, Yön = 3'tür. Yönü "Alt" olduğundan, "gemi hücreleri" nin geri kalanı "kafasının" üzerine "konumlandırılır (X = 3, Y = 3) & (X = 3, Y = 2)

Oyuncunun haritası

Her oyuncunun aldığı son argüman "kendi" haritasıdır. Varsayılan olarak, bir gemi 5 hücre aralığındaki her şeyi algılar , ancak bu aralığı 9'a çıkarmak için bir Taramayı etkinleştirebilir .

Argüman daima 361 (19 x 19) karakter uzunluğundadır. Her karakterin bu şekilde tanımlanan bir öğeye karşılık geldiği, geminizin "başı" etrafında merkezlenmiş kareyi temsil eder:

.: Boş hücre
O: Geminiz
M: Madenler
X: Duvar (harita dışındaki hücreler)
U: Bilinmiyor (tarama ile gösterilecek)
A: Düşman gemisi hasarsız hücre
B: Düşman gemisi hasarlı hücre
C: Düşman gemisi sualtı hasarsız hücre (sadece tarama ile görüldü)
D: Düşman gemisi sualtı hasarlı hücresi (sadece tarama ile görülür)
W: Enkaz (ölü gemi)

Dize, ilk satırın 19 karakterinden, ardından ikinci satırın 19 karakterinden oluşur ... 19. satıra kadar.

2 nolu oyuncunun tarama ile ve tarama olmadan ne aldıklarına bir göz atalım (daha iyi anlaşılması için satır kesilir, ancak oyunculara gönderilmez):

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

Maden

Mayınlar, bir gemi bir mayın tarafından işgal edilen bir hücreye geçtiğinde veya madende bir atış yapıldığında tetiklenir. Mayınlar "Ram" eylemiyle tetiklenemez.

Madenler, madeni yerleştiren kişiye bile herkese AOE hasarı (1 menzil sıçrama hasarı) verir. Patlama yarıçapında başka bir maden varsa mayınlar "zincir" patlamalarını tetikleyebilir.

rotasyonlar

Dönüşler geminin "başı" üzerinde merkezlenmiş merkezi simetrilerdir. Rotasyonlar bir madeni yalnızca "hedef pozisyona" yerleştirilirse tetikleyecektir (mayın bir yayda tetiklemeyeceksiniz).

Etki alanı

1 menzil sıçrama hasarı (mayınlar ve Taşıyıcı atışları için) ilk atış / patlama (x, y) üzerinde ortalanmış 3x3 (9 hücre) kare ile tanımlanır. Bu koordinatlara çarpıyor:[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]

puanlama

Puanlama bu formülle tanımlanır:
Score = Hits + (Sunken x 5) - Damage taken - (Alive ? 0 : 10)

burada:
hitsRam, Shot veya Mine patlaması ile düşman gemisine isabet
sunkensayısı ( zincir patlamaları dahil hasar gören düşman gemisi hücresinden 1 vuruş) : batmasına neden olan bir düşman gemisinde "son isabet"
damagesayısı: alınan isabet sayısı (Onarım tarafından azaltılmadı, ancak Kalkan tarafından engellendi)
alive: geminizin sonunda hayatta olup olmadığını kontrol eder (en az 1 gövde hücresi hasarsız)

kontrolör

Denetleyiciyi GitHub'da bulabilirsiniz . Ayrıca Java ile yazılmış iki örnek robot içerir. Çalıştırmak için projeye göz atın ve Java IDE'nizde açın. Oyun sınıfının ana yöntemindeki giriş noktası. Java 8 gerekir.

Bot eklemek için önce Java için derlenmiş sürüme (.class dosyaları) veya yorumlanmış diller için kaynaklara ihtiyacınız vardır. Bunları projenin kök klasörüne yerleştirin. Ardından, oynatıcılar paketinde yeni bir Java sınıfı oluşturun (mevcut botlara örnek alabilirsiniz). Bu sınıf, String getCmd () yöntemini geçersiz kılmak için Player'ı uygulamalıdır. Döndürülen Dize, botlarınızı çalıştırmak için kabuk komutudur. Örneğin, Ruby botunun şu komutla çalışmasını sağlayabilirsiniz: return "C: \ Ruby \ bin \ ruby.exe MyBot.rb" ;. Son olarak, botu Game sınıfının en üstündeki Players dizisine ekleyin.

kurallar

  • Botlar, diğer belirli botları yenmek veya desteklemek için yazılmamalıdır.
  • Dosyalara yazma izni var. Lütfen "yoursubmissionname.txt" dosyasına yazın, klasör oyun başlamadan önce boşaltılır. Diğer dış kaynaklara izin verilmiyor.
  • Gönderinizin yanıt vermesi için 1 saniye var.
  • Gönderilerinizi derlemek ve çalıştırmak için komutlar sağlayın.
  • Birden fazla başvuru yazabilirsiniz

Desteklenen Diller

Her dili desteklemeye çalışacağım, ancak çevrimiçi olarak ücretsiz olması gerekiyor. "Ana akım" bir dil kullanmıyorsanız lütfen kurulum talimatlarını sağlayın.

Şu an itibariyle, çalıştırabilirim: Java 6-7-8, PHP, Ruby, Perl, Python 2-3, Lua, R, node.js, Haskell, Kotlin, C ++ 11.


İlginç KotH, sadece birkaç sorum var: birden fazla gönderi yazabilir miyiz (örneğin her gemi türü için bir tane)? AoE hakkında konuşurken, doğru konumun etrafında bir kare ([x + 1; y + 1] 'e çarpıyor)?
Katenkyo

@Katenkyo Evet, birden fazla başvuru yazabilirsiniz. Evet, 9 hücreye çarpıyor:[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

yani, denizaltı otomatik olarak yüzeye çıkıyor mu? hangi sırada?
Yıkılabilir Limon

aynı zamanda dönüşler de alınır mı?
Yıkılabilir Limon

ayrıca koç yeteneği hakkında yararlı olan nedir? (neden sadece ateş etmiyorsun?)
Yıkılabilir Limon

Yanıtlar:


3

RandomBot

Bu bir örnek bot. Bir gemi, bir eylem ve bir hedef hücre (gerekirse) rastgele seçer.

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

Bu bir örnek bot. Hiçbir şey yapmaz.

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 (Savaş Gemisi)

PeaceMaker, en yakın düşmanlara 3 kez ateş eder (spiral mesafe) ve mayınlardan en az 2 hücre uzak dururken bir çizgi içinde ileri geri hareket eder.

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 vuruyor'. Beni orada kaybettin.
Okx
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.