Madras1 commited on
Commit
0fb7cb2
·
verified ·
1 Parent(s): c6d15a3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -88
app.py CHANGED
@@ -9,11 +9,62 @@ import time
9
  # --- CONFIGURAÇÕES ---
10
  BOARD_SIZE = 8
11
  DEVICE = torch.device("cpu")
12
- MODEL_PATH = "checkers_master_final.pth" # Certifique-se de que este arquivo está no Space!
13
-
14
- # --- DEFINIÇÃO DAS CLASSES (Rede Neural e Jogo) ---
15
- # A Berta copiou a lógica exata do seu script para garantir que funcione igual.
16
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  class Checkers:
18
  def get_initial_board(self):
19
  board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=np.int8)
@@ -165,14 +216,8 @@ class MCTS:
165
  node.children[key] = MCTSNode(parent=node, prior=1.0 / len(valid_moves))
166
  return value
167
 
168
- # --- INTERFACE DO STREAMLIT ---
169
 
170
- st.set_page_config(page_title="AlphaCheckerZero", page_icon="♟️")
171
-
172
- st.title("♟️ AlphaCheckerZero Arena")
173
- st.write("Gabriel Yogi's Neural Network AI")
174
-
175
- # 1. Carregar o Modelo (com Cache para ser rápido)
176
  @st.cache_resource
177
  def load_model():
178
  if not os.path.exists(MODEL_PATH):
@@ -185,102 +230,115 @@ def load_model():
185
  model = load_model()
186
 
187
  if model is None:
188
- st.error(f"Arquivo '{MODEL_PATH}' não encontrado. Por favor, faça upload do arquivo .pth para o Space.")
189
  st.stop()
190
 
191
- # 2. Inicializar o Estado do Jogo
192
  if "board" not in st.session_state:
193
  game = Checkers()
194
  st.session_state.board = game.get_initial_board()
195
- st.session_state.player = 1 # Humano começa (1)
196
  st.session_state.game_over = False
197
- st.session_state.message = "Sua vez! Você joga com as Brancas (x)."
198
 
199
  game = Checkers()
200
- mcts = MCTS(game, model, sims=150) # Sims ajustado para performance na web
201
 
202
- # Função para desenhar o tabuleiro como texto (simples e funcional)
203
- def render_board(board):
204
- chars = {1: 'x', 2: 'X', -1: 'o', -2: 'O', 0: '.'}
205
- board_str = " 0 1 2 3 4 5 6 7\n"
206
- board_str += " -----------------\n"
207
- for r_idx, row in enumerate(board):
208
- board_str += f"{r_idx} | {' '.join(chars[val] for val in row)} |\n"
209
- board_str += " -----------------"
210
- return board_str
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
 
212
- # Layout principal
213
- col1, col2 = st.columns([2, 1])
214
 
215
  with col1:
216
- st.text_area("Tabuleiro", render_board(st.session_state.board), height=250, disabled=True, key="board_display")
217
 
218
  with col2:
219
- st.write("### Status")
220
- st.info(st.session_state.message)
221
-
222
- if st.button("Reiniciar Jogo"):
223
- st.session_state.board = game.get_initial_board()
224
- st.session_state.player = 1
225
- st.session_state.game_over = False
226
- st.session_state.message = "Jogo reiniciado. Sua vez!"
227
- st.rerun()
228
-
229
- # Lógica do Jogo
230
- if not st.session_state.game_over:
231
- # Verificar fim de jogo antes de qualquer coisa
232
- result = game.check_game_over(st.session_state.board, st.session_state.player)
233
- if result is not None:
234
- st.session_state.game_over = True
235
- if result == 1: st.session_state.message = "VOCÊ GANHOU! Parabéns Gabriel!"
236
- elif result == -1: st.session_state.message = "A IA GANHOU. Mais sorte na próxima."
237
- else: st.session_state.message = "EMPATE."
238
- st.rerun()
239
-
240
- # VEZ DO HUMANO (Player 1)
241
- if st.session_state.player == 1:
242
- valid_moves = game.get_valid_moves(st.session_state.board, 1)
243
-
244
- if not valid_moves:
245
- # Se não tem movimentos e não deu game over acima, algo estranho aconteceu, mas tratamos como derrota
246
- st.session_state.game_over = True
247
- st.session_state.message = "Sem movimentos válidos. Você perdeu."
248
- st.rerun()
249
-
250
- # Criar lista de strings para o Selectbox
251
- move_options = [str(m) for m in valid_moves]
252
- selected_move_str = st.selectbox("Escolha sua jogada:", move_options)
253
-
254
- if st.button("Jogar"):
255
- # Encontrar o movimento original baseado na string
256
- move_idx = move_options.index(selected_move_str)
257
- move = valid_moves[move_idx]
258
-
259
- # Aplicar movimento
260
- st.session_state.board = game.apply_move(st.session_state.board, move)
261
- st.session_state.player = -1 # Passa a vez para IA
262
- st.session_state.message = "A IA está pensando..."
263
  st.rerun()
