Adding a feature
Adding a play
Making a play is the process of combining existing building blocks with different parameters to make a unique set of activities for the robots. A template was made to aid in the design of a new play (PlayTemplate.cpp and PlayTemplate.h).
Starting requirements: Play() & shouldEndPlay() The startPlayEvaluations are the invariants that need to be true (above a score of 127) to make it valid for consideration by the PlayDecider. A balance needs to be found for the number of invariants that are used, as this restricts the AI by implementing hard-coded design choices. However, this does allow for the play designer to better define the usages of the play. For referee-state plays, the starting requirements are obvious; associated game-state.
For normal plays, the evaluation of NormalPlayGameState needs to be enabled. If this is forgotten, plays that are not meant for a referee-state could be considered as when they should not.
Ending a play: Play() Likewise to the startPlayEvaluations, keepPlayEvaluation vector has to be true in order to continue the play. If a single of the listed evalutations is false, the play will end and a new play will be chosen. Another way to end a play is to add a condition to the shouldEndPlay() function. However, when adding a condition to this function, consider the condition can not be a generalized evaluation. A play will automatically end if all roles are of status success.
Scoring a play: score() The scoring of a play should be a measure of how effective the play will be in the future. Currently this is done when looking at the current game state and evaluating future positions. The startPlayEvaluations could be reused to see how true these invariants are2, and others can be added.
Robot Roles: Play() & decideRoleFlags() The naming of the roles are unique to the play and can be chosen at will. When adding information to roles, this name is reused, therefore try to use informative names for each role.
When assigning flags and priorities to the roles in the decideRoleFlags() function, do not overuse the number of flags, as the distance to a role is often enough to efficiently distribute the roles. The flags are meant for the higher priority roles were certain factors do matter3. Priorities are meant to be able to define the importance of a role in the play. The roles are distributed in the order of the priorities. The ’Keeper’ priority should be given to the keeper as the highest priority. Lastly, forcedRoles are there to ensure smooth transitions between plays. Do not overuse this feature. The feature was added with the PlayInfos in mind, allowing the play designer to force the receiver of a pass between plays.
Info for Roles: calculateInfoForRoles() & calculateInfoForScoredRoles() In these functions, the STPinfo’s for each role is filled. Try to only use functions from other modules here. If a function does not exist, consider generalizing the function so it can be used in other plays as well. PositionComputations handles all the positioning of the robots.
Transferring information to next play: storePlayInfo() To transfer STPInfo to the next play, the PlayInfo structure was build (explained further in section 3.4 on page 20). Use the generalized keys and elements that are provided in the KeyInfo and StoreInfo structure respectively.
Adding a computation
Computations are generalized building block that can be used through all of the STP parts. The intention of this module was the reduce the clutter in the plays, moving all computations from plays into this module and referring to these functions. The computation module is likely the most performance heavy part of STP (aside from pathfinding) and should be optimized for performance. Functions in this module should therefore be written in a manner that allows for easy reviewing by others.
Adding an Evaluation
All transformations from a value to a score value should be done through the Evaluation module. This module allows for building efficient mapping from a value to a uint8-t score. When adding an Evaluation, ensure that there are no big computations done within the function. The idea was to have the evaluations only sum and multiply the input parameters, passing it through a piece-wise function, and to have these evaluations be easily adjusted as the mapping to score is are prone to parameter tweaking.