import gradio as gr import os import subprocess import time from collections import deque import shutil import re def format_colors(text): """Remove todos os códigos de cor e deixa apenas texto puro""" import re # Remover qualquer código ANSI ansi_pattern = r'\x1b\[[0-9;]*m|\[([0-9;]*)m' text = re.sub(ansi_pattern, '', text) # Remover códigos unicode de escape text = text.replace("\\u001B[31m", "") text = text.replace("\\u001B[34m", "") text = text.replace("\\u001B[32m", "") text = text.replace("\\u001B[0m", "") # Remover códigos sem escape text = text.replace("[31m", "") text = text.replace("[34m", "") text = text.replace("[32m", "") text = text.replace("[0m", "") # NÃO alterar os símbolos das aeronaves - deixar como estão # > e < são as aeronaves e devem aparecer normalmente return text def check_and_install_java(): """Verifica se Java está instalado e tenta instalar se necessário""" try: # Verificar se javac está disponível result = subprocess.run(["javac", "-version"], capture_output=True, text=True) if result.returncode == 0: return True, "Java já está instalado" except FileNotFoundError: pass try: # Tentar instalar Java usando apt-get print("🔧 Instalando Java...") subprocess.run(["apt-get", "update"], check=True, capture_output=True) subprocess.run(["apt-get", "install", "-y", "default-jdk"], check=True, capture_output=True) # Verificar se a instalação funcionou result = subprocess.run(["javac", "-version"], capture_output=True, text=True) if result.returncode == 0: return True, "Java instalado com sucesso" except Exception as e: pass # Se chegou até aqui, não conseguiu instalar return False, "Não foi possível instalar Java automaticamente" # Verificar Java na inicialização java_available, java_message = check_and_install_java() print(f"Status do Java: {java_message}") # 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) * * SÍMBOLOS: * - Aeronave: T1 (Time 1) * - Tiro normal: -> * - Tiro supersônico: >> * - Míssil especial: => * - Tiro duplo: => * - Míssil nuclear: -N-> */ 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 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) * * SÍMBOLOS: * - Aeronave: T2 (Time 2) * - Tiro normal: <- * - Tiro supersônico: << * - Míssil especial: <= * - Tiro duplo: <= * - Míssil nuclear: <-N- */ 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 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 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): # Verificar se Java está disponível if not java_available: yield f"""

❌ Java não está disponível

Este aplicativo requer Java para compilar e executar as aeronaves.

Soluções:

  • Execute localmente com Java instalado
  • Use um ambiente Docker com Java
  • Aguarde enquanto tentamos instalar Java automaticamente...

Status: {java_message}

