Spaces:
Sleeping
Sleeping
Commit
·
b3b7541
1
Parent(s):
9855827
a2
Browse files
app.py
CHANGED
@@ -577,8 +577,8 @@ public class BattleMain {{
|
|
577 |
}}
|
578 |
|
579 |
// Posicionar aeronaves no campo de batalha com cores
|
580 |
-
battlefield[team1.getPositionY()][p1PosX] = "
|
581 |
-
battlefield[team2.getPositionY()][p2PosX] = "
|
582 |
|
583 |
// Mover projéteis e verificar colisões
|
584 |
Iterator<Projectile> iterator = projectiles.iterator();
|
@@ -662,4 +662,306 @@ public class BattleMain {{
|
|
662 |
if (p.posX >= 0 && p.posX < screenWidth && p.posY >= 0 && p.posY < battlefieldHeight) {{
|
663 |
// Adicionar cores aos projéteis baseado na direção
|
664 |
if (p.direction > 0) {{
|
665 |
-
battlefield[p.posY][p.posX]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
577 |
}}
|
578 |
|
579 |
// Posicionar aeronaves no campo de batalha com cores
|
580 |
+
battlefield[team1.getPositionY()][p1PosX] = "\\u001B[34m" + team1.symbol + "\\u001B[0m"; // Azul para Time 1
|
581 |
+
battlefield[team2.getPositionY()][p2PosX] = "\\u001B[31m" + team2.symbol + "\\u001B[0m"; // Vermelho para Time 2
|
582 |
|
583 |
// Mover projéteis e verificar colisões
|
584 |
Iterator<Projectile> iterator = projectiles.iterator();
|
|
|
662 |
if (p.posX >= 0 && p.posX < screenWidth && p.posY >= 0 && p.posY < battlefieldHeight) {{
|
663 |
// Adicionar cores aos projéteis baseado na direção
|
664 |
if (p.direction > 0) {{
|
665 |
+
battlefield[p.posY][p.posX] = "\\u001B[34m" + p.symbol + "\\u001B[0m"; // Azul para Time 1
|
666 |
+
}} else {{
|
667 |
+
battlefield[p.posY][p.posX] = "\\u001B[31m" + p.symbol + "\\u001B[0m"; // Vermelho para Time 2
|
668 |
+
}}
|
669 |
+
}}
|
670 |
+
}}
|
671 |
+
|
672 |
+
// Mostrar campo de batalha
|
673 |
+
for (int row = 0; row < battlefieldHeight; row++) {{
|
674 |
+
for (int i = 0; i < screenWidth; i++) {{
|
675 |
+
System.out.print(battlefield[row][i]);
|
676 |
+
}}
|
677 |
+
System.out.println();
|
678 |
+
}}
|
679 |
+
|
680 |
+
// Mostrar status de vida
|
681 |
+
System.out.println("❤️ Vida Time 1: " + team1.getHealth() + " | ❤️ Vida Time 2: " + team2.getHealth());
|
682 |
+
System.out.flush();
|
683 |
+
|
684 |
+
// Pausa para visualização
|
685 |
+
try {{
|
686 |
+
Thread.sleep(200);
|
687 |
+
}} catch (InterruptedException e) {{
|
688 |
+
System.err.println("Erro na pausa: " + e.getMessage());
|
689 |
+
}}
|
690 |
+
}}
|
691 |
+
|
692 |
+
if (team1.isAlive()) {{
|
693 |
+
System.out.println("🏆 Time 1 venceu!");
|
694 |
+
}} else {{
|
695 |
+
System.out.println("🏆 Time 2 venceu!");
|
696 |
+
}}
|
697 |
+
System.out.flush();
|
698 |
+
}}
|
699 |
+
}}"""
|
700 |
+
|
701 |
+
# Salvar os arquivos Java
|
702 |
+
with open(aircraft_path, "w") as f:
|
703 |
+
f.write(aircraft_code)
|
704 |
+
with open(projectile_path, "w") as f:
|
705 |
+
f.write(projectile_code)
|
706 |
+
with open(class1_path, "w") as f1:
|
707 |
+
f1.write(code1)
|
708 |
+
with open(class2_path, "w") as f2:
|
709 |
+
f2.write(code2)
|
710 |
+
with open(main_path, "w") as f_main:
|
711 |
+
f_main.write(battle_main_code)
|
712 |
+
|
713 |
+
try:
|
714 |
+
# Compilar os arquivos Java
|
715 |
+
for java_file in [aircraft_path, projectile_path, class1_path, class2_path, main_path]:
|
716 |
+
compile_result = subprocess.run(["javac", "-cp", "combat_classes", "-d", "combat_classes", java_file], capture_output=True, text=True)
|
717 |
+
if compile_result.returncode != 0:
|
718 |
+
return f"❌ Erro na compilação:\\n{compile_result.stderr}"
|
719 |
+
|
720 |
+
# Executar a simulação
|
721 |
+
process = subprocess.Popen(
|
722 |
+
["java", "-cp", "combat_classes", "BattleMain"],
|
723 |
+
stdout=subprocess.PIPE,
|
724 |
+
stderr=subprocess.PIPE,
|
725 |
+
text=True,
|
726 |
+
bufsize=1
|
727 |
+
)
|
728 |
+
|
729 |
+
# Usar deque para manter os últimos turnos na visualização
|
730 |
+
turnos = deque(maxlen=4) # Últimos 4 turnos para visualização fluida
|
731 |
+
|
732 |
+
# Guardar saída completa
|
733 |
+
saida_completa = ""
|
734 |
+
turno_atual = ""
|
735 |
+
coletando_turno = False
|
736 |
+
resultado_final = None
|
737 |
+
|
738 |
+
for line in iter(process.stdout.readline, ""):
|
739 |
+
saida_completa += line
|
740 |
+
|
741 |
+
# Detectar novo turno
|
742 |
+
if "=== NOVO TURNO ===" in line:
|
743 |
+
if turno_atual:
|
744 |
+
turnos.append(turno_atual)
|
745 |
+
turno_atual = line
|
746 |
+
coletando_turno = True
|
747 |
+
elif coletando_turno:
|
748 |
+
turno_atual += line
|
749 |
+
|
750 |
+
# Verificar se é o resultado final
|
751 |
+
if "venceu" in line:
|
752 |
+
resultado_final = line
|
753 |
+
|
754 |
+
# Atualizar a cada turno
|
755 |
+
texto = "".join(list(turnos)) + turno_atual
|
756 |
+
|
757 |
+
# Conversão de cores
|
758 |
+
formatted_texto = texto.replace("\\033[31m", "<span style='color:red;'>")
|
759 |
+
formatted_texto = formatted_texto.replace("\\033[34m", "<span style='color:blue;'>")
|
760 |
+
formatted_texto = formatted_texto.replace("\\033[32m", "<span style='color:green;'>")
|
761 |
+
formatted_texto = formatted_texto.replace("\\033[0m", "</span>")
|
762 |
+
|
763 |
+
# Script de scroll
|
764 |
+
scroll_js = """
|
765 |
+
<script>
|
766 |
+
(function() {
|
767 |
+
function forceScrollBottom() {
|
768 |
+
const container = document.getElementById('battle-container');
|
769 |
+
if (container) {
|
770 |
+
container.scrollTop = container.scrollHeight * 10;
|
771 |
+
setTimeout(() => {
|
772 |
+
container.scrollTop = container.scrollHeight * 10;
|
773 |
+
}, 50);
|
774 |
+
}
|
775 |
+
}
|
776 |
+
forceScrollBottom();
|
777 |
+
const scrollInterval = setInterval(forceScrollBottom, 100);
|
778 |
+
setTimeout(() => { clearInterval(scrollInterval); }, 2000);
|
779 |
+
})();
|
780 |
+
</script>
|
781 |
+
"""
|
782 |
+
|
783 |
+
html_output = f"""
|
784 |
+
<div id="battle-container" style="height:400px; overflow:auto; border:1px solid #ccc; padding:10px;
|
785 |
+
font-family:monospace; white-space:pre; background-color:#f8f8f8;">
|
786 |
+
{formatted_texto}
|
787 |
+
</div>
|
788 |
+
{scroll_js}
|
789 |
+
"""
|
790 |
+
|
791 |
+
yield html_output
|
792 |
+
time.sleep(0.05)
|
793 |
+
|
794 |
+
# Ao final, mostrar resultado destacado
|
795 |
+
if resultado_final:
|
796 |
+
formatted_saida = saida_completa.replace("\\033[31m", "<span style='color:red;'>")
|
797 |
+
formatted_saida = formatted_saida.replace("\\033[34m", "<span style='color:blue;'>")
|
798 |
+
formatted_saida = formatted_saida.replace("\\033[32m", "<span style='color:green;'>")
|
799 |
+
formatted_saida = formatted_saida.replace("\\033[0m", "</span>")
|
800 |
+
|
801 |
+
vencedor = "Time 1" if "Time 1 venceu" in resultado_final else "Time 2"
|
802 |
+
cor = "blue" if vencedor == "Time 1" else "red"
|
803 |
+
|
804 |
+
final_scroll_js = """
|
805 |
+
<script>
|
806 |
+
(function() {
|
807 |
+
function finalForceScroll() {
|
808 |
+
const container = document.querySelector('#historico-completo');
|
809 |
+
if (container) {
|
810 |
+
container.scrollTop = container.scrollHeight * 20;
|
811 |
+
}
|
812 |
+
}
|
813 |
+
finalForceScroll();
|
814 |
+
for (let i = 1; i <= 20; i++) {
|
815 |
+
setTimeout(finalForceScroll, i * 100);
|
816 |
+
}
|
817 |
+
const scrollInterval = setInterval(finalForceScroll, 200);
|
818 |
+
setTimeout(() => { clearInterval(scrollInterval); }, 5000);
|
819 |
+
})();
|
820 |
+
</script>
|
821 |
+
"""
|
822 |
+
|
823 |
+
final_html = f"""
|
824 |
+
<div>
|
825 |
+
<div style="padding:15px; background-color:#e9f7e9; border:2px solid #4CAF50;
|
826 |
+
margin:15px 0; text-align:center; border-radius:5px;">
|
827 |
+
<h3 style="color:{cor}; margin:0; font-size:24px;">🏆 {vencedor} VENCEU! 🏆</h3>
|
828 |
+
</div>
|
829 |
+
|
830 |
+
<h4>Histórico Completo da Batalha:</h4>
|
831 |
+
|
832 |
+
<div id="historico-completo" style="height:500px; overflow:auto; border:1px solid #ccc; padding:10px;
|
833 |
+
font-family:monospace; white-space:pre; background-color:#f8f8f8;">
|
834 |
+
{formatted_saida}
|
835 |
+
</div>
|
836 |
+
{final_scroll_js}
|
837 |
+
</div>
|
838 |
+
"""
|
839 |
+
|
840 |
+
yield final_html
|
841 |
+
|
842 |
+
except Exception as e:
|
843 |
+
yield f"⚠ Erro inesperado: {str(e)}"
|
844 |
+
|
845 |
+
# Funções para carregar templates
|
846 |
+
def load_team1_template():
|
847 |
+
return TEAM1_TEMPLATE
|
848 |
+
|
849 |
+
def load_team2_template():
|
850 |
+
return TEAM2_TEMPLATE
|
851 |
+
|
852 |
+
# Função para preparar e executar a batalha
|
853 |
+
def prepare_battle(code1, code2, width, height, p1_pos, p2_auto, p2_pos, t1_health, t2_health):
|
854 |
+
# Se a posição do Time 2 é automática, calcule-a com base na largura
|
855 |
+
final_p2_pos = width - 2 if p2_auto else p2_pos
|
856 |
+
# Executar a simulação e retornar o iterador
|
857 |
+
for output in run_battle(code1, code2, width, height, p1_pos, final_p2_pos, t1_health, t2_health):
|
858 |
+
yield output
|
859 |
+
|
860 |
+
# Interface Gradio
|
861 |
+
with gr.Blocks(title="Java Air Combat", theme=gr.themes.Soft()) as app:
|
862 |
+
gr.Markdown("# ⯐🛦🛧 JAVA-Aircraft-Combat - Time 1 vs Time 2")
|
863 |
+
|
864 |
+
gr.Markdown("""
|
865 |
+
## Instruções Rápidas
|
866 |
+
|
867 |
+
1. Use os botões "Carregar Template" para obter um modelo editável para cada time
|
868 |
+
2. Personalize os atributos da aeronave (máximo de 100 pontos)
|
869 |
+
3. Configure a arena no painel de configurações abaixo se desejar
|
870 |
+
4. Clique em "🔥 Combate!" para iniciar a batalha
|
871 |
+
|
872 |
+
**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!
|
873 |
+
""")
|
874 |
+
|
875 |
+
with gr.Row():
|
876 |
+
with gr.Column():
|
877 |
+
team1_code = gr.Textbox(label="🟦 Código Time 1", lines=20, placeholder="Clique em 'Carregar Template Time 1' para começar")
|
878 |
+
team1_template_btn = gr.Button("📝 Carregar Template Time 1", variant="secondary")
|
879 |
+
|
880 |
+
with gr.Column():
|
881 |
+
team2_code = gr.Textbox(label="🟥 Código Time 2", lines=20, placeholder="Clique em 'Carregar Template Time 2' para começar")
|
882 |
+
team2_template_btn = gr.Button("📝 Carregar Template Time 2", variant="secondary")
|
883 |
+
|
884 |
+
# Conectar botões às funções
|
885 |
+
team1_template_btn.click(load_team1_template, inputs=[], outputs=team1_code)
|
886 |
+
team2_template_btn.click(load_team2_template, inputs=[], outputs=team2_code)
|
887 |
+
|
888 |
+
with gr.Accordion("⚙️ Configurações da Arena", open=False):
|
889 |
+
with gr.Row():
|
890 |
+
screen_width = gr.Slider(minimum=50, maximum=200, value=100, step=10,
|
891 |
+
label="Largura da Tela", info="Define a largura do campo de batalha")
|
892 |
+
battlefield_height = gr.Slider(minimum=3, maximum=7, value=3, step=1,
|
893 |
+
label="Altura do Campo", info="Define o número de linhas no campo de batalha")
|
894 |
+
|
895 |
+
with gr.Row():
|
896 |
+
p1_start_pos = gr.Slider(minimum=0, maximum=49, value=2, step=1,
|
897 |
+
label="Posição Inicial Time 1", info="Define onde o Time 1 começa na arena")
|
898 |
+
p2_start_pos_auto = gr.Checkbox(label="Posicionar Time 2 automaticamente",
|
899 |
+
info="Se marcado, o Time 2 será posicionado no lado oposto", value=True)
|
900 |
+
p2_start_pos = gr.Slider(minimum=51, maximum=200, value=98, step=1,
|
901 |
+
label="Posição Inicial Time 2", info="Define onde o Time 2 começa na arena",
|
902 |
+
visible=False)
|
903 |
+
|
904 |
+
with gr.Row():
|
905 |
+
team1_health = gr.Slider(minimum=50, maximum=500, value=100, step=10,
|
906 |
+
label="❤️ Vida Time 1", info="Define a vida inicial da aeronave do Time 1")
|
907 |
+
team2_health = gr.Slider(minimum=50, maximum=500, value=100, step=10,
|
908 |
+
label="❤️ Vida Time 2", info="Define a vida inicial da aeronave do Time 2")
|
909 |
+
|
910 |
+
# Botão para equalizar as vidas
|
911 |
+
def equalize_health(health_value):
|
912 |
+
return health_value, health_value
|
913 |
+
|
914 |
+
equalize_btn = gr.Button("🔄 Igualar Vidas", variant="secondary")
|
915 |
+
equalize_btn.click(fn=equalize_health, inputs=team1_health, outputs=[team1_health, team2_health])
|
916 |
+
|
917 |
+
# Lógica para mostrar/esconder a posição do Time 2
|
918 |
+
def toggle_p2_pos(auto_checked):
|
919 |
+
return {"visible": not auto_checked}
|
920 |
+
|
921 |
+
p2_start_pos_auto.change(toggle_p2_pos, inputs=p2_start_pos_auto, outputs=p2_start_pos)
|
922 |
+
|
923 |
+
# Atualizar posição do Time 2 automaticamente com base na largura da tela
|
924 |
+
def update_p2_pos(width):
|
925 |
+
return width - 2
|
926 |
+
|
927 |
+
screen_width.change(update_p2_pos, inputs=screen_width, outputs=p2_start_pos)
|
928 |
+
|
929 |
+
btn = gr.Button("🔥 Combate!", variant="primary", size="lg")
|
930 |
+
|
931 |
+
# Configurar o componente HTML
|
932 |
+
css = """
|
933 |
+
<style>
|
934 |
+
#battle-result .prose {
|
935 |
+
padding: 0 !important;
|
936 |
+
margin: 0 !important;
|
937 |
+
display: block !important;
|
938 |
+
visibility: visible !important;
|
939 |
+
}
|
940 |
+
</style>
|
941 |
+
"""
|
942 |
+
|
943 |
+
output = gr.HTML(label="Resultado do Combate", elem_id="battle-result", value=css)
|
944 |
+
|
945 |
+
# Conectar o botão à função
|
946 |
+
btn.click(fn=prepare_battle,
|
947 |
+
inputs=[team1_code, team2_code, screen_width, battlefield_height,
|
948 |
+
p1_start_pos, p2_start_pos_auto, p2_start_pos,
|
949 |
+
team1_health, team2_health],
|
950 |
+
outputs=output)
|
951 |
+
|
952 |
+
# Adicionar informações de rodapé
|
953 |
+
gr.Markdown("""
|
954 |
+
### Dicas
|
955 |
+
- Equilibre seus pontos! Uma distribuição balanceada geralmente é melhor.
|
956 |
+
- Lembre que cada atributo tem limites (indicados nos comentários).
|
957 |
+
- O radar permite detectar projéteis inimigos e realizar manobras evasivas automáticas.
|
958 |
+
- O tiro duplo ataca em duas altitudes ao mesmo tempo, aumentando suas chances de acerto.
|
959 |
+
- O míssil nuclear causa dano massivo, mas tem um longo cooldown de 5 turnos.
|
960 |
+
- Use toda a altura do campo (configure nas opções) para estratégias mais interessantes!
|
961 |
+
- Agora você pode ajustar a vida inicial das aeronaves para batalhas mais longas ou equilibrar times desiguais!
|
962 |
+
|
963 |
+
Desenvolvido para a disciplina de Programação. Bons combates!
|
964 |
+
""")
|
965 |
+
|
966 |
+
if __name__ == "__main__":
|
967 |
+
app.launch()
|