rmayormartins commited on
Commit
b3b7541
·
1 Parent(s): 9855827
Files changed (1) hide show
  1. app.py +305 -3
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] = "\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,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()