""" return # 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 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 MISSIL 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 MISSIL 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 sem cores battlefield[team1.getPositionY()][p1PosX] = team1.symbol; // Time 1 battlefield[team2.getPositionY()][p2PosX] = team2.symbol; // Time 2 // Mover projéteis e verificar colisões Iterator 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("<-N-")) {{ // Míssil nuclear do Time 2 damage = team2.nuclearPower * 2; System.out.println("!!! MISSIL 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("-N->")) {{ // Míssil nuclear do Time 1 damage = team1.nuclearPower * 2; System.out.println("!!! MISSIL 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 sem cores if (p.posX >= 0 && p.posX < screenWidth && p.posY >= 0 && p.posY < battlefieldHeight) {{ battlefield[p.posY][p.posX] = p.symbol; }} }} // Mostrar campo de batalha for (int row = 0; row < battlefieldHeight; row++) {{ for (int i = 0; i < screenWidth; i++) {{ System.out.print(battlefield[row][i]); }} System.out.println(); }} // Mostrar status de vida e posições das aeronaves System.out.println("Vida Time 1: " + team1.getHealth() + " | Vida Time 2: " + team2.getHealth()); System.out.println("Posições - Time 1: (" + p1PosX + "," + team1.getPositionY() + ") | Time 2: (" + p2PosX + "," + team2.getPositionY() + ")"); System.out.flush(); // Pausa para visualização try {{ Thread.sleep(200); }} catch (InterruptedException e) {{ System.err.println("Erro na pausa: " + e.getMessage()); }} }} if (team1.isAlive()) {{ System.out.println("*** Time 1 venceu! ***"); }} else {{ System.out.println("*** Time 2 venceu! ***"); }} System.out.flush(); }} }}""" # Salvar os arquivos Java with open(aircraft_path, "w") as f: f.write(aircraft_code) with open(projectile_path, "w") as f: f.write(projectile_code) with open(class1_path, "w") as f1: f1.write(code1) with open(class2_path, "w") as f2: f2.write(code2) with open(main_path, "w") as f_main: f_main.write(battle_main_code) try: # Compilar os arquivos Java for java_file in [aircraft_path, projectile_path, class1_path, class2_path, main_path]: compile_result = subprocess.run(["javac", "-cp", "combat_classes", "-d", "combat_classes", java_file], capture_output=True, text=True) if compile_result.returncode != 0: return f"❌ Erro na compilação:\\n{compile_result.stderr}" # Executar a simulação process = subprocess.Popen( ["java", "-cp", "combat_classes", "BattleMain"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1 ) # Usar deque para manter os últimos turnos na visualização turnos = deque(maxlen=4) # Últimos 4 turnos para visualização fluida # Guardar saída completa saida_completa = "" turno_atual = "" coletando_turno = False resultado_final = None for line in iter(process.stdout.readline, ""): saida_completa += line # Detectar novo turno if "=== NOVO TURNO ===" in line: if turno_atual: turnos.append(turno_atual) turno_atual = line coletando_turno = True elif coletando_turno: turno_atual += line # Verificar se é o resultado final if "venceu" in line: resultado_final = line # Atualizar a cada turno texto = "".join(list(turnos)) + turno_atual # Conversão de cores usando função robusta formatted_texto = format_colors(texto) # Script de scroll scroll_js = """ """ html_output = f"""
{formatted_texto}
{scroll_js} """ yield html_output time.sleep(0.05) # Ao final, mostrar resultado destacado if resultado_final: # Usar função robusta para formatar cores formatted_saida = format_colors(saida_completa) vencedor = "Time 1" if "Time 1 venceu" in resultado_final else "Time 2" cor = "blue" if vencedor == "Time 1" else "red" final_scroll_js = """ """ final_html = f"""

🏆 {vencedor} VENCEU! 🏆

Histórico Completo da Batalha:

