Make an advanced and tactical chess engine that go by; "Devil's Gambit" - It likes to sacrifice pawns/materials to further develop and trick the other player. It also likes to be aggressive and tactical with further development. I already made a nnue: nn-bc638d5ec9-20240730.nnue. And also a bench.csv: bench.csv.

Features: Tactical Pattern - (Fork Detection, Material Detection, Discovered Attack, Further AI Development)
2. Stockfish CSV Move Generation. (Stockfish Name: stockfish-windows-x86-64-sse41-popcnt.exe)
3. Gambit Core.
4. Deadly Move Heuristic
5. Open: Bench Evaluation Pruning.

Reference Script:

```
import chess
import random
import time
import chess.engine
from typing import Optional, Tuple

class GambitChessEngine:
    def __init__(self, max_depth: int = 3, iterative_depth_limit: int = 5, stockfish_path: str = r"C:\Users\hp\Downloads\berserk-13-sse2.exe"):
        self.board = chess.Board()
        self.max_depth = max_depth
        self.iterative_depth_limit = iterative_depth_limit
        self.gambit_moves = []
        self.passive_moves = []
        self.stockfish_path = stockfish_path
        self.engine = chess.engine.SimpleEngine.popen_uci(self.stockfish_path)
        self.piece_values = {
            chess.PAWN: 3, chess.KNIGHT: 3, chess.BISHOP: 3,
            chess.ROOK: 5, chess.QUEEN: 9, chess.KING: 0
        }

    def evaluate_board(self) -> float:
        """Advanced evaluation function for the Gambit playstyle."""
        evaluation = 0
        # Material evaluation
        material_value = sum(len(self.board.pieces(piece, color)) * self.piece_values[piece] * (1 if color == chess.WHITE else -1)
                             for piece in chess.PIECE_TYPES
                             for color in [chess.WHITE, chess.BLACK])

        # Piece activity, center control, king safety
        center_squares = [chess.E4, chess.E5, chess.D4, chess.D5]
        center_control = sum(1 if self.board.piece_at(sq) and self.board.piece_at(sq).color == chess.WHITE else
                             -1 if self.board.piece_at(sq) and self.board.piece_at(sq).color == chess.BLACK else 0
                             for sq in center_squares) * 0.5

        king_safety = 0
        for color in [chess.WHITE, chess.BLACK]:
            king = self.board.king(color)
            if king:
                king_safety += len(self.board.attackers(not color, king)) * 0.5 * (-1 if color == chess.WHITE else 1)

        # Pawn structure (Isolated/Doubled pawns)
        pawn_structure = sum((-0.5 if self.is_isolated(pawn) else 0) + (-0.5 if self.is_doubled(pawn) else 0)
                             for pawn in self.board.pieces(chess.PAWN, chess.WHITE)) + \
                         sum((0.5 if self.is_isolated(pawn) else 0) + (0.5 if self.is_doubled(pawn) else 0)
                             for pawn in self.board.pieces(chess.PAWN, chess.BLACK))

        # Piece coordination and aggression
        piece_coordination = sum(len(self.board.pieces(piece, color)) * 0.1 * (1 if color == chess.WHITE else -1)
                                 for piece in chess.PIECE_TYPES
                                 for color in [chess.WHITE, chess.BLACK])

        aggression_factor = sum(0.5 for move in self.board.legal_moves if self.is_aggressive_move(move))

        evaluation = (material_value + center_control + king_safety +
                      pawn_structure + piece_coordination + aggression_factor)

        # Add randomness for variation in play
        evaluation += random.uniform(-0.5, 0.5)

        return evaluation

    def is_isolated(self, square: chess.Square) -> bool:
        file, rank = chess.square_file(square), chess.square_rank(square)
        return all(self.board.piece_at(chess.square(f, r)) is None or
                   self.board.piece_at(chess.square(f, r)).piece_type != chess.PAWN
                   for f in [max(0, file - 1), min(7, file + 1)]
                   for r in range(8))

    def is_doubled(self, square: chess.Square) -> bool:
        file = chess.square_file(square)
        return any(self.board.piece_at(chess.square(file, r)) is not None and
                   self.board.piece_at(chess.square(file, r)).piece_type == chess.PAWN
                   for r in range(8) if r != chess.square_rank(square))

    def is_aggressive_move(self, move: chess.Move) -> bool:
        """Detect aggressive moves based on checks and captures."""
        self.board.push(move)
        is_aggressive = self.board.is_check() or self.board.is_checkmate() or \
                        self.board.is_capture(move) or self.board.gives_check(move)
        self.board.pop()
        return is_aggressive

    def gambit_pruning(self, depth: int, alpha: float, beta: float, is_maximizing: bool) -> Tuple[float, Optional[chess.Move]]:
        """Minimax with pruning and aggressive move prioritization."""
        if depth == 0 or self.board.is_game_over():
            return self.evaluate_board(), None

        best_move = None
        legal_moves = list(self.board.legal_moves)
        
        # Move ordering: prioritize aggressive moves
        legal_moves.sort(key=lambda move: self.is_aggressive_move(move), reverse=is_maximizing)
        
        if is_maximizing:
            best_value = float('-inf')
            for move in legal_moves:
                self.board.push(move)
                board_value, _ = self.gambit_pruning(depth - 1, alpha, beta, False)
                self.board.pop()
                if board_value > best_value:
                    best_value, best_move = board_value, move
                alpha = max(alpha, best_value)
                if beta <= alpha:
                    break
        else:
            best_value = float('inf')
            for move in legal_moves:
                self.board.push(move)
                board_value, _ = self.gambit_pruning(depth - 1, alpha, beta, True)
                self.board.pop()
                if board_value < best_value:
                    best_value, best_move = board_value, move
                beta = min(beta, best_value)
                if beta <= alpha:
                    break

        return best_value, best_move

    def iterative_deepening(self) -> Optional[chess.Move]:
        best_move = None
        for depth in range(1, self.iterative_depth_limit + 1):
            _, move = self.gambit_pruning(depth, float('-inf'), float('inf'), True)
            if move:
                best_move = move
        return best_move

    def make_gambit_move(self) -> Optional[chess.Move]:
        """Attempt to make a gambit move early in the game."""
        legal_moves = list(self.board.legal_moves)
        gambit_moves = [move for move in legal_moves if self.is_aggressive_move(move)]
        
        if gambit_moves:
            return random.choice(gambit_moves)
        
        if self.board.fullmove_number < 10:
            return self.gambit_variation()

        return random.choice(legal_moves) if legal_moves else None

    def passive_tactic_play(self) -> Optional[chess.Move]:
        """Fallback for when no aggressive gambit moves are available."""
        legal_moves = list(self.board.legal_moves)
        if not legal_moves:
            return None
        
        return max(legal_moves, key=lambda move: self.evaluate_move(move))

    def stockfish_helper(self) -> Optional[chess.Move]:
        try:
            result = self.engine.play(self.board, chess.engine.Limit(time=2))
            return result.move if result else None
        except Exception as e:
            print(f"Stockfish error: {e}")
            return None

    def play_engine_move(self, use_gambit: bool = True) -> Optional[chess.Move]:
        """Main engine move logic."""
        move = None

        if use_gambit and len(self.gambit_moves) < 5:
            move = self.make_gambit_move()
        
        if move is None:
            move = self.iterative_deepening()
        
        if move is None:
            move = self.passive_tactic_play()

        if move is None and len(self.board.piece_map()) < 8:
            move = self.stockfish_helper()

        if move:
            self.board.push(move)
        else:
            # Fallback if no move is determined
            print("No move determined, passing turn.")
            move = chess.Move.null()  # or any valid fallback move

        return move

    def display_board(self) -> str:
        """Returns the current board state as a string."""
        return str(self.board)

    def close(self):
        """Close the Stockfish engine to release resources."""
        self.engine.quit()

def main():
    engine = GambitChessEngine(max_depth=3, iterative_depth_limit=5, stockfish_path=r"C:\Users\hp\Downloads\berserk-13-sse2.exe")
    print("Welcome to Gambit V.2 Chess Engine!")
    print("This engine plays aggressively with a gambit variation and a passive tactic playstyle when needed.")
    print("It also uses Stockfish's evaluation to assist in move selection when more pieces are gone.")
    print("Enter your moves in standard algebraic notation (e.g., e2e4). Type 'quit' to exit.")

    while not engine.board.is_game_over():
        print(engine.display_board())
        user_move = input("Your move: ")
        if user_move.lower() == 'quit':
            break
        try:
            engine.board.push_san(user_move)
        except ValueError:
            print("Invalid move. Please try again.")
            continue
        
        if not engine.board.is_game_over():
            time.sleep(1)  # Short pause for realism
            engine_move = engine.play_engine_move()
            if engine_move:
                print(f"Engine move: {engine_move}")
            else:
                print("Engine failed to make a move.")

    print("Game over!")
    print(engine.display_board())
    engine.close()

if __name__ == "__main__":
    main()