import random import gradio as gr FILES = "abcdefgh" RANKS = "12345678" # Pièces Unicode PIECES = { ("W", "p"): "♙", ("B", "p"): "♟", ("W", "t"): "♖", ("B", "t"): "♜", ("W", "c"): "♘", ("B", "c"): "♞", ("W", "f"): "♗", ("B", "f"): "♝", ("W", "R"): "♕", ("B", "R"): "♛", ("W", "k"): "♔", ("B", "k"): "♚", } def in_bounds(x, y): return 0 <= x < 8 and 0 <= y < 8 def initial_board(): b = [[None for _ in range(8)] for _ in range(8)] white_row = ['t', 'c', 'f', 'R', 'k', 'f', 'c', 't'] for x, p in enumerate(white_row): b[x][0] = ('W', p) b[x][1] = ('W', 'p') black_row = ['t', 'c', 'f', 'R', 'k', 'f', 'c', 't'] for x, p in enumerate(black_row): b[x][7] = ('B', p) b[x][6] = ('B', 'p') return b def sq_to_coords(sq): sq = sq.lower() return FILES.index(sq[0]), RANKS.index(sq[1]) def coords_to_sq(x, y): return FILES[x] + RANKS[y] def generate_mines(board, density=0.15): empty = [(x, y) for x in range(8) for y in range(8) if board[x][y] is None] n = max(1, int(len(empty) * density)) mines = set(random.sample(empty, n)) return mines, set(), set() def count_adjacent_mines(x, y, mines): return sum((nx, ny) in mines for nx in range(x-1, x+2) for ny in range(y-1, y+2) if (nx, ny) != (x, y) and in_bounds(nx, ny)) def render_board(board, mines, revealed, exploded, hints): grid = [] for y in range(7, -1, -1): row = [] for x in range(8): if (x, y) in exploded: cell = "💥" elif board[x][y]: cell = PIECES[board[x][y]] elif (x, y) in revealed: cell = str(hints.get((x, y), 0)) if hints.get((x, y), 0) > 0 else "·" else: cell = "⬜" if (x + y) % 2 else "⬛" row.append(cell) grid.append(row) return "\n".join(" ".join(row) for row in grid) def apply_move(board, mines, revealed, exploded, hints, move, turn): from_sq, to_sq = move fx, fy = sq_to_coords(from_sq) tx, ty = sq_to_coords(to_sq) piece = board[fx][fy] if not piece or piece[0] != turn: return board, "Coup invalide" if not in_bounds(tx, ty): return board, "Coup hors du plateau" # Déplacement board[fx][fy] = None if (tx, ty) in mines: exploded.add((tx, ty)) text = f"💥 {from_sq}->{to_sq} : Mine ! Pièce détruite." else: board[tx][ty] = piece revealed.add((tx, ty)) count = count_adjacent_mines(tx, ty, mines) hints[(tx, ty)] = count text = f"{from_sq}->{to_sq} (zone sûre, {count} mines autour)" return board, text def new_game(density): board = initial_board() mines, revealed, exploded = generate_mines(board, density) hints = {} state = dict(board=board, mines=mines, revealed=revealed, exploded=exploded, hints=hints, turn="W", log=["Nouvelle partie"]) return render_board(board, mines, revealed, exploded, hints), "\n".join(state["log"]), state def play_move(move_input, state): if not state: return "Pas de partie", "Commence une nouvelle partie", None move_input = move_input.strip().lower() if len(move_input) != 4: return render_board(**state), "Format invalide (ex: e2e4)", state from_sq, to_sq = move_input[:2], move_input[2:] board, text = apply_move(state["board"], state["mines"], state["revealed"], state["exploded"], state["hints"], (from_sq, to_sq), state["turn"]) state["board"] = board state["log"].append(text) state["turn"] = "B" if state["turn"] == "W" else "W" return render_board(board, state["mines"], state["revealed"], state["exploded"], state["hints"]), "\n".join(state["log"]), state with gr.Blocks() as demo: gr.Markdown("# ♟️ ChessMine — Échecs + 💣 Démineur") gr.Markdown("Deux joueurs alternent leurs coups. Si une pièce marche sur une mine 💥 elle explose, sinon la case révèle le nombre de mines autour 🔢.") density = gr.Slider(0.05, 0.4, value=0.15, label="Densité de mines") start = gr.Button("Nouvelle partie") board_box = gr.Textbox(label="Plateau", lines=10, interactive=False) move_in = gr.Textbox(label="Coup (ex: e2e4)") play = gr.Button("Jouer") log_box = gr.Textbox(label="Journal", lines=8, interactive=False) state = gr.State() start.click(new_game, inputs=[density], outputs=[board_box, log_box, state]) play.click(play_move, inputs=[move_in, state], outputs=[board_box, log_box, state]) gr.Markdown("**Règles :**\n- Entrez vos coups en format `e2e4`.\n- Si la case cible contient une 💣 → explosion !\n- Sinon, un nombre indique combien de mines se trouvent autour.\n- Les pièces utilisent les symboles Unicode standards ♙♟♖♜♘♞♗♝♕♛♔♚.") if __name__ == "__main__": demo.launch()