Files
Main/simulator/modules/robot_utils.py
2025-11-07 11:39:23 +00:00

121 lines
3.7 KiB
Python

"""General utilities that are useful across runners."""
from __future__ import annotations
import json
import platform
import subprocess
import sys
from pathlib import Path
from typing import NamedTuple
# Configure path to import the environment configuration
sys.path.insert(0, str(Path(__file__).parents[1]))
import environment
# Reset the path
del sys.path[0]
class MatchData(NamedTuple):
"""
Data about the current match.
:param match_number: The current match number
:param match_duration: The duration of the match in seconds
:param video_enabled: Whether video recording is enabled
:param video_resolution: The resolution of the video recording
"""
match_number: int | None = None
match_duration: int = environment.DEFAULT_MATCH_DURATION
video_enabled: bool = True
video_resolution: tuple[int, int] = (1920, 1080)
def get_robot_file(robot_zone: int) -> Path:
"""
Get the path to the robot file for the given zone.
:param robot_zone: The zone number
:return: The path to the robot file
:raises FileNotFoundError: If no robot controller is found for the given zone
"""
robot_file = environment.ZONE_ROOT / f'zone_{robot_zone}' / 'robot.py'
# Check if the robot file exists
if not robot_file.exists():
raise FileNotFoundError(f"No robot code to run for zone {robot_zone}")
return robot_file
def get_game_mode() -> str:
"""
Get the game mode from the game mode file.
Default to 'dev' if the file does not exist.
:return: The game mode
"""
if environment.GAME_MODE_FILE.exists():
game_mode = environment.GAME_MODE_FILE.read_text().strip()
else:
game_mode = 'dev'
assert game_mode in ['dev', 'comp'], f'Invalid game mode: {game_mode}'
return game_mode
def print_simulation_version() -> None:
"""
Print the version of the simulator that is running.
Uses a VERSION file in the root of the simulator to determine the version.
For development, the version is uses the git describe command.
The version is printed to the console.
"""
version_file = environment.SIM_ROOT / 'VERSION'
if version_file.exists():
version = version_file.read_text().strip()
else:
try:
version = subprocess.check_output(
['git', 'describe', '--tags', '--always'],
cwd=str(environment.SIM_ROOT.resolve()),
).decode().strip()
except subprocess.CalledProcessError:
version = 'unknown'
print(
f"Running simulator version: {version} in Python {platform.python_version()} "
f"({platform.system()}-{platform.machine()})"
)
def get_match_data() -> MatchData:
"""Load the match data from the match data file."""
match_data_file = environment.ARENA_ROOT / 'match.json'
default_match_data = MatchData()
if match_data_file.exists():
# TODO error handling for invalid json
raw_data = json.loads(match_data_file.read_text())
match_data = MatchData(
match_number=raw_data.get('match_number', default_match_data.match_number),
match_duration=raw_data.get('duration', default_match_data.match_duration),
video_enabled=(
raw_data.get('recording_config', {})
.get('enabled', default_match_data.video_enabled)
),
video_resolution=(
raw_data.get('recording_config', {})
.get('video_resolution', default_match_data.video_resolution)
),
)
else:
match_data = default_match_data
return match_data