264
-
265
- # VEZ DA IA (Player -1)
266
  else:
267
- with st.spinner("A AlphaCheckerZero está pensando..."):
268
- # Pequeno delay para a interface atualizar e mostrar a mensagem
269
- time.sleep(0.5)
270
-
271
- valid_moves, policy = mcts.run(np.copy(st.session_state.board), -1)
272
 
273
  if not valid_moves:
274
  st.session_state.game_over = True
275
- st.session_state.message = "A IA não tem movimentos. Você venceu!"
276
  st.rerun()
277
 
278
- move = valid_moves[np.argmax(policy)]
 
 
279
 
280
- st.session_state.board = game.apply_move(st.session_state.board, move)
281
- st.session_state.player = 1 # Devolve a vez para Humano
282
- st.session_state.message = f"IA jogou: {move}. Sua vez!"
283
- st.rerun()
 
 
284
 
285
- else:
286
- st.success(st.session_state.message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  # --- CONFIGURAÇÕES ---
10
  BOARD_SIZE = 8
11
  DEVICE = torch.device("cpu")
12
+ MODEL_PATH = "checkers_master_final.pth"
13
+
14
+ st.set_page_config(page_title="AlphaCheckerZero", page_icon="♟️", layout="wide")
15
+
16
+ # --- ESTILOS CSS PERSONALIZADOS (A MÁGICA VISUAL) ---
17
+ st.markdown("""
18
+ <style>
19
+ .board-container {
20
+ display: grid;
21
+ grid-template-columns: 30px repeat(8, 60px); /* Coluna guia + 8 colunas do jogo */
22
+ grid-template-rows: 30px repeat(8, 60px); /* Linha guia + 8 linhas do jogo */
23
+ gap: 2px;
24
+ background-color: #444;
25
+ padding: 10px;
26
+ border-radius: 10px;
27
+ width: fit-content;
28
+ margin: 0 auto;
29
+ }
30
+ .header-cell {
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ color: white;
35
+ font-weight: bold;
36
+ font-family: monospace;
37
+ }
38
+ .square {
39
+ width: 60px;
40
+ height: 60px;
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ font-size: 40px;
45
+ cursor: default;
46
+ }
47
+ .white-square { background-color: #f0d9b5; } /* Cor clara (madeira) */
48
+ .black-square { background-color: #b58863; } /* Cor escura (madeira) */
49
+
50
+ .piece-white {
51
+ color: #fff;
52
+ text-shadow: 0 0 5px rgba(0,0,0,0.5);
53
+ transform: scale(1.2);
54
+ }
55
+ .piece-black {
56
+ color: #333;
57
+ text-shadow: 0 0 2px rgba(255,255,255,0.3);
58
+ transform: scale(1.2);
59
+ }
60
+ .king { border: 2px solid gold; border-radius: 50%; padding: 2px; box-shadow: 0 0 10px gold;}
61
+
62
+ /* Ajuste para deixar o selectbox mais bonito */
63
+ .stSelectbox label { font-size: 1.2rem; font-weight: bold; }
64
+ </style>
65
+ """, unsafe_allow_html=True)
66
+
67
+ # --- LÓGICA DO JOGO (Inalterada) ---
68
  class Checkers:
69
  def get_initial_board(self):
70
  board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=np.int8)
 
216
  node.children[key] = MCTSNode(parent=node, prior=1.0 / len(valid_moves))
217
  return value
218
 
219
+ # --- INTERFACE GRÁFICA MELHORADA ---
220
 
 
 
 
 
 
 
221
  @st.cache_resource
222
  def load_model():
223
  if not os.path.exists(MODEL_PATH):
 
230
  model = load_model()
231
 
232
  if model is None:
233
+ st.error(f"Arquivo '{MODEL_PATH}' não encontrado!")
234
  st.stop()
235
 
 
236
  if "board" not in st.session_state:
237
  game = Checkers()
238
  st.session_state.board = game.get_initial_board()
239
+ st.session_state.player = 1
240
  st.session_state.game_over = False
241
+ st.session_state.message = "Bem-vindo à Arena! Você joga com as BRANCAS ()."
242
 
243
  game = Checkers()
244
+ mcts = MCTS(game, model, sims=150)
245
 
