Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions docs/simulation_competitions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Tutorial: Simulation Competitions

This tutorial walks you through interacting with a Kaggle simulation competition using the CLI — from finding the competition to downloading episode replays and agent logs.

Simulation competitions (e.g., [Connect X](https://www.kaggle.com/competitions/connectx), [Lux AI](https://www.kaggle.com/competitions/lux-ai-season-3)) differ from standard competitions. Instead of submitting a CSV of predictions, you submit an agent (code) that plays against other agents in episodes. Each episode contains multiple agents competing against each other. You can identify simulation competitions on the [competitions page](https://www.kaggle.com/competitions) by their "Simulation" tag, or by looking for competitions that mention agents, bots, or game environments in their description.

## 1. Find and Inspect the Competition

Search for simulation competitions by keyword:

```bash
kaggle competitions list -s simulation
```

Once you've identified a competition (e.g., `connectx`), view its pages to read the rules, evaluation criteria, and other details:

```bash
kaggle competitions pages connectx
```

This lists the available pages (e.g., `description`, `rules`, `evaluation`, `data-description`). To read the full content of a page:

```bash
kaggle competitions pages connectx --content
```

## 2. Accept the Competition Rules

Before you can submit or download data, you **must** accept the competition rules on the Kaggle website. Navigate to the competition page (e.g., `https://www.kaggle.com/competitions/connectx`) and click "Join Competition" or "I Understand and Accept".

You can verify you've joined by checking your entered competitions:

```bash
kaggle competitions list --group entered
```

## 3. Download Competition Data

Download the competition's starter kit and any provided data:

```bash
kaggle competitions download connectx -p connectx-data
```

## 4. Submit Your Agent

Simulation competitions require you to submit agent code. You can upload files directly from your local machine.

**Single file agent** — if your agent is a single `main.py`:

```bash
kaggle competitions submit connectx -f main.py -m "Single file agent v1"
```

**Multi-file agent** — if your agent spans multiple files, bundle them into a `submission.tar.gz` with `main.py` at the root:

```bash
tar -czf submission.tar.gz main.py helper.py model_weights.pkl
kaggle competitions submit connectx -f submission.tar.gz -m "Multi-file agent v1"
```

**Notebook submission** — alternatively, you can submit via an existing Kaggle notebook:

```bash
kaggle competitions submit connectx -k YOUR_USERNAME/connectx-agent -f submission.tar.gz -v 1 -m "Notebook agent v1"
```

## 5. Monitor Your Submission

Check the status of your submissions:

```bash
kaggle competitions submissions connectx
```

Note the submission ID from the output — you'll need it to view episodes.

## 6. List Episodes for a Submission

Once your submission has played some games, list the episodes:

```bash
kaggle competitions episodes 12345678
```

Replace `12345678` with your submission ID. This shows a table of episodes with columns: `id`, `createTime`, `endTime`, `state`, and `type`.

To get the output in CSV format for scripting:

```bash
kaggle competitions episodes 12345678 -v
```

## 7. Download an Episode Replay

To download the replay data for a specific episode (useful for visualizing what happened):

```bash
kaggle competitions replay 98765432
```

This downloads the replay JSON to your current directory as `episode-98765432-replay.json`. To specify a download location:

```bash
kaggle competitions replay 98765432 -p ./replays
```

## 8. Download Agent Logs

To debug your agent's behavior, download the logs for a specific agent in an episode. You need the episode ID and the agent's index (0-based):

```bash
# Download logs for the first agent (index 0)
kaggle competitions logs 98765432 0

# Download logs for the second agent (index 1)
kaggle competitions logs 98765432 1 -p ./logs
```

This downloads the log file as `episode-98765432-agent-0-logs.json`.

## Putting It All Together

Here's a typical workflow for iterating on a simulation competition agent:

```bash
# Download competition data
kaggle competitions download connectx -p connectx-data

# Submit your agent (single file)
kaggle competitions submit connectx -f main.py -m "v1"

# Check submission status
kaggle competitions submissions connectx

# List episodes (replace with your submission ID)
kaggle competitions episodes 12345678

# Download replay and logs for an episode
kaggle competitions replay 98765432
kaggle competitions logs 98765432 0

# Check the leaderboard
kaggle competitions leaderboard connectx -s
```
164 changes: 164 additions & 0 deletions src/kaggle/api/kaggle_api_extended.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@
ApiDataFile,
ApiCreateCodeSubmissionResponse,
ApiListCompetitionsResponse,
ApiListSubmissionEpisodesRequest,
ApiListSubmissionEpisodesResponse,
ApiGetEpisodeReplayRequest,
ApiGetEpisodeAgentLogsRequest,
ApiListCompetitionPagesRequest,
ApiListCompetitionPagesResponse,
)
from kagglesdk.competitions.types.competition_enums import (
CompetitionListTab,
Expand Down Expand Up @@ -624,6 +630,9 @@ class KaggleApi:
model_instance_labels = ["version", "notes", "created", "size"]
model_instance_version_fields = ["versionNumber", "variationSlug", "modelTitle", "isPrivate"]
model_instance_version_labels = ["version", "variation", "title", "private"]
episode_fields = ["id", "createTime", "endTime", "state", "type"]
episode_agent_fields = ["submissionId", "index", "reward", "state", "teamName", "teamId"]
competition_page_fields = ["name"]

def __init__(self, enable_oauth: bool = False):
self.enable_oauth = enable_oauth
Expand Down Expand Up @@ -1742,6 +1751,161 @@ def competition_leaderboard_cli(
else:
print("No results found")

def competition_list_episodes(self, submission_id: int):
"""List episodes for a submission in a simulation competition.

Args:
submission_id (int): The submission ID to list episodes for.

Returns:
list: A list of ApiEpisode objects.
"""
with self.build_kaggle_client() as kaggle:
request = ApiListSubmissionEpisodesRequest()
request.submission_id = submission_id
response = kaggle.competitions.competition_api_client.list_submission_episodes(request)
return response.episodes

def competition_list_episodes_cli(self, submission_id, csv_display=False, quiet=False):
"""CLI wrapper for competition_list_episodes.

Args:
submission_id (int): The submission ID.
csv_display (bool): If True, print CSV instead of table.
quiet (bool): Suppress verbose output.
"""
episodes = self.competition_list_episodes(submission_id)
if episodes:
if csv_display:
self.print_csv(episodes, self.episode_fields)
else:
self.print_table(episodes, self.episode_fields)
if not quiet:
print(
'\nUse "kaggle competitions replay <episode_id>" to download a replay, '
'or "kaggle competitions logs <episode_id> <agent_index>" for agent logs.'
)
else:
print("No episodes found")

def competition_episode_replay(self, episode_id: int, path: Optional[str] = None, quiet: bool = True):
"""Download the replay for an episode.

Args:
episode_id (int): The episode ID.
path (Optional[str]): A path to download the file to.
quiet (bool): Suppress verbose output.
"""
with self.build_kaggle_client() as kaggle:
request = ApiGetEpisodeReplayRequest()
request.episode_id = episode_id
response = kaggle.competitions.competition_api_client.get_episode_replay(request)
if path is None:
effective_path = os.getcwd()
else:
effective_path = path
outfile = os.path.join(effective_path, f"episode-{episode_id}-replay.json")
self.download_file(response, outfile, kaggle.http_client(), quiet)
if not quiet:
print(f"Replay downloaded to: {outfile}")

def competition_episode_replay_cli(self, episode_id, path=None, quiet=False):
"""CLI wrapper for competition_episode_replay.

Args:
episode_id (int): The episode ID.
path (Optional[str]): A path to download the file to.
quiet (bool): Suppress verbose output.
"""
self.competition_episode_replay(episode_id, path, quiet)

def competition_episode_agent_logs(
self, episode_id: int, agent_index: int, path: Optional[str] = None, quiet: bool = True
):
"""Download logs for a specific agent in an episode.

Args:
episode_id (int): The episode ID.
agent_index (int): The agent index.
path (Optional[str]): A path to download the file to.
quiet (bool): Suppress verbose output.
"""
with self.build_kaggle_client() as kaggle:
request = ApiGetEpisodeAgentLogsRequest()
request.episode_id = episode_id
request.agent_index = agent_index
response = kaggle.competitions.competition_api_client.get_episode_agent_logs(request)
if path is None:
effective_path = os.getcwd()
else:
effective_path = path
outfile = os.path.join(effective_path, f"episode-{episode_id}-agent-{agent_index}-logs.json")
self.download_file(response, outfile, kaggle.http_client(), quiet)
if not quiet:
print(f"Agent logs downloaded to: {outfile}")

def competition_episode_agent_logs_cli(self, episode_id, agent_index, path=None, quiet=False):
"""CLI wrapper for competition_episode_agent_logs.

Args:
episode_id (int): The episode ID.
agent_index (int): The agent index.
path (Optional[str]): A path to download the file to.
quiet (bool): Suppress verbose output.
"""
self.competition_episode_agent_logs(episode_id, agent_index, path, quiet)

def competition_list_pages(self, competition: str, page_name: Optional[str] = None):
"""List pages for a competition.

Args:
competition (str): The competition name.
page_name (Optional[str]): Filter to a specific page by name.

Returns:
list: A list of ApiCompetitionPage objects.
"""
with self.build_kaggle_client() as kaggle:
request = ApiListCompetitionPagesRequest()
request.competition_name = competition
if page_name:
request.page_name = page_name
response = kaggle.competitions.competition_api_client.list_competition_pages(request)
return response.pages

def competition_list_pages_cli(
self, competition=None, competition_opt=None, csv_display=False, quiet=False, content=False,
page_name=None
):
"""CLI wrapper for competition_list_pages.

Args:
competition: The competition name.
competition_opt: An alternative competition option provided by cli.
csv_display (bool): If True, print CSV instead of table.
quiet (bool): Suppress verbose output.
content (bool): If True, show full page content.
page_name (Optional[str]): Filter to a specific page by name.
"""
competition = competition or competition_opt
if competition is None:
competition = self.get_config_value(self.CONFIG_NAME_COMPETITION)
if competition is not None and not quiet:
print("Using competition: " + competition)

if competition is None:
raise ValueError("No competition specified")

pages = self.competition_list_pages(competition, page_name=page_name)
if pages:
fields = ["name", "content"] if content else self.competition_page_fields
if csv_display:
self.print_csv(pages, fields)
else:
self.print_table(pages, fields)
else:
print("No pages found")

def dataset_list(
self,
sort_by: Optional[str] = None,
Expand Down
Loading
Loading