From 57919a77cc819edfebaec5d966e375c5114cf52f Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sat, 14 Feb 2026 17:21:20 -0800 Subject: [PATCH 01/24] add halt_test_play fsm --- src/plan.md | 214 ++++++++++++++++++ .../stp/play/test_plays/halt_test_play_fsm.h | 46 ++++ 2 files changed, 260 insertions(+) create mode 100644 src/plan.md create mode 100644 src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h diff --git a/src/plan.md b/src/plan.md new file mode 100644 index 0000000000..af3d86b129 --- /dev/null +++ b/src/plan.md @@ -0,0 +1,214 @@ +# Plan: Remove Coroutine Support from Plays (Ticket #2359) + +## Context + +The play framework currently supports two patterns: **coroutine-based** (legacy, using `boost::coroutines2`) and **FSM-based** (modern, using Boost SML). 12 plays have already been migrated to FSM but still carry dead coroutine stub methods. 11 plays still actively use coroutines. The `Play` base class contains significant coroutine infrastructure marked with `TODO (#2359)` comments. This plan converts all remaining coroutine plays to FSM and removes all coroutine support code from the play framework. It also converts the validation test coroutines. + +--- + +## Phase 1: Convert Simple Single-State Coroutine Plays to FSM + +These plays have a single `do { ... yield(); } while(true)` loop — they map to a single FSM state that self-transitions on every update. + +### 1a. StopPlay +- **Create** `software/ai/hl/stp/play/stop_play/stop_play_fsm.h` — single `StopState` with `updateStop` action +- **Rewrite** `stop_play.h` → inherit `PlayBase`, remove `getNextTactics` +- **Rewrite** `stop_play.cpp` → implement `updateTactics` via `fsm.process_event()` +- **Move** files into new `stop_play/` subdirectory (matching existing convention) +- **Update** BUILD files + +### 1b. KickoffEnemyPlay +- **Create** `software/ai/hl/stp/play/kickoff_enemy/kickoff_enemy_play_fsm.h` — single `DefendState` with `updateDefense` action +- **Rewrite** `kickoff_enemy_play.h/cpp` → `PlayBase` +- **Move** into `kickoff_enemy/` subdirectory +- **Update** BUILD files + +### 1c. HaltTestPlay +- **Create** `software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h` — single `HaltState` +- **Rewrite** `halt_test_play.h/cpp` → `PlayBase` +- **Update** BUILD + +### 1d. Hardware Challenge Plays (4 plays) +All 4 have identical structure: `do { if(playing) {action} else {setup} yield(); } while(true)` + +Each gets a single FSM with one state and a guard for `isPlaying()`: +- `dribbling_parcour_play_fsm.h` — DribblingParcourPlayFSM +- `pass_endurance_play_fsm.h` — PassEndurancePlayFSM +- `scoring_from_contested_possession_play_fsm.h` — ScoringFromContestedPossessionPlayFSM +- `scoring_with_static_defenders_play_fsm.h` — ScoringWithStaticDefendersPlayFSM + +Rewrite each play to inherit `PlayBase<*FSM>` and implement `updateTactics`. + +--- + +## Phase 2: Convert Multi-State Coroutine Plays to FSM + +### 2a. KickoffFriendlyPlay (2 stages) +- **States:** `SetupState` (while `isSetupState()`), `ChipState` (while `!isPlaying()`) +- **Guards:** `setupDone` (transitions when `!isSetupState()`), `chipDone` (when `isPlaying()`) +- **Create** `kickoff_friendly/kickoff_friendly_play_fsm.h` +- **Move** into `kickoff_friendly/` subdirectory +- **Rewrite** play files + +### 2b. ShootOrChipPlay (conditional loop) +- **State:** Single `ShootOrChipState` with `attackerDone` guard for terminal transition +- **Create** `shoot_or_chip/shoot_or_chip_play_fsm.h` +- **Move** into `shoot_or_chip/` subdirectory +- **Rewrite** play files + +### 2c. MoveTestPlay (conditional loop) +- **State:** Single `MoveState` with `moveDone` guard checking `move_test_tactic_center_field->done()` +- **Create** `test_plays/move_test_play_fsm.h` +- **Rewrite** play files + +--- + +## Phase 3: Handle AssignedTacticsPlay (Special Case) + +`AssignedTacticsPlay` overrides `get()` entirely and already has an empty `updateTactics()`. Its coroutine method is dead code. +- **Remove** `getNextTactics` override from header and source +- No FSM needed — this play has its own unique dispatch pattern via `get()` + +--- + +## Phase 4: Clean Up Play Base Class + +Once all plays are FSM-based, remove all coroutine infrastructure from the base class. + +### Files: `play.h`, `play.cpp` + +**Remove from `play.h`:** +- `#include ` +- `using TacticCoroutine = ...` typedef +- `PriorityTacticVector getTactics(...)` private method +- `void getNextTacticsWrapper(...)` private method +- `virtual void getNextTactics(...)` pure virtual +- `TacticCoroutine::pull_type tactic_sequence` member +- `std::optional world_ptr_` member +- `PriorityTacticVector priority_tactics` member +- All `TODO (#2359)` comments + +**Make `updateTactics` pure virtual** (currently has default impl that delegates to coroutine) + +**Remove from `play.cpp`:** +- `getTactics()` function (lines 30-85) +- `getNextTacticsWrapper()` function (lines 236-251) +- Default `updateTactics()` implementation (lines 253-257) +- Coroutine initialization in constructor (tactic_sequence, world_ptr_ init) + +**Update `play.h` constructor** — remove `tactic_sequence` and `world_ptr_` from initializer list + +**Remove from BUILD** (`software/ai/hl/stp/play/BUILD`): +- `@boost//:coroutine2` from the `play` target deps + +--- + +## Phase 5: Clean Up FSM Play Stubs + +Remove empty `getNextTactics` overrides from all 12 existing FSM plays: + +| Play | File | +|------|------| +| HaltPlay | `halt_play/halt_play.h` + `.cpp` | +| ExamplePlay | `example/example_play.h` + `.cpp` | +| OffensePlay | `offense/offense_play.h` + `.cpp` | +| ShootOrPassPlay | `shoot_or_pass/shoot_or_pass_play.h` + `.cpp` | +| PenaltyKickPlay | `penalty_kick/penalty_kick_play.h` + `.cpp` | +| PenaltyKickEnemyPlay | `penalty_kick_enemy/penalty_kick_enemy_play.h` + `.cpp` | +| FreeKickPlay | `free_kick/free_kick_play.h` + `.cpp` | +| BallPlacementPlay | `ball_placement/ball_placement_play.h` + `.cpp` | +| CreaseDefensePlay | `crease_defense/crease_defense_play.h` + `.cpp` | +| DefensePlay | `defense/defense_play.h` + `.cpp` | +| EnemyBallPlacementPlay | `enemy_ball_placement/enemy_ball_placement_play.h` + `.cpp` | +| EnemyFreeKickPlay | `enemy_free_kick/enemy_free_kick_play.h` + `.cpp` | + +For each: remove `getNextTactics` declaration from `.h` and empty implementation from `.cpp`. + +--- + +## Phase 6: Convert Validation Coroutines + +### 6a. Replace Validation Infrastructure + +**Files:** +- `software/simulated_tests/validation/validation_function.h` +- `software/simulated_tests/validation/terminating_function_validator.h` + `.cpp` +- `software/simulated_tests/validation/non_terminating_function_validator.h` + `.cpp` + +**Change `ValidationFunction` signature** from: +```cpp +std::function, ValidationCoroutine::push_type&)> +``` +to a per-tick checker: +```cpp +std::function(std::shared_ptr)> +``` + +**Rewrite `TerminatingFunctionValidator`:** +- Remove coroutine state (`pull_type`, wrapper) +- Track completion: call the function each tick. If it returns `nullopt`, mark as complete. If it returns a string, record the error and keep checking. + +**Rewrite `NonTerminatingFunctionValidator`:** +- Same simplification: call function each tick, return error or nullopt +- No restart logic needed since there's no coroutine to restart + +Remove `boost::coroutine2` includes and typedefs. + +### 6b. Rewrite All 17 Validation Functions + +**8 Terminating validation functions** (in `simulated_tests/terminating_validation_functions/`): +- `ball_at_point_validation` +- `ball_kicked_validation` +- `friendly_scored_validation` +- `robot_halt_validation` +- `robot_in_center_circle_validation` +- `robot_in_polygon_validation` +- `robot_received_ball_validation` +- `robot_state_validation` + +**9 Non-terminating validation functions** (in `simulated_tests/non_terminating_validation_functions/`): +- `ball_in_play_or_scored_validation` +- `ball_never_moves_backward_validation` +- `enemy_never_scores_validation` +- `robot_not_excessively_dribbling_validation` +- `robots_avoid_ball_validation` +- `robots_in_friendly_half_validation` +- `robots_not_in_center_circle_validation` +- `robots_slow_down_validation` +- `robots_violating_motion_constraint` + +Each function changes from `void fn(World, yield)` with while-loop-yield to `optional fn(World)` returning error or nullopt. + +**For stateful validators** (e.g., `ball_never_moves_backward` which tracks previous ball position): convert to a class or use `std::function` with captured state via a factory function. + +### 6c. Update BUILD Files +- Remove `@boost//:coroutine2` from: + - `software/simulated_tests/validation/BUILD` + - `software/simulated_tests/terminating_validation_functions/BUILD` + - `software/simulated_tests/non_terminating_validation_functions/BUILD` + +--- + +## Key Patterns to Reuse + +- **FSM template:** `PlayFSM` in `play_fsm.hpp` — all new FSMs inherit from this +- **Play template:** `PlayBase` in `play_base.hpp` — all converted plays inherit from this +- **SML macros:** `DEFINE_SML_STATE`, `DEFINE_SML_EVENT`, `DEFINE_SML_ACTION`, `DEFINE_SML_GUARD` in `software/util/sml_fsm/sml_fsm.h` +- **Reference FSM plays:** `HaltPlayFSM` (simplest), `FreeKickPlayFSM` (multi-state) +- **Factory registration:** `TGenericFactory` pattern stays the same + +--- + +## Verification + +1. **Build:** `bazel build //software/ai/hl/stp/play/...` — ensure all play targets compile +2. **Play tests:** Run existing play tests: + - `bazel test //software/ai/hl/stp/play:kickoff_friendly_play_cpp_test` + - `bazel test //software/ai/hl/stp/play:kickoff_enemy_play_cpp_test` + - `bazel test //software/ai/hl/stp/play:stop_play_test` + - `bazel test //software/ai/hl/stp/play:shoot_or_chip_play_cpp_test` + - `bazel test //software/ai/hl/stp/play:play_factory_test` +3. **Validation tests:** + - `bazel test //software/simulated_tests/validation/...` +4. **Full build:** `bazel build //...` — ensure no boost::coroutine2 references remain in play/validation code +5. **Grep check:** Verify no remaining `TacticCoroutine`, `getNextTactics`, or coroutine yield patterns in play files diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h new file mode 100644 index 0000000000..9fa2bcbb6b --- /dev/null +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h @@ -0,0 +1,46 @@ +#pragma once + +#include "proto/parameters.pb.h" +#include "shared/constants.h" +#include "software/ai/hl/stp/play/play_fsm.hpp" +#include "software/ai/hl/stp/tactic/halt/halt_tactic.h" + +struct HaltTestPlayFSM : PlayFSM + { + struct ControlParams + { + }; + + class HaltTestState; + + explicit HaltTestPlayFSM(std::shared_ptr ai_config_ptr) + : PlayFSM(ai_config_ptr), + halt_tactics({{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + }}) + { + } + + void updateHalt(const Update& event) + { + event.common.set_tactics(halt_tactics); + } + + auto operator()() + { + using namespace boost::sml; + + DEFINE_SML_STATE(HaltTestState) + DEFINE_SML_EVENT(Update) + DEFINE_SML_ACTION(updateHalt) + + return make_transition_table( + *HaltTestState_S + Update_E / updateHalt_A = HaltTestState_S, + X + Update_E / updateHalt_A = X); + } + + private: + PriorityTacticVector halt_tactics; + }; From 061e6d65dab6b3b5ec190ca5b6fddff5f8cd56c8 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sat, 14 Feb 2026 17:31:34 -0800 Subject: [PATCH 02/24] update halt_test_play.h --- src/software/ai/hl/stp/play/test_plays/halt_test_play.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h index aeeed0cfad..2cbce35b76 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h @@ -2,6 +2,8 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" +#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" // your new FSM +#include "software/ai/hl/stp/play/play_base.hpp" /** * A test Play that halts 3 robots. @@ -11,7 +13,7 @@ * This play is applicable when the ball's y coordinate is >= 0 * This play's invariant holds while the ball is within the field */ -class HaltTestPlay : public Play +class HaltTestPlay : public PlayBase { public: /** @@ -21,6 +23,5 @@ class HaltTestPlay : public Play */ HaltTestPlay(std::shared_ptr ai_config_ptr); - void getNextTactics(TacticCoroutine::push_type &yield, - const WorldPtr &world_ptr) override; + void updateTactics(const PlayUpdate &play_update) override; }; From 8dae978b705978b7a6444156dcbfb8e301427171 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sat, 14 Feb 2026 17:39:07 -0800 Subject: [PATCH 03/24] convert halt_test_play.cpp --- .../hl/stp/play/test_plays/halt_test_play.cpp | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp b/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp index 50b7cc7dc9..be2711eebb 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp @@ -1,27 +1,15 @@ #include "software/ai/hl/stp/play/test_plays/halt_test_play.h" -#include "software/ai/hl/stp/tactic/halt/halt_tactic.h" -#include "software/geom/algorithms/contains.h" #include "software/util/generic_factory/generic_factory.h" HaltTestPlay::HaltTestPlay(std::shared_ptr ai_config_ptr) - : Play(ai_config_ptr, false) + : PlayBase(ai_config_ptr, false) { } -void HaltTestPlay::getNextTactics(TacticCoroutine::push_type &yield, - const WorldPtr &world_ptr) -{ - auto halt_test_tactic_1 = std::make_shared(ai_config_ptr); - auto halt_test_tactic_2 = std::make_shared(ai_config_ptr); - auto halt_test_tactic_3 = std::make_shared(ai_config_ptr); - - do - { - yield({{halt_test_tactic_1, halt_test_tactic_2, halt_test_tactic_3}}); - } while (true); -} - +void HaltTestPlay::updateTactics(const PlayUpdate &play_update){ + fsm.process_event(HaltTestPlayFSM::Update(control_params, play_update)); +}; // Register this play in the genericFactory static TGenericFactory> From ed8a8cfa03665510cef8eaf694cbad22b5447bb3 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sat, 14 Feb 2026 17:49:35 -0800 Subject: [PATCH 04/24] add test and update build --- src/software/ai/hl/stp/play/test_plays/BUILD | 20 +++++++++++-- .../test_plays/halt_test_play_fsm_test.cpp | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp diff --git a/src/software/ai/hl/stp/play/test_plays/BUILD b/src/software/ai/hl/stp/play/test_plays/BUILD index bc08c72b17..a995a2d885 100644 --- a/src/software/ai/hl/stp/play/test_plays/BUILD +++ b/src/software/ai/hl/stp/play/test_plays/BUILD @@ -2,8 +2,14 @@ package(default_visibility = ["//visibility:public"]) cc_library( name = "halt_test_play", - srcs = ["halt_test_play.cpp"], - hdrs = ["halt_test_play.h"], + srcs = [ + "halt_test_play.cpp", + "halt_test_play_fsm.cpp" + ], + hdrs = [ + "halt_test_play.h", + "halt_test_play.h" + ], deps = [ "//software/ai/hl/stp/play", "//software/ai/hl/stp/tactic/halt:halt_tactic", @@ -23,3 +29,13 @@ cc_library( ], alwayslink = True, ) + +cc_test( + name = "halt_test_play_fsm_test", + srcs = ["halt_test_play_fsm_test.cpp"], + deps = [ + ":halt_test_play", + "//shared/test_util:tbots_gtest_main", + "//software/test_util", + ], +) diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp new file mode 100644 index 0000000000..669d213758 --- /dev/null +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp @@ -0,0 +1,30 @@ +#include "software/ai/hl/stp/play/halt_play/halt_test_play_fsm.h" + +#include + +#include "proto/parameters.pb.h" +#include "software/test_util/equal_within_tolerance.h" +#include "software/test_util/test_util.h" + + TEST(HaltTestPlayFSMTest, test_transitions) + { + std::shared_ptr world = ::TestUtil::createBlankTestingWorld(); + FSM fsm(HaltTestPlayFSM{std::make_shared()}); + + // Verify initial state + EXPECT_TRUE(fsm.is(boost::sml::state)); + + // Capture tactics from callback + PriorityTacticVector received_tactics; + fsm.process_event(HaltTestPlayFSM::Update( + HaltTestPlayFSM::ControlParams{}, + PlayUpdate( + world, 3, + [&received_tactics](PriorityTacticVector new_tactics) { + received_tactics = std::move(new_tactics); + }, + InterPlayCommunication{}, [](InterPlayCommunication) {}))); + + // Verify state stays the same (single-state loop) + EXPECT_TRUE(fsm.is(boost::sml::state)); + } From ca79647a879aa790d14b2ed8c52b100407d5e095 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sat, 14 Feb 2026 17:53:42 -0800 Subject: [PATCH 05/24] fix bugs --- src/software/ai/hl/stp/play/test_plays/BUILD | 11 +++++------ .../ai/hl/stp/play/test_plays/halt_test_play.cpp | 2 +- .../ai/hl/stp/play/test_plays/halt_test_play.h | 2 +- .../stp/play/test_plays/halt_test_play_fsm_test.cpp | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/software/ai/hl/stp/play/test_plays/BUILD b/src/software/ai/hl/stp/play/test_plays/BUILD index a995a2d885..66bb2de98b 100644 --- a/src/software/ai/hl/stp/play/test_plays/BUILD +++ b/src/software/ai/hl/stp/play/test_plays/BUILD @@ -3,13 +3,12 @@ package(default_visibility = ["//visibility:public"]) cc_library( name = "halt_test_play", srcs = [ - "halt_test_play.cpp", - "halt_test_play_fsm.cpp" - ], + "halt_test_play.cpp", + ], hdrs = [ - "halt_test_play.h", - "halt_test_play.h" - ], + "halt_test_play.h", + "halt_test_play_fsm.h", + ], deps = [ "//software/ai/hl/stp/play", "//software/ai/hl/stp/tactic/halt:halt_tactic", diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp b/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp index be2711eebb..5c202b4a7c 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp @@ -3,7 +3,7 @@ #include "software/util/generic_factory/generic_factory.h" HaltTestPlay::HaltTestPlay(std::shared_ptr ai_config_ptr) - : PlayBase(ai_config_ptr, false) + : PlayBase(ai_config_ptr, false) { } diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h index 2cbce35b76..8b41b97239 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h @@ -13,7 +13,7 @@ * This play is applicable when the ball's y coordinate is >= 0 * This play's invariant holds while the ball is within the field */ -class HaltTestPlay : public PlayBase +class HaltTestPlay : public PlayBase { public: /** diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp index 669d213758..c61fcde267 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp @@ -1,4 +1,4 @@ -#include "software/ai/hl/stp/play/halt_play/halt_test_play_fsm.h" +#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" #include From f886ed8afa024ea10790ed08a33944c2d29e3567 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 11:48:51 -0800 Subject: [PATCH 06/24] pass fsm test --- .../ai/hl/stp/play/test_plays/halt_test_play.cpp | 14 +++++++++++--- .../ai/hl/stp/play/test_plays/halt_test_play.h | 4 +++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp b/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp index 5c202b4a7c..b4a2e695a3 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.cpp @@ -7,9 +7,17 @@ HaltTestPlay::HaltTestPlay(std::shared_ptr ai_config { } -void HaltTestPlay::updateTactics(const PlayUpdate &play_update){ - fsm.process_event(HaltTestPlayFSM::Update(control_params, play_update)); -}; +void HaltTestPlay::getNextTactics(TacticCoroutine::push_type &yield, + const WorldPtr &world_ptr) +{ + // This function doesn't get called and will be removed when coroutines are phased + // out. +} + +void HaltTestPlay::updateTactics(const PlayUpdate &play_update) +{ + fsm.process_event(HaltTestPlayFSM::Update(control_params, play_update)); +} // Register this play in the genericFactory static TGenericFactory> diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h index 8b41b97239..66eaa19e4c 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h @@ -23,5 +23,7 @@ class HaltTestPlay : public PlayBase */ HaltTestPlay(std::shared_ptr ai_config_ptr); - void updateTactics(const PlayUpdate &play_update) override; + void getNextTactics(TacticCoroutine::push_type &yield, + const WorldPtr &world_ptr) override; + void updateTactics(const PlayUpdate &play_update) override; }; From c6c8c8b52038c6e955b025e53a9646693c4e360d Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 12:20:13 -0800 Subject: [PATCH 07/24] finish fsm.h for move --- .../stp/play/test_plays/move_test_play_fsm.h | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h new file mode 100644 index 0000000000..26f14457e4 --- /dev/null +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h @@ -0,0 +1,67 @@ +#pragma once + +#include "proto/parameters.pb.h" +#include "shared/constants.h" +#include "software/ai/hl/stp/play/play_fsm.hpp" +#include "software/ai/hl/stp/tactic/move/move_tactic.h" + +struct MoveTestPlayFSM : PlayFSM + { + struct ControlParams + { + }; + + class MoveTestState; + + explicit MoveTestPlayFSM(std::shared_ptr ai_config_ptr) + : PlayFSM(ai_config_ptr), + move_test_tactic_friendly_goal(std::make_shared(ai_config_ptr)), + move_test_tactic_enemy_goal(std::make_shared(ai_config_ptr)), + move_test_tactic_center_field(std::make_shared(ai_config_ptr)) + { + } + + void updateMove(const Update& event) + { + move_test_tactic_friendly_goal->updateControlParams( + event.common.world_ptr->field().friendlyGoalCenter(), Angle::zero(), + TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, + TbotsProto::ObstacleAvoidanceMode::SAFE); + move_test_tactic_enemy_goal->updateControlParams( + event.common.world_ptr->field().enemyGoalCenter(), Angle::zero(), + TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, + TbotsProto::ObstacleAvoidanceMode::SAFE); + move_test_tactic_center_field->updateControlParams( + Point(0, 0), Angle::zero(), TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, + TbotsProto::ObstacleAvoidanceMode::SAFE); + + event.common.set_tactics({{move_test_tactic_center_field, move_test_tactic_friendly_goal, + move_test_tactic_enemy_goal}}); + } + + bool moveDone(const Update& event){ + return move_test_tactic_center_field->done(); + + } + + + auto operator()() + { + using namespace boost::sml; + + DEFINE_SML_STATE(MoveTestState) + DEFINE_SML_EVENT(Update) + DEFINE_SML_ACTION(updateMove) + DEFINE_SML_GUARD(moveDone) + + return make_transition_table( + *MoveTestState_S + Update_E [!moveDone_G] / updateMove_A = MoveTestState_S, + MoveTestState_S + Update_E [moveDone_G] / updateMove_A = X, + X + Update_E / updateMove_A = X); + } + + private: + std::shared_ptr move_test_tactic_friendly_goal; + std::shared_ptr move_test_tactic_enemy_goal; + std::shared_ptr move_test_tactic_center_field; + }; From 322884f505bd817ca4e3d945f88a8e5fcf349340 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 12:22:05 -0800 Subject: [PATCH 08/24] finish constructor for move_test_play --- src/software/ai/hl/stp/play/test_plays/move_test_play.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.h b/src/software/ai/hl/stp/play/test_plays/move_test_play.h index f1d03b8a70..88b2c926cf 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.h @@ -12,7 +12,7 @@ * This play is applicable when the ball's x and y coordinates are >= 0 * This play's invariant holds while the ball's x coordinate is >= 0 */ -class MoveTestPlay : public Play +class MoveTestPlay : public PlayBase { public: /** @@ -24,4 +24,6 @@ class MoveTestPlay : public Play void getNextTactics(TacticCoroutine::push_type &yield, const WorldPtr &world_ptr) override; + + void updateTactics(const PlayUpdate &play_update) override; }; From de66e650f480e462b4fbd90e01b302fab7da2462 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 12:27:49 -0800 Subject: [PATCH 09/24] fix bugs: --- .../hl/stp/play/test_plays/move_test_play.cpp | 25 +++---------------- .../hl/stp/play/test_plays/move_test_play.h | 4 ++- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp b/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp index 21ca1555ad..3ea39de390 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp @@ -4,34 +4,17 @@ #include "software/util/generic_factory/generic_factory.h" MoveTestPlay::MoveTestPlay(std::shared_ptr ai_config_ptr) - : Play(ai_config_ptr, false) + : PlayBase(ai_config_ptr, false) { } void MoveTestPlay::getNextTactics(TacticCoroutine::push_type &yield, const WorldPtr &world_ptr) { - auto move_test_tactic_friendly_goal = std::make_shared(ai_config_ptr); - auto move_test_tactic_enemy_goal = std::make_shared(ai_config_ptr); - auto move_test_tactic_center_field = std::make_shared(ai_config_ptr); - - do - { - move_test_tactic_friendly_goal->updateControlParams( - world_ptr->field().friendlyGoalCenter(), Angle::zero(), - TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, - TbotsProto::ObstacleAvoidanceMode::SAFE); - move_test_tactic_enemy_goal->updateControlParams( - world_ptr->field().enemyGoalCenter(), Angle::zero(), - TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, - TbotsProto::ObstacleAvoidanceMode::SAFE); - move_test_tactic_center_field->updateControlParams( - Point(0, 0), Angle::zero(), TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, - TbotsProto::ObstacleAvoidanceMode::SAFE); +} - yield({{move_test_tactic_center_field, move_test_tactic_friendly_goal, - move_test_tactic_enemy_goal}}); - } while (!move_test_tactic_center_field->done()); +void MoveTestPlay::updateTactics(const PlayUpdate &play_update){ + fsm.process_event(MoveTestPlayFSM::Update(control_params, play_update)); } // Register this play in the genericFactory diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.h b/src/software/ai/hl/stp/play/test_plays/move_test_play.h index 88b2c926cf..43fd2507c4 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.h @@ -2,6 +2,8 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" +#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" // your new FSM +#include "software/ai/hl/stp/play/play_base.hpp" /** * A test Play that moves a robot to the friendly goal, a robot to the enemy goal, and @@ -12,7 +14,7 @@ * This play is applicable when the ball's x and y coordinates are >= 0 * This play's invariant holds while the ball's x coordinate is >= 0 */ -class MoveTestPlay : public PlayBase +class MoveTestPlay : public PlayBase { public: /** From d5f353028ef9ccc56ce1bb2d1b6b7778241d2b68 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 12:30:05 -0800 Subject: [PATCH 10/24] update build --- src/software/ai/hl/stp/play/test_plays/BUILD | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/software/ai/hl/stp/play/test_plays/BUILD b/src/software/ai/hl/stp/play/test_plays/BUILD index 66bb2de98b..c7e07d7b14 100644 --- a/src/software/ai/hl/stp/play/test_plays/BUILD +++ b/src/software/ai/hl/stp/play/test_plays/BUILD @@ -20,7 +20,8 @@ cc_library( cc_library( name = "move_test_play", srcs = ["move_test_play.cpp"], - hdrs = ["move_test_play.h"], + hdrs = ["move_test_play.h", + "move_test_play_fsm.h"], deps = [ "//software/ai/hl/stp/play", "//software/ai/hl/stp/tactic/move:move_tactic", From 5788d40bb93685e84a2b9307bf9395d2d04b2065 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 12:31:48 -0800 Subject: [PATCH 11/24] add test and test passes --- src/software/ai/hl/stp/play/test_plays/BUILD | 10 ++++++ .../test_plays/move_test_play_fsm_test.cpp | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp diff --git a/src/software/ai/hl/stp/play/test_plays/BUILD b/src/software/ai/hl/stp/play/test_plays/BUILD index c7e07d7b14..958c359875 100644 --- a/src/software/ai/hl/stp/play/test_plays/BUILD +++ b/src/software/ai/hl/stp/play/test_plays/BUILD @@ -39,3 +39,13 @@ cc_test( "//software/test_util", ], ) + +cc_test( + name = "move_test_play_fsm_test", + srcs = ["move_test_play_fsm_test.cpp"], + deps = [ + ":move_test_play", + "//shared/test_util:tbots_gtest_main", + "//software/test_util", + ], +) diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp new file mode 100644 index 0000000000..50ea36af85 --- /dev/null +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp @@ -0,0 +1,33 @@ +#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" + +#include + +#include "proto/parameters.pb.h" +#include "software/test_util/test_util.h" + +TEST(MoveTestPlayFSMTest, test_stays_in_move_state) +{ + std::shared_ptr world = ::TestUtil::createBlankTestingWorld(); + FSM fsm( + MoveTestPlayFSM{std::make_shared()}); + + // Verify initial state + EXPECT_TRUE(fsm.is(boost::sml::state)); + + // Capture tactics from callback + PriorityTacticVector received_tactics; + fsm.process_event(MoveTestPlayFSM::Update( + MoveTestPlayFSM::ControlParams{}, + PlayUpdate( + world, 3, + [&received_tactics](PriorityTacticVector new_tactics) + { received_tactics = std::move(new_tactics); }, + InterPlayCommunication{}, [](InterPlayCommunication) {}))); + + // Verify state stays the same (tactic not done yet) + EXPECT_TRUE(fsm.is(boost::sml::state)); + + // Verify we got exactly 1 priority level with 3 tactics + ASSERT_EQ(received_tactics.size(), 1); + EXPECT_EQ(received_tactics[0].size(), 3); +} From dc128ef9fbc351d56818a1c230a4eb5625c3c3a2 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 13:44:25 -0800 Subject: [PATCH 12/24] reorganize shoot or chip --- .../ai/hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play.cpp | 0 .../ai/hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play.h | 0 .../hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play_test.cpp | 0 .../ai/hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play_test.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/software/ai/hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play.cpp (100%) rename src/software/ai/hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play.h (100%) rename src/software/ai/hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play_test.cpp (100%) rename src/software/ai/hl/stp/play/{ => shoot_or_chip}/shoot_or_chip_play_test.py (100%) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip_play.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp similarity index 100% rename from src/software/ai/hl/stp/play/shoot_or_chip_play.cpp rename to src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp diff --git a/src/software/ai/hl/stp/play/shoot_or_chip_play.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h similarity index 100% rename from src/software/ai/hl/stp/play/shoot_or_chip_play.h rename to src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h diff --git a/src/software/ai/hl/stp/play/shoot_or_chip_play_test.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.cpp similarity index 100% rename from src/software/ai/hl/stp/play/shoot_or_chip_play_test.cpp rename to src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.cpp diff --git a/src/software/ai/hl/stp/play/shoot_or_chip_play_test.py b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.py similarity index 100% rename from src/software/ai/hl/stp/play/shoot_or_chip_play_test.py rename to src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.py From 9d813b8431fed1a0bafe2d551f9cc301688499e7 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 14:33:25 -0800 Subject: [PATCH 13/24] finish shoot or chip fsm --- .../shoot_or_chip/shoot_or_chip_play_fsm.cpp | 91 +++++++++++++++++++ .../shoot_or_chip/shoot_or_chip_play_fsm.h | 52 +++++++++++ 2 files changed, 143 insertions(+) create mode 100644 src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp create mode 100644 src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp new file mode 100644 index 0000000000..2129a1a8a9 --- /dev/null +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp @@ -0,0 +1,91 @@ +#include "software/ai/hl/stp/play/shoot_or_chip_play.h" + +#include "proto/message_translation/tbots_protobuf.h" +#include "shared/constants.h" +#include "software/ai/evaluation/enemy_threat.h" +#include "software/ai/evaluation/find_open_areas.h" +#include "software/ai/evaluation/possession.h" +#include "software/ai/hl/stp/tactic/attacker/attacker_tactic.h" +#include "software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic.h" +#include "software/ai/hl/stp/tactic/halt/halt_tactic.h" +#include "software/ai/hl/stp/tactic/move/move_tactic.h" +#include "software/ai/hl/stp/tactic/shadow_enemy/shadow_enemy_tactic.h" + +ShootOrChipPlayFSM::ShootOrChipPlayFSM(std::shared_ptr ai_config_ptr) + : PlayFSM(ai_config_ptr), + crease_defender_tactics{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + }, + move_to_open_area_tactics{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + }, + attacker(std::make_shared(ai_config_ptr)){ + + } + +void ShootOrChipPlayFSM::updateShootOrChip(const Update& event){ + + + double fallback_chip_target_x_offset = 1.5; + + Point fallback_chip_target = + event.common.world_ptr->field().enemyGoalCenter() - Vector(fallback_chip_target_x_offset, 0); + + + attacker->updateControlParams(fallback_chip_target); + + PriorityTacticVector result = {{}}; + + // Update crease defenders + std::get<0>(crease_defender_tactics) + ->updateControlParams(event.common.world_ptr->ball().position(), + TbotsProto::CreaseDefenderAlignment::LEFT); + result[0].emplace_back(std::get<0>(crease_defender_tactics)); + std::get<1>(crease_defender_tactics) + ->updateControlParams(event.common.world_ptr->ball().position(), + TbotsProto::CreaseDefenderAlignment::RIGHT); + result[0].emplace_back(std::get<1>(crease_defender_tactics)); + + // Update tactics moving to open areas + std::vector enemy_robot_points; + for (auto const &robot : event.common.world_ptr->enemyTeam().getAllRobots()) + { + enemy_robot_points.emplace_back(robot.position()); + } + std::vector chip_targets = findGoodChipTargets(*event.common.world_ptr); + for (unsigned i = 0; + i < chip_targets.size() && i < move_to_open_area_tactics.size(); i++) + { + // Face towards the ball + Angle orientation = + (event.common.world_ptr->ball().position() - chip_targets[i].origin()).orientation(); + // Move a bit backwards to make it more likely we'll receive the chip + Point position = + chip_targets[i].origin() - + Vector::createFromAngle(orientation).normalize(ROBOT_MAX_RADIUS_METERS); + ; + move_to_open_area_tactics[i]->updateControlParams(position, orientation); + result[0].emplace_back(move_to_open_area_tactics[i]); + } + + // Update chipper + std::optional chip_target = std::nullopt; + if (!chip_targets.empty()) + { + chip_target = chip_targets[0].origin(); + } + attacker->updateControlParams(chip_target); + + // We want this second in priority only to the goalie + result[0].insert(result[0].begin() + 1, attacker); + + // set the the Tactics this Play wants to run, in order of priority + event.common.set_tactics(result); +} + +bool ShootOrChipPlayFSM::attackerDone(){ + return attacker->done(); +} + diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h new file mode 100644 index 0000000000..26e47fc84a --- /dev/null +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h @@ -0,0 +1,52 @@ +#pragma once + +#include "proto/parameters.pb.h" +#include "shared/constants.h" +#include "software/ai/hl/stp/play/play_fsm.hpp" + +struct ShootOrChipPlayFSM : PlayFSM + { + struct ControlParams + { + }; + + class ShootOrChipPlayState; + + explicit ShootOrChipPlayFSM(std::shared_ptr ai_config_ptr) + : PlayFSM(ai_config_ptr), + crease_defender_tactics{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + }, + move_to_open_area_tactics{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr)}; + }, + attacker(std::make_shared(ai_config_ptr)) + + void updateShootOrChip(const Update& event); + + bool attackerDone(const Update& event); + + + + auto operator()() + { + using namespace boost::sml; + + DEFINE_SML_STATE(ShootOrChipState) + DEFINE_SML_EVENT(Update) + DEFINE_SML_ACTION(updateShootOrChip) + DEFINE_SML_GUARD(attackerDone) + + return make_transition_table( + *ShootOrChipPlayState_S + Update_E [!attackerDone_G] / updateShootOrChip_A = ShootOrChipState_S, + ShootOrChipPlayState_S + Update_E [attackerDone_G] / updateShootOrChip_A = X, + X + Update_E / updateShootOrChip_A = X); + } + + private: + std::array, 2> crease_defender_tactics; + std::array, 2> move_to_open_area_tactics; + std::shared_ptr attacker; + }; From d564baef5be6c213b05c787a4e8904a28937c569 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 14:42:13 -0800 Subject: [PATCH 14/24] fix bugs --- .../play/shoot_or_chip/shoot_or_chip_play.h | 2 ++ .../shoot_or_chip/shoot_or_chip_play_fsm.cpp | 15 +++++++++-- .../shoot_or_chip/shoot_or_chip_play_fsm.h | 26 +++++++------------ 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h index f50b7e76c6..a6a285fafc 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h @@ -14,4 +14,6 @@ class ShootOrChipPlay : public Play void getNextTactics(TacticCoroutine::push_type &yield, const WorldPtr &world_ptr) override; + + void updateTactics(const PlayUpdate &play_update) override; }; diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp index 2129a1a8a9..742596dd85 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp @@ -1,4 +1,4 @@ -#include "software/ai/hl/stp/play/shoot_or_chip_play.h" +#include "software/ai/hl/stp/play/sshoot_or_chip_play/shoot_or_chip_play_fsm.h" #include "proto/message_translation/tbots_protobuf.h" #include "shared/constants.h" @@ -27,7 +27,18 @@ ShootOrChipPlayFSM::ShootOrChipPlayFSM(std::shared_ptrdone(); } diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h index 26e47fc84a..409660abb8 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h @@ -3,6 +3,9 @@ #include "proto/parameters.pb.h" #include "shared/constants.h" #include "software/ai/hl/stp/play/play_fsm.hpp" +#include "software/ai/hl/stp/tactic/attacker/attacker_tactic.h" +#include "software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic.h" +#include "software/ai/hl/stp/tactic/move/move_tactic.h" struct ShootOrChipPlayFSM : PlayFSM { @@ -12,18 +15,7 @@ struct ShootOrChipPlayFSM : PlayFSM class ShootOrChipPlayState; - explicit ShootOrChipPlayFSM(std::shared_ptr ai_config_ptr) - : PlayFSM(ai_config_ptr), - crease_defender_tactics{ - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr), - }, - move_to_open_area_tactics{ - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr)}; - }, - attacker(std::make_shared(ai_config_ptr)) - + explicit ShootOrChipPlayFSM(std::shared_ptr ai_config_ptr); void updateShootOrChip(const Update& event); bool attackerDone(const Update& event); @@ -34,15 +26,15 @@ struct ShootOrChipPlayFSM : PlayFSM { using namespace boost::sml; - DEFINE_SML_STATE(ShootOrChipState) + DEFINE_SML_STATE(ShootOrChipPlayState) DEFINE_SML_EVENT(Update) - DEFINE_SML_ACTION(updateShootOrChip) + DEFINE_SML_ACTION(updateShootOrChipPlay) DEFINE_SML_GUARD(attackerDone) return make_transition_table( - *ShootOrChipPlayState_S + Update_E [!attackerDone_G] / updateShootOrChip_A = ShootOrChipState_S, - ShootOrChipPlayState_S + Update_E [attackerDone_G] / updateShootOrChip_A = X, - X + Update_E / updateShootOrChip_A = X); + *ShootOrChipPlayState_S + Update_E [!attackerDone_G] / updateShootOrChipPlay_A = ShootOrChipPlayState_S, + ShootOrChipPlayState_S + Update_E [attackerDone_G] / updateShootOrChipPlay_A = X, + X + Update_E / updateShootOrChipPlay_A = X); } private: From b77ad5eab15913fc1be4d370920a09a3686d44da Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 14:51:52 -0800 Subject: [PATCH 15/24] fix more bugs and integrate into original shoot or chip play' --- .../play/shoot_or_chip/shoot_or_chip_play_fsm.cpp | 12 +++--------- .../stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h | 10 +++++----- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp index 742596dd85..34f5a6a07c 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp @@ -1,4 +1,4 @@ -#include "software/ai/hl/stp/play/sshoot_or_chip_play/shoot_or_chip_play_fsm.h" +#include "software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h" #include "proto/message_translation/tbots_protobuf.h" #include "shared/constants.h" @@ -44,8 +44,9 @@ void ShootOrChipPlayFSM::updateShootOrChip(const Update& event){ Point fallback_chip_target = event.common.world_ptr->field().enemyGoalCenter() - Vector(fallback_chip_target_x_offset, 0); + // Update chipper + std::optional chip_target = fallback_chip_target; - attacker->updateControlParams(fallback_chip_target); PriorityTacticVector result = {{}}; @@ -60,11 +61,6 @@ void ShootOrChipPlayFSM::updateShootOrChip(const Update& event){ result[0].emplace_back(std::get<1>(crease_defender_tactics)); // Update tactics moving to open areas - std::vector enemy_robot_points; - for (auto const &robot : event.common.world_ptr->enemyTeam().getAllRobots()) - { - enemy_robot_points.emplace_back(robot.position()); - } std::vector chip_targets = findGoodChipTargets(*event.common.world_ptr); for (unsigned i = 0; i < chip_targets.size() && i < move_to_open_area_tactics.size(); i++) @@ -81,8 +77,6 @@ void ShootOrChipPlayFSM::updateShootOrChip(const Update& event){ result[0].emplace_back(move_to_open_area_tactics[i]); } - // Update chipper - std::optional chip_target = std::nullopt; if (!chip_targets.empty()) { chip_target = chip_targets[0].origin(); diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h index 409660abb8..ab0fbfa736 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h @@ -26,15 +26,15 @@ struct ShootOrChipPlayFSM : PlayFSM { using namespace boost::sml; - DEFINE_SML_STATE(ShootOrChipPlayState) + DEFINE_SML_STATE(ShootOrChipState) DEFINE_SML_EVENT(Update) - DEFINE_SML_ACTION(updateShootOrChipPlay) + DEFINE_SML_ACTION(updateShootOrChip) DEFINE_SML_GUARD(attackerDone) return make_transition_table( - *ShootOrChipPlayState_S + Update_E [!attackerDone_G] / updateShootOrChipPlay_A = ShootOrChipPlayState_S, - ShootOrChipPlayState_S + Update_E [attackerDone_G] / updateShootOrChipPlay_A = X, - X + Update_E / updateShootOrChipPlay_A = X); + *ShootOrChipState_S + Update_E [!attackerDone_G] / updateShootOrChip_A = ShootOrChipState_S, + ShootOrChipState_S + Update_E [attackerDone_G] / updateShootOrChip_A = X, + X + Update_E / updateShootOrChip_A = X); } private: From df3988fffa3d811422f4648669604c1f010ff3a0 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 14:59:16 -0800 Subject: [PATCH 16/24] finish integration --- .../play/shoot_or_chip/shoot_or_chip_play.cpp | 94 ++----------------- .../play/shoot_or_chip/shoot_or_chip_play.h | 4 +- .../shoot_or_chip/shoot_or_chip_play_fsm.h | 3 +- 3 files changed, 11 insertions(+), 90 deletions(-) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp index 30234e0d28..f0e2fb3602 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp @@ -1,108 +1,26 @@ -#include "software/ai/hl/stp/play/shoot_or_chip_play.h" +#include "software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h" #include "proto/message_translation/tbots_protobuf.h" #include "shared/constants.h" -#include "software/ai/evaluation/enemy_threat.h" -#include "software/ai/evaluation/find_open_areas.h" -#include "software/ai/evaluation/possession.h" -#include "software/ai/hl/stp/tactic/attacker/attacker_tactic.h" -#include "software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic.h" -#include "software/ai/hl/stp/tactic/halt/halt_tactic.h" -#include "software/ai/hl/stp/tactic/move/move_tactic.h" -#include "software/ai/hl/stp/tactic/shadow_enemy/shadow_enemy_tactic.h" #include "software/logger/logger.h" #include "software/util/generic_factory/generic_factory.h" #include "software/world/game_state.h" ShootOrChipPlay::ShootOrChipPlay( std::shared_ptr ai_config_ptr) - : Play(ai_config_ptr, true) + : PlayBase(ai_config_ptr, true) { } void ShootOrChipPlay::getNextTactics(TacticCoroutine::push_type &yield, const WorldPtr &world_ptr) { - /** - * Our general strategy here is: - * - 1 goalie - * - 2 crease defenders moving around the friendly defense box - * - 2 robots moving into the first and second largest open free space on - * the enemy half - * - 1 robot trying to shoot on the goal. If an enemy gets too close to this - * robot, it will chip to right in front of the robot in the largest open free area - */ - - std::array, 2> crease_defender_tactics = { - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr), - }; - - std::array, 2> move_to_open_area_tactics = { - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr)}; - - // Figure out where the fallback chip target is - // Experimentally determined to be a reasonable value - double fallback_chip_target_x_offset = 1.5; - - Point fallback_chip_target = - world_ptr->field().enemyGoalCenter() - Vector(fallback_chip_target_x_offset, 0); - - auto attacker = std::make_shared(ai_config_ptr); - attacker->updateControlParams(fallback_chip_target); - - do - { - PriorityTacticVector result = {{}}; - - // Update crease defenders - std::get<0>(crease_defender_tactics) - ->updateControlParams(world_ptr->ball().position(), - TbotsProto::CreaseDefenderAlignment::LEFT); - result[0].emplace_back(std::get<0>(crease_defender_tactics)); - std::get<1>(crease_defender_tactics) - ->updateControlParams(world_ptr->ball().position(), - TbotsProto::CreaseDefenderAlignment::RIGHT); - result[0].emplace_back(std::get<1>(crease_defender_tactics)); - - // Update tactics moving to open areas - std::vector enemy_robot_points; - for (auto const &robot : world_ptr->enemyTeam().getAllRobots()) - { - enemy_robot_points.emplace_back(robot.position()); - } - std::vector chip_targets = findGoodChipTargets(*world_ptr); - for (unsigned i = 0; - i < chip_targets.size() && i < move_to_open_area_tactics.size(); i++) - { - // Face towards the ball - Angle orientation = - (world_ptr->ball().position() - chip_targets[i].origin()).orientation(); - // Move a bit backwards to make it more likely we'll receive the chip - Point position = - chip_targets[i].origin() - - Vector::createFromAngle(orientation).normalize(ROBOT_MAX_RADIUS_METERS); - ; - move_to_open_area_tactics[i]->updateControlParams(position, orientation); - result[0].emplace_back(move_to_open_area_tactics[i]); - } - - // Update chipper - std::optional chip_target = std::nullopt; - if (!chip_targets.empty()) - { - chip_target = chip_targets[0].origin(); - } - attacker->updateControlParams(chip_target); - - // We want this second in priority only to the goalie - result[0].insert(result[0].begin() + 1, attacker); +} - // yield the Tactics this Play wants to run, in order of priority - yield(result); - } while (!attacker->done()); +void ShootOrChipPlay::updateTactics(const PlayUpdate& play_update) +{ + fsm.process_event(ShootOrChipPlayFSM::Update(control_params, play_update)); } // Register this play in the genericFactory diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h index a6a285fafc..ab5f92b5b5 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h @@ -2,12 +2,14 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" +#include "software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h" +#include "software/ai/hl/stp/play/play_base.hpp" /** * The Defense Play tries to grab the ball from the enemy that has it, and all other * robots shadow the enemy robots in order of how threatening they are. */ -class ShootOrChipPlay : public Play +class ShootOrChipPlay : public PlayBase { public: ShootOrChipPlay(std::shared_ptr ai_config_ptr); diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h index ab0fbfa736..4ef6cf8472 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h @@ -13,9 +13,10 @@ struct ShootOrChipPlayFSM : PlayFSM { }; - class ShootOrChipPlayState; + class ShootOrChipState; explicit ShootOrChipPlayFSM(std::shared_ptr ai_config_ptr); + void updateShootOrChip(const Update& event); bool attackerDone(const Update& event); From 5fe618c4433bb3ab55add6a26dc0f20650d294e1 Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 15:04:06 -0800 Subject: [PATCH 17/24] update BUILD --- src/software/ai/hl/stp/play/BUILD | 56 +---------------- .../ai/hl/stp/play/shoot_or_chip/BUILD | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 src/software/ai/hl/stp/play/shoot_or_chip/BUILD diff --git a/src/software/ai/hl/stp/play/BUILD b/src/software/ai/hl/stp/play/BUILD index 678a44e215..2ce82872b8 100644 --- a/src/software/ai/hl/stp/play/BUILD +++ b/src/software/ai/hl/stp/play/BUILD @@ -40,30 +40,6 @@ cc_library( alwayslink = True, ) -cc_library( - name = "shoot_or_chip_play", - srcs = ["shoot_or_chip_play.cpp"], - hdrs = ["shoot_or_chip_play.h"], - deps = [ - ":play", - "//proto/message_translation:tbots_protobuf", - "//shared:constants", - "//software/ai/evaluation:enemy_threat", - "//software/ai/evaluation:find_open_areas", - "//software/ai/evaluation:possession", - "//software/ai/hl/stp/tactic/attacker:attacker_tactic", - "//software/ai/hl/stp/tactic/crease_defender:crease_defender_tactic", - "//software/ai/hl/stp/tactic/goalie:goalie_tactic", - "//software/ai/hl/stp/tactic/halt:halt_tactic", - "//software/ai/hl/stp/tactic/move:move_tactic", - "//software/ai/hl/stp/tactic/shadow_enemy:shadow_enemy_tactic", - "//software/logger", - "//software/util/generic_factory", - "//software/world:game_state", - ], - alwayslink = True, -) - cc_library( name = "stop_play", srcs = ["stop_play.cpp"], @@ -108,7 +84,6 @@ cc_library( deps = [ ":kickoff_enemy_play", ":kickoff_friendly_play", - ":shoot_or_chip_play", ":stop_play", "//software/ai/hl/stp/play/ball_placement:ball_placement_play", "//software/ai/hl/stp/play/crease_defense:crease_defense_play", @@ -118,6 +93,7 @@ cc_library( "//software/ai/hl/stp/play/example:example_play", "//software/ai/hl/stp/play/free_kick:free_kick_play", "//software/ai/hl/stp/play/halt_play", + "//software/ai/hl/stp/play/shoot_or_chip:shoot_or_chip_play", "//software/ai/hl/stp/play/hardware_challenge_plays:dribbling_parcour_play", "//software/ai/hl/stp/play/hardware_challenge_plays:pass_endurance_play", "//software/ai/hl/stp/play/hardware_challenge_plays:scoring_from_contested_possession_play", @@ -193,36 +169,6 @@ cc_test( ], ) -cc_test( - name = "shoot_or_chip_play_cpp_test", - srcs = ["shoot_or_chip_play_test.cpp"], - deps = [ - "//shared/test_util:tbots_gtest_main", - "//software/ai/hl/stp/play:shoot_or_chip_play", - "//software/simulated_tests:simulated_er_force_sim_play_test_fixture", - "//software/simulated_tests/validation:validation_function", - "//software/test_util", - "//software/time:duration", - "//software/world", - ], -) - -py_test( - name = "shoot_or_chip_play_test", - srcs = [ - "shoot_or_chip_play_test.py", - ], - # TODO (#2619) Remove tag to run in parallel - tags = [ - "exclusive", - ], - deps = [ - "//software:conftest", - "//software/simulated_tests:validation", - requirement("pytest"), - ], -) - cc_library( name = "assigned_tactics_play", srcs = ["assigned_tactics_play.cpp"], diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/BUILD b/src/software/ai/hl/stp/play/shoot_or_chip/BUILD new file mode 100644 index 0000000000..2e10e2e42e --- /dev/null +++ b/src/software/ai/hl/stp/play/shoot_or_chip/BUILD @@ -0,0 +1,62 @@ +load("@simulated_tests_deps//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "shoot_or_chip_play", + srcs = [ + "shoot_or_chip_play.cpp", + "shoot_or_chip_play_fsm.cpp", + ], + hdrs = [ + "shoot_or_chip_play.h", + "shoot_or_chip_play_fsm.h", + ], + deps = [ + "//proto/message_translation:tbots_protobuf", + "//shared:constants", + "//software/ai/evaluation:enemy_threat", + "//software/ai/evaluation:find_open_areas", + "//software/ai/evaluation:possession", + "//software/ai/hl/stp/play", + "//software/ai/hl/stp/tactic/attacker:attacker_tactic", + "//software/ai/hl/stp/tactic/crease_defender:crease_defender_tactic", + "//software/ai/hl/stp/tactic/halt:halt_tactic", + "//software/ai/hl/stp/tactic/move:move_tactic", + "//software/ai/hl/stp/tactic/shadow_enemy:shadow_enemy_tactic", + "//software/logger", + "//software/util/generic_factory", + "//software/world:game_state", + ], + alwayslink = True, +) + +cc_test( + name = "shoot_or_chip_play_cpp_test", + srcs = ["shoot_or_chip_play_test.cpp"], + deps = [ + ":shoot_or_chip_play", + "//shared/test_util:tbots_gtest_main", + "//software/simulated_tests:simulated_er_force_sim_play_test_fixture", + "//software/simulated_tests/validation:validation_function", + "//software/test_util", + "//software/time:duration", + "//software/world", + ], +) + +py_test( + name = "shoot_or_chip_play_test", + srcs = [ + "shoot_or_chip_play_test.py", + ], + # TODO (#2619) Remove tag to run in parallel + tags = [ + "exclusive", + ], + deps = [ + "//software:conftest", + "//software/simulated_tests:validation", + requirement("pytest"), + ], +) From 9bb32fc71f5aeb60cee66d0a5503769e02fb639e Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 15 Feb 2026 15:08:54 -0800 Subject: [PATCH 18/24] fix import issues and all shoot_or_pass test passes --- src/plan.md | 214 ------------------ .../shoot_or_chip/shoot_or_chip_play_test.cpp | 2 +- 2 files changed, 1 insertion(+), 215 deletions(-) delete mode 100644 src/plan.md diff --git a/src/plan.md b/src/plan.md deleted file mode 100644 index af3d86b129..0000000000 --- a/src/plan.md +++ /dev/null @@ -1,214 +0,0 @@ -# Plan: Remove Coroutine Support from Plays (Ticket #2359) - -## Context - -The play framework currently supports two patterns: **coroutine-based** (legacy, using `boost::coroutines2`) and **FSM-based** (modern, using Boost SML). 12 plays have already been migrated to FSM but still carry dead coroutine stub methods. 11 plays still actively use coroutines. The `Play` base class contains significant coroutine infrastructure marked with `TODO (#2359)` comments. This plan converts all remaining coroutine plays to FSM and removes all coroutine support code from the play framework. It also converts the validation test coroutines. - ---- - -## Phase 1: Convert Simple Single-State Coroutine Plays to FSM - -These plays have a single `do { ... yield(); } while(true)` loop — they map to a single FSM state that self-transitions on every update. - -### 1a. StopPlay -- **Create** `software/ai/hl/stp/play/stop_play/stop_play_fsm.h` — single `StopState` with `updateStop` action -- **Rewrite** `stop_play.h` → inherit `PlayBase`, remove `getNextTactics` -- **Rewrite** `stop_play.cpp` → implement `updateTactics` via `fsm.process_event()` -- **Move** files into new `stop_play/` subdirectory (matching existing convention) -- **Update** BUILD files - -### 1b. KickoffEnemyPlay -- **Create** `software/ai/hl/stp/play/kickoff_enemy/kickoff_enemy_play_fsm.h` — single `DefendState` with `updateDefense` action -- **Rewrite** `kickoff_enemy_play.h/cpp` → `PlayBase` -- **Move** into `kickoff_enemy/` subdirectory -- **Update** BUILD files - -### 1c. HaltTestPlay -- **Create** `software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h` — single `HaltState` -- **Rewrite** `halt_test_play.h/cpp` → `PlayBase` -- **Update** BUILD - -### 1d. Hardware Challenge Plays (4 plays) -All 4 have identical structure: `do { if(playing) {action} else {setup} yield(); } while(true)` - -Each gets a single FSM with one state and a guard for `isPlaying()`: -- `dribbling_parcour_play_fsm.h` — DribblingParcourPlayFSM -- `pass_endurance_play_fsm.h` — PassEndurancePlayFSM -- `scoring_from_contested_possession_play_fsm.h` — ScoringFromContestedPossessionPlayFSM -- `scoring_with_static_defenders_play_fsm.h` — ScoringWithStaticDefendersPlayFSM - -Rewrite each play to inherit `PlayBase<*FSM>` and implement `updateTactics`. - ---- - -## Phase 2: Convert Multi-State Coroutine Plays to FSM - -### 2a. KickoffFriendlyPlay (2 stages) -- **States:** `SetupState` (while `isSetupState()`), `ChipState` (while `!isPlaying()`) -- **Guards:** `setupDone` (transitions when `!isSetupState()`), `chipDone` (when `isPlaying()`) -- **Create** `kickoff_friendly/kickoff_friendly_play_fsm.h` -- **Move** into `kickoff_friendly/` subdirectory -- **Rewrite** play files - -### 2b. ShootOrChipPlay (conditional loop) -- **State:** Single `ShootOrChipState` with `attackerDone` guard for terminal transition -- **Create** `shoot_or_chip/shoot_or_chip_play_fsm.h` -- **Move** into `shoot_or_chip/` subdirectory -- **Rewrite** play files - -### 2c. MoveTestPlay (conditional loop) -- **State:** Single `MoveState` with `moveDone` guard checking `move_test_tactic_center_field->done()` -- **Create** `test_plays/move_test_play_fsm.h` -- **Rewrite** play files - ---- - -## Phase 3: Handle AssignedTacticsPlay (Special Case) - -`AssignedTacticsPlay` overrides `get()` entirely and already has an empty `updateTactics()`. Its coroutine method is dead code. -- **Remove** `getNextTactics` override from header and source -- No FSM needed — this play has its own unique dispatch pattern via `get()` - ---- - -## Phase 4: Clean Up Play Base Class - -Once all plays are FSM-based, remove all coroutine infrastructure from the base class. - -### Files: `play.h`, `play.cpp` - -**Remove from `play.h`:** -- `#include ` -- `using TacticCoroutine = ...` typedef -- `PriorityTacticVector getTactics(...)` private method -- `void getNextTacticsWrapper(...)` private method -- `virtual void getNextTactics(...)` pure virtual -- `TacticCoroutine::pull_type tactic_sequence` member -- `std::optional world_ptr_` member -- `PriorityTacticVector priority_tactics` member -- All `TODO (#2359)` comments - -**Make `updateTactics` pure virtual** (currently has default impl that delegates to coroutine) - -**Remove from `play.cpp`:** -- `getTactics()` function (lines 30-85) -- `getNextTacticsWrapper()` function (lines 236-251) -- Default `updateTactics()` implementation (lines 253-257) -- Coroutine initialization in constructor (tactic_sequence, world_ptr_ init) - -**Update `play.h` constructor** — remove `tactic_sequence` and `world_ptr_` from initializer list - -**Remove from BUILD** (`software/ai/hl/stp/play/BUILD`): -- `@boost//:coroutine2` from the `play` target deps - ---- - -## Phase 5: Clean Up FSM Play Stubs - -Remove empty `getNextTactics` overrides from all 12 existing FSM plays: - -| Play | File | -|------|------| -| HaltPlay | `halt_play/halt_play.h` + `.cpp` | -| ExamplePlay | `example/example_play.h` + `.cpp` | -| OffensePlay | `offense/offense_play.h` + `.cpp` | -| ShootOrPassPlay | `shoot_or_pass/shoot_or_pass_play.h` + `.cpp` | -| PenaltyKickPlay | `penalty_kick/penalty_kick_play.h` + `.cpp` | -| PenaltyKickEnemyPlay | `penalty_kick_enemy/penalty_kick_enemy_play.h` + `.cpp` | -| FreeKickPlay | `free_kick/free_kick_play.h` + `.cpp` | -| BallPlacementPlay | `ball_placement/ball_placement_play.h` + `.cpp` | -| CreaseDefensePlay | `crease_defense/crease_defense_play.h` + `.cpp` | -| DefensePlay | `defense/defense_play.h` + `.cpp` | -| EnemyBallPlacementPlay | `enemy_ball_placement/enemy_ball_placement_play.h` + `.cpp` | -| EnemyFreeKickPlay | `enemy_free_kick/enemy_free_kick_play.h` + `.cpp` | - -For each: remove `getNextTactics` declaration from `.h` and empty implementation from `.cpp`. - ---- - -## Phase 6: Convert Validation Coroutines - -### 6a. Replace Validation Infrastructure - -**Files:** -- `software/simulated_tests/validation/validation_function.h` -- `software/simulated_tests/validation/terminating_function_validator.h` + `.cpp` -- `software/simulated_tests/validation/non_terminating_function_validator.h` + `.cpp` - -**Change `ValidationFunction` signature** from: -```cpp -std::function, ValidationCoroutine::push_type&)> -``` -to a per-tick checker: -```cpp -std::function(std::shared_ptr)> -``` - -**Rewrite `TerminatingFunctionValidator`:** -- Remove coroutine state (`pull_type`, wrapper) -- Track completion: call the function each tick. If it returns `nullopt`, mark as complete. If it returns a string, record the error and keep checking. - -**Rewrite `NonTerminatingFunctionValidator`:** -- Same simplification: call function each tick, return error or nullopt -- No restart logic needed since there's no coroutine to restart - -Remove `boost::coroutine2` includes and typedefs. - -### 6b. Rewrite All 17 Validation Functions - -**8 Terminating validation functions** (in `simulated_tests/terminating_validation_functions/`): -- `ball_at_point_validation` -- `ball_kicked_validation` -- `friendly_scored_validation` -- `robot_halt_validation` -- `robot_in_center_circle_validation` -- `robot_in_polygon_validation` -- `robot_received_ball_validation` -- `robot_state_validation` - -**9 Non-terminating validation functions** (in `simulated_tests/non_terminating_validation_functions/`): -- `ball_in_play_or_scored_validation` -- `ball_never_moves_backward_validation` -- `enemy_never_scores_validation` -- `robot_not_excessively_dribbling_validation` -- `robots_avoid_ball_validation` -- `robots_in_friendly_half_validation` -- `robots_not_in_center_circle_validation` -- `robots_slow_down_validation` -- `robots_violating_motion_constraint` - -Each function changes from `void fn(World, yield)` with while-loop-yield to `optional fn(World)` returning error or nullopt. - -**For stateful validators** (e.g., `ball_never_moves_backward` which tracks previous ball position): convert to a class or use `std::function` with captured state via a factory function. - -### 6c. Update BUILD Files -- Remove `@boost//:coroutine2` from: - - `software/simulated_tests/validation/BUILD` - - `software/simulated_tests/terminating_validation_functions/BUILD` - - `software/simulated_tests/non_terminating_validation_functions/BUILD` - ---- - -## Key Patterns to Reuse - -- **FSM template:** `PlayFSM` in `play_fsm.hpp` — all new FSMs inherit from this -- **Play template:** `PlayBase` in `play_base.hpp` — all converted plays inherit from this -- **SML macros:** `DEFINE_SML_STATE`, `DEFINE_SML_EVENT`, `DEFINE_SML_ACTION`, `DEFINE_SML_GUARD` in `software/util/sml_fsm/sml_fsm.h` -- **Reference FSM plays:** `HaltPlayFSM` (simplest), `FreeKickPlayFSM` (multi-state) -- **Factory registration:** `TGenericFactory` pattern stays the same - ---- - -## Verification - -1. **Build:** `bazel build //software/ai/hl/stp/play/...` — ensure all play targets compile -2. **Play tests:** Run existing play tests: - - `bazel test //software/ai/hl/stp/play:kickoff_friendly_play_cpp_test` - - `bazel test //software/ai/hl/stp/play:kickoff_enemy_play_cpp_test` - - `bazel test //software/ai/hl/stp/play:stop_play_test` - - `bazel test //software/ai/hl/stp/play:shoot_or_chip_play_cpp_test` - - `bazel test //software/ai/hl/stp/play:play_factory_test` -3. **Validation tests:** - - `bazel test //software/simulated_tests/validation/...` -4. **Full build:** `bazel build //...` — ensure no boost::coroutine2 references remain in play/validation code -5. **Grep check:** Verify no remaining `TacticCoroutine`, `getNextTactics`, or coroutine yield patterns in play files diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.cpp index c617194c6e..63ef6aeddc 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_test.cpp @@ -1,4 +1,4 @@ -#include "software/ai/hl/stp/play/shoot_or_chip_play.h" +#include "software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h" #include From 59c5aea3c8c33bd414870c139582726897062788 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 02:09:44 +0000 Subject: [PATCH 19/24] [pre-commit.ci lite] apply automatic fixes --- docs/fsm-diagrams.md | 41 ++++++ src/software/ai/hl/stp/play/BUILD | 2 +- .../play/shoot_or_chip/shoot_or_chip_play.cpp | 4 +- .../play/shoot_or_chip/shoot_or_chip_play.h | 2 +- .../shoot_or_chip/shoot_or_chip_play_fsm.cpp | 118 +++++++++--------- .../shoot_or_chip/shoot_or_chip_play_fsm.h | 56 +++++---- src/software/ai/hl/stp/play/test_plays/BUILD | 6 +- .../hl/stp/play/test_plays/halt_test_play.h | 2 +- .../stp/play/test_plays/halt_test_play_fsm.h | 76 +++++------ .../test_plays/halt_test_play_fsm_test.cpp | 37 +++--- .../hl/stp/play/test_plays/move_test_play.cpp | 5 +- .../hl/stp/play/test_plays/move_test_play.h | 2 +- .../stp/play/test_plays/move_test_play_fsm.h | 77 ++++++------ .../test_plays/move_test_play_fsm_test.cpp | 3 +- 14 files changed, 239 insertions(+), 192 deletions(-) diff --git a/docs/fsm-diagrams.md b/docs/fsm-diagrams.md index 8059b8e10d..c16f08b4d2 100644 --- a/docs/fsm-diagrams.md +++ b/docs/fsm-diagrams.md @@ -206,6 +206,20 @@ Terminate:::terminate --> Terminate:::terminate ``` +## [ShootOrChipPlayFSM](/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h) + +```mermaid + +stateDiagram-v2 +classDef terminate fill:white,color:black,font-weight:bold +direction LR +[*] --> ShootOrChipState +ShootOrChipState --> ShootOrChipState : [!attackerDone]\nupdateShootOrChip +ShootOrChipState --> Terminate:::terminate : [attackerDone]\nupdateShootOrChip +Terminate:::terminate --> Terminate:::terminate : updateShootOrChip + +``` + ## [ShootOrPassPlayFSM](/src/software/ai/hl/stp/play/shoot_or_pass/shoot_or_pass_play_fsm.h) ```mermaid @@ -225,6 +239,33 @@ Terminate:::terminate --> AttemptShotState : startLookingForPass ``` +## [HaltTestPlayFSM](/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h) + +```mermaid + +stateDiagram-v2 +classDef terminate fill:white,color:black,font-weight:bold +direction LR +[*] --> HaltTestState +HaltTestState --> HaltTestState : updateHalt +Terminate:::terminate --> Terminate:::terminate : updateHalt + +``` + +## [MoveTestPlayFSM](/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h) + +```mermaid + +stateDiagram-v2 +classDef terminate fill:white,color:black,font-weight:bold +direction LR +[*] --> MoveTestState +MoveTestState --> MoveTestState : [!moveDone]\nupdateMove +MoveTestState --> Terminate:::terminate : [moveDone]\nupdateMove +Terminate:::terminate --> Terminate:::terminate : updateMove + +``` + ## [AttackerFSM](/src/software/ai/hl/stp/tactic/attacker/attacker_fsm.h) ```mermaid diff --git a/src/software/ai/hl/stp/play/BUILD b/src/software/ai/hl/stp/play/BUILD index 2ce82872b8..5de81bde83 100644 --- a/src/software/ai/hl/stp/play/BUILD +++ b/src/software/ai/hl/stp/play/BUILD @@ -93,7 +93,6 @@ cc_library( "//software/ai/hl/stp/play/example:example_play", "//software/ai/hl/stp/play/free_kick:free_kick_play", "//software/ai/hl/stp/play/halt_play", - "//software/ai/hl/stp/play/shoot_or_chip:shoot_or_chip_play", "//software/ai/hl/stp/play/hardware_challenge_plays:dribbling_parcour_play", "//software/ai/hl/stp/play/hardware_challenge_plays:pass_endurance_play", "//software/ai/hl/stp/play/hardware_challenge_plays:scoring_from_contested_possession_play", @@ -101,6 +100,7 @@ cc_library( "//software/ai/hl/stp/play/offense:offense_play", "//software/ai/hl/stp/play/penalty_kick:penalty_kick_play", "//software/ai/hl/stp/play/penalty_kick_enemy:penalty_kick_enemy_play", + "//software/ai/hl/stp/play/shoot_or_chip:shoot_or_chip_play", "//software/ai/hl/stp/play/shoot_or_pass:shoot_or_pass_play", ], ) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp index f0e2fb3602..ab7b04ddb7 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp @@ -18,9 +18,9 @@ void ShootOrChipPlay::getNextTactics(TacticCoroutine::push_type &yield, } -void ShootOrChipPlay::updateTactics(const PlayUpdate& play_update) +void ShootOrChipPlay::updateTactics(const PlayUpdate &play_update) { - fsm.process_event(ShootOrChipPlayFSM::Update(control_params, play_update)); + fsm.process_event(ShootOrChipPlayFSM::Update(control_params, play_update)); } // Register this play in the genericFactory diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h index ab5f92b5b5..9690ef720b 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.h @@ -2,8 +2,8 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" -#include "software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h" #include "software/ai/hl/stp/play/play_base.hpp" +#include "software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h" /** * The Defense Play tries to grab the ball from the enemy that has it, and all other diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp index 34f5a6a07c..ea38982e03 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp @@ -11,22 +11,23 @@ #include "software/ai/hl/stp/tactic/move/move_tactic.h" #include "software/ai/hl/stp/tactic/shadow_enemy/shadow_enemy_tactic.h" -ShootOrChipPlayFSM::ShootOrChipPlayFSM(std::shared_ptr ai_config_ptr) - : PlayFSM(ai_config_ptr), - crease_defender_tactics{ - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr), - }, - move_to_open_area_tactics{ - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr), - }, - attacker(std::make_shared(ai_config_ptr)){ - - } - -void ShootOrChipPlayFSM::updateShootOrChip(const Update& event){ +ShootOrChipPlayFSM::ShootOrChipPlayFSM( + std::shared_ptr ai_config_ptr) + : PlayFSM(ai_config_ptr), + crease_defender_tactics{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + }, + move_to_open_area_tactics{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + }, + attacker(std::make_shared(ai_config_ptr)) +{ +} +void ShootOrChipPlayFSM::updateShootOrChip(const Update& event) +{ /** * Our general strategy here is: * - 1 goalie @@ -36,61 +37,62 @@ void ShootOrChipPlayFSM::updateShootOrChip(const Update& event){ * - 1 robot trying to shoot on the goal. If an enemy gets too close to this * robot, it will chip to right in front of the robot in the largest open free area */ - + // Figure out where the fallback chip target is // Experimentally determined to be a reasonable value double fallback_chip_target_x_offset = 1.5; - Point fallback_chip_target = - event.common.world_ptr->field().enemyGoalCenter() - Vector(fallback_chip_target_x_offset, 0); + Point fallback_chip_target = event.common.world_ptr->field().enemyGoalCenter() - + Vector(fallback_chip_target_x_offset, 0); - // Update chipper - std::optional chip_target = fallback_chip_target; + // Update chipper + std::optional chip_target = fallback_chip_target; - PriorityTacticVector result = {{}}; + PriorityTacticVector result = {{}}; - // Update crease defenders - std::get<0>(crease_defender_tactics) - ->updateControlParams(event.common.world_ptr->ball().position(), - TbotsProto::CreaseDefenderAlignment::LEFT); - result[0].emplace_back(std::get<0>(crease_defender_tactics)); - std::get<1>(crease_defender_tactics) - ->updateControlParams(event.common.world_ptr->ball().position(), - TbotsProto::CreaseDefenderAlignment::RIGHT); - result[0].emplace_back(std::get<1>(crease_defender_tactics)); + // Update crease defenders + std::get<0>(crease_defender_tactics) + ->updateControlParams(event.common.world_ptr->ball().position(), + TbotsProto::CreaseDefenderAlignment::LEFT); + result[0].emplace_back(std::get<0>(crease_defender_tactics)); + std::get<1>(crease_defender_tactics) + ->updateControlParams(event.common.world_ptr->ball().position(), + TbotsProto::CreaseDefenderAlignment::RIGHT); + result[0].emplace_back(std::get<1>(crease_defender_tactics)); - // Update tactics moving to open areas - std::vector chip_targets = findGoodChipTargets(*event.common.world_ptr); - for (unsigned i = 0; - i < chip_targets.size() && i < move_to_open_area_tactics.size(); i++) - { - // Face towards the ball - Angle orientation = - (event.common.world_ptr->ball().position() - chip_targets[i].origin()).orientation(); - // Move a bit backwards to make it more likely we'll receive the chip - Point position = - chip_targets[i].origin() - - Vector::createFromAngle(orientation).normalize(ROBOT_MAX_RADIUS_METERS); - ; - move_to_open_area_tactics[i]->updateControlParams(position, orientation); - result[0].emplace_back(move_to_open_area_tactics[i]); - } + // Update tactics moving to open areas + std::vector chip_targets = findGoodChipTargets(*event.common.world_ptr); + for (unsigned i = 0; i < chip_targets.size() && i < move_to_open_area_tactics.size(); + i++) + { + // Face towards the ball + Angle orientation = + (event.common.world_ptr->ball().position() - chip_targets[i].origin()) + .orientation(); + // Move a bit backwards to make it more likely we'll receive the chip + Point position = + chip_targets[i].origin() - + Vector::createFromAngle(orientation).normalize(ROBOT_MAX_RADIUS_METERS); + ; + move_to_open_area_tactics[i]->updateControlParams(position, orientation); + result[0].emplace_back(move_to_open_area_tactics[i]); + } - if (!chip_targets.empty()) - { - chip_target = chip_targets[0].origin(); - } - attacker->updateControlParams(chip_target); + if (!chip_targets.empty()) + { + chip_target = chip_targets[0].origin(); + } + attacker->updateControlParams(chip_target); - // We want this second in priority only to the goalie - result[0].insert(result[0].begin() + 1, attacker); + // We want this second in priority only to the goalie + result[0].insert(result[0].begin() + 1, attacker); - // set the the Tactics this Play wants to run, in order of priority - event.common.set_tactics(result); + // set the the Tactics this Play wants to run, in order of priority + event.common.set_tactics(result); } -bool ShootOrChipPlayFSM::attackerDone(const Update& event){ - return attacker->done(); +bool ShootOrChipPlayFSM::attackerDone(const Update& event) +{ + return attacker->done(); } - diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h index 4ef6cf8472..e08045cc55 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h @@ -8,38 +8,40 @@ #include "software/ai/hl/stp/tactic/move/move_tactic.h" struct ShootOrChipPlayFSM : PlayFSM - { - struct ControlParams - { - }; +{ + struct ControlParams + { + }; - class ShootOrChipState; + class ShootOrChipState; - explicit ShootOrChipPlayFSM(std::shared_ptr ai_config_ptr); + explicit ShootOrChipPlayFSM( + std::shared_ptr ai_config_ptr); - void updateShootOrChip(const Update& event); + void updateShootOrChip(const Update& event); - bool attackerDone(const Update& event); - - + bool attackerDone(const Update& event); - auto operator()() - { - using namespace boost::sml; - DEFINE_SML_STATE(ShootOrChipState) - DEFINE_SML_EVENT(Update) - DEFINE_SML_ACTION(updateShootOrChip) - DEFINE_SML_GUARD(attackerDone) - return make_transition_table( - *ShootOrChipState_S + Update_E [!attackerDone_G] / updateShootOrChip_A = ShootOrChipState_S, - ShootOrChipState_S + Update_E [attackerDone_G] / updateShootOrChip_A = X, - X + Update_E / updateShootOrChip_A = X); - } + auto operator()() + { + using namespace boost::sml; - private: - std::array, 2> crease_defender_tactics; - std::array, 2> move_to_open_area_tactics; - std::shared_ptr attacker; - }; + DEFINE_SML_STATE(ShootOrChipState) + DEFINE_SML_EVENT(Update) + DEFINE_SML_ACTION(updateShootOrChip) + DEFINE_SML_GUARD(attackerDone) + + return make_transition_table( + *ShootOrChipState_S + Update_E[!attackerDone_G] / updateShootOrChip_A = + ShootOrChipState_S, + ShootOrChipState_S + Update_E[attackerDone_G] / updateShootOrChip_A = X, + X + Update_E / updateShootOrChip_A = X); + } + + private: + std::array, 2> crease_defender_tactics; + std::array, 2> move_to_open_area_tactics; + std::shared_ptr attacker; +}; diff --git a/src/software/ai/hl/stp/play/test_plays/BUILD b/src/software/ai/hl/stp/play/test_plays/BUILD index 958c359875..8197258f06 100644 --- a/src/software/ai/hl/stp/play/test_plays/BUILD +++ b/src/software/ai/hl/stp/play/test_plays/BUILD @@ -20,8 +20,10 @@ cc_library( cc_library( name = "move_test_play", srcs = ["move_test_play.cpp"], - hdrs = ["move_test_play.h", - "move_test_play_fsm.h"], + hdrs = [ + "move_test_play.h", + "move_test_play_fsm.h", + ], deps = [ "//software/ai/hl/stp/play", "//software/ai/hl/stp/tactic/move:move_tactic", diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h index 66eaa19e4c..2ae96543dc 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h @@ -2,8 +2,8 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" -#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" // your new FSM #include "software/ai/hl/stp/play/play_base.hpp" +#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" // your new FSM /** * A test Play that halts 3 robots. diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h index 9fa2bcbb6b..e99c3c68ec 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h @@ -6,41 +6,41 @@ #include "software/ai/hl/stp/tactic/halt/halt_tactic.h" struct HaltTestPlayFSM : PlayFSM - { - struct ControlParams - { - }; - - class HaltTestState; - - explicit HaltTestPlayFSM(std::shared_ptr ai_config_ptr) - : PlayFSM(ai_config_ptr), - halt_tactics({{ - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr), - std::make_shared(ai_config_ptr), - }}) - { - } - - void updateHalt(const Update& event) - { - event.common.set_tactics(halt_tactics); - } - - auto operator()() - { - using namespace boost::sml; - - DEFINE_SML_STATE(HaltTestState) - DEFINE_SML_EVENT(Update) - DEFINE_SML_ACTION(updateHalt) - - return make_transition_table( - *HaltTestState_S + Update_E / updateHalt_A = HaltTestState_S, - X + Update_E / updateHalt_A = X); - } - - private: - PriorityTacticVector halt_tactics; - }; +{ + struct ControlParams + { + }; + + class HaltTestState; + + explicit HaltTestPlayFSM(std::shared_ptr ai_config_ptr) + : PlayFSM(ai_config_ptr), + halt_tactics({{ + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + std::make_shared(ai_config_ptr), + }}) + { + } + + void updateHalt(const Update& event) + { + event.common.set_tactics(halt_tactics); + } + + auto operator()() + { + using namespace boost::sml; + + DEFINE_SML_STATE(HaltTestState) + DEFINE_SML_EVENT(Update) + DEFINE_SML_ACTION(updateHalt) + + return make_transition_table( + *HaltTestState_S + Update_E / updateHalt_A = HaltTestState_S, + X + Update_E / updateHalt_A = X); + } + + private: + PriorityTacticVector halt_tactics; +}; diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp index c61fcde267..3af71370dc 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm_test.cpp @@ -6,25 +6,24 @@ #include "software/test_util/equal_within_tolerance.h" #include "software/test_util/test_util.h" - TEST(HaltTestPlayFSMTest, test_transitions) - { - std::shared_ptr world = ::TestUtil::createBlankTestingWorld(); - FSM fsm(HaltTestPlayFSM{std::make_shared()}); +TEST(HaltTestPlayFSMTest, test_transitions) +{ + std::shared_ptr world = ::TestUtil::createBlankTestingWorld(); + FSM fsm(HaltTestPlayFSM{std::make_shared()}); - // Verify initial state - EXPECT_TRUE(fsm.is(boost::sml::state)); + // Verify initial state + EXPECT_TRUE(fsm.is(boost::sml::state)); - // Capture tactics from callback - PriorityTacticVector received_tactics; - fsm.process_event(HaltTestPlayFSM::Update( - HaltTestPlayFSM::ControlParams{}, - PlayUpdate( - world, 3, - [&received_tactics](PriorityTacticVector new_tactics) { - received_tactics = std::move(new_tactics); - }, - InterPlayCommunication{}, [](InterPlayCommunication) {}))); + // Capture tactics from callback + PriorityTacticVector received_tactics; + fsm.process_event(HaltTestPlayFSM::Update( + HaltTestPlayFSM::ControlParams{}, + PlayUpdate( + world, 3, + [&received_tactics](PriorityTacticVector new_tactics) + { received_tactics = std::move(new_tactics); }, + InterPlayCommunication{}, [](InterPlayCommunication) {}))); - // Verify state stays the same (single-state loop) - EXPECT_TRUE(fsm.is(boost::sml::state)); - } + // Verify state stays the same (single-state loop) + EXPECT_TRUE(fsm.is(boost::sml::state)); +} diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp b/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp index 3ea39de390..82f6fc6808 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp @@ -13,8 +13,9 @@ void MoveTestPlay::getNextTactics(TacticCoroutine::push_type &yield, { } -void MoveTestPlay::updateTactics(const PlayUpdate &play_update){ - fsm.process_event(MoveTestPlayFSM::Update(control_params, play_update)); +void MoveTestPlay::updateTactics(const PlayUpdate &play_update) +{ + fsm.process_event(MoveTestPlayFSM::Update(control_params, play_update)); } // Register this play in the genericFactory diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.h b/src/software/ai/hl/stp/play/test_plays/move_test_play.h index 43fd2507c4..8d6bca46d3 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.h @@ -2,8 +2,8 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" -#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" // your new FSM #include "software/ai/hl/stp/play/play_base.hpp" +#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" // your new FSM /** * A test Play that moves a robot to the friendly goal, a robot to the enemy goal, and diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h index 26f14457e4..e331a1edf1 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h @@ -6,23 +6,23 @@ #include "software/ai/hl/stp/tactic/move/move_tactic.h" struct MoveTestPlayFSM : PlayFSM - { - struct ControlParams - { - }; +{ + struct ControlParams + { + }; - class MoveTestState; + class MoveTestState; - explicit MoveTestPlayFSM(std::shared_ptr ai_config_ptr) - : PlayFSM(ai_config_ptr), - move_test_tactic_friendly_goal(std::make_shared(ai_config_ptr)), - move_test_tactic_enemy_goal(std::make_shared(ai_config_ptr)), - move_test_tactic_center_field(std::make_shared(ai_config_ptr)) - { - } + explicit MoveTestPlayFSM(std::shared_ptr ai_config_ptr) + : PlayFSM(ai_config_ptr), + move_test_tactic_friendly_goal(std::make_shared(ai_config_ptr)), + move_test_tactic_enemy_goal(std::make_shared(ai_config_ptr)), + move_test_tactic_center_field(std::make_shared(ai_config_ptr)) + { + } - void updateMove(const Update& event) - { + void updateMove(const Update& event) + { move_test_tactic_friendly_goal->updateControlParams( event.common.world_ptr->field().friendlyGoalCenter(), Angle::zero(), TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, @@ -35,33 +35,34 @@ struct MoveTestPlayFSM : PlayFSM Point(0, 0), Angle::zero(), TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, TbotsProto::ObstacleAvoidanceMode::SAFE); - event.common.set_tactics({{move_test_tactic_center_field, move_test_tactic_friendly_goal, - move_test_tactic_enemy_goal}}); - } + event.common.set_tactics( + {{move_test_tactic_center_field, move_test_tactic_friendly_goal, + move_test_tactic_enemy_goal}}); + } - bool moveDone(const Update& event){ - return move_test_tactic_center_field->done(); - - } + bool moveDone(const Update& event) + { + return move_test_tactic_center_field->done(); + } - auto operator()() - { - using namespace boost::sml; + auto operator()() + { + using namespace boost::sml; - DEFINE_SML_STATE(MoveTestState) - DEFINE_SML_EVENT(Update) - DEFINE_SML_ACTION(updateMove) - DEFINE_SML_GUARD(moveDone) + DEFINE_SML_STATE(MoveTestState) + DEFINE_SML_EVENT(Update) + DEFINE_SML_ACTION(updateMove) + DEFINE_SML_GUARD(moveDone) - return make_transition_table( - *MoveTestState_S + Update_E [!moveDone_G] / updateMove_A = MoveTestState_S, - MoveTestState_S + Update_E [moveDone_G] / updateMove_A = X, - X + Update_E / updateMove_A = X); - } + return make_transition_table( + *MoveTestState_S + Update_E[!moveDone_G] / updateMove_A = MoveTestState_S, + MoveTestState_S + Update_E[moveDone_G] / updateMove_A = X, + X + Update_E / updateMove_A = X); + } - private: - std::shared_ptr move_test_tactic_friendly_goal; - std::shared_ptr move_test_tactic_enemy_goal; - std::shared_ptr move_test_tactic_center_field; - }; + private: + std::shared_ptr move_test_tactic_friendly_goal; + std::shared_ptr move_test_tactic_enemy_goal; + std::shared_ptr move_test_tactic_center_field; +}; diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp index 50ea36af85..e6a56b830a 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm_test.cpp @@ -8,8 +8,7 @@ TEST(MoveTestPlayFSMTest, test_stays_in_move_state) { std::shared_ptr world = ::TestUtil::createBlankTestingWorld(); - FSM fsm( - MoveTestPlayFSM{std::make_shared()}); + FSM fsm(MoveTestPlayFSM{std::make_shared()}); // Verify initial state EXPECT_TRUE(fsm.is(boost::sml::state)); From ad60d5d19b11081cc1ce5061e737ade1d1f0555b Mon Sep 17 00:00:00 2001 From: Samuel <92961466+StarrryNight@users.noreply.github.com> Date: Sat, 21 Feb 2026 13:30:05 -0800 Subject: [PATCH 20/24] Fix include statement for halt_test_play_fsm.h --- src/software/ai/hl/stp/play/test_plays/halt_test_play.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h index 2ae96543dc..ca8dd5a938 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h @@ -3,7 +3,7 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" #include "software/ai/hl/stp/play/play_base.hpp" -#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" // your new FSM +#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" /** * A test Play that halts 3 robots. From a4c9cf0a3b13db251fc505c243e5b05455dc5d53 Mon Sep 17 00:00:00 2001 From: Samuel <92961466+StarrryNight@users.noreply.github.com> Date: Sat, 21 Feb 2026 13:30:44 -0800 Subject: [PATCH 21/24] Fix include statement for move_test_play_fsm.h --- src/software/ai/hl/stp/play/test_plays/move_test_play.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.h b/src/software/ai/hl/stp/play/test_plays/move_test_play.h index 8d6bca46d3..ef1faef0d1 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.h @@ -3,7 +3,7 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" #include "software/ai/hl/stp/play/play_base.hpp" -#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" // your new FSM +#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" /** * A test Play that moves a robot to the friendly goal, a robot to the enemy goal, and From 95d4cd4c841cd90948580a67c4a0866fdd94fcae Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 21:37:15 +0000 Subject: [PATCH 22/24] [pre-commit.ci lite] apply automatic fixes --- src/software/ai/hl/stp/play/test_plays/halt_test_play.h | 2 +- src/software/ai/hl/stp/play/test_plays/move_test_play.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h index ca8dd5a938..cbab38c25d 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play.h @@ -3,7 +3,7 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" #include "software/ai/hl/stp/play/play_base.hpp" -#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" +#include "software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h" /** * A test Play that halts 3 robots. diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.h b/src/software/ai/hl/stp/play/test_plays/move_test_play.h index ef1faef0d1..92b7e55783 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.h +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.h @@ -3,7 +3,7 @@ #include "proto/parameters.pb.h" #include "software/ai/hl/stp/play/play.h" #include "software/ai/hl/stp/play/play_base.hpp" -#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" +#include "software/ai/hl/stp/play/test_plays/move_test_play_fsm.h" /** * A test Play that moves a robot to the friendly goal, a robot to the enemy goal, and From 015a52e26088b3f046e1713d2c16013f81dd950b Mon Sep 17 00:00:00 2001 From: "lausing@student.ubc.ca" Date: Tue, 24 Feb 2026 14:31:30 -0800 Subject: [PATCH 23/24] add doc comments --- .../ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp | 2 ++ .../ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h | 1 + src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h | 1 + src/software/ai/hl/stp/play/test_plays/move_test_play.cpp | 2 ++ src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h | 1 + 5 files changed, 7 insertions(+) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp index ab7b04ddb7..5d1ec92377 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play.cpp @@ -15,6 +15,8 @@ ShootOrChipPlay::ShootOrChipPlay( void ShootOrChipPlay::getNextTactics(TacticCoroutine::push_type &yield, const WorldPtr &world_ptr) { + // This function doesn't get called, it should be removed once coroutines + // are phased out } diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h index e08045cc55..e9edb745ac 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.h @@ -34,6 +34,7 @@ struct ShootOrChipPlayFSM : PlayFSM DEFINE_SML_GUARD(attackerDone) return make_transition_table( + // src_state + event [guard] / action = dest_state *ShootOrChipState_S + Update_E[!attackerDone_G] / updateShootOrChip_A = ShootOrChipState_S, ShootOrChipState_S + Update_E[attackerDone_G] / updateShootOrChip_A = X, diff --git a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h index e99c3c68ec..dcad1a6f03 100644 --- a/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h +++ b/src/software/ai/hl/stp/play/test_plays/halt_test_play_fsm.h @@ -37,6 +37,7 @@ struct HaltTestPlayFSM : PlayFSM DEFINE_SML_ACTION(updateHalt) return make_transition_table( + // src_state + event [guard] / action = dest_state *HaltTestState_S + Update_E / updateHalt_A = HaltTestState_S, X + Update_E / updateHalt_A = X); } diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp b/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp index 82f6fc6808..6acaea6495 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play.cpp @@ -11,6 +11,8 @@ MoveTestPlay::MoveTestPlay(std::shared_ptr ai_config void MoveTestPlay::getNextTactics(TacticCoroutine::push_type &yield, const WorldPtr &world_ptr) { + // This function doesn't get called, it should be removed once coroutines + // are phased out } void MoveTestPlay::updateTactics(const PlayUpdate &play_update) diff --git a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h index e331a1edf1..ee99fcfe3e 100644 --- a/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h +++ b/src/software/ai/hl/stp/play/test_plays/move_test_play_fsm.h @@ -56,6 +56,7 @@ struct MoveTestPlayFSM : PlayFSM DEFINE_SML_GUARD(moveDone) return make_transition_table( + // src_state + event [guard] / action = dest_state *MoveTestState_S + Update_E[!moveDone_G] / updateMove_A = MoveTestState_S, MoveTestState_S + Update_E[moveDone_G] / updateMove_A = X, X + Update_E / updateMove_A = X); From 0b192932b50e4de528698c2294847f37b936faee Mon Sep 17 00:00:00 2001 From: StarrryNight Date: Sun, 1 Mar 2026 14:59:10 -0800 Subject: [PATCH 24/24] remove halt tactic --- .../ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp index ea38982e03..b5cafba8a9 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp +++ b/src/software/ai/hl/stp/play/shoot_or_chip/shoot_or_chip_play_fsm.cpp @@ -7,7 +7,6 @@ #include "software/ai/evaluation/possession.h" #include "software/ai/hl/stp/tactic/attacker/attacker_tactic.h" #include "software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic.h" -#include "software/ai/hl/stp/tactic/halt/halt_tactic.h" #include "software/ai/hl/stp/tactic/move/move_tactic.h" #include "software/ai/hl/stp/tactic/shadow_enemy/shadow_enemy_tactic.h"