```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Mini Golf Game with Smart AI</title>
    <style>
        body {
            text-align: center;
            background-color: #2E8B57;
            margin: 0;
            padding: 0;
            color: white;
            font-family: Arial, sans-serif;
        }
        canvas {
            background-color: #228B22;
            display: block;
            margin: 20px auto;
            border: 2px solid #006400;
        }
        #info {
            margin-top: -10px;
            color: white;
            font-size: 16px;
        }
    </style>
</head>
<body>
    <h1>Mini Golf Game</h1>
    <canvas id="gameCanvas" width="800" height="600"></canvas>
    <div id="info">Click and drag to aim and set power. Get the ball in the hole! Press Alt+R to toggle AI.</div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const WIDTH = canvas.width;
        const HEIGHT = canvas.height;

        // Ball and Hole properties
        const ballRadius = 10;
        const holeRadius = 15;
        const maxShotPower = 15; // Maximum velocity per axis

        let shotsTaken = 0;

        let ball = {
            x: 50,
            y: HEIGHT - 50,
            vx: 0,
            vy: 0,
            color: 'white'
        };

        let hole = {
            x: WIDTH - 50,
            y: 50,
            radius: holeRadius,
            color: 'black'
        };

        // Obstacles
        const obstacles = [];
        const numObstacles = 5;
        const obstacleSizeRange = { minWidth: 60, maxWidth: 150, minHeight: 30, maxHeight: 60 };

        // Game State for Dragging
        let isDragging = false;
        let dragStart = { x: 0, y: 0 };
        let dragEnd = { x: 0, y: 0 };

        // AI State
        let aiActive = false;
        let aiShotQueued = false; // Flag to prevent multiple shot scheduling

        // Generate random obstacles without overlapping
        function generateObstacles() {
            obstacles.length = 0;
            let attempts = 0;

            while (obstacles.length < numObstacles && attempts < 1000) {
                attempts++;
                let width = getRandom(obstacleSizeRange.minWidth, obstacleSizeRange.maxWidth);
                let height = getRandom(obstacleSizeRange.minHeight, obstacleSizeRange.maxHeight);
                let x = getRandom(50, WIDTH - width - 50);
                let y = getRandom(50, HEIGHT - height - 50);

                let newObstacle = { x, y, width, height, color: 'grey' };

                // Check for overlap with ball, hole, and existing obstacles
                if (
                    !rectCircleOverlap(newObstacle, ball.x, ball.y, ballRadius + 10) &&
                    !rectCircleOverlap(newObstacle, hole.x, hole.y, holeRadius + 30) &&
                    !obstacles.some(obs => rectsOverlap(newObstacle, obs))
                ) {
                    obstacles.push(newObstacle);
                }
            }

            if (obstacles.length < numObstacles) {
                console.warn("Could not place all obstacles without overlapping.");
            }
        }

        // Utility function to get random number in range
        function getRandom(min, max) {
            return Math.random() * (max - min) + min;
        }

        // Check if two rectangles overlap
        function rectsOverlap(rect1, rect2) {
            return !(
                rect1.x + rect1.width < rect2.x ||
                rect1.x > rect2.x + rect2.width ||
                rect1.y + rect1.height < rect2.y ||
                rect1.y > rect2.y + rect2.height
            );
        }

        // Check if circle overlaps with rectangle
        function rectCircleOverlap(rect, cx, cy, radius) {
            const distX = Math.abs(cx - (rect.x + rect.width / 2));
            const distY = Math.abs(cy - (rect.y + rect.height / 2));

            if (distX > (rect.width / 2 + radius)) return false;
            if (distY > (rect.height / 2 + radius)) return false;

            if (distX <= (rect.width / 2)) return true;
            if (distY <= (rect.height / 2)) return true;

            const dx = distX - rect.width / 2;
            const dy = distY - rect.height / 2;
            return (dx * dx + dy * dy <= (radius * radius));
        }

        // Draw ball
        function drawBall() {
            ctx.beginPath();
            ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI * 2);
            ctx.fillStyle = ball.color;
            ctx.fill();
            ctx.closePath();
        }

        // Draw hole
        function drawHole() {
            ctx.beginPath();
            ctx.arc(hole.x, hole.y, hole.radius, 0, Math.PI * 2);
            ctx.fillStyle = hole.color;
            ctx.fill();
            ctx.closePath();
        }

        // Draw obstacles
        function drawObstacles() {
            obstacles.forEach(obs => {
                ctx.fillStyle = obs.color;
                ctx.fillRect(obs.x, obs.y, obs.width, obs.height);
            });
        }

        // Draw shots taken at top-left corner
        function drawShotsTaken() {
            const padding = 10;
            ctx.font = '20px Arial';
            ctx.fillStyle = 'white';
            ctx.textAlign = 'left';
            ctx.fillText(`Shots Taken: ${shotsTaken}`, padding, 30);
        }

        // Draw AI Status at top-right corner
        function drawAIStatus() {
            const padding = 10;
            ctx.font = '20px Arial';
            ctx.fillStyle = aiActive ? 'yellow' : 'white';
            ctx.textAlign = 'right';
            ctx.fillText(`AI: ${aiActive ? 'Active' : 'Inactive'}`, WIDTH - padding, 30);
        }

        // Draw shot indicator
        function drawShotIndicator() {
            const dx = ball.x - dragEnd.x; // Inverted direction
            const dy = ball.y - dragEnd.y; // Inverted direction
            const distanceDragged = Math.hypot(dx, dy);
            const maxDistance = 150;
            const scalingFactor = Math.min(distanceDragged / maxDistance, 1);
            const power = scalingFactor * 100; // Percentage

            if (distanceDragged === 0) return; // Prevent division by zero

            // Calculate angle
            const angle = Math.atan2(dy, dx);

            // Determine color based on power (Green to Red)
            const powerColor = getPowerColor(scalingFactor);

            // Adjust arrow length based on drag distance
            const arrowLength = 50 * scalingFactor;

            // Calculate end point of the arrow
            const endX = ball.x + Math.cos(angle) * arrowLength;
            const endY = ball.y + Math.sin(angle) * arrowLength;

            // Draw arrow line
            ctx.beginPath();
            ctx.moveTo(ball.x, ball.y);
            ctx.lineTo(endX, endY);
            ctx.strokeStyle = powerColor;
            ctx.lineWidth = 3;
            ctx.stroke();
            ctx.closePath();

            // Draw arrowhead
            drawArrowhead(endX, endY, angle, powerColor);
        }

        // Helper function to draw arrowhead
        function drawArrowhead(x, y, angle, color) {
            const size = 10;
            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(x - size * Math.cos(angle - Math.PI / 6), y - size * Math.sin(angle - Math.PI / 6));
            ctx.lineTo(x - size * Math.cos(angle + Math.PI / 6), y - size * Math.sin(angle + Math.PI / 6));
            ctx.lineTo(x, y);
            ctx.fillStyle = color;
            ctx.fill();
            ctx.closePath();
        }

        // Function to get color based on power (Green to Red)
        function getPowerColor(scalingFactor) {
            const r = Math.floor(255 * scalingFactor);
            const g = Math.floor(255 * (1 - scalingFactor));
            return `rgb(${r},${g},0)`;
        }

        // Reset game
        function resetGame() {
            ball.x = 50;
            ball.y = HEIGHT - 50;
            ball.vx = 0;
            ball.vy = 0;
            shotsTaken = 0;
            aiShotQueued = false; // Reset AI shot queue flag
            generateObstacles();
        }

        // Collision detection between circle and rectangle with precise response
        function handleCollisions() {
            // Collision with walls
            if (ball.x - ballRadius < 0) {
                ball.x = ballRadius;
                ball.vx = -ball.vx;
            }
            if (ball.x + ballRadius > WIDTH) {
                ball.x = WIDTH - ballRadius;
                ball.vx = -ball.vx;
            }
            if (ball.y - ballRadius < 0) {
                ball.y = ballRadius;
                ball.vy = -ball.vy;
            }
            if (ball.y + ballRadius > HEIGHT) {
                ball.y = HEIGHT - ballRadius;
                ball.vy = -ball.vy;
            }

            // Collision with obstacles
            obstacles.forEach(obs => {
                if (rectCircleOverlap(obs, ball.x, ball.y, ballRadius)) {
                    // Calculate the nearest point on the rectangle to the ball
                    const nearestX = Math.max(obs.x, Math.min(ball.x, obs.x + obs.width));
                    const nearestY = Math.max(obs.y, Math.min(ball.y, obs.y + obs.height));

                    const deltaX = ball.x - nearestX;
                    const deltaY = ball.y - nearestY;

                    const distance = Math.hypot(deltaX, deltaY);

                    if (distance === 0) {
                        // Prevent division by zero by nudging the ball away upwards
                        ball.y += 1;
                        return;
                    }

                    // Normalize the collision vector
                    const collisionNormX = deltaX / distance;
                    const collisionNormY = deltaY / distance;

                    // Reflect the velocity vector
                    const dotProduct = ball.vx * collisionNormX + ball.vy * collisionNormY;
                    ball.vx -= 2 * dotProduct * collisionNormX;
                    ball.vy -= 2 * dotProduct * collisionNormY;

                    // Move the ball out of the obstacle
                    const overlap = ballRadius - distance;
                    ball.x += collisionNormX * overlap;
                    ball.y += collisionNormY * overlap;
                }
            });
        }

        // Update game state
        function update() {
            // Update ball position
            ball.x += ball.vx;
            ball.y += ball.vy;

            // Apply friction
            ball.vx *= 0.98;
            ball.vy *= 0.98;

            // Limit velocity
            const velocity = Math.hypot(ball.vx, ball.vy);
            if (velocity > maxShotPower) {
                const scaling = maxShotPower / velocity;
                ball.vx *= scaling;
                ball.vy *= scaling;
            }

            // Stop the ball if velocity is very low
            if (Math.abs(ball.vx) < 0.05) ball.vx = 0;
            if (Math.abs(ball.vy) < 0.05) ball.vy = 0;

            // Handle collisions
            handleCollisions();

            // Check if ball is in the hole
            if (distance(ball.x, ball.y, hole.x, hole.y) < hole.radius) {
                alert(`Congratulations! You've sunk the ball in ${shotsTaken} shots!`);
                resetGame();
            }

            // If AI is active, the ball is stationary, and no shot is queued, let AI take a shot
            if (aiActive && ball.vx === 0 && ball.vy === 0 && !aiShotQueued) {
                aiShotQueued = true; // Set the flag to prevent multiple shots
                setTimeout(() => {
                    aiTakeShot();
                    aiShotQueued = false; // Reset the flag after taking the shot
                }, 500); // Slight delay for better UX
            }
        }

        // AI takes a shot towards the hole while avoiding obstacles
        function aiTakeShot() {
            if (!aiActive) return;

            // Calculate vector from ball to hole
            const forceX = hole.x - ball.x;
            const forceY = hole.y - ball.y;

            const distanceToHole = Math.hypot(forceX, forceY);
            const maxShotDistance = 150;
            const scalingFactor = Math.min(distanceToHole / maxShotDistance, 1);

            // Normalize the force vector
            const distanceDragged = Math.hypot(forceX, forceY);
            let normalizedForceX = 0;
            let normalizedForceY = 0;

            if (distanceDragged !== 0) {
                normalizedForceX = forceX / distanceDragged;
                normalizedForceY = forceY / distanceDragged;
            }

            // Check if direct path is clear
            if (isPathClear(ball.x, ball.y, hole.x, hole.y)) {
                // Direct shot
                ball.vx = normalizedForceX * scalingFactor * maxShotPower;
                ball.vy = normalizedForceY * scalingFactor * maxShotPower;
                shotsTaken++;
                return;
            }

            // If direct path is blocked, try to find an alternate direction
            const adjustedShot = findClearShot(ball.x, ball.y, hole.x, hole.y);

            if (adjustedShot) {
                ball.vx = adjustedShot.forceX;
                ball.vy = adjustedShot.forceY;
                shotsTaken++;
            } else {
                // If no clear path found, make a minimal adjustment and shoot
                ball.vx = normalizedForceX * scalingFactor * (maxShotPower / 2);
                ball.vy = normalizedForceY * scalingFactor * (maxShotPower / 2);
                shotsTaken++;
            }
        }

        // Function to check if the path between two points is clear of obstacles
        function isPathClear(x1, y1, x2, y2) {
            for (let obs of obstacles) {
                if (doesLineIntersectRect(x1, y1, x2, y2, obs)) {
                    return false;
                }
            }
            return true;
        }

        // Function to determine if a line segment intersects a rectangle
        function doesLineIntersectRect(x1, y1, x2, y2, rect) {
            // Define the four sides of the rectangle
            const sides = [
                {x1: rect.x, y1: rect.y, x2: rect.x + rect.width, y2: rect.y}, // Top
                {x1: rect.x + rect.width, y1: rect.y, x2: rect.x + rect.width, y2: rect.y + rect.height}, // Right
                {x1: rect.x + rect.width, y1: rect.y + rect.height, x2: rect.x, y2: rect.y + rect.height}, // Bottom
                {x1: rect.x, y1: rect.y + rect.height, x2: rect.x, y2: rect.y} // Left
            ];

            for (let side of sides) {
                if (doLinesIntersect(x1, y1, x2, y2, side.x1, side.y1, side.x2, side.y2)) {
                    return true;
                }
            }
            return false;
        }

        // Function to check if two lines intersect
        function doLinesIntersect(x1, y1, x2, y2, x3, y3, x4, y4) {
            // Calculate denominators
            const den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
            if (den === 0) return false; // Parallel lines

            const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den;
            const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den;

            return t > 0 && t < 1 && u > 0 && u < 1;
        }

        // Function to find a clear shot by adjusting angle
        function findClearShot(x1, y1, x2, y2) {
            const angleToHole = Math.atan2(y2 - y1, x2 - x1);
            const angleStep = Math.PI / 36; // 5 degrees
            const maxSteps = 18; // Up to 90 degrees

            for (let i = 1; i <= maxSteps; i++) {
                // Try positive angle
                let newAngle = angleToHole + angleStep * i;
                let targetX = x1 + Math.cos(newAngle) * 150;
                let targetY = y1 + Math.sin(newAngle) * 150;

                if (isPathClear(x1, y1, targetX, targetY)) {
                    const forceX = (targetX - x1) / Math.hypot(targetX - x1, targetY - y1) * maxShotPower;
                    const forceY = (targetY - y1) / Math.hypot(targetX - x1, targetY - y1) * maxShotPower;
                    return { forceX, forceY };
                }

                // Try negative angle
                newAngle = angleToHole - angleStep * i;
                targetX = x1 + Math.cos(newAngle) * 150;
                targetY = y1 + Math.sin(newAngle) * 150;

                if (isPathClear(x1, y1, targetX, targetY)) {
                    const forceX = (targetX - x1) / Math.hypot(targetX - x1, targetY - y1) * maxShotPower;
                    const forceY = (targetY - y1) / Math.hypot(targetX - x1, targetY - y1) * maxShotPower;
                    return { forceX, forceY };
                }
            }

            // If no clear path found, return null
            return null;
        }

        // Render the game
        function render() {
            ctx.clearRect(0, 0, WIDTH, HEIGHT);
            drawHole();
            drawObstacles();
            drawBall();
            drawShotsTaken();
            drawAIStatus();

            // If dragging, draw the shot indicator
            if (isDragging) {
                drawShotIndicator();
            }
        }

        // Game loop
        function gameLoop() {
            update();
            render();
            requestAnimationFrame(gameLoop);
        }

        // Handle mouse input for aiming and shooting
        canvas.addEventListener('mousedown', (e) => {
            // Only allow aiming if the ball is stationary and AI is not active
            if (ball.vx === 0 && ball.vy === 0 && !aiActive) {
                isDragging = true;
                const rect = canvas.getBoundingClientRect();
                dragStart.x = e.clientX - rect.left;
                dragStart.y = e.clientY - rect.top;
                dragEnd.x = dragStart.x;
                dragEnd.y = dragStart.y;
            }
        });

        canvas.addEventListener('mousemove', (e) => {
            if (isDragging) {
                const rect = canvas.getBoundingClientRect();
                dragEnd.x = e.clientX - rect.left;
                dragEnd.y = e.clientY - rect.top;
            }
        });

        canvas.addEventListener('mouseup', (e) => {
            if (isDragging) {
                const rect = canvas.getBoundingClientRect();
                dragEnd.x = e.clientX - rect.left;
                dragEnd.y = e.clientY - rect.top;

                // Calculate the force based on drag distance
                const forceX = ball.x - dragEnd.x; // Inverted direction
                const forceY = ball.y - dragEnd.y; // Inverted direction

                // Calculate distance to normalize force
                const distanceDragged = Math.hypot(forceX, forceY);
                const maxDistance = 150;
                const scalingFactor = Math.min(distanceDragged / maxDistance, 1);

                // Prevent division by zero
                if (distanceDragged === 0) {
                    isDragging = false;
                    return;
                }

                // Apply scaling to force
                ball.vx = (forceX / distanceDragged) * scalingFactor * maxShotPower;
                ball.vy = (forceY / distanceDragged) * scalingFactor * maxShotPower;

                shotsTaken++;
                isDragging = false;
            }
        });

        // Keyboard event listener for Alt+R to toggle AI
        window.addEventListener('keydown', (e) => {
            if (e.altKey && (e.key === 'r' || e.key === 'R')) {
                aiActive = !aiActive;
                e.preventDefault(); // Prevent default browser behavior
                if (aiActive) {
                    console.log("AI Activated");
                } else {
                    console.log("AI Deactivated");
                }
            }
        });

        // Utility function to calculate distance between two points
        function distance(x1, y1, x2, y2) {
            return Math.hypot(x2 - x1, y2 - y1);
        }

        // Initialize the game
        resetGame();
        gameLoop();
    </script>
</body>
</html>
```

---

This code has an AI, the AI isn't aware of the obstacles, it shoots itself straight to the hole, which could be interrupted by some obstacles, so, make the AI aware of the obstacles and know how to go around them...