import chess import random import sys KING_MOVE = False PIECE_VALUES = { chess.PAWN: 100, chess.KNIGHT: 300, chess.BISHOP: 320, chess.ROOK: 500, chess.QUEEN: 800, chess.KING: 999999, } def evaluate_move(board, move): score = 0 from_sq = move.from_square to_sq = move.to_square piece = board.piece_at(from_sq) if not piece: return 0 piece_type = piece.piece_type # --- LOGIQUE DE SÉCURITÉ ET SAUVETAGE --- current_attackers = list(board.attackers(not board.turn, from_sq)) current_defenders = list(board.attackers(board.turn, from_sq)) # Simulation du futur (pour voir si la case d'arrivée est sûre) board.push(move) future_attackers = list(board.attackers(board.turn, to_sq)) # turn a changé après push future_defenders = list(board.attackers(not board.turn, to_sq)) board.pop() # Si la pièce est en danger sur sa case actuelle if len(current_attackers) > len(current_defenders): # Si on la déplace vers une case plus sûre, gros bonus (Sauvetage) if len(future_attackers) <= len(future_defenders): score += PIECE_VALUES[piece_type] # Si on déplace une pièce vers une case suicidaire, gros malus if future_attackers: if len(future_attackers) >= len(future_defenders): score -= PIECE_VALUES[piece_type] elif len(future_attackers) == len(future_defenders) + 1: # Échange de même nombre : on compare la valeur totale des pièces sum_att = 0 sum_def = 0 # On parcourt les cases des attaquants pour trouver leurs types de pièces for sq in future_attackers: p = board.piece_at(sq) if p: sum_att += PIECE_VALUES[p.piece_type] # On parcourt les cases des défenseurs (les nôtres) for sq in future_defenders: p = board.piece_at(sq) if p: sum_def += PIECE_VALUES[p.piece_type] # Si les attaquants sont "plus chers" que les défenseurs, c'est bon pour nous score += (sum_def - sum_att) else: # On est en supériorité numérique sur la case # On ajoute un petit bonus de sécurité score += PIECE_VALUES[piece_type] // 4 # --- DÉTECTION DE CONTRE-ATTAQUE SÉCURISÉE --- board.push(move) # 1. On vérifie si notre pièce est protégée sur sa nouvelle case # Attention : après board.push(move), c'est au tour de l'adversaire. # On cherche donc les attaquants de la couleur qui VIENT de jouer (not board.turn) mes_defenseurs = list(board.attackers(not board.turn, to_sq)) # 2. On analyse les menaces créées # On regarde ce que notre pièce attaque sur sa nouvelle case attacked_squares = board.attacks(to_sq) for sq in attacked_squares: target = board.piece_at(sq) # Si on menace une pièce ennemie if target and target.color == board.turn: # board.turn est l'adversaire ici val_cible = PIECE_VALUES[target.piece_type] val_ma_piece = PIECE_VALUES[piece_type] # CONDITION DE SÉCURITÉ : # On ne donne le bonus que si la pièce est protégée OU si la cible vaut bcp plus cher if len(mes_defenseurs) > 0 or val_cible > (val_ma_piece * 2): #SI CEST PAS LE ROI !!!!!!!! if val_cible > val_ma_piece: score += (val_cible // 2) # Bonus supplémentaire pour les pièces majeures if target.piece_type in [chess.QUEEN, chess.ROOK]: score += 100 board.pop() # --- BONUS D'INTERPOSITION (Bloquer l'échec) --- # On ne donne ce bonus que si le coup n'est pas suicidaire if board.is_check() and piece_type != chess.KING: if len(mes_defenseurs) > 0: # Si le pion/pièce qui bloque est défendu score += 200 # --- GAIN MATÉRIEL (Capture) --- if board.is_capture(move): captured_piece = board.piece_at(to_sq) if captured_piece: score += PIECE_VALUES[captured_piece.piece_type] else: # Prise en passant score += PIECE_VALUES[chess.PAWN] # --- POSITIONNEL --- center_squares = [chess.E4, chess.D4, chess.E5, chess.D5] if to_sq in center_squares: score += 30 # --- TACTIQUE --- board.push(move) if board.is_check(): score += 50 if move.promotion: score += 700 board.pop() # --- PÉNALITÉ ROI --- if piece_type == chess.KING: # On n'aime pas bouger le roi, surtout au début (avant le coup 20) if board.fullmove_number < 20 and not KING_MOVE: if not board.is_capture(move): score -= 100 return score #+ random.randint(0, 10) def get_best_move(board): legal_moves = list(board.legal_moves) # On trie les coups du meilleur au moins bon selon notre fonction scored_moves = [(move, evaluate_move(board, move)) for move in legal_moves] scored_moves.sort(key=lambda x: x[1], reverse=True) ###### MODIFIER ICI POUR UN TRUC COMPREHENSIBLE ######### return scored_moves[0][0] if scored_moves else None # --- BOUCLE DE PROTOCOLE UCI --- def uci_loop(): board = chess.Board() while True: line = sys.stdin.readline().strip() if not line: continue parts = line.split() command = parts[0] if command == "uci": print("id name MonMoteur3") print("uciok") sys.stdout.flush() elif command == "isready": print("readyok") sys.stdout.flush() elif command == "go": best_move = get_best_move(board) print(f"bestmove {best_move}") sys.stdout.flush() elif command == "position": if "" in line: board = chess.Board() if "moves" in line: for move in parts[parts.index("moves") + 1:]: board.push_uci(move) elif "fen" in line: fen_index = parts.index("fen") fen_str = " ".join(parts[fen_index + 1 : fen_index + 7]) board = chess.Board(fen_str) elif command == "quit": break if __name__ == "__main__": uci_loop()