From 19460175a7d7edeea26cb1bc24a39f2226088ab6 Mon Sep 17 00:00:00 2001 From: Matthew Hausknecht <matthew.hausknecht@gmail.com> Date: Thu, 23 Jun 2016 14:16:57 -0500 Subject: [PATCH] Refactored high-level state features, adding opponent features. --- doc/manual.pdf | Bin 291681 -> 291796 bytes doc/manual.tex | 26 +++++----- src/HFO.cpp | 8 ++- src/highlevel_feature_extractor.cpp | 76 +++++++++++++++++----------- src/highlevel_feature_extractor.h | 7 +-- 5 files changed, 68 insertions(+), 49 deletions(-) diff --git a/doc/manual.pdf b/doc/manual.pdf index 4749d34ef99f21a7c34ad6c0ec2edb05b9433999..189d61b32a235f143506dbcf8993e6deb4fc4dc6 100644 GIT binary patch delta 12774 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 UkP8$k0yhUc0yVXiiZsIi19q1uQUCw| delta 12711 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	hlAJMcA%?V#eRZ^v}^i#NP;QJS@ zo;WR@3_jA#n3{Pt%t&mNb4To7vhF(R4$n!LLgx74P+ovz^P6#Wl;Dl`>K#U!4h?_u zRDp~W7L^w5Ma$IrQ5{z`(mgwT@|PNv?<m&pwtM#j9V|jDhm192EeY%q+x$aeApZ*! ze1jBdV4RdK9kQ`tf;$_ldw*mSQfMoNP4;x}6kzpC+sh~dVh=aL9FmnIDiu=p%DTL- z3L&^_Vn}xP-Ao&t)V)7L_|hv7<Knws1w86mEe;Vtko}M^;!G%pL}C=4k>6+F(YuXd zYxC-PmpO*OXr$Xc<Ba>i#DX#{u?=~iwxfSoJ14`Ked7_!=j~OCDJE5DYj9dQSyJ)V zWFI5g=LG{Id6+{bLhrerPF1Y589Amuhb+BiT*>X0bNh5uIg;?hy6c|2YU#2V0gj~~ zr(kcP;XRDiO3kOB>*S5q=s&usnSgaj)2B7>={Rx|ONemztwPD*GxUYUt|Hnpxr@`P z<QlCoEveB!kbJDXLz+s<y(mzqH8Gg~qS-$yFhQds1Lhb0{-Enu_$<(VuaGuW<fc$7 z6l;*eCZ`c+QNch6Tk}}L0DZ1C&}@6LKiQ;Pe?Qc&NjEm<TRW#Qw#H!T262w<Xll1_ z)2h~8t6OFJsavgkRy*0;ZuPK7UTv@QiVoirC1Iu^_NBxjNksk;`LI#4hSNDYzA{SR z>^CEg7E#;iH3PL)dT3h-AKlnsAa==NwUe;fL#%i3?!tNKovqS&+}|%%YK;plDKa+) NJ2D-ew8}^1{{wA)CsF_a diff --git a/doc/manual.tex b/doc/manual.tex index 8872a66..b14d22d 100644 --- a/doc/manual.tex +++ b/doc/manual.tex @@ -273,9 +273,9 @@ are encoded a floating point values and normalized to the range of follows: \subsubsection{High Level State Feature List} -Let $T$ denote the number of teammates in the HFO game. Then there are -a total of $9 + 5T$ high-level features with an additional $T+1$ -features if at least one opponent is present. +Let $T$ denote the number of teammates in the HFO game and $O$ the +number of opponents. There are a total of $10 + 6T + 3O$ high-level +features. \begin{enumerate}[noitemsep] \setcounter{enumi}{-1} @@ -292,17 +292,16 @@ features if at least one opponent is present. \item{\textbf{Goal Opening Angle} - The size of the largest open angle of the agent to the goal, shown as $\theta_g$ in Figure \ref{fig:openAngle}. Invalid if agent is not playing offense.} -\item [$T$] {\textbf{Teammate i's Goal Opening Angle} - For each - teammate i: i’s goal opening angle. Invalid if agent is not playing - offense.} -\item [$1$] {\textbf{Proximity to Opponent} - If an opponent is - present, proximity to the closest opponent. This feature is absent - if there are no opponents.} +\item{\textbf{Proximity to Opponent} - If an opponent is present, + proximity to the closest opponent. Invalid if there are no + opponents.} +\item [$T$] {\textbf{Teammate's Goal Opening Angle} - For each + teammate $i$: $i$’s goal opening angle. Invalid if agent is not + playing offense.} \item [$T$] {\textbf{Proximity from Teammate i to Opponent} - For each teammate i: the proximity from the teammate to the closest - opponent. This feature is absent if there are no opponents. If - teammates are present but not detected, this feature is considered - invalid and given the value of -2.} + opponent. This feature is invalid if there are no opponents or if + teammates are present but not detected.} \item [$T$] {\textbf{Pass Opening Angle} - For each teammate i: the open angle available to pass to teammate i. Shown as $\theta_p$ in Figure \ref{fig:openAngle}. If teammates are present but not detected, this @@ -310,6 +309,9 @@ features if at least one opponent is present. \item [$3T$] {\textbf{Proximity, Angle, and Uniform Number of Teammates} - For each teammate i: the proximity, angle, and uniform number of that teammate.} +\item [$3O$] {\textbf{Proximity, Angle, and Uniform Number of + Opponents} - For each opponent: the proximity, angle, and + uniform number of that opponent.} \end{enumerate} \begin{figure}[htp] diff --git a/src/HFO.cpp b/src/HFO.cpp index 83b77f7..cc0d9a9 100644 --- a/src/HFO.cpp +++ b/src/HFO.cpp @@ -137,19 +137,17 @@ status_t HFOEnvironment::step() { // Update the state features agent->preAction(); - assert(agent->currentTime().cycle() == (current_cycle + 1)); current_cycle = agent->currentTime().cycle(); - status_t status = agent->getGameStatus(); - // If the episode is over, take three NOOPs to refresh state features if (status != IN_GAME && status != SERVER_DOWN) { for (int i = 0; i < 3; ++i) { act(NOOP); - step(); + if (step() == SERVER_DOWN) { + return SERVER_DOWN; + } } } - return status; } diff --git a/src/highlevel_feature_extractor.cpp b/src/highlevel_feature_extractor.cpp index 35a889d..7faa4c7 100644 --- a/src/highlevel_feature_extractor.cpp +++ b/src/highlevel_feature_extractor.cpp @@ -14,11 +14,8 @@ HighLevelFeatureExtractor::HighLevelFeatureExtractor(int num_teammates, { assert(numTeammates >= 0); assert(numOpponents >= 0); - numFeatures = num_basic_features + features_per_teammate * numTeammates; - if (numOpponents > 0) { - // One extra basic feature and one feature per teammate - numFeatures += 1 + numTeammates; - } + numFeatures = num_basic_features + features_per_teammate * numTeammates + + features_per_opponent * numOpponents; feature_vec.resize(numFeatures); } @@ -32,6 +29,7 @@ const std::vector<float>& HighLevelFeatureExtractor::ExtractFeatures( const Vector2D& self_pos = self.pos(); const float self_ang = self.body().radian(); const PlayerCont& teammates = wm.teammates(); + const PlayerCont& opponents = wm.opponents(); float maxR = sqrtf(SP.pitchHalfLength() * SP.pitchHalfLength() + SP.pitchHalfWidth() * SP.pitchHalfWidth()); // features about self pos @@ -44,49 +42,52 @@ const std::vector<float>& HighLevelFeatureExtractor::ExtractFeatures( } else { addNormFeature(self_pos.x, -SP.pitchHalfLength()-tolerance_x, tolerance_x); } - // addFeature(self_pos.x); // Feature[1]: Y-Position addNormFeature(self_pos.y, -SP.pitchHalfWidth() - tolerance_y, SP.pitchHalfWidth() + tolerance_y); - // addFeature(self_pos.y); // Feature[2]: Self Angle - addNormFeature(self_ang, -M_PI, M_PI); // addFeature(self_ang); + addNormFeature(self_ang, -M_PI, M_PI); float r; float th; - // features about the ball + // Features about the ball Vector2D ball_pos = wm.ball().pos(); angleDistToPoint(self_pos, ball_pos, th, r); // Feature[3]: Dist to ball - addNormFeature(r, 0, maxR); // addFeature(r); + addNormFeature(r, 0, maxR); // Feature[4]: Ang to ball - addNormFeature(th, -M_PI, M_PI); // addFeature(th); + addNormFeature(th, -M_PI, M_PI); // Feature[5]: Able to kick - addNormFeature(self.isKickable(), false, true); // addFeature(self.isKickable()); + addNormFeature(self.isKickable(), false, true); - // features about distance to goal center + // Features about distance to goal center Vector2D goalCenter(SP.pitchHalfLength(), 0); if (!playingOffense) { goalCenter.assign(-SP.pitchHalfLength(), 0); } angleDistToPoint(self_pos, goalCenter, th, r); // Feature[6]: Goal Center Distance - addNormFeature(r, 0, maxR); // addFeature(r); + addNormFeature(r, 0, maxR); // Feature[7]: Angle to goal center - addNormFeature(th, -M_PI, M_PI); // addFeature(th); + addNormFeature(th, -M_PI, M_PI); // Feature[8]: largest open goal angle addNormFeature(calcLargestGoalAngle(wm, self_pos), 0, M_PI); - // addFeature(calcLargestGoalAngle(wm, self_pos)); + // Feature[9]: Dist to our closest opp + if (numOpponents > 0) { + calcClosestOpp(wm, self_pos, th, r); + addNormFeature(r, 0, maxR); + } else { + addFeature(FEAT_INVALID); + } - // Features [9+T - 9 + 2T]: teammate's open angle to goal + // Features[9 - 9+T]: teammate's open angle to goal int detected_teammates = 0; for (PlayerCont::const_iterator it=teammates.begin(); it != teammates.end(); ++it) { const PlayerObject& teammate = *it; if (valid(teammate) && detected_teammates < numTeammates) { addNormFeature(calcLargestGoalAngle(wm, teammate.pos()), 0, M_PI); - // addFeature(calcLargestGoalAngle(wm, teammate.pos())); detected_teammates++; } } @@ -95,18 +96,14 @@ const std::vector<float>& HighLevelFeatureExtractor::ExtractFeatures( addFeature(FEAT_INVALID); } - // dist to our closest opp + // Features[9+T - 9+2T]: teammates' dists to closest opps if (numOpponents > 0) { - calcClosestOpp(wm, self_pos, th, r); - addNormFeature(r, 0, maxR); // addFeature(r); - - // teammates dists to closest opps detected_teammates = 0; for (PlayerCont::const_iterator it=teammates.begin(); it != teammates.end(); ++it) { const PlayerObject& teammate = *it; if (valid(teammate) && detected_teammates < numTeammates) { calcClosestOpp(wm, teammate.pos(), th, r); - addNormFeature(r, 0, maxR); // addFeature(r); + addNormFeature(r, 0, maxR); detected_teammates++; } } @@ -114,6 +111,10 @@ const std::vector<float>& HighLevelFeatureExtractor::ExtractFeatures( for (int i=detected_teammates; i<numTeammates; ++i) { addFeature(FEAT_INVALID); } + } else { // If no opponents, add invalid features + for (int i=0; i<numTeammates; ++i) { + addFeature(FEAT_INVALID); + } } // Features [9+2T - 9+3T]: open angle to teammates @@ -122,7 +123,6 @@ const std::vector<float>& HighLevelFeatureExtractor::ExtractFeatures( const PlayerObject& teammate = *it; if (valid(teammate) && detected_teammates < numTeammates) { addNormFeature(calcLargestTeammateAngle(wm, self_pos, teammate.pos()),0,M_PI); - // addFeature(calcLargestTeammateAngle(wm, self_pos, teammate.pos())); detected_teammates++; } } @@ -131,14 +131,14 @@ const std::vector<float>& HighLevelFeatureExtractor::ExtractFeatures( addFeature(FEAT_INVALID); } - // Features [9+3T - end]: dist, angle, unum of teammates + // Features [9+3T - 9+6T]: dist, angle, unum of teammates detected_teammates = 0; for (PlayerCont::const_iterator it=teammates.begin(); it != teammates.end(); ++it) { const PlayerObject& teammate = *it; if (valid(teammate) && detected_teammates < numTeammates) { angleDistToPoint(self_pos, teammate.pos(), th, r); - addNormFeature(r,0,maxR); // addFeature(r); - addNormFeature(th,-M_PI,M_PI); // addFeature(th); + addNormFeature(r,0,maxR); + addNormFeature(th,-M_PI,M_PI); addFeature(teammate.unum()); detected_teammates++; } @@ -150,8 +150,26 @@ const std::vector<float>& HighLevelFeatureExtractor::ExtractFeatures( addFeature(FEAT_INVALID); } + // Features [9+6T - 9+6T+3O]: dist, angle, unum of opponents + int detected_opponents = 0; + for (PlayerCont::const_iterator it = opponents.begin(); it != opponents.end(); ++it) { + const PlayerObject& opponent = *it; + if (valid(opponent) && detected_opponents < numOpponents) { + angleDistToPoint(self_pos, opponent.pos(), th, r); + addNormFeature(r,0,maxR); + addNormFeature(th,-M_PI,M_PI); + addFeature(opponent.unum()); + detected_opponents++; + } + } + // Add zero features for any missing opponents + for (int i=detected_opponents; i<numOpponents; ++i) { + addFeature(FEAT_INVALID); + addFeature(FEAT_INVALID); + addFeature(FEAT_INVALID); + } + assert(featIndx == numFeatures); // checkFeatures(); - //std::cout << "features: " << features.rows(0,ind-1).t(); return feature_vec; } diff --git a/src/highlevel_feature_extractor.h b/src/highlevel_feature_extractor.h index 5b5585a..87004fd 100644 --- a/src/highlevel_feature_extractor.h +++ b/src/highlevel_feature_extractor.h @@ -22,9 +22,10 @@ public: protected: // Number of features for non-player objects. - const static int num_basic_features = 9; - // Number of features for each player or opponent in game. - const static int features_per_teammate = 5; + const static int num_basic_features = 10; + // Number of features for each teammate and opponent in game. + const static int features_per_teammate = 6; + const static int features_per_opponent = 3; }; #endif // HIGHLEVEL_FEATURE_EXTRACTOR_H -- 2.24.1