From 674dfc7ee0c36e322369d3ba524ec41d893155c1 Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 3 Jun 2026 23:19:36 +0100 Subject: [PATCH] remove random movement test --- .../motion_planning/random_movement_test.py | 202 ------------------ 1 file changed, 202 deletions(-) delete mode 100644 utama_core/tests/motion_planning/random_movement_test.py diff --git a/utama_core/tests/motion_planning/random_movement_test.py b/utama_core/tests/motion_planning/random_movement_test.py deleted file mode 100644 index 278d4c31..00000000 --- a/utama_core/tests/motion_planning/random_movement_test.py +++ /dev/null @@ -1,202 +0,0 @@ -"""Tests for random movement collision avoidance with multiple robots.""" - -import os -import random -from dataclasses import dataclass -from typing import Dict - -import numpy as np - -from utama_core.config.field_params import STANDARD_FIELD_DIMS -from utama_core.config.physical_constants import ROBOT_RADIUS -from utama_core.entities.data.vector import Vector2D -from utama_core.entities.game import Game -from utama_core.entities.game.field import Field, FieldBounds -from utama_core.run import StrategyRunner -from utama_core.strategy.examples.motion_planning.random_movement_strategy import ( - RandomMovementStrategy, -) -from utama_core.team_controller.src.controllers import AbstractSimController -from utama_core.tests.common.abstract_test_manager import ( - AbstractTestManager, - TestingStatus, -) - -# Fix pygame window position for screen capture -os.environ["SDL_VIDEO_WINDOW_POS"] = "100,100" - - -@dataclass -class RandomMovementScenario: - """Configuration for random movement collision test.""" - - n_robots: int - field_bounds: FieldBounds - min_target_distance: float - required_targets_per_robot: int - collision_threshold: float = ROBOT_RADIUS * 2.0 - endpoint_tolerance: float = 0.25 - - -class RandomMovementTestManager(AbstractTestManager): - """Test manager for random movement with collision detection.""" - - n_episodes = 1 - - def __init__(self, scenario: RandomMovementScenario): - super().__init__() - self.scenario = scenario - self.collision_detected = False - self.min_distance = float("inf") - self.targets_reached_count: Dict[int, int] = {} - # track targets reached per robot - - def reset_field(self, sim_controller: AbstractSimController, game: Game): - """Reset field with robots in random starting positions within bounds.""" - bounds = self.scenario.field_bounds - min_x = min(bounds.top_left[0], bounds.bottom_right[0]) - max_x = max(bounds.top_left[0], bounds.bottom_right[0]) - min_y = min(bounds.top_left[1], bounds.bottom_right[1]) - max_y = max(bounds.top_left[1], bounds.bottom_right[1]) - - # Use a fixed seed for reproducibility across test runs - rng = random.Random(420 + self.current_episode_number) - - for i in range(self.scenario.n_robots): - x = rng.uniform(min_x + 0.5, max_x - 0.5) - y = rng.uniform(min_y + 0.5, max_y - 0.5) - sim_controller.teleport_robot(game.my_team_is_yellow, i, x, y, 0.0) - self.targets_reached_count[i] = 0 - - self._reset_metrics() - - def _reset_metrics(self): - """Reset tracking metrics for new episode.""" - self.collision_detected = False - self.min_distance = float("inf") - - def eval_status(self, game: Game): - """Evaluate collision status and target achievement.""" - # Check collisions between all pairs of friendly robots - for robot_id, robot in game.friendly_robots.items(): - robot_pos = Vector2D(robot.p.x, robot.p.y) - - # Check collisions with other friendly robots - for other_id, other_robot in game.friendly_robots.items(): - if robot_id >= other_id: - continue - other_pos = Vector2D(other_robot.p.x, other_robot.p.y) - distance = robot_pos.distance_to(other_pos) - self.min_distance = min(self.min_distance, distance) - - if distance < self.scenario.collision_threshold: - self.collision_detected = True - return TestingStatus.FAILURE - - # Check if all robots have reached required number of targets - # This is tracked by the strategy itself - all_completed = all( - count >= self.scenario.required_targets_per_robot for count in self.targets_reached_count.values() - ) - if all_completed: - return TestingStatus.SUCCESS - - return TestingStatus.IN_PROGRESS - - def update_target_reached(self, robot_id: int): - """Called by strategy when a robot reaches a target.""" - if robot_id in self.targets_reached_count: - self.targets_reached_count[robot_id] += 1 - - -def test_random_movement_same_team( - headless: bool, - mode: str = "rsim", -): - """ - Test where 2 robots from the same team move randomly within half court. - - The robots should: - 1. Start at random positions within their half court - 2. Navigate to random targets with minimum distance requirement - 3. Each robot reaches at least 3 different targets - 4. Avoid collisions with all teammates throughout the movement - """ - my_team_is_yellow = True - my_team_is_right = False # Yellow on left half - - # use small bounds to increase chance of collision - small_bounds = FieldBounds( - top_left=( - -STANDARD_FIELD_DIMS.full_field_half_length + 1, - STANDARD_FIELD_DIMS.full_field_half_width - 1, - ), - bottom_right=( - -STANDARD_FIELD_DIMS.full_field_half_length + 3, - STANDARD_FIELD_DIMS.full_field_half_width - 3, - ), - ) - - # Max is 6 robots - n_robots = 2 - - seed = 42 - - random.seed(seed) - np.random.seed(seed) - - scenario = RandomMovementScenario( - n_robots=n_robots, - field_bounds=small_bounds, - min_target_distance=1.0, # Minimum distance for next target - required_targets_per_robot=5, # Each robot must reach 5 targets - endpoint_tolerance=0.3, - ) - - test_manager = RandomMovementTestManager(scenario) - - # Create random movement strategy - strategy = RandomMovementStrategy( - n_robots=n_robots, - field_bounds=small_bounds, - min_target_distance=scenario.min_target_distance, - seed=seed, - endpoint_tolerance=scenario.endpoint_tolerance, - on_target_reached=test_manager.update_target_reached, - ) - - runner = StrategyRunner( - strategy=strategy, - my_team_is_yellow=my_team_is_yellow, - my_team_is_right=my_team_is_right, - mode=mode, - exp_friendly=n_robots, - exp_enemy=0, - exp_ball=False, - ) - - test_passed = runner.run_test( - test_manager=test_manager, - episode_timeout=60.0, # 60 seconds to complete random movements - rsim_headless=headless, - ) - - # Assertions - assert test_passed, "Random movement test failed to complete" - - # Check that all robots reached required targets - for robot_id in range(n_robots): - assert test_manager.targets_reached_count[robot_id] >= scenario.required_targets_per_robot, ( - f"Robot {robot_id} only reached {test_manager.targets_reached_count[robot_id]} targets " - f"(required: {scenario.required_targets_per_robot})" - ) - - assert not test_manager.collision_detected, ( - f"Robots collided during random movement! " - f"Minimum distance: {test_manager.min_distance:.3f}m " - f"(threshold: {scenario.collision_threshold:.3f}m)" - ) - assert test_manager.min_distance >= scenario.collision_threshold, ( - f"Robots got too close: {test_manager.min_distance:.3f}m " - f"(minimum safe distance: {scenario.collision_threshold:.3f}m)" - )