racquet-lab 0.1.0
A Python library for tennis equipment physics and analytics
Requires Python: >=3.7

# racquet-lab

[![PyPI version](https://badge.fury.io/py/racquet-lab.svg)](https://badge.fury.io/py/racquet-lab)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.7+](https://img.shields.io/badge/python-3.7+-blue.svg)](https://www.python.org/downloads/)

**racquet-lab** is a Python library that bridges the gap between Tennis Equipment Physics and Software Engineering. It provides tools to calculate advanced racket properties like Recoil Weight and MGR/I (Maneuverability Index), simulates racket customization with scientific accuracy, and includes a recommendation engine for string tensions and racket matching.

## 🚀 Features

*   **Physics Engine**: Calculate **Recoil Weight** and **MGR/I** (Maneuverability Index) with high precision.
*   **Customization Lab**: Simulate adding weight (lead tape) at any position and instantly see the effects on **Balance**, **Swingweight**, and **Recoil Weight** using the Parallel Axis Theorem. Includes Immutability for safe chainable operations.
*   **Recommendation Advisor**:
    *   **Tension Calculator**: Get scientifically backed tension suggestions based on string material (Poly, Gut, etc.), head size, and player injury history.
    *   **Similarity Search**: Find rackets in a database that maximize "feel" similarity to a target frame using weighted Euclidean distance.

## 📦 Installation

Install the package via pip:

```bash
pip install racquet-lab
```

## 🛠 Usage

### 1. Physics & Customization

```python
from racquet_lab.racket import Racket

# 1. Initialize a racket (Mass in g, Balance in cm, Swingweight in kg·cm²)
pure_aero = Racket(name="Pure Aero", mass_g=300, balance_cm=32.0, swingweight=290)

print(f"Recoil Weight: {pure_aero.recoil_weight():.1f}")  # Output: 144.8

# 2. Customize: Add 4g of lead tape at 12 o'clock (70cm from handle)
custom_spec = pure_aero.customize(mass_added_g=4, position_cm=70)

print(f"New Swingweight: {custom_spec.swingweight:.1f}")  # Output: 304.4
print(f"New Balance: {custom_spec.balance_cm:.2f} cm")    # Output: 32.49 cm
# Original instance remains unchanged (Immutable)
```

### 2. String Tension Advisor

```python
from racquet_lab.advisor import StringsAdvisor, StringMaterial, PlayerProfile

# Configure player profile
profile = PlayerProfile(has_injury_history=True, level="intermediate")

# Get recommendation for a Polyester string on a 100 sq in head
tension = StringsAdvisor.suggest_tension(
    material=StringMaterial.POLYESTER, 
    head_size_sq_in=100, 
    profile=profile
)

print(f"Recommended Tension: {tension} lbs") # Returns lower tension for arm safety
```

### 3. Finding Similar Rackets

```python
from racquet_lab.advisor import RacketMatcher

# Find the closest match to 'pure_aero' in a list of candidate rackets
match = RacketMatcher.find_closest_match(pure_aero, candidate_rackets_list)
print(f"Most similar racket: {match.name}")
```

## 📚 Physics Background

*   **Recoil Weight**: $SW - Mass_{kg} \times (Balance_{cm} - 10)^2$
    *   Describes the racket's resistance to angular acceleration (kicking back) upon contact. Higher RW = more stability.
*   **MGR/I**: derived from double pendulum physics.
    *   describes how easily a racket can be maneuvered to generate racket head speed. Typical values range from 20.0 to 21.5.

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1.  Fork the repository
2.  Create your feature branch (`git checkout -b feature/AmazingFeature`)
3.  Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4.  Push to the branch (`git push origin feature/AmazingFeature`)
5.  Open a Pull Request

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.