File size: 5,528 Bytes
a2f6240
 
 
c79a44e
a2f6240
 
 
 
 
 
 
 
 
 
c79a44e
a2f6240
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c79a44e
a2f6240
c79a44e
a2f6240
 
 
 
 
 
 
 
c79a44e
a2f6240
c79a44e
 
 
 
a2f6240
 
 
 
 
 
 
c79a44e
a2f6240
 
 
c79a44e
a2f6240
 
c79a44e
a2f6240
 
 
 
 
c79a44e
a2f6240
 
 
c79a44e
a2f6240
 
c79a44e
a2f6240
 
c79a44e
 
a2f6240
 
 
 
 
 
 
 
 
c79a44e
 
 
a2f6240
c79a44e
 
a2f6240
 
c79a44e
 
a2f6240
 
c79a44e
a2f6240
c79a44e
 
 
 
 
 
 
 
a2f6240
 
 
 
 
c79a44e
a2f6240
c79a44e
 
 
 
 
a2f6240
 
c79a44e
a2f6240
c79a44e
a2f6240
 
c79a44e
 
a2f6240
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import gradio as gr
import time

# Dados baseados na sua versão 1.4 EN
GRID_NUMBERS = [
    10, 12, 14, 15, 16, 18, 20, 21,
    24, 25, 27, 28, 30, 32, 35, 36,
    40, 42, 45, 48, 50, 54, 56, 60,
    63, 64, 70, 72, 80, 81, 90, 100
]
KEYBOARD_KEYS = [2, 3, 4, 5, 6, 7, 8, 9, 10]
MAX_TIME = 150

def get_empty_state():
    """Inicializa o estado conforme o script original"""
    return {
        "solved": [False] * 32,
        "selected_idx": None,
        "current_factors": [],
        "start_time": time.time(),
        "game_over": False,
        "score": MAX_TIME
    }

def format_grid_button(idx, solved_list, selected_idx):
    label = str(GRID_NUMBERS[idx])
    if solved_list[idx]:
        return gr.update(value=f"✅ {label}", variant="success", interactive=False)
    if selected_idx == idx:
        return gr.update(variant="primary", interactive=True)
    return gr.update(value=label, variant="secondary", interactive=True)

def handle_game_logic(state, action_type, value=None):
    if state["game_over"]:
        return state, "Fim de jogo! Reinicie para jogar novamente."

    feedback = "Selecione um número na grade..."
    
    if action_type == "select_target":
        state["selected_idx"] = value
        state["current_factors"] = []
        feedback = f"Fatorar o número: {GRID_NUMBERS[value]}"
        
    elif action_type == "select_factor":
        if state["selected_idx"] is None:
            feedback = "⚠️ Selecione um número na grade primeiro!"
        else:
            state["current_factors"].append(int(value))
            # Mostra os fatores atuais
            factors_str = " x ".join(map(str, state["current_factors"]))
            feedback = f"Calculando: {factors_str}"
            
            if len(state["current_factors"]) == 2:
                a, b = state["current_factors"]
                target = GRID_NUMBERS[state["selected_idx"]]
                
                if a * b == target:
                    state["solved"][state["selected_idx"]] = True
                    feedback = f"✔️ {a} x {b} = {target}! Correto!"
                    state["selected_idx"] = None
                    state["current_factors"] = []
                else:
                    feedback = f"❌ {a} x {b} = {a*b} (Errado para {target}). Tente de novo!"
                    state["current_factors"] = []

    # Atualiza Score e Verifica Conclusão
    elapsed = int(time.time() - state["start_time"])
    state["score"] = max(0, MAX_TIME - elapsed)
    
    if all(state["solved"]):
        state["game_over"] = True
        feedback = f"🏆 PARABÉNS! Você completou a grade com {state['score']} pontos!"

    return state, feedback

with gr.Blocks(title="Interactive Factorization v1.4", css=".grid-btn { height: 70px !important; }") as demo:
    state = gr.State(get_empty_state())
    
    gr.Markdown(f"# 🎮 Interactive Factorization - Marcos Autúori")
    
    with gr.Row():
        with gr.Column(scale=3):
            # Grade de Números (4x8)
            grid_buttons = []
            for r in range(4):
                with gr.Row():
                    for c in range(8):
                        idx = r * 8 + c
                        btn = gr.Button(str(GRID_NUMBERS[idx]), elem_classes="grid-btn")
                        grid_buttons.append(btn)
        
        with gr.Column(scale=1):
            # Painel Lateral de Status
            status_box = gr.Textbox(label="Instruções / Feedback", value="Clique em um número azul para começar", interactive=False)
            score_display = gr.Number(label="Pontuação", value=MAX_TIME, interactive=False)
            
            gr.Markdown("### Teclado de Fatores")
            # Criamos os botões do teclado e vinculamos a lógica
            keyboard_btns = []
            with gr.Row():
                for val in KEYBOARD_KEYS:
                    kb_btn = gr.Button(str(val), variant="secondary", min_width=50)
                    keyboard_btns.append(kb_btn)
            
            reset_btn = gr.Button("Reiniciar Partida", variant="stop")

    # --- MAPEAMENTO DE EVENTOS ---

    # Função auxiliar para atualizar visualmente toda a interface
    def update_ui(s):
        updates = [format_grid_button(i, s["solved"], s["selected_idx"]) for i in range(32)]
        return updates + [s["score"]]

    # Clique na Grade
    for i, btn in enumerate(grid_buttons):
        btn.click(
            fn=lambda s, idx=i: handle_game_logic(s, "select_target", idx),
            inputs=[state],
            outputs=[state, status_box]
        ).then(fn=update_ui, inputs=[state], outputs=grid_buttons + [score_display])

    # Clique no Teclado (Correção da Closure aqui)
    for kb_btn in keyboard_btns:
        # Usamos o próprio valor do botão como entrada para garantir que o número correto seja enviado
        kb_btn.click(
            fn=lambda s, v=kb_btn.value: handle_game_logic(s, "select_factor", v),
            inputs=[state],
            outputs=[state, status_box]
        ).then(fn=update_ui, inputs=[state], outputs=grid_buttons + [score_display])

    # Função de Reset
    def reset_all():
        new_state = get_empty_state()
        updates = [gr.update(value=str(num), variant="secondary", interactive=True) for num in GRID_NUMBERS]
        return [new_state, "Jogo reiniciado!"] + updates + [MAX_TIME]

    reset_btn.click(
        fn=reset_all,
        outputs=[state, status_box] + grid_buttons + [score_display]
    )

if __name__ == "__main__":
    demo.launch()