KOTH: Hit and Sunk


12

introduzione

Per il mio 5 ° KOTH, vi presento una sfida basata sul noto gioco Battleship con alcuni colpi di scena. Comanderai solo una nave, il cui tipo potrai scegliere tra le 5 classi "tradizionali", ma sarai in grado di intraprendere più azioni ogni turno, incluso lo spostamento! Questo è giocato come FFA (gratuito per tutti) e il tuo obiettivo sarà quello di essere l'ultima nave in piedi.

Principio

Il gioco è a turni. All'inizio del gioco, dovrai scegliere la classe della tua nave. Quindi ogni turno, i giocatori saranno in grado di eseguire diverse azioni a seconda della loro nave.

Il gioco si svolge su una griglia 2D (X, Y) il cui lato è definito in questo modo:
X = 30 + numberOfPlayer
Y = 30 + numberOfPlayer
la posizione iniziale di ogni nave è casuale.

L'ordine di gioco è randomizzato ad ogni turno e non conoscerai la tua posizione nella "coda" né il numero di giocatori. Il gioco dura 100 turni o fino a quando rimane una sola nave viva.

Ogni volta che colpisci una nave nemica o vieni colpito, guadagnerai o perderai punti. Vince il giocatore con il punteggio più alto. Verrà assegnata una taglia al vincitore (valore che dipende dal numero di partecipanti).

Il controller ti fornisce input tramite argomenti di comando e il tuo programma deve essere emesso tramite stdout.

Sintassi

Primo turno

Il tuo programma verrà chiamato una volta senza alcun argomento. Devi selezionare un numero intero compreso tra 1 e 5 (incluso) per selezionare la tua nave:

1: Distruttore [lunghezza: 2, mosse / giro: 3, colpi / giro: 1, raggio: 9, mine: 4]
Abilità : Rotazioni libere della nave (nessun tempo di recupero)

2: Sottomarino [lunghezza: 3, mosse / giro: 2, colpi / giro: 1, distanza: 5, mine: 4]
Abilità : può tuffarsi / superficie (vedi uscite). Mentre sei sott'acqua, puoi usare solo azioni "Movimento" e puoi vederlo solo con una scansione. Non puoi essere colpito da un colpo, ma puoi subire danni dalle mine.

3: Incrociatore [lunghezza: 3, mosse / giro: 1, colpi / giro: 2, distanza: 9, mine: 2]
Abilità : può riparare (vedi uscite)

4: Battleship [lunghezza: 4, mosse / giro: 1, colpi / giro: 3, distanza: 7, mine: 1]
Abilità : Can Shield (vedi uscite)

5: Portatore [lunghezza: 5, mosse / giro: 1, colpi / giro: 1, raggio: 7, mine: 3]
Abilità : I colpi infliggono danni da AOE (area di effetto) al bersaglio (danni da spruzzo di 1 raggio). Se il bersaglio viene colpito con il tiro, verranno danneggiate anche fino a 2 celle di questa nave.

Giri

Ingresso

Ogni volta che viene chiamato il tuo programma, riceverà argomenti in questo formato:

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

I round sono 1 indicizzati.

Esempio di 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

Ecco il primo round, sei il giocatore 8. La
tua nave è posizionata su (X = 1, Y = 12) e la tua direzione è verso l'alto (0 = Alto, 1 = Destro, 2 = Basso, 3 = Sinistra ).
Lo scafo non è danneggiato (la nave ha una lunghezza di 3 e ogni bit è vero [1 = OK, 0 = Danneggiato]). Puoi muoverti 1 volta, sparare 2 volte, lasciare 2 mine e la tua "abilità" è disponibile (tempo di recupero = 0).
Non hai colpito nulla, né hai affondato alcuna nave e non sei stato colpito neanche.
Non sei sott'acqua, i tuoi scudi (se presenti) non sono attivati ​​e neanche la tua scansione.
Più sulla mappa più tardi ...

Produzione

Devi produrre una stringa che descriva quali azioni eseguirai in questo turno. L'ordine dei caratteri nella stringa di output definirà gli ordini delle azioni. Puoi eseguire le stesse azioni più volte se non supera i limiti della tua nave. Se una o più azioni non sono valide, ognuna verrà considerata separatamente come W. Ecco l'elenco delle azioni disponibili:

