java-air-combat / app.py
rmayormartins's picture
a1
9855827
raw
history blame
26 kB
import gradio as gr
import os
import subprocess
import time
from collections import deque
# Criar pasta para armazenar as classes Java
os.makedirs("combat_classes", exist_ok=True)
# Templates de código para as aeronaves com altura dinâmica e novos atributos
TEAM1_TEMPLATE = '''import java.util.ArrayList;
import java.util.Random;
/**
* Time 1 - Configure sua aeronave!
*
* SISTEMA DE PONTOS:
* - Você tem 100 pontos para distribuir entre os atributos
* - Escolha com sabedoria para criar uma aeronave competitiva
*
* ATRIBUTOS:
* - speed: Velocidade da aeronave (1-10) - Afeta quão rápido sua aeronave pode se mover
* - fireRate: Taxa de disparo (1-10) - Controla com que frequência sua aeronave pode atirar
* - maneuverability: Manobrabilidade (1-10) - Facilita mudanças de altitude e esquivas
* - shotPower: Poder do tiro normal (5-20) - Dano causado por tiros normais
* - supersonicPower: Poder do tiro supersônico (10-30) - Dano causado por tiros supersônicos
* - missilePower: Poder do míssil (15-40) - Dano causado pelo míssil especial
* - defense: Defesa (5-25) - Reduz o dano recebido
* - stealthChance: Chance de furtividade (0-20) - Probabilidade de evitar ataques
* - radar: Radar (0-10) - Capacidade de detectar projéteis inimigos
* - doubleShot: Tiro duplo (0-10) - Permite disparar em duas altitudes diferentes
* - nuclearPower: Poder nuclear (0-10) - Poder do míssil nuclear (dano massivo)
*/
public class Team1Aircraft extends Aircraft {
private Random random = new Random();
private int maxAltitude; // Armazena a altura máxima do campo
public Team1Aircraft() {
super(
// DISTRIBUA 100 PONTOS ENTRE ESSES ATRIBUTOS
5, // Velocidade (1-10)
5, // Taxa de fogo (1-10)
5, // Manobrabilidade (1-10)
15, // Dano do tiro normal (5-20)
20, // Dano do tiro supersônico (10-30)
25, // Dano do míssil (15-40)
15, // Defesa (5-25)
5, // Chance de furtividade (0-20)
2, // Radar (0-10)
2, // Tiro duplo (0-10)
1, // Poder nuclear (0-10)
"▶" // Símbolo da aeronave (não altere)
);
// IMPORTANTE: A soma de todos os atributos deve ser <= 100
// Exemplo: 5+5+5+15+20+25+15+5+2+2+1 = 100
// Verifica dinamicamente a altura do campo (será definida pelo BattleMain)
try {
String heightEnv = System.getProperty("battlefield.height", "3");
maxAltitude = Integer.parseInt(heightEnv) - 1;
} catch (Exception e) {
maxAltitude = 2; // Valor padrão se não conseguir ler
}
}
/**
* Controla o movimento da aeronave.
* Valor padrão: Movimento aleatório baseado na velocidade
* Dica: Você pode personalizar para criar padrões de movimento mais inteligentes
*/
@Override
public int move() {
// Retorna um número entre -speed/2 e +speed
return random.nextInt(speed + 1) - speed / 2;
}
/**
* Controla a mudança de altitude da aeronave.
* Valor padrão: Mudança aleatória entre subir, descer ou manter altitude
* Dica: Uma boa estratégia pode aumentar suas chances de esquiva
*/
@Override
public int changeAltitude() {
int direction = random.nextInt(3) - 1; // -1 (descer), 0 (manter), 1 (subir)
this.posY = Math.max(0, Math.min(maxAltitude, posY + direction));
return direction;
}
/**
* Tiro normal - mais frequente, menos dano
*/
@Override
public Projectile shoot(int posX, int direction) {
return new Projectile(posX, this.posY, direction, 1, "->");
}
/**
* Tiro supersônico - mais rápido, mais dano
*/
@Override
public Projectile shootSupersonic(int posX, int direction) {
return new Projectile(posX, this.posY, direction, 2, ">>");
}
/**
* Míssil especial - muito dano, com cooldown
*/
@Override
public Projectile specialMissile(int posX, int direction) {
if (missileCooldown == 0) {
missileCooldown = 3; // Espera 3 turnos para usar novamente
return new Projectile(posX, this.posY, direction, 1, "=>");
}
missileCooldown--;
return null;
}
/**
* Tiro duplo - ataca em duas altitudes diferentes
*/
@Override
public Projectile doubleShot(int posX, int direction) {
// Define a segunda altitude para o tiro (diferente da atual)
int currentAlt = this.posY;
int secondAlt = (currentAlt + 1) % (maxAltitude + 1);
// Guarda essa altitude para ser usada pelo BattleMain
this.secondShotAltitude = secondAlt;
// Retorna o projétil principal
return new Projectile(posX, this.posY, direction, 1, "⇉");
}
/**
* Míssil nuclear - dano massivo
*/
@Override
public Projectile nuclearMissile(int posX, int direction) {
if (missileCooldown == 0) {
missileCooldown = 5; // Longo cooldown para o poder nuclear
return new Projectile(posX, this.posY, direction, 1, "-]=>");
}
return null;
}
/**
* Radar - detecta projéteis inimigos
*/
@Override
public void radarScan(ArrayList<Projectile> projectiles, int enemyPosX, int enemyPosY) {
// Implementação básica: apenas detecta projéteis próximos
// Em uma implementação mais avançada, você poderia usar essas informações
// para ajustar seu movimento e evitar projéteis
}
}'''
TEAM2_TEMPLATE = '''import java.util.ArrayList;
import java.util.Random;
/**
* Time 2 - Configure sua aeronave!
*
* SISTEMA DE PONTOS:
* - Você tem 100 pontos para distribuir entre os atributos
* - Escolha com sabedoria para criar uma aeronave competitiva
*
* ATRIBUTOS:
* - speed: Velocidade da aeronave (1-10) - Afeta quão rápido sua aeronave pode se mover
* - fireRate: Taxa de disparo (1-10) - Controla com que frequência sua aeronave pode atirar
* - maneuverability: Manobrabilidade (1-10) - Facilita mudanças de altitude e esquivas
* - shotPower: Poder do tiro normal (5-20) - Dano causado por tiros normais
* - supersonicPower: Poder do tiro supersônico (10-30) - Dano causado por tiros supersônicos
* - missilePower: Poder do míssil (15-40) - Dano causado pelo míssil especial
* - defense: Defesa (5-25) - Reduz o dano recebido
* - stealthChance: Chance de furtividade (0-20) - Probabilidade de evitar ataques
* - radar: Radar (0-10) - Capacidade de detectar projéteis inimigos
* - doubleShot: Tiro duplo (0-10) - Permite disparar em duas altitudes diferentes
* - nuclearPower: Poder nuclear (0-10) - Poder do míssil nuclear (dano massivo)
*/
public class Team2Aircraft extends Aircraft {
private Random random = new Random();
private int maxAltitude; // Armazena a altura máxima do campo
public Team2Aircraft() {
super(
// DISTRIBUA 100 PONTOS ENTRE ESSES ATRIBUTOS
5, // Velocidade (1-10)
5, // Taxa de fogo (1-10)
5, // Manobrabilidade (1-10)
15, // Dano do tiro normal (5-20)
20, // Dano do tiro supersônico (10-30)
25, // Dano do míssil (15-40)
15, // Defesa (5-25)
5, // Chance de furtividade (0-20)
2, // Radar (0-10)
2, // Tiro duplo (0-10)
1, // Poder nuclear (0-10)
"◀" // Símbolo da aeronave (não altere)
);
// IMPORTANTE: A soma de todos os atributos deve ser <= 100
// Exemplo: 5+5+5+15+20+25+15+5+2+2+1 = 100
// Verifica dinamicamente a altura do campo (será definida pelo BattleMain)
try {
String heightEnv = System.getProperty("battlefield.height", "3");
maxAltitude = Integer.parseInt(heightEnv) - 1;
} catch (Exception e) {
maxAltitude = 2; // Valor padrão se não conseguir ler
}
}
/**
* Controla o movimento da aeronave.
* Valor padrão: Movimento aleatório baseado na velocidade
* Dica: Você pode personalizar para criar padrões de movimento mais inteligentes
*/
@Override
public int move() {
// Retorna um número entre -speed/2 e +speed
return random.nextInt(speed + 1) - speed / 2;
}
/**
* Controla a mudança de altitude da aeronave.
* Valor padrão: Mudança aleatória entre subir, descer ou manter altitude
* Dica: Uma boa estratégia pode aumentar suas chances de esquiva
*/
@Override
public int changeAltitude() {
int direction = random.nextInt(3) - 1; // -1 (descer), 0 (manter), 1 (subir)
this.posY = Math.max(0, Math.min(maxAltitude, posY + direction));
return direction;
}
/**
* Tiro normal - mais frequente, menos dano
*/
@Override
public Projectile shoot(int posX, int direction) {
return new Projectile(posX, this.posY, direction, 1, "<-");
}
/**
* Tiro supersônico - mais rápido, mais dano
*/
@Override
public Projectile shootSupersonic(int posX, int direction) {
return new Projectile(posX, this.posY, direction, 2, "<<");
}
/**
* Míssil especial - muito dano, com cooldown
*/
@Override
public Projectile specialMissile(int posX, int direction) {
if (missileCooldown == 0) {
missileCooldown = 3; // Espera 3 turnos para usar novamente
return new Projectile(posX, this.posY, direction, 1, "<=");
}
missileCooldown--;
return null;
}
/**
* Tiro duplo - ataca em duas altitudes diferentes
*/
@Override
public Projectile doubleShot(int posX, int direction) {
// Define a segunda altitude para o tiro (diferente da atual)
int currentAlt = this.posY;
int secondAlt = (currentAlt + 1) % (maxAltitude + 1);
// Guarda essa altitude para ser usada pelo BattleMain
this.secondShotAltitude = secondAlt;
// Retorna o projétil principal
return new Projectile(posX, this.posY, direction, 1, "⇇");
}
/**
* Míssil nuclear - dano massivo
*/
@Override
public Projectile nuclearMissile(int posX, int direction) {
if (missileCooldown == 0) {
missileCooldown = 5; // Longo cooldown para o poder nuclear
return new Projectile(posX, this.posY, direction, 1, "<[=-");
}
return null;
}
/**
* Radar - detecta projéteis inimigos
*/
@Override
public void radarScan(ArrayList<Projectile> projectiles, int enemyPosX, int enemyPosY) {
// Implementação básica: apenas detecta projéteis próximos
// Em uma implementação mais avançada, você poderia usar essas informações
// para ajustar seu movimento e evitar projéteis
}
}'''
# Código base das classes Aircraft e Projectile
aircraft_code = """
import java.util.ArrayList;
public abstract class Aircraft {
protected int health; // Agora definido externamente
protected int speed;
protected int fireRate;
protected int maneuverability;
protected int shotPower;
protected int supersonicPower;
protected int missilePower;
protected int defense;
protected int stealthChance;
protected int radar;
protected int doubleShot;
protected int doubleShotPower;
protected int nuclearPower;
protected int secondShotAltitude = -1;
protected int missileCooldown = 0;
protected int posY = 1;
protected String symbol;
protected static final int TOTAL_POINTS = 100;
public Aircraft(int speed, int fireRate, int maneuverability, int shotPower, int supersonicPower,
int missilePower, int defense, int stealthChance, int radar, int doubleShot,
int nuclearPower, String symbol) {
this.health = 100; // Valor padrão que será substituído
this.speed = speed;
this.fireRate = fireRate;
this.maneuverability = maneuverability;
this.shotPower = shotPower;
this.supersonicPower = supersonicPower;
this.missilePower = missilePower;
this.defense = defense;
this.stealthChance = stealthChance;
this.radar = radar;
this.doubleShot = doubleShot;
this.doubleShotPower = doubleShot;
this.nuclearPower = nuclearPower;
this.symbol = symbol;
validateAttributes();
}
public void setInitialHealth(int health) {
this.health = health;
}
private void validateAttributes() {
int total = speed + fireRate + maneuverability + shotPower + supersonicPower +
missilePower + defense + stealthChance + radar + doubleShot + nuclearPower;
if (total > TOTAL_POINTS) {
throw new IllegalArgumentException("Erro: A soma dos atributos excede " + TOTAL_POINTS + " pontos! Total: " + total);
}
}
public abstract int move();
public abstract int changeAltitude();
public abstract Projectile shoot(int posX, int direction);
public abstract Projectile shootSupersonic(int posX, int direction);
public abstract Projectile specialMissile(int posX, int direction);
public abstract Projectile doubleShot(int posX, int direction);
public abstract Projectile nuclearMissile(int posX, int direction);
public abstract void radarScan(ArrayList<Projectile> projectiles, int enemyPosX, int enemyPosY);
public int getHealth() {
return health;
}
public void takeDamage(int damage) {
this.health -= Math.max(0, damage - (defense / 10));
}
public boolean isAlive() {
return health > 0;
}
public int getPositionY() {
return posY;
}
public int getSecondShotAltitude() {
int alt = secondShotAltitude;
secondShotAltitude = -1; // Reset após uso
return alt;
}
}
"""
projectile_code = """
public class Projectile {
int posX;
int posY;
int direction;
int speed;
String symbol;
int power = 0; // Poder do projétil, usado para dano personalizado
public Projectile(int posX, int posY, int direction, int speed, String symbol) {
this.posX = posX;
this.posY = posY;
this.direction = direction;
this.speed = speed;
this.symbol = symbol;
}
public Projectile(int posX, int posY, int direction, int speed, String symbol, int power) {
this(posX, posY, direction, speed, symbol);
this.power = power;
}
public void move() {
posX += direction * speed;
}
public boolean isOutOfBounds(int screenWidth) {
return (posX < 0 || posX >= screenWidth);
}
public int getPower() {
return power;
}
}
"""
def run_battle(code1, code2, screen_width, battlefield_height, p1_start_pos, p2_start_pos, team1_health, team2_health):
# Caminhos dos arquivos Java
aircraft_path = "combat_classes/Aircraft.java"
projectile_path = "combat_classes/Projectile.java"
class1_path = "combat_classes/Team1Aircraft.java"
class2_path = "combat_classes/Team2Aircraft.java"
main_path = "combat_classes/BattleMain.java"
# Gerar o código do BattleMain com os parâmetros configuráveis
battle_main_code = f"""
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
public class BattleMain {{
public static void main(String[] args) {{
// Definir a altura do campo como propriedade do sistema
System.setProperty("battlefield.height", "{battlefield_height}");
Aircraft team1 = new Team1Aircraft();
Aircraft team2 = new Team2Aircraft();
// Definir a vida inicial de cada aeronave
team1.setInitialHealth({team1_health});
team2.setInitialHealth({team2_health});
Random random = new Random();
int p1PosX = {p1_start_pos};
int p2PosX = {p2_start_pos};
int screenWidth = {screen_width};
int battlefieldHeight = {battlefield_height};
ArrayList<Projectile> projectiles = new ArrayList<>();
// Inicializar as altitudes das naves em uma posição média do campo
team1.posY = battlefieldHeight / 2;
team2.posY = battlefieldHeight / 2;
while (team1.isAlive() && team2.isAlive()) {{
System.out.println("\\n=== NOVO TURNO ===");
System.out.flush();
String[][] battlefield = new String[battlefieldHeight][screenWidth];
for (int row = 0; row < battlefieldHeight; row++) {{
for (int i = 0; i < screenWidth; i++) {{
battlefield[row][i] = " ";
}}
}}
// Radar scan para detectar projéteis
team1.radarScan(projectiles, p2PosX, team2.getPositionY());
team2.radarScan(projectiles, p1PosX, team1.getPositionY());
// Movimento das aeronaves
p1PosX += team1.move();
p2PosX += team2.move();
p1PosX = Math.max(0, Math.min(screenWidth - 1, p1PosX));
p2PosX = Math.max(0, Math.min(screenWidth - 1, p2PosX));
// Mudança de altitude
team1.changeAltitude();
team2.changeAltitude();
// Garantir que a altitude não exceda o novo tamanho do campo de batalha
team1.posY = Math.min(team1.posY, battlefieldHeight - 1);
team2.posY = Math.min(team2.posY, battlefieldHeight - 1);
// Atirar para Time 1
if (random.nextInt(10) < team1.fireRate) {{
Projectile shot = null;
int shotType = random.nextInt(100);
// Escolha aleatória do tipo de tiro baseado na probabilidade
if (shotType < 5 && team1.nuclearPower > 0) {{
// Tiro nuclear (baixa probabilidade)
shot = team1.nuclearMissile(p1PosX, 1);
if (shot != null) {{
System.out.println("☢️ Time 1 lançou um MÍSSIL NUCLEAR!");
}}
}} else if (shotType < 15 && team1.doubleShot > 0) {{
// Tiro duplo
shot = team1.doubleShot(p1PosX, 1);
if (shot != null) {{
System.out.println("➡️ Time 1 disparou um TIRO DUPLO!");
// Adicionar o segundo projétil em uma altitude diferente
int secAlt = team1.getSecondShotAltitude();
if (secAlt >= 0 && secAlt < battlefieldHeight) {{
projectiles.add(new Projectile(p1PosX, secAlt, 1, 1, "->", team1.doubleShotPower));
}}
}}
}} else if (shotType < 30) {{
// Míssil especial
shot = team1.specialMissile(p1PosX, 1);
}} else if (shotType < 60) {{
// Tiro supersônico
shot = team1.shootSupersonic(p1PosX, 1);
}} else {{
// Tiro normal
shot = team1.shoot(p1PosX, 1);
}}
if (shot != null) {{
// Garantir que a altitude do projétil não exceda o campo de batalha
shot.posY = Math.min(shot.posY, battlefieldHeight - 1);
projectiles.add(shot);
}}
}}
// Atirar para Time 2
if (random.nextInt(10) < team2.fireRate) {{
Projectile shot = null;
int shotType = random.nextInt(100);
// Escolha aleatória do tipo de tiro baseado na probabilidade
if (shotType < 5 && team2.nuclearPower > 0) {{
// Tiro nuclear (baixa probabilidade)
shot = team2.nuclearMissile(p2PosX, -1);
if (shot != null) {{
System.out.println("☢️ Time 2 lançou um MÍSSIL NUCLEAR!");
}}
}} else if (shotType < 15 && team2.doubleShot > 0) {{
// Tiro duplo
shot = team2.doubleShot(p2PosX, -1);
if (shot != null) {{
System.out.println("⬅️ Time 2 disparou um TIRO DUPLO!");
// Adicionar o segundo projétil em uma altitude diferente
int secAlt = team2.getSecondShotAltitude();
if (secAlt >= 0 && secAlt < battlefieldHeight) {{
projectiles.add(new Projectile(p2PosX, secAlt, -1, 1, "<-", team2.doubleShotPower));
}}
}}
}} else if (shotType < 30) {{
// Míssil especial
shot = team2.specialMissile(p2PosX, -1);
}} else if (shotType < 60) {{
// Tiro supersônico
shot = team2.shootSupersonic(p2PosX, -1);
}} else {{
// Tiro normal
shot = team2.shoot(p2PosX, -1);
}}
if (shot != null) {{
// Garantir que a altitude do projétil não exceda o campo de batalha
shot.posY = Math.min(shot.posY, battlefieldHeight - 1);
projectiles.add(shot);
}}
}}
// Posicionar aeronaves no campo de batalha com cores
battlefield[team1.getPositionY()][p1PosX] = "\u001B[34m" + team1.symbol + "\u001B[0m"; // Azul para Time 1
battlefield[team2.getPositionY()][p2PosX] = "\u001B[31m" + team2.symbol + "\u001B[0m"; // Vermelho para Time 2
// Mover projéteis e verificar colisões
Iterator<Projectile> iterator = projectiles.iterator();
while (iterator.hasNext()) {{
Projectile p = iterator.next();
p.move();
// Verificar colisões com Time 1
if (p.posX == p1PosX && p.posY == team1.getPositionY()) {{
int damage = 0;
// Verificar se o projétil tem poder personalizado
if (p.getPower() > 0) {{
damage = p.getPower();
}} else if (p.symbol.contains("<[=-")) {{ // Míssil nuclear do Time 2
damage = team2.nuclearPower * 2;
System.out.println("💥💥💥 MÍSSIL NUCLEAR do Time 2 atingiu o Time 1!");
}} else if (p.symbol.contains("⇇")) {{ // Tiro duplo do Time 2
damage = team2.doubleShotPower;
}} else if (p.symbol.equals("<=")) {{
damage = team2.missilePower;
}} else if (p.symbol.equals("<<")) {{
damage = team2.supersonicPower;
}} else {{
damage = team2.shotPower;
}}
if (random.nextInt(100) >= team1.stealthChance) {{
team1.takeDamage(damage);
System.out.println("💥 Aeronave do Time 1 atingida! -" + damage + " pontos");
}} else {{
System.out.println("👻 Aeronave do Time 1 esquivou!");
if (team1.radar > 0) {{
System.out.println("📡 Radar do Time 1 detectou o projétil!");
}}
}}
iterator.remove();
continue;
}}
// Verificar colisões com Time 2
if (p.posX == p2PosX && p.posY == team2.getPositionY()) {{
int damage = 0;
// Verificar se o projétil tem poder personalizado
if (p.getPower() > 0) {{
damage = p.getPower();
}} else if (p.symbol.contains("-]=>")) {{ // Míssil nuclear do Time 1
damage = team1.nuclearPower * 2;
System.out.println("💥💥💥 MÍSSIL NUCLEAR do Time 1 atingiu o Time 2!");
}} else if (p.symbol.contains("⇉")) {{ // Tiro duplo do Time 1
damage = team1.doubleShotPower;
}} else if (p.symbol.equals("=>")) {{
damage = team1.missilePower;
}} else if (p.symbol.equals(">>")) {{
damage = team1.supersonicPower;
}} else {{
damage = team1.shotPower;
}}
if (random.nextInt(100) >= team2.stealthChance) {{
team2.takeDamage(damage);
System.out.println("💥 Aeronave do Time 2 atingida! -" + damage + " pontos");
}} else {{
System.out.println("👻 Aeronave do Time 2 esquivou!");
if (team2.radar > 0) {{
System.out.println("📡 Radar do Time 2 detectou o projétil!");
}}
}}
iterator.remove();
continue;
}}
// Remover projéteis fora dos limites
if (p.isOutOfBounds(screenWidth)) {{
iterator.remove();
continue;
}}
// Mostrar projéteis no campo de batalha com cores
if (p.posX >= 0 && p.posX < screenWidth && p.posY >= 0 && p.posY < battlefieldHeight) {{
// Adicionar cores aos projéteis baseado na direção
if (p.direction > 0) {{
battlefield[p.posY][p.posX]