# Problem Description
The task is to generate a dataset of 1000 2D points that follows a specific distribution pattern shown in the figure. The points should be distributed within a circular area with a radius of 0.25. The output should be a 2D array of shape (1000, 2) where each row represents the (x,y) coordinates of a point.

# Visual Facts
1. The plot shows a square coordinate system with both x and y axes ranging from 0.0 to 1.0.
2. Blue dots are scattered throughout the square area.
3. There's an orange dashed line labeled "R=0.25" indicating a radius.
4. The plot appears to have approximately 1000 points.
5. Points are densely packed within a circular region centered at (0.5, 0.5).
6. The circular region has a radius of 0.25 (as indicated by "R=0.25").

# Visual Patterns
1. Distribution Pattern:
   - The points are densely packed within a circular region centered at (0.5, 0.5).
   - The circular region has a radius of 0.25 (as indicated by "R=0.25").
   - Outside this circular region, points are non-existent.

2. Mathematical Constraints:
   - For any point (x,y), 0 ≤ x ≤ 1 and 0 ≤ y ≤ 1 (square boundary).
   - Points are more likely to appear within: (x-0.5)² + (y-0.5)² ≤ 0.25².
   - The distribution appears to be dense within this circular region.

3. Generation Rules:
   - Generate random points uniformly in the 1x1 square.
   - Accept points that fall within the circle defined by (x-0.5)² + (y-0.5)² ≤ 0.25².
   - Continue generating points until 1000 valid points are obtained.

# Solution
from typing import List
import numpy as np

def solution() -> List[List[float]]:
    """
    generate a set of 1000 data points that match the distribution shown in the figure

    Returns:
        List[List[float]]: A 2D array of shape (1000, 2), where each row contains the x and y coordinates of a point.
    """
    num_points = 1000
    points = np.zeros((num_points, 2))  # Initialize array to hold points
    center_x, center_y = 0.5, 0.5
    radius = 0.25
    count = 0

    while count < num_points:
        x, y = np.random.rand(2)  # Generate random x, y coordinates
        # Check if the point is inside the circle
        if (x - center_x)**2 + (y - center_y)**2 <= radius**2:
            points[count] = [x, y]
            count += 1

    return points.tolist()


# Test Script
import numpy as np

def quartile_test(points):
    x_quartiles = np.percentile(points[:, 0], [25, 50, 75])
    y_quartiles = np.percentile(points[:, 1], [25, 50, 75])
    
    theoretical_quartiles = [0.4, 0.5, 0.6]
    x_check = np.allclose(x_quartiles, theoretical_quartiles, atol=0.1)
    y_check = np.allclose(y_quartiles, theoretical_quartiles, atol=0.1)
    
    return x_check and y_check

def test():
    try:
        points = np.array(solution())
    except Exception as e:
        error_message = (
            f"An exception occurred while running solution():\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message

    # Test shape of output
    if points.shape != (1000, 2):
        error_message = (
            f"The following Test Case failed:\n"
            f"`points.shape`: {points.shape}\n"
            f"Expected Output: (1000, 2)"
        )
        assert False, error_message
    
    # Test points are outside exclusion zone
    center_x, center_y = 0.5, 0.5
    radius = 0.25
    distances = np.sqrt((points[:, 0] - center_x)**2 + (points[:, 1] - center_y)**2)
    if not np.all(distances <= radius):
        invalid_points = points[distances > radius]
        error_message = (
            f"The following Test Case failed:\n"
            f"`points`: Points found inside exclusion zone\n"
            f"Invalid points coordinates: {invalid_points}\n"
            f"Center: ({center_x}, {center_y}), Radius: {radius}"
        )
        assert False, error_message
    
    # Test uniform distribution via quartiles
    if not quartile_test(points):
        x_quartiles = np.percentile(points[:, 0], [25, 50, 75])
        y_quartiles = np.percentile(points[:, 1], [25, 50, 75])
        theoretical_quartiles = [0.4, 0.5, 0.6]
        error_message = (
            f"The following Test Case failed:\n"
            f"`points`: Distribution not uniform\n"
            f"Actual x quartiles: {x_quartiles}\n"
            f"Actual y quartiles: {y_quartiles}\n"
            f"Expected quartiles: {theoretical_quartiles}"
        )
        assert False, error_message

test()