M: Sposta 1 cella nella direzione in cui ti trovi (consuma 1 mossa)
B: indietro di 1 cella nella direzione in cui ti trovi (consuma 1 mossa)
C: ruota la tua nave in senso orario (consuma 1 mossa / libera per i Distruttori)
K: ruota la tua nave in senso antiorario (consuma 1 mossa / libera per i cacciatorpediniere)
A: Ram la tua nave nella direzione in cui sei rivolto (funziona solo se un'altra nave sta occupando la cella nella direzione in cui sei rivolto / non muove la tua nave / consuma tutte le mosse)
F: Spara 1 colpo a una cella nel raggio di azione (consuma 1 colpo). Deve essere seguita dalla cellula mirata in questo formato ([+ -] X [+ -]) Y / Esempio: F+2-3)
N: Luogo 1 miniera per una cella adiacente alla tua nave (consumare tutti i colpi e 1 mio). Deve essere seguito dalla cella targetizzata in questo formato ([+ -] X [+ -]) Y / esempio N+0+1:)
S: Attiva la scansione per il turno successivo (consuma tutti i colpi)
R: ripara lo scafo danneggiato il più vicino alla "testa" della tua nave (consuma tutti i colpi, tempo di recupero = 3 turni / solo incrociatore)
P: immersione / superficie (consuma tutti i colpi, cooldown = 3 turni, durata massima = 5 turni / solo sottomarino)
D: attiva il tuo scudo prevenendo il danno successivo durante il tuo prossimo turno (consuma tutti i colpi, tempo di recupero = 3 / solo corazzata)
W: aspetta (non fa nulla)

Chiarimento : "Consuma tutte le mosse / colpi" significa che puoi usare questa azione solo se non hai mai usato nessuna delle tue mosse / colpi durante questo turno.

Esempio di output

MF+9-8CM : Sposta 1 cella, quindi spara sulla cella la cui posizione relativa alla "testa" della tua nave è (targetX = X + 9, targetY = Y - 8), gira in senso orario e infine sposta di nuovo 1 cella.

gameplay

La griglia

Ecco una griglia di esempio (33 x 13) in cui sono posizionati 3 giocatori:

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

Come possiamo vedere, c'è anche un mio Mproprio accanto al giocatore 1.

Prendiamo il giocatore 2 per capire il posizionamento e la direzione:

La posizione del giocatore 2 è X = 3, Y = 4, Direzione = 3. Poiché la sua direzione è "In basso", il resto delle sue "celle della nave" sono posizionate "sopra" la "testa" (X = 3, Y = 3) & (X = 3, Y = 2)

Mappa del giocatore

L'ultimo argomento che ogni giocatore riceve è la sua "propria" mappa. Per impostazione predefinita, una nave rileva tutto in un intervallo di 5 celle , ma può attivare una Scansione per aumentare questo intervallo a 9 .

L'argomento è sempre lungo 361 (19 x 19) caratteri. Rappresenta il quadrato centrato attorno alla "testa" della tua nave, dove ogni personaggio corrisponde a un elemento definito in questo modo:

.: Cella vuota
O: La tua nave
M: Miniere
X: Muro (celle fuori dalla mappa)
U: Sconosciuto (verrà rivelato da una scansione)
A: Cella non
Bdanneggiata della
Cnave nemica: Cella danneggiata della nave nemica: Cella non danneggiata della nave nemica (vista solo con una scansione)
D: Cella danneggiata subacquea della nave nemica (vista solo con una scansione)
W: Relitto (nave morta)

La stringa è composta da 19 caratteri della prima riga, seguiti da 19 caratteri della seconda riga ... fino alla 19a riga.

Diamo un'occhiata a ciò che il giocatore 2 riceve con e senza una scansione (interruzioni di riga per una migliore comprensione, ma non invio ai giocatori):

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

Mines

Le mine vengono attivate quando una nave si sposta in una cella occupata da una miniera o quando un colpo viene sparato sulla miniera. Le mine non possono essere attivate con l'azione "Ram".

