Faisons une guerre de chars!
Partiellement inspiré par Destroy Them With Lazers
Objectif
Votre tâche consiste à contrôler un réservoir. Déplacez-vous et tirez sur d'autres chars et obstacles sur le champ de bataille 2D. Le dernier tank debout sera le vainqueur!
Format de carte
Votre réservoir sera sur un champ 2D basé sur un n
par n
grille de carrés unitaires. Je déciderai ce qui n
est basé sur le nombre de soumissions. Chaque carré ne peut contenir qu'un seul des éléments suivants:
- Un réservoir
- Un arbre
- Un rocher
- Un mur
- Rien
Tous les obstacles et les chars remplissent complètement leurs espaces, et ils bloquent tous les tirs qui les frappent d'endommager les choses plus bas.
Voici un exemple de champ avec #
= tank; T
= arbre; R
= roche; W
= mur; .
= rien avec n
= 10
.....#....
..T....R..
WWW...WWWW
W......T..
T...R...Ww
W...W.....
W....W...T
WWWWWW...R
W.........
WWWWWWRT..
Les coordonnées sont dans le format x, y
où x
augmente de gauche à droite et y
augmente de bas en haut. L'espace en bas à gauche a les coordonnées 0, 0
. Chaque char peut se déplacer vers n'importe quel espace vide et tirer dans n'importe quelle direction.
Dynamique de la carte
Votre char n'a pas qu'à tirer sur d'autres chars! S'il tire quelque chose sur la carte, des choses peuvent arriver.
- Si un mur est abattu, il sera détruit après un certain nombre de tirs, allant de 1 à 4
- Si un arbre est abattu, il sera immédiatement détruit
- Si un rocher est abattu, le tir passe dessus et endommage la prochaine chose qu'il frappe
Une fois que quelque chose est détruit, il n'est plus sur la carte (il sera remplacé par rien). Si un tir détruit un obstacle, il sera bloqué et n'endommagera plus rien sur sa trajectoire.
Dynamique du réservoir
Chaque réservoir commence avec life
= 100. Chaque tir sur un char réduit de 20 à 30 en life
fonction de la distance. Cela peut être calculé avec delta_life=-30+(shot_distance*10/diagonal_map_length)
(où diagonal_map_length
est (n-1)*sqrt(2)
). De plus, chaque tank régénère 1 life
par tour.
Se tourne
Un certain nombre de tours seront organisés (je déciderai une fois que j'aurai des soumissions). Au début de chaque manche, une carte sera générée aléatoirement et des chars y seront placés dans des emplacements vides aléatoires. À chaque tour, chaque tank recevra un tour, dans n'importe quel ordre arbitraire. Après que chaque char ait reçu un tour, il recevra à nouveau des tours dans le même ordre. La manche se poursuit jusqu'à ce qu'il ne reste plus qu'un tank. Ce char sera le vainqueur et il recevra 1 point. Le jeu se poursuivra ensuite au tour suivant.
Une fois tous les tours terminés, je publierai les scores sur cette question.
Pendant le tour d'un tank, il peut effectuer l'une des actions suivantes
- Déplacez jusqu'à 3 espaces dans une seule direction, horizontalement ou verticalement. Si le réservoir est bloqué par un obstacle ou un autre réservoir, il sera déplacé le plus loin possible sans passer par l'obstacle ou le réservoir.
- Tirez dans une certaine direction, représentée par un angle à virgule flottante en degrés. L'axe des x de l'espace local de votre réservoir (horizontalement de gauche à droite, alias est ou
TurnAction.Direction.EAST
) est de 0 degré et les angles augmentent dans le sens antihoraire. Les prises de vue sont inexactes et l'angle réel de la prise de vue peut être supérieur ou inférieur de 5 degrés à l'angle que vous choisissez. - Ne fais rien.
Les virages ne sont pas limités dans le temps, mais cela ne signifie pas que vous pouvez intentionnellement perdre du temps pour tout raccrocher.
Soumissions / Protocole
Chaque programme soumis contrôlera un réservoir sur le terrain. Le programme de contrôle est en Java, donc vos programmes doivent être en Java pour l'instant (je vais probablement écrire un wrapper pour d'autres langages à un moment donné, ou vous pourriez écrire le vôtre).
Vos programmes implémenteront l' Tank
interface, qui a les méthodes suivantes:
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 contient un tableau 2D d'objets ( Battlefield.FIELD_SIZE
par Battlefield.FIELD_SIZE
) qui représente des choses sur le champ de bataille. Battlefield.getObjectTypeAt(...)
donnera une FieldObjectType
de l'objet aux coordonnées spécifiées ( l' un des FieldObjectType.ROCK
, FieldObjectType.TREE
, FieldObjectType.TANK
, FieldObjectType.WALL
, ou FieldObjectType.NOTHING
). Si vous essayez de sortir un objet hors de portée de la carte (coordonnées <0 ou> = Battlefield.FIELD_SIZE
), un IllegalArgumentException
sera lancé.
MapPoint
est une classe permettant de spécifier des points sur la carte. Utilisez MapPoint.getX()
et MapPoint.getY()
pour accéder aux coordonnées.
EDIT: Certaines méthodes utilitaires ont été ajoutées: MapPoint.distanceTo(MapPoint)
, MapPoint.angleBetween(MapPoint)
, Battlefield.find(FieldObjectType)
et TurnAction.createShootActionRadians(double)
comme suggéré par Wasmoo .
Plus d'informations peuvent être trouvées dans les javadocs, voir la section ci-dessous.
Toutes les classes (API publiques) sont sous le package zove.ppcg.tankwar
.
Programme de contrôle
La source complète et les javadocs du programme de contrôle et de l'API du réservoir peuvent être trouvés sur mon dépôt GitHub: https://github.com/Hungary-Dude/TankWarControl
N'hésitez pas à envoyer des demandes de tirage et / ou des commentaires si vous voyez un bug ou souhaitez une amélioration.
J'ai écrit deux exemples de programmes de réservoir, RandomMoveTank
et RandomShootTank
(le nom dit tout).
Pour exécuter votre réservoir, ajoutez votre classe de réservoir entièrement qualifiée (nom du package + nom de classe) à tanks.list
(une classe par ligne), modifiez les paramètres si nécessaire dans zove.ppcg.tankwar.Control
(délai de rotation, pour afficher ou non une représentation GUI du champ, etc.), et courir zove.ppcg.tankwar.Control
. Assurez-vous qu'il y a au moins 2 réservoirs sur la liste, sinon les résultats ne sont pas définis. (Utilisez les réservoirs d'échantillonnage si nécessaire).
Vos programmes seront exécutés sur ma machine sous ce programme de contrôle. Je vais inclure un lien vers la source une fois que je l'ai écrit. N'hésitez pas à suggérer des modifications à la source.
Règles
- Vos soumissions doivent suivre les directives ci-dessus
- Vos programmes ne peuvent pas accéder au système de fichiers, au réseau ou tenter d'attaquer ma machine de quelque manière que ce soit
- Vos programmes ne peuvent pas tenter d'exploiter mon programme de contrôle pour tricher
- Pas de pêche à la traîne (comme faire intentionnellement perdre du temps à votre programme pour tout raccrocher)
- Vous pouvez avoir plus d'une soumission
- Essayez d'être créatif avec les soumissions!
- Je me réserve le droit d'autoriser ou non les programmes arbitrairement
Bonne chance!
MISE À JOUR: Après avoir corrigé le bug de téléportation du mur et implémenté la régénération, j'ai exécuté les soumissions actuelles pendant 100 tours avecBattlefield.FIELD_SIZE = 30
MISE À JOUR 2: J'ai ajouté la nouvelle soumission, RunTank, après avoir un peu trompé Groovy ...
Résultats mis à jour:
+-----------------+----+
| RandomMoveTank | 0 |
| RandomShootTank | 0 |
| Bouncing Tank | 4 |
| Richard-A Tank | 9 |
| Shoot Closest | 19 |
| HunterKiller 2 | 22 |
| RunTank | 23 |
| Dodge Tank | 24 |
+-----------------+----+
Actuellement, les tanks régénèrent 1 point de vie par tour. Cela devrait-il être augmenté?
MapPoint
« sx
ety
floats
? Ne devraient-ils pas l'êtreints
?