{formatted_saida}
{final_scroll_js}
""" yield final_html except Exception as e: yield f"⚠ Erro inesperado: {str(e)}" # Funções para carregar templates def load_team1_template(): return TEAM1_TEMPLATE def load_team2_template(): return TEAM2_TEMPLATE # Função para preparar e executar a batalha def prepare_battle(code1, code2, width, height, p1_pos, p2_auto, p2_pos, t1_health, t2_health): # Se a posição do Time 2 é automática, calcule-a com base na largura final_p2_pos = width - 2 if p2_auto else p2_pos # Executar a simulação e retornar o iterador for output in run_battle(code1, code2, width, height, p1_pos, final_p2_pos, t1_health, t2_health): yield output # Interface Gradio with gr.Blocks(title="Java Air Combat", theme=gr.themes.Soft()) as app: gr.Markdown("# ⯐🛦🛧 JAVA-Aircraft-Combat - Time 1 vs Time 2") gr.Markdown(""" ## Instruções Rápidas 1. Use os botões "Carregar Template" para obter um modelo editável para cada time 2. Personalize os atributos da aeronave (máximo de 100 pontos) 3. Configure a arena no painel de configurações abaixo se desejar 4. Clique em "🔥 Combate!" para iniciar a batalha **NOVIDADES**: Agora suas aeronaves podem ter radar para detectar projéteis, tiro duplo para atacar em duas altitudes diferentes e até mísseis nucleares para dano massivo! """) with gr.Row(): with gr.Column(): team1_code = gr.Textbox(label="🟦 Código Time 1", lines=20, placeholder="Clique em 'Carregar Template Time 1' para começar") team1_template_btn = gr.Button("📝 Carregar Template Time 1", variant="secondary") with gr.Column(): team2_code = gr.Textbox(label="🟥 Código Time 2", lines=20, placeholder="Clique em 'Carregar Template Time 2' para começar") team2_template_btn = gr.Button("📝 Carregar Template Time 2", variant="secondary") # Conectar botões às funções team1_template_btn.click(load_team1_template, inputs=[], outputs=team1_code) team2_template_btn.click(load_team2_template, inputs=[], outputs=team2_code) with gr.Accordion("⚙️ Configurações da Arena", open=False): with gr.Row(): screen_width = gr.Slider(minimum=50, maximum=200, value=100, step=10, label="Largura da Tela", info="Define a largura do campo de batalha") battlefield_height = gr.Slider(minimum=3, maximum=7, value=3, step=1, label="Altura do Campo", info="Define o número de linhas no campo de batalha") with gr.Row(): p1_start_pos = gr.Slider(minimum=0, maximum=49, value=2, step=1, label="Posição Inicial Time 1", info="Define onde o Time 1 começa na arena") p2_start_pos_auto = gr.Checkbox(label="Posicionar Time 2 automaticamente", info="Se marcado, o Time 2 será posicionado no lado oposto", value=True) p2_start_pos = gr.Slider(minimum=51, maximum=200, value=98, step=1, label="Posição Inicial Time 2", info="Define onde o Time 2 começa na arena", visible=False) with gr.Row(): team1_health = gr.Slider(minimum=50, maximum=500, value=100, step=10, label="❤️ Vida Time 1", info="Define a vida inicial da aeronave do Time 1") team2_health = gr.Slider(minimum=50, maximum=500, value=100, step=10, label="❤️ Vida Time 2", info="Define a vida inicial da aeronave do Time 2") # Botão para equalizar as vidas def equalize_health(health_value): return health_value, health_value equalize_btn = gr.Button("🔄 Igualar Vidas", variant="secondary") equalize_btn.click(fn=equalize_health, inputs=team1_health, outputs=[team1_health, team2_health]) # Lógica para mostrar/esconder a posição do Time 2 def toggle_p2_pos(auto_checked): return {"visible": not auto_checked} p2_start_pos_auto.change(toggle_p2_pos, inputs=p2_start_pos_auto, outputs=p2_start_pos) # Atualizar posição do Time 2 automaticamente com base na largura da tela def update_p2_pos(width): return width - 2 screen_width.change(update_p2_pos, inputs=screen_width, outputs=p2_start_pos) btn = gr.Button("🔥 Combate!", variant="primary", size="lg") # Configurar o componente HTML css = """ """ output = gr.HTML(label="Resultado do Combate", elem_id="battle-result", value=css) # Conectar o botão à função btn.click(fn=prepare_battle, inputs=[team1_code, team2_code, screen_width, battlefield_height, p1_start_pos, p2_start_pos_auto, p2_start_pos, team1_health, team2_health], outputs=output) # Adicionar informações de rodapé gr.Markdown(""" ### Dicas - Equilibre seus pontos! Uma distribuição balanceada geralmente é melhor. - Lembre que cada atributo tem limites (indicados nos comentários). - O radar permite detectar projéteis inimigos e realizar manobras evasivas automáticas. - O tiro duplo ataca em duas altitudes ao mesmo tempo, aumentando suas chances de acerto. - O míssil nuclear causa dano massivo, mas tem um longo cooldown de 5 turnos. - Use toda a altura do campo (configure nas opções) para estratégias mais interessantes! - Agora você pode ajustar a vida inicial das aeronaves para batalhas mais longas ou equilibrar times desiguais! Desenvolvido para a disciplina de Programação. Bons combates! """) if __name__ == "__main__": app.launch()