Introduction

Baseball scouts do not just list batting lines. They turn numbers into a clear story about approach, consistency, and upside.

In this project, you will build a Python program that turns baseball stats into a clean scouting report.

What we're building

By the end of this project, you will:

  • Format report text with strings and f-strings
  • Use functions to generate reusable scouting templates
  • Turn baseball stats into analysis language
  • Load player data from CSV and generate multiple reports

Why this matters

This mirrors real front-office workflows: one reporting format that can be reused across many players.

Part 1: Quick Start

Set up your project in Cursor

For this project, you will create your files from scratch (no starter pack download).

Before you start: quick vocabulary

  • A folder is a container that holds files.
  • A file is one item inside a folder.
  • A file extension is the ending in the file name:
    • .py means Python code.
    • .csv means table-style data.
  1. Pick an easy location for your project folder:
    • Mac: Desktop in Finder
    • Windows: Desktop in File Explorer
    • Chromebook: My files in the Files app
  2. Create a folder called baseball-scouting-report.
  3. In Cursor, go to File > Open Folder and open baseball-scouting-report.
  4. In Cursor's left file explorer:
    • click New Folder and create data
    • click New File and create scouting_report.py
    • open data, click New File, and create players.csv
  5. If you do not see file extensions on your computer, that is okay. Type the full names exactly, including .py and .csv.

Writing the code

Type this into scouting_report.py:

player_name = "Diego Alvarez"
team_name = "Greenville Hawks"
primary_stat_name = "Batting average"
primary_stat_value = 0.311

print(f"Scouting Report: {player_name} ({team_name})")
print(f"Top stat: {primary_stat_name} - {primary_stat_value}")

This is your first quick win. You are already generating a readable baseball report line.

Running the code

Save the file (Cmd + S on Mac, Ctrl + S on Windows/Chromebook).

Run the file with Cursor's built-in Run Python File play button in the top-right.

If the play button is missing, install/enable the Python extension in Cursor and reopen scouting_report.py.

Expected output:

Scouting Report: Diego Alvarez (Greenville Hawks)
Top stat: Batting average - 0.311

If your output matches, your setup is working.

Part 2: Project Milestones

Milestone 1: Build a reusable report function

A function is a reusable recipe. Write it once, then use it for every player.

Add this below your existing code:

def build_report(player_name, team_name, position, batting_avg, obp, slg):
    report = (
        f"=== Scouting Report ===\n"
        f"Player: {player_name}\n"
        f"Team: {team_name}\n"
        f"Position: {position}\n"
        f"AVG: {batting_avg}\n"
        f"OBP: {obp}\n"
        f"SLG: {slg}\n"
    )
    return report

print(build_report("Diego Alvarez", "Greenville Hawks", "SS", 0.311, 0.382, 0.512))

Expected output:

=== Scouting Report ===
Player: Diego Alvarez
Team: Greenville Hawks
Position: SS
AVG: 0.311
OBP: 0.382
SLG: 0.512

Milestone 2: Add strengths and growth areas

Now add decision logic (if/elif/else) so your code can describe what the stats mean.

Add this below Milestone 1 code:

def contact_label(batting_avg):
    if batting_avg >= 0.300:
        return "Strength: Excellent contact consistency."
    if batting_avg >= 0.260:
        return "Strength: Solid hit tool."
    return "Growth Area: Improve quality of contact."

def discipline_label(obp):
    if obp >= 0.370:
        return "Strength: Advanced plate discipline."
    if obp >= 0.330:
        return "Strength: Serviceable on-base profile."
    return "Growth Area: Improve swing decisions."

print(contact_label(0.311))
print(discipline_label(0.382))

Expected output:

Strength: Excellent contact consistency.
Strength: Advanced plate discipline.

Try different values to see how labels update.

Milestone 3: Create a full scouting summary paragraph

Now build one polished paragraph that sounds like a scouting note.

Add this below your current code:

def build_summary(player_name, role, trend_note, strength_line, growth_line):
    return (
        f"{player_name} projects as a {role}. "
        f"{strength_line} {growth_line} "
        f"Recent trend: {trend_note}."
    )

summary = build_summary(
    "Diego Alvarez",
    "top-of-order contact bat with gap power",
    "multi-hit games in 5 of the last 8 contests",
    "Stays through the middle of the field with consistent timing.",
    "Can improve damage on inside fastballs."
)

print(summary)

Expected output:

Diego Alvarez projects as a top-of-order contact bat with gap power. Stays through the middle of the field with consistent timing. Can improve damage on inside fastballs. Recent trend: multi-hit games in 5 of the last 8 contests.

