Vamos ter uma guerra de tanques!
Parcialmente inspirado por Destroy The With With Lazers
Objetivo
Sua tarefa é controlar um tanque. Mova-se e atire em outros tanques e obstáculos no campo de batalha 2D. O último tanque em pé será o vencedor!
Formato do mapa
Seu tanque será em um campo 2D baseado em um n
por n
grade de unidade quadrados. Decidirei o que n
é baseado no número de envios. Cada quadrado pode conter apenas um dos seguintes:
- Um tanque
- Uma árvore
- Uma pedra
- Uma parede
- Nada
Todos os obstáculos e tanques preenchem completamente seus espaços e bloqueiam todos os tiros que os atingem de danificar as coisas mais abaixo.
Aqui está um exemplo de um campo com #
= tank; T
= árvore; R
= rock; W
= parede; .
= nada com n
= 10
.....#....
..T....R..
WWW...WWWW
W......T..
T...R...Ww
W...W.....
W....W...T
WWWWWW...R
W.........
WWWWWWRT..
As coordenadas estão no formato em x, y
que x
aumenta da esquerda para a direita e y
aumenta de baixo para cima. O espaço inferior esquerdo tem a coordenada 0, 0
. Cada tanque pode se mover para qualquer espaço vazio e disparar em qualquer direção.
Map Dynamics
Seu tanque não precisa apenas atirar em outros tanques! Se disparar algo no mapa, as coisas podem acontecer.
- Se uma parede for atingida, ela será destruída após um certo número de disparos, variando de 1 a 4
- Se uma árvore é atingida, ela será destruída imediatamente
- Se uma pedra é atingida, ela passa por cima dela e danifica a próxima coisa que atinge
Depois que algo é destruído, ele não está mais no mapa (será substituído por nada). Se um tiro destruir um obstáculo, ele será bloqueado e não danificará mais nada ao longo de seu caminho.
Dinâmica do tanque
Cada tanque começa com life
= 100. Cada tiro em um tanque reduzirá de 20 a 30 com life
base na distância. Isso pode ser calculado com delta_life=-30+(shot_distance*10/diagonal_map_length)
(onde diagonal_map_length
está (n-1)*sqrt(2)
). Além disso, cada tanque regenera 1 life
por turno.
Turns
Algum número de rodadas será executado (eu decidirei assim que tiver finalizações). No início de cada rodada, um mapa será gerado aleatoriamente e tanques serão colocados nele em locais vazios aleatórios. Durante cada rodada, cada tanque recebe um turno, em qualquer ordem arbitrária. Após cada turno ter sido dado, cada turno será novamente na mesma ordem. A rodada continua até restar apenas um tanque. Esse tanque será o vencedor e eles receberão 1 ponto. O jogo continuará para a próxima rodada.
Depois que todas as rodadas tiverem sido executadas, colocarei as pontuações nesta questão.
Durante a virada de um tanque, ele pode executar uma das seguintes ações
- Mova até 3 espaços em uma única direção, horizontal ou verticalmente. Se o tanque estiver bloqueado por um obstáculo ou outro tanque, ele será movido o mais longe possível, sem passar pelo obstáculo ou tanque.
- Fotografe em alguma direção, representada por um ângulo de ponto flutuante em graus. O eixo x do espaço local do seu tanque (horizontalmente da esquerda para a direita, também conhecido como leste ou
TurnAction.Direction.EAST
) é de 0 graus e os ângulos aumentam no sentido anti-horário. As fotos são imprecisas e o ângulo real da foto pode ser 5 graus maior ou menor que o ângulo escolhido. - Fazer nada.
As voltas não são limitadas no tempo, mas isso não significa que você pode perder tempo intencionalmente para desligar tudo.
Submissões / Protocolo
Cada programa enviado controlará um tanque no campo. O programa de controle está em Java; portanto, seus programas precisam estar em Java por enquanto (provavelmente escreverei um wrapper para outras linguagens em algum momento, ou você poderá escrever o seu próprio).
Seus programas implementarão a Tank
interface, que possui os seguintes métodos:
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();
}
A Battlefield
classe contém um conjunto de objetos 2D ( Battlefield.FIELD_SIZE
by Battlefield.FIELD_SIZE
) que representa coisas no campo de batalha. Battlefield.getObjectTypeAt(...)
dará um FieldObjectType
para o objecto nas coordenadas especificadas (um de FieldObjectType.ROCK
, FieldObjectType.TREE
, FieldObjectType.TANK
, FieldObjectType.WALL
, ou FieldObjectType.NOTHING
). Se você tentar tirar um objeto fora do alcance do mapa (coordenadas <0 ou> = Battlefield.FIELD_SIZE
), um IllegalArgumentException
será lançado.
MapPoint
é uma classe para especificar pontos no mapa. Use MapPoint.getX()
e MapPoint.getY()
para acessar as coordenadas.
EDIT: Alguns métodos utilitários foram adicionados: MapPoint.distanceTo(MapPoint)
, MapPoint.angleBetween(MapPoint)
, Battlefield.find(FieldObjectType)
, e TurnAction.createShootActionRadians(double)
como sugerido por Wasmoo .
Mais informações podem ser encontradas nos javadocs, consulte a seção abaixo.
Todas as classes (API pública) estão no pacote zove.ppcg.tankwar
.
Programa de Controle
A fonte completa e os javadocs do programa de controle e da API do tanque podem ser encontrados no repositório GitHub: https://github.com/Hungary-Dude/TankWarControl
Sinta-se à vontade para enviar solicitações pull e / ou comentar se você encontrar um bug ou quiser uma melhoria.
Eu escrevi dois programas de tanque de amostra RandomMoveTank
e RandomShootTank
(o nome já diz tudo).
Para executar o seu tanque, adicione sua classe de tanque totalmente qualificada (nome do pacote + nome da classe) a tanks.list
(uma classe por linha), edite as configurações conforme necessário em zove.ppcg.tankwar.Control
(atraso de turno, se deve ou não mostrar uma representação GUI do campo, etc.), e corra zove.ppcg.tankwar.Control
. Verifique se há pelo menos 2 tanques na lista ou se os resultados não estão definidos. (Use os tanques de amostras, se necessário).
Seus programas serão executados na minha máquina sob este programa de controle. Vou incluir um link para a fonte assim que o escrever. Sinta-se livre para sugerir edições na fonte.
Regras
- Seus envios devem seguir as diretrizes acima
- Seus programas podem não acessar o sistema de arquivos, a rede ou tentar atacar minha máquina de forma alguma
- Seus programas podem não tentar explorar meu programa de controle para enganar
- Sem trollagem (como intencionalmente fazer com que seu programa perca tempo para desligar tudo)
- Você pode ter mais de um envio
- Tente ser criativo com os envios!
- Reservo-me o direito de permitir ou não programas arbitrariamente
Boa sorte!
ATUALIZAÇÃO: Depois de corrigir o erro de teletransporte de parede e implementar a regeneração, executei os envios atuais por 100 rodadas comBattlefield.FIELD_SIZE = 30
ATUALIZAÇÃO 2: Adicionei o novo envio, RunTank, depois de brincar um pouco com o Groovy ...
Resultados atualizados:
+-----------------+----+
| RandomMoveTank | 0 |
| RandomShootTank | 0 |
| Bouncing Tank | 4 |
| Richard-A Tank | 9 |
| Shoot Closest | 19 |
| HunterKiller 2 | 22 |
| RunTank | 23 |
| Dodge Tank | 24 |
+-----------------+----+
Atualmente, os tanques regeneram 1 ponto de vida por turno. Isso deveria ser aumentado?
MapPoint
éx
ey
floats
? Eles não deveriam serints
?