246
+ def format_move_for_human(move):
247
+ """Transforma ((2,1), (3,2)) em algo mais legível"""
248
+ if isinstance(move, list): # Pulo múltiplo
249
+ path = " -> ".join([f"({r},{c})" for (r,c), _ in move] + [str(move[-1][1])])
250
+ return f"Salto Múltiplo: {path}"
251
+ else:
252
+ (r1, c1), (r2, c2) = move
253
+ return f"Mover de ({r1}, {c1}) para ({r2}, {c2})"
254
+
255
+ def render_board_html(board):
256
+ html = '<div class="board-container">'
257
+
258
+ # Cabeçalho das colunas (0-7)
259
+ html += '<div class="header-cell"></div>' # Canto vazio
260
+ for c in range(8):
261
+ html += f'<div class="header-cell">{c}</div>'
262
+
263
+ for r in range(8):
264
+ # Cabeçalho da linha (0-7)
265
+ html += f'<div class="header-cell">{r}</div>'
266
+
267
+ for c in range(8):
268
+ color_class = "black-square" if (r + c) % 2 == 1 else "white-square"
269
+ piece = board[r, c]
270
+
271
+ content = ""
272
+ if piece == 1: content = '<span class="piece-white">⚪</span>'
273
+ elif piece == 2: content = '<span class="piece-white king">👑</span>' # Dama branca
274
+ elif piece == -1: content = '<span class="piece-black">⚫</span>'
275
+ elif piece == -2: content = '<span class="piece-black king">👑</span>' # Dama preta (coroa dourada no CSS)
276
+
277
+ html += f'<div class="square {color_class}">{content}</div>'
278
+
279
+ html += '</div>'
280
+ return html
281
+
282
+ st.title("♟️ AlphaCheckerZero Arena")
283
 
284
+ col1, col2 = st.columns([1.5, 1])
 
285
 
286
  with col1:
287
+ st.markdown(render_board_html(st.session_state.board), unsafe_allow_html=True)
288
 
289
  with col2:
290
+ st.write("### 🕹️ Painel de Controle")
291
+
292
+ if st.session_state.game_over:
293
+ st.warning(st.session_state.message)
294
+ if st.button("🔄 Jogar Novamente", use_container_width=True):
295
+ st.session_state.board = game.get_initial_board()
296
+ st.session_state.player = 1
297
+ st.session_state.game_over = False
298
+ st.session_state.message = "Novo jogo iniciado!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  st.rerun()
 
 
300
  else:
301
+ st.info(st.session_state.message)
302
+
303
+ # Lógica de Turno
304
+ if st.session_state.player == 1:
305
+ valid_moves = game.get_valid_moves(st.session_state.board, 1)
306
 
307
  if not valid_moves:
308
  st.session_state.game_over = True
309
+ st.session_state.message = "Sem movimentos válidos. Você perdeu. 😔"
310
  st.rerun()
311
 
312
+ # Dicionário para mapear a descrição bonita para o objeto de movimento real
313
+ move_map = {format_move_for_human(m): m for m in valid_moves}
314
+ selected_desc = st.selectbox("Sua vez! Escolha o movimento:", list(move_map.keys()))
315
 
316
+ if st.button("✅ Confirmar Jogada", type="primary", use_container_width=True):
317
+ move = move_map[selected_desc]
318
+ st.session_state.board = game.apply_move(st.session_state.board, move)
319
+ st.session_state.player = -1
320
+ st.session_state.message = "A IA está calculando..."
321
+ st.rerun()
322
 
323
+ else:
324
+ # Vez da IA
325
+ with st.spinner("A AlphaCheckerZero está pensando..."):
326
+ time.sleep(0.2) # UX Feel
327
+
328
+ valid_moves, policy = mcts.run(np.copy(st.session_state.board), -1)
329
+
330
+ if not valid_moves:
331
+ st.session_state.game_over = True
332
+ st.session_state.message = "A IA travou! VOCÊ VENCEU! 🎉"
333
+ st.rerun()
334
+
335
+ move = valid_moves[np.argmax(policy)]
336
+ st.session_state.board = game.apply_move(st.session_state.board, move)
337
+ st.session_state.player = 1
338
+ st.session_state.message = f"IA moveu: {format_move_for_human(move)}. Sua vez!"
339
+ st.rerun()
340
+
341
+ # Rodapé explicativo
342
+ st.markdown("---")
343
+ st.caption("**Legenda:** ⚪ Suas Peças | ⚫ Peças da IA | 👑 Dama")
344
+ st.caption("Desenvolvido por Gabriel Yogi com auxílio de Berta.")