Le mine infliggono danni da AOE (danni da spruzzo a 1 raggio) a tutti, anche alla persona che ha piazzato la miniera. Le mine possono innescare esplosioni "a catena" se un'altra miniera si trova nel raggio dell'esplosione.

rotazioni

Le rotazioni sono simmetrie centrali centrate sulla "testa" della nave. Le rotazioni attiveranno una miniera solo se è posizionata sulla "posizione di destinazione" (non si innescheranno mine in un arco.

Area d'effetto

Il danno da spruzzo a 1 raggio (per mine e colpi del Portatore) è definito da un quadrato 3x3 (9 celle) centrato sul colpo / esplosione iniziale (x, y). Colpisce quelle coordinate:[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]

punteggio

Il punteggio è definito da questa formula:
Score = Hits + (Sunken x 5) - Damage taken - (Alive ? 0 : 10)

dove::
hitsnumero di colpi sulla nave nemica, sia per esplosione di Ariete, Tiro o Miniera (1 colpo danneggiato dalla cellula della nave nemica, comprese le esplosioni a catena)
sunken: numero di "ultimo colpo" su una nave nemica che l'ha fatto affondare
damage: numero di colpi ricevuti (non diminuiti dalla riparazione, ma prevenuti dallo scudo)
alive: controlla se la tua nave è viva alla fine (almeno 1 cella di scafo non danneggiata)

controllore

Puoi trovare il controller su GitHub . Contiene anche due samplebot, scritti in Java. Per farlo funzionare, controlla il progetto e aprilo nel tuo IDE Java. Il punto di ingresso nel metodo principale della classe Gioco. Java 8 richiesto.

Per aggiungere i bot, prima devi avere la versione compilata per Java (file .class) o i sorgenti per le lingue interpretate. Inseriscili nella cartella principale del progetto. Quindi, crea una nuova classe Java nel pacchetto giocatori (puoi fare un esempio sui robot già esistenti). Questa classe deve implementare Player per sovrascrivere il metodo String getCmd (). La stringa restituita è il comando shell per eseguire i tuoi robot. Ad esempio, puoi far funzionare un bot Ruby con questo comando: return "C: \ Ruby \ bin \ ruby.exe MyBot.rb" ;. Infine, aggiungi il bot nella matrice dei giocatori nella parte superiore della classe di gioco.

Regole

  • I robot non devono essere scritti per battere o supportare altri robot specifici.
  • La scrittura su file è consentita. Scrivi a "yoursubmissionname.txt", la cartella verrà svuotata prima dell'inizio di una partita. Altre risorse esterne non sono consentite.
  • Il tuo invio ha 1 secondo per rispondere.
  • Fornisci comandi per compilare ed eseguire i tuoi invii.
  • Puoi scrivere più invii

Lingue supportate

Proverò a supportare tutte le lingue, ma deve essere disponibile online gratuitamente. Fornire istruzioni per l'installazione se non si utilizza un linguaggio "tradizionale".

A partire da ora, posso eseguire: Java 6-7-8, PHP, Ruby, Perl, Python 2-3, Lua, R, node.js, Haskell, Kotlin, C ++ 11.


Interessante KotH, ho solo alcune domande: possiamo scrivere più invii (uno per ogni tipo di nave ad esempio)? Quando parli di AoE, è un quadrato attorno alla posizione giusta (colpisce [x + 1; y + 1])?
Katenkyo,

@Katenkyo Sì, puoi scrivere più invii. Sì, colpisce 9 cellule:[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,

quindi, il sottomarino affiora automaticamente? in quale turno?
Limone distruttibile,

anche le curve vengono prese contemporaneamente?
Limone distruttibile,

anche cosa è utile sull'abilità ram? (perché non sparare?)
Destructible Lemon

Risposte:


3

RandomBot

Questo è un bot di esempio. Sceglie una nave, un'azione e una cellula bersaglio (se necessario) in modo casuale.

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

Questo è un bot di esempio. Non fa niente.

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 (Battleship)

PeaceMaker spara 3 volte ai nemici più vicini (distanza a spirale) e si muove avanti e indietro in linea rimanendo ad almeno 2 celle di distanza dalle mine.

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 spara'. Mi hai perso lì.
Okx,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.