Milestone 4: Load player reports from CSV data

Now separate data from code with data/players.csv. This is how you scale from one player to a full lineup.

  1. Open data/players.csv.
  2. Paste the data below.
  3. Save the file.
  4. Make sure the file name is exactly players.csv (not players.csv.txt).

Paste this into data/players.csv:

name,team,position,batting_avg,obp,slg,ops,trend_note
Diego Alvarez,Greenville Hawks,SS,0.311,0.382,0.512,0.894,multi-hit games in 5 of last 8 contests
Noah Bennett,Greenville Hawks,CF,0.287,0.356,0.471,0.827,extra-base hit in 4 of last 7 contests
Eli Ramos,Greenville Hawks,3B,0.263,0.338,0.446,0.784,walk rate improved over last 10 games

Now load that file in Python. Add this below your existing code:

import csv

players = []

with open("data/players.csv", "r") as file:
    reader = csv.DictReader(file)
    for row in reader:
        players.append({
            "name": row["name"],
            "team": row["team"],
            "position": row["position"],
            "batting_avg": float(row["batting_avg"]),
            "obp": float(row["obp"]),
            "slg": float(row["slg"]),
            "ops": float(row["ops"]),
            "trend_note": row["trend_note"]
        })

print(players)

Click Run Python File again.

Expected output (shortened example):

[{'name': 'Diego Alvarez', 'team': 'Greenville Hawks', ...}, {'name': 'Noah Bennett', ...}, ...]

If you see a list of dictionaries, your CSV load worked.

Milestone 5: Print final scouting cards for each player

Now combine:

  • your report template
  • your label rules
  • your summary paragraph
  • your CSV player list

Add this below Milestone 4:

def print_scouting_card(player):
    strength = contact_label(player["batting_avg"])
    growth = discipline_label(player["obp"])
    summary = build_summary(
        player["name"],
        "lineup bat who can control at-bats",
        player["trend_note"],
        strength,
        growth
    )

    print("=" * 48)
    print(f"SCOUTING CARD: {player['name']}")
    print("=" * 48)
    print(build_report(
        player["name"],
        player["team"],
        player["position"],
        player["batting_avg"],
        player["obp"],
        player["slg"]
    ))
    print(summary)
    print("=" * 48)

for player in players:
    print_scouting_card(player)

Expected result:

  • You should see one scouting card per player.
  • Each card should include report lines and a summary paragraph.

If you made it this far, you built a full baseball scouting report generator from scratch.

Common Fixes

  • FileNotFoundError: confirm the path is exactly data/players.csv.
  • ValueError: check that batting_avg, obp, and slg are numeric in CSV.
  • No play button: install/enable Python extension in Cursor and reopen scouting_report.py.

Bonus Exercises: Push It Further with Your Agent

Use this short prompt structure for better AI help:

  1. Goal: what you want to build
  2. Context: file name + what code already exists
  3. Constraints: keep beginner-friendly, minimal changes
  4. Output format: ask for exact code + where to paste + expected output

Bonus 1: Add Letter Grades

Try this prompt:

You are my Python tutor and coding assistant.

Goal:
Add letter grades (A/B/C) for AVG, OBP, and SLG.

Context:
I am editing scouting_report.py.
I already have build_report(...), build_summary(...), and print_scouting_card(...).

Constraints:
- Keep my existing output working.
- Make minimal code changes.
- Keep code beginner-friendly.

Output format:
1) Short plan (3 bullets)
2) Exact code blocks to add/change
3) Where to paste each block
4) Expected output example for one player

Bonus 2: Add a Batted-Ball Profile Section

Try this prompt:

You are my Python tutor and coding assistant.

Goal:
Add a "Batted-Ball Profile" section with line-drive and hard-hit notes.

Context:
I am using data/players.csv in scouting_report.py.
Include any CSV header updates.

Constraints:
- Keep the same project structure.
- Do not rewrite the full file.
- Explain changes in simple language.

Output format:
1) Updated CSV header + sample row
2) Code changes only
3) Where to paste changes
4) One test run to verify output

Bonus 3: Export Reports to a File

Try this prompt:

You are my Python tutor and coding assistant.

Goal:
Write all scouting cards to scouting_reports.txt.

Context:
I already loop through players and print each card in scouting_report.py.

Constraints:
- Keep terminal output and save to file.
- Use simple Python only.

Output format:
1) Minimal code changes
2) Where each change goes
3) Expected first 8 lines of scouting_reports.txt
4) One troubleshooting tip if file is empty