Spaces:
Sleeping
Sleeping
import gradio as gr | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import random | |
class Minesweeper: | |
def __init__(self, width=8, height=8, num_mines=10): | |
self.width = width | |
self.height = height | |
self.num_mines = num_mines | |
self.game_over = False | |
self.won = False | |
self.first_move = True | |
self.initialize_board() | |
def initialize_board(self): | |
# Tabuleiro com as minas (-1 para minas, 0-8 para números) | |
self.board = np.zeros((self.height, self.width), dtype=int) | |
# Tabuleiro visível para o jogador (-2 coberto, -1 bandeira, números para revelados) | |
self.visible_board = np.full((self.height, self.width), -2, dtype=int) | |
def place_mines(self, first_x, first_y): | |
# Coloca minas aleatoriamente, evitando a primeira posição clicada | |
positions = [(x, y) for x in range(self.height) for y in range(self.width)] | |
positions.remove((first_x, first_y)) | |
mine_positions = random.sample(positions, self.num_mines) | |
for x, y in mine_positions: | |
self.board[x, y] = -1 | |
# Calcula números para células adjacentes às minas | |
for x in range(self.height): | |
for y in range(self.width): | |
if self.board[x, y] != -1: | |
self.board[x, y] = self.count_adjacent_mines(x, y) | |
def count_adjacent_mines(self, x, y): | |
count = 0 | |
for dx in [-1, 0, 1]: | |
for dy in [-1, 0, 1]: | |
if dx == 0 and dy == 0: | |
continue | |
new_x, new_y = x + dx, y + dy | |
if (0 <= new_x < self.height and | |
0 <= new_y < self.width and | |
self.board[new_x, new_y] == -1): | |
count += 1 | |
return count | |
def reveal(self, x, y): | |
if self.game_over or self.won: | |
return | |
if self.first_move: | |
self.place_mines(x, y) | |
self.first_move = False | |
# Se clicou em uma mina | |
if self.board[x, y] == -1: | |
self.game_over = True | |
return | |
# Revela a célula clicada | |
self.flood_fill(x, y) | |
# Verifica vitória | |
if np.count_nonzero(self.visible_board == -2) == self.num_mines: | |
self.won = True | |
def flood_fill(self, x, y): | |
if (not (0 <= x < self.height and 0 <= y < self.width) or | |
self.visible_board[x, y] != -2): | |
return | |
self.visible_board[x, y] = self.board[x, y] | |
if self.board[x, y] == 0: | |
for dx in [-1, 0, 1]: | |
for dy in [-1, 0, 1]: | |
self.flood_fill(x + dx, y + dy) | |
def toggle_flag(self, x, y): | |
if self.game_over or self.won: | |
return | |
if self.visible_board[x, y] == -2: | |
self.visible_board[x, y] = -1 | |
elif self.visible_board[x, y] == -1: | |
self.visible_board[x, y] = -2 | |
def create_board_image(game): | |
fig, ax = plt.subplots(figsize=(8, 8)) | |
# Cores para diferentes números | |
colors = { | |
-2: '#CCCCCC', # Coberto | |
-1: '#FF0000', # Bandeira/Mina | |
0: '#FFFFFF', # Vazio | |
1: '#0000FF', # Azul | |
2: '#008000', # Verde | |
3: '#FF0000', # Vermelho | |
4: '#000080', # Azul escuro | |
5: '#800000', # Vermelho escuro | |
6: '#008080', # Ciano | |
7: '#000000', # Preto | |
8: '#808080' # Cinza | |
} | |
# Desenha células | |
for i in range(game.height): | |
for j in range(game.width): | |
color = colors[game.visible_board[i, j]] | |
ax.add_patch(plt.Rectangle((j, game.height-1-i), 1, 1, facecolor=color, edgecolor='black')) | |
# Adiciona números | |
if game.visible_board[i, j] > 0: | |
plt.text(j+0.5, game.height-1-i+0.5, str(game.visible_board[i, j]), | |
horizontalalignment='center', | |
verticalalignment='center', | |
color='black') | |
elif game.visible_board[i, j] == -1: | |
plt.text(j+0.5, game.height-1-i+0.5, 'F', | |
horizontalalignment='center', | |
verticalalignment='center', | |
color='black') | |
# Mostra todas as minas se o jogo acabou | |
if game.game_over: | |
for i in range(game.height): | |
for j in range(game.width): | |
if game.board[i, j] == -1: | |
ax.add_patch(plt.Rectangle((j, game.height-1-i), 1, 1, facecolor='red', edgecolor='black')) | |
plt.text(j+0.5, game.height-1-i+0.5, 'M', | |
horizontalalignment='center', | |
verticalalignment='center', | |
color='black') | |
ax.set_xlim(0, game.width) | |
ax.set_ylim(0, game.height) | |
ax.set_xticks(range(game.width)) | |
ax.set_yticks(range(game.height)) | |
ax.grid(True) | |
status = "Jogando" | |
if game.game_over: | |
status = "Game Over!" | |
elif game.won: | |
status = "Você Venceu!" | |
plt.title(f'Campo Minado - {status}') | |
return fig | |
def handle_click(pos, button, game_state): | |
if not pos: | |
return None, game_state | |
x, y = int(pos[1]), int(pos[0]) | |
game = Minesweeper(8, 8, 10) | |
game.__dict__ = game_state | |
if button == "left": | |
game.reveal(x, y) | |
else: | |
game.toggle_flag(x, y) | |
fig = create_board_image(game) | |
return fig, game.__dict__ | |
def new_game(): | |
game = Minesweeper(8, 8, 10) | |
fig = create_board_image(game) | |
return fig, game.__dict__ | |
with gr.Blocks(title="Campo Minado") as demo: | |
gr.Markdown(""" | |
# Campo Minado | |
Instruções: | |
- Clique esquerdo para revelar uma célula | |
- Clique direito para colocar/remover bandeira | |
- Evite as minas! | |
- Descubra todas as células sem minas para vencer | |
""") | |
game_state = gr.State() | |
board = gr.Plot(label="Tabuleiro") | |
with gr.Row(): | |
new_game_btn = gr.Button("Novo Jogo") | |
board.select(handle_click, [board, gr.Button.update(value="left"), game_state], [board, game_state]) | |
board.select(handle_click, [board, gr.Button.update(value="right"), game_state], [board, game_state], trigger_mode="right_click") | |
new_game_btn.click(new_game, outputs=[board, game_state]) | |
demo.load(new_game, outputs=[board, game_state]) | |
demo.launch() |