Facciamo una guerra di carri armati!
Parzialmente ispirato a Distruggili con lacci
Obbiettivo
Il tuo compito è controllare un carro armato. Muoviti e spara ad altri carri armati e ostacoli nel campo di battaglia 2D. L'ultimo carro armato in piedi sarà il vincitore!
Formato mappa
Il tank sarà su un campo 2D basato sulla n
dalla n
griglia di quadrati unitari. Deciderò cosa n
si basa sul numero di invii. Ogni quadrato può contenere solo uno di:
- Un serbatoio
- Un albero
- Una pietra
- Un muro
- Niente
Tutti gli ostacoli e i carri armati riempiono completamente i loro spazi e bloccano tutti i colpi che li colpiscono danneggiando le cose più in basso.
Ecco un esempio di un campo con #
= serbatoio; T
= albero; R
= roccia; W
= parete; .
= niente con n
= 10
.....#....
..T....R..
WWW...WWWW
W......T..
T...R...Ww
W...W.....
W....W...T
WWWWWW...R
W.........
WWWWWWRT..
Le coordinate sono nel formato in x, y
cui x
aumenta da sinistra a destra e y
aumenta dal basso verso l'alto. Lo spazio in basso a sinistra ha le coordinate 0, 0
. Ogni carro armato può spostarsi in qualsiasi spazio vuoto e sparare in qualsiasi direzione.
Dinamica delle mappe
Il tuo carro armato non deve solo sparare ad altri carri armati! Se spara qualcosa sulla mappa, le cose possono succedere.
- Se un muro viene colpito, verrà distrutto dopo un certo numero di colpi, che vanno da 1 a 4
- Se un albero viene colpito, verrà immediatamente distrutto
- Se viene colpito a un sasso, il colpo lo passerà sopra e danneggerà la prossima cosa che colpisce
Una volta che qualcosa viene distrutto, non è più sulla mappa (verrà sostituito con nulla). Se un tiro distrugge un ostacolo, verrà bloccato e non danneggerà più nulla lungo il suo cammino.
Dinamica del serbatoio
Ogni serbatoio inizia con life
= 100. Ogni colpo in un carro armato ridurrà di 20-30 in life
base alla distanza. Questo può essere calcolato con delta_life=-30+(shot_distance*10/diagonal_map_length)
(dove si diagonal_map_length
trova (n-1)*sqrt(2)
). Inoltre, ogni carro armato rigenera 1 life
per turno.
Giri
Verrà eseguito un numero di round (deciderò una volta che avrò invii). All'inizio di ogni round, una mappa verrà generata casualmente e i carri armati verranno posizionati su di essa in posizioni vuote casuali. Durante ogni round, a ogni carro armato verrà dato un turno, in qualsiasi ordine arbitrario. Dopo che a ogni carro armato è stato dato un turno, gli verranno dati di nuovo turni nello stesso ordine. Il round continua fino a quando rimane solo un serbatoio. Quel carro armato sarà il vincitore e riceveranno 1 punto. Il gioco passerà quindi al turno successivo.
Una volta che tutti i round sono stati eseguiti, posterò i punteggi su questa domanda.
Durante il turno di un carro armato, può effettuare una delle seguenti operazioni
- Spostare fino a 3 spazi in una sola direzione, sia in orizzontale che in verticale. Se il serbatoio viene bloccato da un ostacolo o da un altro serbatoio, verrà spostato il più lontano possibile senza attraversare l'ostacolo o il serbatoio.
- Scatta in una direzione, rappresentata da un angolo in virgola mobile in gradi. L'asse x dello spazio locale del tuo carro armato (orizzontalmente da sinistra a destra, aka est o
TurnAction.Direction.EAST
) è 0 gradi, e gli angoli aumentano in senso antiorario. I colpi non sono accurati e l'angolo effettivo del tiro può essere maggiore o minore di 5 gradi rispetto all'angolo scelto. - Fare niente.
I turni non sono limitati nel tempo, ma ciò non significa che puoi intenzionalmente perdere tempo per appendere tutto.
Inseriti / Protocollo
Ogni programma presentato controllerà un serbatoio sul campo. Il programma di controllo è in Java, quindi per ora i tuoi programmi devono essere in Java (probabilmente a un certo punto scriverò un wrapper per altre lingue, oppure potresti scriverne uno tuo).
I tuoi programmi implementeranno l' Tank
interfaccia, che ha i seguenti metodi:
public interface Tank {
// Called when the tank is placed on the battlefield.
public void onSpawn(Battlefield field, MapPoint position);
// Called to get an action for the tank on each turn.
public TurnAction onTurn(Battlefield field, MapPoint position, float health);
// Called with feedback after a turn is executed.
// newPosition and hit will be populated if applicable.
public void turnFeedback(MapPoint newPosition, FieldObjectType hit);
// Called when the tank is destroyed, either by another tank,
// or because the tank won. The won parameter indicates this.
public void onDestroyed(Battlefield field, boolean won);
// Return a unique name for your tank here.
public String getName();
}
La Battlefield
classe contiene una matrice 2D di oggetti ( Battlefield.FIELD_SIZE
by Battlefield.FIELD_SIZE
) che rappresenta le cose sul campo di battaglia. Battlefield.getObjectTypeAt(...)
darà una FieldObjectType
per l'oggetto alle coordinate specificate (uno FieldObjectType.ROCK
, FieldObjectType.TREE
, FieldObjectType.TANK
, FieldObjectType.WALL
, o FieldObjectType.NOTHING
). Se si tenta di ottenere un oggetto fuori dal raggio della mappa (coordinate <0 o> = Battlefield.FIELD_SIZE
), IllegalArgumentException
verrà lanciato un oggetto.
MapPoint
è una classe per specificare i punti sulla mappa. Utilizzare MapPoint.getX()
e MapPoint.getY()
per accedere alle coordinate.
EDIT: Sono stati aggiunti alcuni metodi di utilità: MapPoint.distanceTo(MapPoint)
, MapPoint.angleBetween(MapPoint)
, Battlefield.find(FieldObjectType)
, e TurnAction.createShootActionRadians(double)
come suggerito da Wasmoo .
Ulteriori informazioni sono disponibili nei javadocs, vedere la sezione seguente.
Tutte le classi (API pubbliche) sono incluse nel pacchetto zove.ppcg.tankwar
.
Programma di controllo
La fonte completa e javadocs del programma di controllo e dell'API del serbatoio sono disponibili sul mio repository GitHub: https://github.com/Hungary-Dude/TankWarControl
Sentiti libero di inviare richieste pull e / o commenti se vedi un bug o desideri un miglioramento.
Ho scritto due programmi di esempio per il serbatoio RandomMoveTank
e RandomShootTank
(il nome dice tutto).
Per far funzionare il tuo carro armato, aggiungi la tua classe di carro armato (nome del pacchetto + nome della classe) pienamente qualificata a tanks.list
(una classe per riga), modifica le impostazioni come necessario in zove.ppcg.tankwar.Control
(ritardo di virata, se mostrare o meno una rappresentazione GUI del campo, ecc.), e corri zove.ppcg.tankwar.Control
. Assicurati che ci siano almeno 2 serbatoi nell'elenco o che i risultati non siano definiti. (Utilizzare i serbatoi di campionamento se necessario).
I tuoi programmi verranno eseguiti sulla mia macchina con questo programma di controllo. Includerò un link alla fonte una volta che lo scrivo. Sentiti libero di suggerire modifiche alla fonte.
Regole
- I tuoi invii devono seguire le linee guida sopra
- I tuoi programmi non possono accedere al filesystem, alla rete o tentare di attaccare la mia macchina in alcun modo
- I tuoi programmi potrebbero non tentare di sfruttare il mio programma di controllo per imbrogliare
- Nessuna pesca a traina (come ad esempio perdere intenzionalmente il tuo programma per appendere tutto)
- Potresti avere più di un invio
- Cerca di essere creativo con i contributi!
- Mi riservo il diritto di autorizzare o meno i programmi arbitrariamente
In bocca al lupo!
AGGIORNAMENTO: Dopo aver corretto il bug di teletrasporto a muro e aver implementato la rigenerazione, ho eseguito gli invii correnti per 100 round conBattlefield.FIELD_SIZE = 30
AGGIORNAMENTO 2: Ho aggiunto il nuovo invio, RunTank, dopo aver preso in giro un po 'con Groovy ...
Risultati aggiornati:
+-----------------+----+
| RandomMoveTank | 0 |
| RandomShootTank | 0 |
| Bouncing Tank | 4 |
| Richard-A Tank | 9 |
| Shoot Closest | 19 |
| HunterKiller 2 | 22 |
| RunTank | 23 |
| Dodge Tank | 24 |
+-----------------+----+
Attualmente i carri armati rigenerano 1 punto vita per turno. Dovrebbe essere aumentato?
MapPoint
'sx
ey
floats
? Non dovrebbero essereints
?