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?
fonte
MapPoint
éx
ey
floats
? Eles não deveriam serints
?Respostas:
HunterKiller
Esse caçador inteligente tentará encontrar uma posição segura onde possa atirar de maneira limpa em exatamente um alvo. (E assim, apenas um alvo pode atirar nele)
Funciona melhor quando há muita cobertura.
E é isso. Estou exausta.
fonte
Este tanque direto encontra o tanque inimigo mais próximo e atira nele. Seria bom se
find
,distance
eangle
foram construídos em, e secreateShootAction
aceitou uma dupla em radianos (ou seja, o resultado deangle
)Editar: Classe reescrita para incluir novos métodos utilitários
fonte
Would be nice if find, distance, and angle were built in, and if createShootAction accepted a double in radians (i.e. the result of angle)
- Ótima idéia, adicionarei.Eu não sou muito bom nisso, mas pensei que ainda daria uma chance, você sabe, prática e outras coisas.
Meu tanque decidirá aleatoriamente se mover ou atirar. Quando decide atirar, tentará atirar no alvo disponível mais próximo.
O código completo, incluindo o programa de controle, pode ser encontrado aqui .
fonte
Direction.getRandom()
Dodge Tank
Este tanque dispara no tanque mais próximo. De vez em quando, dependendo de sua saúde e da última vez em que se moveu, tentará se mover perpendicularmente ao tanque mais próximo, na tentativa de desviar de seus lasers.
fonte
Isso foi muito mais complicado do que eu pensava ..
Esta é a minha entrada no groovy, você precisa do groovy instalado e compila-o com
Para chamá-lo, você precisa adicionar $ GROOVY_HOME / Groovy / Groovy-2.3.4 / lib / groovy-2.3.4.jar (ou qualquer outra versão) ao caminho de classe.
Eu poderia enviar um arquivo .class compilado e a biblioteca, se você não quiser instalá-lo.
Parece haver uma situação em que os tanques não podem ver outra coisa, não sei se isso é pretendido. Isso causou conflitos durante o teste.
De qualquer forma, aqui está o RunTank: o RunTank avança ousadamente na direção oposta do tanque mais próximo, se for o tanque mais próximo do tanque mais próximo ou se mais de um tanque estiver dentro de FIELD_SIZE / 3. Espero que faça sentido, estou bêbado :)
Tenho uma sugestão: adicione cores ao tanque e um método para implementá-lo. Também os rótulos seriam bons na GUI :)
fonte
def RandomMoveTank() {}
- isso deveria estar lá? (Eu não sei Groovy)Essa é uma variante do Shoot-Closest, pois, a cada dois turnos, ela se move em uma direção até que não possa mais. Ele dispara a cada duas voltas.
Possui um utilitário útil
path
, que pode ser usado para identificar todos os pontos (e, portanto, objetos) entre dois pontos.fonte