From 85a0d4aa9a0676656effc6ae69b143375a8239e2 Mon Sep 17 00:00:00 2001 From: drallensmith <drallensmith@users.noreply.github.com> Date: Sun, 6 Aug 2017 14:40:48 -0500 Subject: [PATCH] Revise feedback with enum, use of ACTION_STATUS_UNKNOWN when appropriate --- doc/manual.pdf | Bin 303244 -> 303230 bytes doc/manual.tex | 6 +- example/explore_offense_actions_fullstate.py | 141 ++++++++++++++--- hfo/hfo.py | 6 +- src/HFO.cpp | 2 +- src/HFO.hpp | 2 +- src/agent.cpp | 151 ++++++++++++------- src/agent.h | 27 ++-- src/bhv_basic_move.cpp | 30 +++- src/bhv_basic_move.h | 4 +- src/common.hpp | 43 +++++- 11 files changed, 300 insertions(+), 112 deletions(-) diff --git a/doc/manual.pdf b/doc/manual.pdf index 7f9e2ac90a5957ea3186140037fff524b6364bf8..4a0b8719c0df7472ac4bdd7caf13dbf5d316ff45 100644 GIT binary patch delta 4481 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 Q8lni3r4ST^n`l$~A0PZ?{{R30 delta 4464 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 Ce`YcO diff --git a/doc/manual.tex b/doc/manual.tex index 2d763ff..62964be 100644 --- a/doc/manual.tex +++ b/doc/manual.tex @@ -622,13 +622,13 @@ Team. unum invalid & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & N & Opponent loc invalid & Y & Y & Y & Y & Y & Y & Y? & Y & N & Y? & Y & Y? & Y & Y & Y & Y & N \\ Opp. unum invalid & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & Y & N \\ \hline -Ball kickable & Y & Y & Y & Y & Y & Y & Y & ? & * & Y & Y & Y & Y & ? & ? & ? & Y \\ +Ball kickable & Y & Y & Y & Y & Y & Y & Y & N & * & Y & Y & Y & Y & ? & ? & N & Y \\ Ball not kickable & Y & Y & Y & N & N & Y & Y & Y & Y & N & N & N & Y & Y & Y & Y & Y \\ \hline Frozen & N & N & N & N & N & N & N? & N & N? & N & N & Y & N? & N & N & N & N \\ -Colliding w/ball & Y & Y & ? & ? & ? & Y? & ? & ? & ? & ? & ? & ? & ? & ? & ? & ? & ? \\ +Colliding w/ball & Y & Y & ? & N & Y & Y & Y & Y & ? & ? & ? & ? & ? & ? & ? & N & ? \\ Colliding w/player & Y & Y? & ? & N? & N? & Y? & ? & Y? & ? & ? & ? & Y? & ? & ? & ? & Y? & ? \\ -Colliding w/post & Y & Y & N? & N? & N? & Y & ? & Y & ? & ? & ? & ? & ? & ? & ? & Y & ? \\ +Colliding w/post & Y & Y & N? & N? & N? & Y & Y & Y & Y & ? & ? & Y & ? & Y & Y & Y & Y \\ \hline Offense & Y & Y & N & Y & Y & Y & Y & Y & Y & Y & Y & Y & N & N & N & Y & N \\ Defense, not goalie & Y & Y & Y & N? & N? & Y & N & Y & Y & N & N & N & N & Y & ? & Y & Y \\ diff --git a/example/explore_offense_actions_fullstate.py b/example/explore_offense_actions_fullstate.py index 75444a7..db55f11 100755 --- a/example/explore_offense_actions_fullstate.py +++ b/example/explore_offense_actions_fullstate.py @@ -284,7 +284,7 @@ def get_abs_x_y_pos(abs_angle, dist, self_x_pos, self_y_pos, warn=True, of_what= if dist < 10: raise RuntimeError("\n".join(error_strings)) else: - if warn or (dist < 60): + if warn or (dist < 50): print("\n".join(error_strings), file=sys.stderr) sys.stderr.flush() return (None, None) @@ -641,9 +641,36 @@ def evaluate_previous_action(hfo_env, action_status_observed = hfo.ACTION_STATUS_UNKNOWN # NOTE: Check intent + other bitflags! if namespace.action == hfo.DASH: - pass # TODO + if (namespace.intent != + INTENT_GOAL_COLLISION) and namespace.prestate_bit_list[3] and (not bit_list[3]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent != + INTENT_BALL_COLLISION) and namespace.prestate_bit_list[2] and (not bit_list[2]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_BALL_KICKABLE) and (not namespace.prestate_bit_list[4]) and bit_list[4]: + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_GOAL_COLLISION) and (not namespace.prestate_bit_list[3]) and bit_list[3]: + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_BALL_COLLISION) and (((not namespace.prestate_bit_list[2]) and bit_list[2]) or + ((not namespace.prestate_bit_list[4]) and bit_list[4])): + action_status_observed = hfo.ACTION_STATUS_MAYBE + else: + pass # TODO elif namespace.action == hfo.TURN: - if (namespace.prestate_self_dict['body_angle'] is not None) and (self_dict['body_angle'] is not None): + if (namespace.intent != + INTENT_GOAL_COLLISION) and namespace.prestate_bit_list[3] and (not bit_list[3]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent != + INTENT_BALL_COLLISION) and namespace.prestate_bit_list[2] and (not bit_list[2]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_BALL_KICKABLE) and (not namespace.prestate_bit_list[4]) and bit_list[4]: + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_GOAL_COLLISION) and (not namespace.prestate_bit_list[3]) and bit_list[3]: + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_BALL_COLLISION) and (((not namespace.prestate_bit_list[2]) and bit_list[2]) or + ((not namespace.prestate_bit_list[4]) and bit_list[4])): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.prestate_self_dict['body_angle'] is not None) and (self_dict['body_angle'] is not None): intended_body_angle = namespace.prestate_self_dict['body_angle'] + namespace.action_params[0] if get_angle_diff(namespace.prestate_self_dict['body_angle'], intended_body_angle) > get_angle_diff(self_dict['body_angle'], @@ -652,7 +679,15 @@ def evaluate_previous_action(hfo_env, else: action_status_observed = hfo.ACTION_STATUS_BAD elif namespace.action == hfo.KICK: - pass # TODO + if bit_list[4]: + if namespace.prestate_bit_list[2] and (not bit_list[2]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif namespace.prestate_bit_list[3] and (not bit_list[3]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + else: + action_status_observed = hfo.ACTION_STATUS_BAD + else: + pass # TODO elif namespace.action == hfo.KICK_TO: if (namespace.prestate_ball_dict['x_pos'] is not None) and (ball_dict['x_pos'] is not None): dist_before = get_dist_real(namespace.prestate_ball_dict['x_pos'], @@ -665,10 +700,30 @@ def evaluate_previous_action(hfo_env, namespace.action_params[1]) if dist_before > dist_after: action_status_observed = hfo.ACTION_STATUS_MAYBE + elif bit_list[4]: + if namespace.prestate_bit_list[2] and (not bit_list[2]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif namespace.prestate_bit_list[3] and (not bit_list[3]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + else: + action_status_observed = hfo.ACTION_STATUS_BAD else: action_status_observed = hfo.ACTION_STATUS_BAD elif namespace.action == hfo.MOVE_TO: - if (namespace.prestate_self_dict['x_pos'] is not None) and (self_dict['x_pos'] is not None): + if (namespace.intent != + INTENT_GOAL_COLLISION) and namespace.prestate_bit_list[3] and (not bit_list[3]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent != + INTENT_BALL_COLLISION) and namespace.prestate_bit_list[2] and (not bit_list[2]): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_BALL_KICKABLE) and (not namespace.prestate_bit_list[4]) and bit_list[4]: + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_GOAL_COLLISION) and (not namespace.prestate_bit_list[3]) and bit_list[3]: + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_BALL_COLLISION) and (((not namespace.prestate_bit_list[2]) and bit_list[2]) or + ((not namespace.prestate_bit_list[4]) and bit_list[4])): + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.prestate_self_dict['x_pos'] is not None) and (self_dict['x_pos'] is not None): dist_before = get_dist_real(namespace.prestate_self_dict['x_pos'], namespace.prestate_self_dict['y_pos'], namespace.action_params[0], @@ -685,6 +740,10 @@ def evaluate_previous_action(hfo_env, if namespace.prestate_bit_list[4]: if not bit_list[4]: action_status_observed = hfo.ACTION_STATUS_BAD + elif namespace.prestate_bit_list[3] and (not bit_list[3]): # goal collision + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif namespace.prestate_bit_list[2] and (not bit_list[2]): # ball collision + action_status_observed = hfo.ACTION_STATUS_MAYBE elif (namespace.prestate_self_dict['x_pos'] is not None) and (self_dict['x_pos'] is not None): dist_before = get_dist_real(namespace.prestate_self_dict['x_pos'], namespace.prestate_self_dict['y_pos'], @@ -700,6 +759,10 @@ def evaluate_previous_action(hfo_env, action_status_observed = hfo.ACTION_STATUS_BAD elif bit_list[4]: action_status_observed = hfo.ACTION_STATUS_MAYBE + elif namespace.prestate_bit_list[3] and (not bit_list[3]): # goal collision + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif namespace.prestate_bit_list[2] and (not bit_list[2]): # ball collision + action_status_observed = hfo.ACTION_STATUS_MAYBE elif namespace.prestate_ball_dict['dist'] > ball_dict['dist']: action_status_observed = hfo.ACTION_STATUS_MAYBE elif namespace.prestate_ball_dict['dist'] < ball_dict['dist']: @@ -709,11 +772,20 @@ def evaluate_previous_action(hfo_env, elif (namespace.action == hfo.INTERCEPT) or (namespace.action == hfo.GO_TO_BALL): if namespace.prestate_bit_list[4]: if bit_list[4]: - action_status_observed = hfo.ACTION_STATUS_MAYBE + if (namespace.intent != INTENT_BALL_COLLISION) and bit_list[2]: + action_status_observed = hfo.ACTION_STATUS_BAD + elif (namespace.intent != INTENT_GOAL_COLLISION) and bit_list[3]: + action_status_observed = hfo.ACTION_STATUS_BAD + else: + action_status_observed = hfo.ACTION_STATUS_MAYBE else: action_status_observed = hfo.ACTION_STATUS_BAD elif bit_list[4]: action_status_observed = hfo.ACTION_STATUS_MAYBE + elif namespace.prestate_bit_list[3] and (not bit_list[3]): # goal collision + action_status_observed = hfo.ACTION_STATUS_MAYBE + elif (namespace.intent == INTENT_BALL_COLLISION) and (not namespace.prestate_bit_list[2]) and bit_list[2]: + action_status_observed = hfo.ACTION_STATUS_MAYBE elif namespace.prestate_ball_dict['dist'] > ball_dict['dist']: action_status_observed = hfo.ACTION_STATUS_MAYBE elif namespace.prestate_ball_dict['dist'] < ball_dict['dist']: @@ -759,16 +831,18 @@ def evaluate_previous_action(hfo_env, namespace.struct_tried[pack_action_bit_list(namespace.action,namespace.prestate_bit_list)] += 1 # further analysis... - # further analysis... - if namespace.prestate_bit_list[3] and (namespace.action in (hfo.DASH, hfo.MOVE_TO)) and (action_status_guessed == hfo.ACTION_STATUS_MAYBE): - print("OK status from {0!s} despite goal collision in prestate (poststate: {1!s})".format( - action_string, bit_list[3])) - sys.stdout.flush() - - if namespace.prestate_bit_list[2] and (namespace.action in (hfo.DASH, hfo.TURN, hfo.MOVE_TO)) and (action_status_guessed == hfo.ACTION_STATUS_MAYBE): - print("OK status from {0!s} despite ball collision in prestate (poststate: {1!s})".format( - action_string, bit_list[2])) - sys.stdout.flush() + if action_status_guessed == hfo.ACTION_STATUS_MAYBE: + # further analysis... + if namespace.prestate_bit_list[3] and (namespace.action in (hfo.KICK, hfo.KICK_TO)): + print("OK status from {0!s} despite goal collision in prestate (poststate: {1!s})".format( + action_string, bit_list[3])) + sys.stdout.flush() + + if namespace.prestate_bit_list[2] and (namespace.action in (hfo.KICK, hfo.MOVE_TO, + hfo.GO_TO_BALL)): + print("OK status from {0!s} despite ball collision in prestate (poststate: {1!s})".format( + action_string, bit_list[2])) + sys.stdout.flush() def save_action_prestate(action, prestate_bit_list, @@ -886,6 +960,8 @@ def do_intent(hfo_env, poss_actions_list.append(hfo.TURN) if abs(ball_rel_angle) < 1.0: poss_actions_list.append(hfo.DASH) + if bit_list[0] and (ball_dict['x_pos'] is not None): + poss_actions_list.append(hfo.MOVE_TO) action = determine_which_action(poss_actions_list, namespace, bit_list) @@ -899,6 +975,11 @@ def do_intent(hfo_env, hfo_env.act(*save_action_prestate(action=hfo.DASH, action_params=[80, ball_rel_angle], **prestate_dict)) + elif action == hfo.MOVE_TO: + hfo_env.act(*save_action_prestate(action=hfo.MOVE_TO, + action_params=[ball_dict['x_pos'], + ball_dict['y_pos']], + **prestate_dict)) else: raise RuntimeError("Unknown action {0!r}".format(action)) @@ -1023,13 +1104,15 @@ def do_next_action(hfo_env, # figure out what to do next - if not (bit_list[2] or bit_list[3] or bit_list[4]): + if not (bit_list[2] or bit_list[3]): poss_intent_set = set([INTENT_BALL_KICKABLE,INTENT_BALL_COLLISION,INTENT_GOAL_COLLISION]) if not bit_list[5]: poss_intent_set.remove(INTENT_BALL_KICKABLE) poss_intent_set.remove(INTENT_BALL_COLLISION) if not bit_list[0]: poss_intent_set.remove(INTENT_GOAL_COLLISION) + if bit_list[4]: + poss_intent_set.remove(INTENT_BALL_KICKABLE) if not poss_intent_set: raise NotImplementedError("Not yet set up for self+ball location invalid") @@ -1044,14 +1127,22 @@ def do_next_action(hfo_env, return do_intent(hfo_env, state, namespace) - elif bit_list[4]: # kickable - actions_want_check = set([hfo.INTERCEPT, hfo.GO_TO_BALL]) - if bit_list[2] or bit_list[3]: - actions_want_check |= set([hfo.KICK, hfo.KICK_TO]) - else: # colliding - actions_want_check = set([hfo.DASH, hfo.TURN, hfo.KICK, hfo.KICK_TO, - hfo.MOVE_TO, hfo.DRIBBLE_TO, hfo.INTERCEPT, - hfo.GO_TO_BALL]) +## elif bit_list[4]: # kickable +## actions_want_check = set([hfo.INTERCEPT, hfo.GO_TO_BALL]) +## if bit_list[2] or bit_list[3]: +## actions_want_check |= set([hfo.KICK, hfo.KICK_TO]) + elif bit_list[2]: # colliding with ball + actions_want_check = set([hfo.GO_TO_BALL]) + if bit_list[3]: # colliding with goal + actions_want_check |= set([hfo.KICK, hfo.KICK_TO, hfo.DRIBBLE_TO]) + else: # colliding with goal + actions_want_check = set([hfo.KICK, hfo.KICK_TO, hfo.DRIBBLE_TO]) + + if prior_intent is not None: + print("INTENT: WAS {}".format(INTENT_DICT[prior_intent])) + else: + print("INTENT: NONE") + sys.stdout.flush() if bit_list[4] and (prior_intent not in (None, INTENT_BALL_KICKABLE)): namespace.intent_done[INTENT_BALL_KICKABLE] += 1 diff --git a/hfo/hfo.py b/hfo/hfo.py index 7e5c8b8..feaf774 100644 --- a/hfo/hfo.py +++ b/hfo/hfo.py @@ -68,9 +68,6 @@ STATUS_STRINGS = {IN_GAME: "InGame", OUT_OF_TIME: "OutOfTime", SERVER_DOWN: "ServerDown"} -"""Possible sides.""" -RIGHT, NEUTRAL, LEFT = list(range(-1,2)) - """Possible action result statuses.""" ACTION_STATUS_UNKNOWN, ACTION_STATUS_BAD, ACTION_STATUS_MAYBE = list(range(-1,2)) ACTION_STATUS_MAYBE_OK = ACTION_STATUS_MAYBE # typos @@ -78,6 +75,9 @@ ACTION_STATUS_STRINGS = {ACTION_STATUS_UNKNOWN: "Unknown", ACTION_STATUS_BAD: "Bad", ACTION_STATUS_MAYBE: "MaybeOK"} +"""Possible sides.""" +RIGHT, NEUTRAL, LEFT = list(range(-1,2)) + class Player(Structure): pass Player._fields_ = [ ('side', c_int), diff --git a/src/HFO.cpp b/src/HFO.cpp index 47d47f3..dda1c6e 100644 --- a/src/HFO.cpp +++ b/src/HFO.cpp @@ -123,7 +123,7 @@ int HFOEnvironment::getNumOpponents() { return agent->getNumOpponents(); } -int HFOEnvironment::getLastActionStatus(action_t last_action) { +action_status_t HFOEnvironment::getLastActionStatus(action_t last_action) { return agent->getLastActionStatus(last_action); } diff --git a/src/HFO.hpp b/src/HFO.hpp index ced8384..c64daf7 100644 --- a/src/HFO.hpp +++ b/src/HFO.hpp @@ -55,7 +55,7 @@ class HFOEnvironment { // Returns the number of opponents virtual int getNumOpponents(); - virtual int getLastActionStatus(action_t last_action); + virtual action_status_t getLastActionStatus(action_t last_action); // Get the current player holding the ball virtual Player playerOnBall(); diff --git a/src/agent.cpp b/src/agent.cpp index 10d418b..3ac3df2 100644 --- a/src/agent.cpp +++ b/src/agent.cpp @@ -153,7 +153,7 @@ Agent::Agent() // setup last_action variables last_action_with_status = NOOP; - last_action_status = -1; + last_action_status = ACTION_STATUS_UNKNOWN; } Agent::~Agent() { @@ -166,20 +166,27 @@ int Agent::getUnum() { return world().self().unum(); } -int Agent::getLastActionStatus(action_t last_action) { +action_status_t Agent::getLastActionStatus(action_t last_action) { if (last_action == last_action_with_status) { return last_action_status; } else { - return -1; + return ACTION_STATUS_UNKNOWN; } } -void Agent::addLastActionStatus(action_t last_action, bool action_status) { +void Agent::addLastActionStatus(action_t last_action, action_status_t action_status) { last_action_with_status = last_action; - if (action_status) { - last_action_status = 1; + last_action_status = action_status; +} + +void Agent::addLastActionStatusCollision(action_t last_action, bool may_fix, bool likely_success) { + last_action_with_status = last_action; + if (likely_success) { + last_action_status = ACTION_STATUS_MAYBE; + } else if (may_fix) { + last_action_status = ACTION_STATUS_UNKNOWN; } else { - last_action_status = 0; + last_action_status = ACTION_STATUS_BAD; } } @@ -268,42 +275,55 @@ void Agent::actionImpl() { << " parameters, given " << params.size() << std::endl; exit(1); } + + // For now let's not worry about turning the neck or setting the vision. + // But do the settings now, so that doesn't override any set by the actions below. + // TODO: Add setViewActionDefault, setNeckActionDefault to librcsc that only set if not already set. + this->setViewAction(new View_Tactical()); + this->setNeckAction(new Neck_TurnToBallOrScan()); + + const WorldModel & wm = this->world(); + bool may_fix = wm.self().collidesWithPost(); + switch(requested_action) { case DASH: - addLastActionStatus(DASH, this->doDash(params[0], params[1])); + addLastActionStatusCollision(DASH, may_fix, this->doDash(params[0], params[1])); break; case TURN: - addLastActionStatus(TURN, this->doTurn(params[0])); + addLastActionStatusCollision(TURN, may_fix, this->doTurn(params[0])); break; case TACKLE: - addLastActionStatus(TACKLE, this->doTackle(params[0], false)); + addLastActionStatus(TACKLE, BooleanToActionStatus(this->doTackle(params[0], false))); break; case KICK: - addLastActionStatus(KICK, this->doKick(params[0], params[1])); + addLastActionStatus(KICK, BooleanToActionStatus(this->doKick(params[0], params[1]))); break; case KICK_TO: if (feature_extractor != NULL) { - addLastActionStatus(KICK_TO, Body_SmartKick(Vector2D(feature_extractor->absoluteXPos(params[0]), - feature_extractor->absoluteYPos(params[1])), - params[2], params[2] * 0.99, 3).execute(this)); + addLastActionStatus(KICK_TO, + BooleanToActionStatus(Body_SmartKick(Vector2D(feature_extractor->absoluteXPos(params[0]), + feature_extractor->absoluteYPos(params[1])), + params[2], params[2] * 0.99, 3).execute(this))); } break; case MOVE_TO: if (feature_extractor != NULL) { - addLastActionStatus(MOVE_TO, Body_GoToPoint(Vector2D(feature_extractor->absoluteXPos(params[0]), - feature_extractor->absoluteYPos(params[1])), 0.25, - ServerParam::i().maxDashPower()).execute(this)); + addLastActionStatusCollision(MOVE_TO, may_fix, + Body_GoToPoint(Vector2D(feature_extractor->absoluteXPos(params[0]), + feature_extractor->absoluteYPos(params[1])), 0.25, + ServerParam::i().maxDashPower()).execute(this)); } break; case DRIBBLE_TO: if (feature_extractor != NULL) { - addLastActionStatus(DRIBBLE_TO, Body_Dribble(Vector2D(feature_extractor->absoluteXPos(params[0]), - feature_extractor->absoluteYPos(params[1])), 1.0, - ServerParam::i().maxDashPower(), 2).execute(this)); + addLastActionStatusCollision(DRIBBLE_TO, may_fix, + Body_Dribble(Vector2D(feature_extractor->absoluteXPos(params[0]), + feature_extractor->absoluteYPos(params[1])), 1.0, + ServerParam::i().maxDashPower(), 2).execute(this)); } break; case INTERCEPT: - addLastActionStatus(INTERCEPT, Body_Intercept().execute(this)); + addLastActionStatusCollision(INTERCEPT, may_fix, Body_Intercept().execute(this)); break; case MOVE: addLastActionStatus(MOVE, this->doMove()); @@ -318,7 +338,7 @@ void Agent::actionImpl() { addLastActionStatus(DRIBBLE, this->doDribble()); break; case CATCH: - addLastActionStatus(CATCH, this->doCatch()); + addLastActionStatus(CATCH, BooleanToActionStatus(this->doCatch())); break; case NOOP: break; @@ -343,9 +363,7 @@ void Agent::actionImpl() { << requested_action << std::endl; exit(1); } - // For now let's not worry about turning the neck or setting the vision. - this->setViewAction(new View_Tactical()); - this->setNeckAction(new Neck_TurnToBallOrScan()); + } void @@ -723,7 +741,7 @@ Agent::doPreprocess() /*! */ -bool +action_status_t Agent::doShoot() { const WorldModel & wm = this->world(); @@ -738,21 +756,23 @@ Agent::doShoot() // reset intention this->setIntention( static_cast< SoccerIntention * >( 0 ) ); - return true; + return ACTION_STATUS_MAYBE; } - return false; + return ACTION_STATUS_BAD; } -bool +action_status_t Agent::doSmartKick() { const ShootGenerator::Container & cont = ShootGenerator::instance().courses(this->world(), false); ShootGenerator::Container::const_iterator best_shoot = std::min_element(cont.begin(), cont.end(), ShootGenerator::ScoreCmp()); - return Body_SmartKick(best_shoot->target_point_, best_shoot->first_ball_speed_, - best_shoot->first_ball_speed_ * 0.99, 3).execute(this); + return BooleanToActionStatus(Body_SmartKick(best_shoot->target_point_, + best_shoot->first_ball_speed_, + best_shoot->first_ball_speed_ * 0.99, + 3).execute(this)); } @@ -769,19 +789,19 @@ Agent::doPass() return true; } -bool +action_status_t Agent::doPassTo(int receiver) { Force_Pass pass; pass.get_pass_to_player(this->world(), receiver); - return pass.execute(this); + return BooleanToActionStatus(pass.execute(this)); } /*-------------------------------------------------------------------*/ /*! */ -bool +action_status_t Agent::doDribble() { bool success = false; @@ -795,9 +815,9 @@ Agent::doDribble() success = doPreprocess(); ActionChainHolder::instance().update( world() ); if (Bhv_ChainAction(ActionChainHolder::instance().graph()).execute(this)) { - return true; + return ACTION_STATUS_MAYBE; } else { - return success; + return BooleanToActionStatus(success); } } @@ -805,19 +825,19 @@ Agent::doDribble() /*! */ -bool +action_status_t Agent::doMove() { Strategy::instance().update( world() ); - int role_num = Strategy::i().roleNumber(world().self().unum()); - return Bhv_BasicMove().execute(this); + int role_num = Strategy::i().roleNumber(world().self().unum()); // Unused? + return Bhv_BasicMove().action_execute(this); } /*-------------------------------------------------------------------*/ /*! * This Action marks the player with the specified uniform number. */ -bool Agent::doMarkPlayer(int unum) { +action_status_t Agent::doMarkPlayer(int unum) { const WorldModel & wm = this->world(); Vector2D kicker_pos = Vector2D :: INVALIDATED; Vector2D player_pos = Vector2D :: INVALIDATED; @@ -841,19 +861,27 @@ bool Agent::doMarkPlayer(int unum) { if (!player_pos.isValid()) { //Player to be marked not found - return false; + return ACTION_STATUS_BAD; } if (!kicker_pos.isValid()) { //Kicker not found - return false; + return ACTION_STATUS_BAD; } if (unum == kicker_unum || kicker_pos.equals(player_pos)) { //Player to be marked is kicker - return false; + return ACTION_STATUS_BAD; } double x = player_pos.x + (kicker_pos.x - player_pos.x)*0.1; double y = player_pos.y + (kicker_pos.y - player_pos.y)*0.1; - return Body_GoToPoint(Vector2D(x,y), 0.25, ServerParam::i().maxDashPower()).execute(this); + bool may_fix = wm.self().collidesWithPost(); + + if (Body_GoToPoint(Vector2D(x,y), 0.25, ServerParam::i().maxDashPower()).execute(this)) { + return ACTION_STATUS_MAYBE; + } else if (may_fix) { + return ACTION_STATUS_UNKNOWN; + } else { + return ACTION_STATUS_BAD; + } } /*-------------------------------------------------------------------*/ @@ -867,7 +895,7 @@ bool compare_y_pos (PlayerObject* i, PlayerObject* j) { return i->pos().y < j->pos().y; } -bool Agent::doReduceAngleToGoal() { +action_status_t Agent::doReduceAngleToGoal() { const WorldModel & wm = this->world(); Vector2D goal_pos1( -ServerParam::i().pitchHalfLength(), ServerParam::i().goalHalfWidth() ); Vector2D goal_pos2( -ServerParam::i().pitchHalfLength(), -ServerParam::i().goalHalfWidth() ); @@ -876,7 +904,7 @@ bool Agent::doReduceAngleToGoal() { const BallObject& ball = wm.ball(); if (! ball.rposValid()) { - return false; + return ACTION_STATUS_BAD; } Vector2D ball_pos = ball.pos(); @@ -945,23 +973,30 @@ bool Agent::doReduceAngleToGoal() { double dist_to_end2 = targetLineEnd2.dist2(ball_pos); double ratio = dist_to_end2/(dist_to_end1+dist_to_end2); Vector2D target = targetLineEnd1 * ratio + targetLineEnd2 * (1-ratio); - return Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this); + bool may_fix = wm.self().collidesWithPost(); + if (Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this)) { + return ACTION_STATUS_MAYBE; + } else if (may_fix) { + return ACTION_STATUS_UNKNOWN; + } else { + return ACTION_STATUS_BAD; + } } /*-------------------------------------------------------------------*/ /*! * - * This action cuts off the angle between the shooter and the goal the players always moves on a fixed line. + * This action cuts off the angle between the shooter and the goal; the player always moves on a fixed line. */ -bool Agent::doDefendGoal() { +action_status_t Agent::doDefendGoal() { const WorldModel & wm = this->world(); Vector2D goal_pos1( -ServerParam::i().pitchHalfLength() + ServerParam::i().goalAreaLength(), ServerParam::i().goalHalfWidth() ); Vector2D goal_pos2( -ServerParam::i().pitchHalfLength() + ServerParam::i().goalAreaLength(), -ServerParam::i().goalHalfWidth() ); const BallObject& ball = wm.ball(); if (! ball.rposValid()) { - return false; + return ACTION_STATUS_BAD; } Vector2D ball_pos = ball.pos(); @@ -969,7 +1004,15 @@ bool Agent::doDefendGoal() { double dist_to_post2 = goal_pos2.dist2(ball_pos); double ratio = dist_to_post2/(dist_to_post1+dist_to_post2); Vector2D target = goal_pos1 * ratio + goal_pos2 * (1-ratio); - return Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this); + bool may_fix = wm.self().collidesWithPost(); + + if (Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this)) { + return ACTION_STATUS_MAYBE; + } else if (may_fix) { + return ACTION_STATUS_UNKNOWN; + } else { + return ACTION_STATUS_BAD; + } } /*-------------------------------------------------------------------*/ @@ -980,13 +1023,13 @@ bool Agent::doDefendGoal() { */ -bool Agent::doGoToBall() { +action_status_t Agent::doGoToBall() { const WorldModel & wm = this->world(); const BallObject& ball = wm.ball(); if (! ball.rposValid()) { - return false; + return ACTION_STATUS_BAD; } - return Body_GoToPoint(ball.pos(), 0.25, ServerParam::i().maxDashPower()).execute(this); + return BooleanToActionStatus(Body_GoToPoint(ball.pos(), 0.25, ServerParam::i().maxDashPower()).execute(this)); } /*-------------------------------------------------------------------*/ diff --git a/src/agent.h b/src/agent.h index 2a22911..3f4112f 100644 --- a/src/agent.h +++ b/src/agent.h @@ -1,3 +1,5 @@ +// -*-c++-*- + #ifndef AGENT_H #define AGENT_H @@ -64,7 +66,7 @@ protected: int num_teammates; // Number of teammates int num_opponents; // Number of opponents hfo::action_t last_action_with_status; // Last action with a recorded return status - int last_action_status; // Recorded return status of last action (1 = true, 0 = false, -1 = not available) + hfo::action_status_t last_action_status; // Recorded return status of last action public: inline const std::vector<float>& getState() { return state; } @@ -74,7 +76,7 @@ protected: int getUnum(); // Returns the uniform number of the player inline int getNumTeammates() { return num_teammates; } inline int getNumOpponents() { return num_opponents; } - int getLastActionStatus(hfo::action_t last_action); // if last_action is correct, returns status if available + hfo::action_status_t getLastActionStatus(hfo::action_t last_action); // if last_action is correct, returns status if available inline void setFeatureSet(hfo::feature_set_t fset) { feature_set = fset; } inline std::vector<float>* mutable_params() { return ¶ms; } @@ -83,21 +85,22 @@ protected: private: bool doPreprocess(); - bool doSmartKick(); - bool doShoot(); + hfo::action_status_t doSmartKick(); + hfo::action_status_t doShoot(); bool doPass(); - bool doPassTo(int receiver); - bool doDribble(); - bool doMove(); + hfo::action_status_t doPassTo(int receiver); + hfo::action_status_t doDribble(); + hfo::action_status_t doMove(); bool doForceKick(); bool doHeardPassReceive(); - bool doMarkPlayer(int unum); + hfo::action_status_t doMarkPlayer(int unum); bool doMarkPlayerNearIndex(int near_index); - bool doReduceAngleToGoal(); - bool doDefendGoal(); - bool doGoToBall(); + hfo::action_status_t doReduceAngleToGoal(); + hfo::action_status_t doDefendGoal(); + hfo::action_status_t doGoToBall(); bool doNewAction1(); - void addLastActionStatus(hfo::action_t last_action, bool action_status); + void addLastActionStatus(hfo::action_t last_action, hfo::action_status_t action_status); + void addLastActionStatusCollision(hfo::action_t last_action, bool may_fix, bool likely_success); Communication::Ptr M_communication; diff --git a/src/bhv_basic_move.cpp b/src/bhv_basic_move.cpp index 1c1bf94..9c10ca7 100644 --- a/src/bhv_basic_move.cpp +++ b/src/bhv_basic_move.cpp @@ -48,25 +48,36 @@ #include <rcsc/common/server_param.h> #include "neck_offensive_intercept_neck.h" +#include "common.hpp" using namespace rcsc; +bool +Bhv_BasicMove::execute( PlayerAgent * agent ) +{ + if (Bhv_BasicMove::action_execute(agent) == hfo::ACTION_STATUS_MAYBE) { + return true; + } else { + return false; + } +} + /*-------------------------------------------------------------------*/ /*! */ -bool -Bhv_BasicMove::execute( PlayerAgent * agent ) +hfo::action_status_t +Bhv_BasicMove::action_execute( PlayerAgent * agent ) { dlog.addText( Logger::TEAM, __FILE__": Bhv_BasicMove" ); - bool success = true; + hfo::action_status_t success = hfo::ACTION_STATUS_UNKNOWN; //----------------------------------------------- // tackle if ( Bhv_BasicTackle( 0.8, 80.0 ).execute( agent ) ) { - return true; + return hfo::ACTION_STATUS_MAYBE; } const WorldModel & wm = agent->world(); @@ -85,9 +96,8 @@ Bhv_BasicMove::execute( PlayerAgent * agent ) { dlog.addText( Logger::TEAM, __FILE__": intercept" ); - success = Body_Intercept().execute( agent ); + success = hfo::BooleanToActionStatus(Body_Intercept().execute( agent )); agent->setNeckAction( new Neck_OffensiveInterceptNeck() ); - return success; } @@ -96,7 +106,9 @@ Bhv_BasicMove::execute( PlayerAgent * agent ) const BallObject& ball = wm.ball(); if (! ball.rposValid()) { - success = false; + if (! wm.self().collidesWithPost()) { + success = hfo::ACTION_STATUS_BAD; + } } double dist_thr = ball.distFromSelf() * 0.1; @@ -115,8 +127,10 @@ Bhv_BasicMove::execute( PlayerAgent * agent ) ).execute( agent ) ) { if (! Body_TurnToBall().execute( agent )) { - success = false; + success = hfo::ACTION_STATUS_BAD; } + } else if (success != hfo::ACTION_STATUS_BAD) { + success = hfo::ACTION_STATUS_MAYBE; } if ( wm.existKickableOpponent() && diff --git a/src/bhv_basic_move.h b/src/bhv_basic_move.h index 1a13568..092c2cd 100644 --- a/src/bhv_basic_move.h +++ b/src/bhv_basic_move.h @@ -29,6 +29,7 @@ #include <rcsc/geom/vector_2d.h> #include <rcsc/player/soccer_action.h> +#include "common.hpp" class Bhv_BasicMove : public rcsc::SoccerBehavior { @@ -36,7 +37,8 @@ public: Bhv_BasicMove() { } - bool execute( rcsc::PlayerAgent * agent ); + bool execute( rcsc::PlayerAgent * agent ); + hfo::action_status_t action_execute( rcsc::PlayerAgent * agent ); private: double getDashPower( const rcsc::PlayerAgent * agent ); diff --git a/src/common.hpp b/src/common.hpp index 255f9be..5e544f3 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -5,6 +5,7 @@ #include <stdlib.h> #include <iostream> #include <sstream> +#include <vector> namespace hfo { @@ -33,14 +34,14 @@ enum action_t DRIBBLE, // [High-Level] Dribble(): Offensive dribble CATCH, // [High-Level] Catch(): Catch the ball (Goalie only!) NOOP, // Do nothing - QUIT, // Special action to quit the game + QUIT, // Special action to quit the game REDUCE_ANGLE_TO_GOAL, // [High-Level] Reduce_Angle_To_Goal : Reduces the shooting angle - MARK_PLAYER, // [High-Level] Mark_Player(opponent_unum [0,11]) : Moves to the position in between the kicker and a given player + MARK_PLAYER, // [High-Level] Mark_Player(opponent_unum [0,11]) : Moves to the position in between the kicker and a given player DEFEND_GOAL, GO_TO_BALL }; -// Status of a HFO game +// Status of an HFO game enum status_t { IN_GAME, // Game is currently active @@ -51,6 +52,24 @@ enum status_t SERVER_DOWN // Server is not alive }; +// Action status +enum action_status_t { + ACTION_STATUS_UNKNOWN = -1, // cannot tell or invalid action # in status request + ACTION_STATUS_BAD = 0, // definitely not OK + ACTION_STATUS_MAYBE = 1, // may be OK, may not +}; + +/** + * Translates from boolean false (bad) or true (maybe OK) to action status + */ +inline action_status_t BooleanToActionStatus(const bool status) { + if (status) { + return ACTION_STATUS_MAYBE; + } else{ + return ACTION_STATUS_BAD; + } +} + // Configuration of the HFO domain including the team names and player // numbers for each team. This struct is populated by ParseConfig(). struct Config { @@ -171,7 +190,7 @@ inline std::string ActionToString(action_t action) { }; /** - * Returns a string representation of a game_status. + * Returns a string representation of a game status. */ inline std::string StatusToString(status_t status) { switch (status) { @@ -192,6 +211,22 @@ inline std::string StatusToString(status_t status) { } }; +/** + * Returns a string representation of an action status. + */ +inline std::string ActionStatusToString(action_status_t status) { + switch (status) { + case ACTION_STATUS_BAD: + return "Bad"; + case ACTION_STATUS_MAYBE: + return "MaybeOK"; + case ACTION_STATUS_UNKNOWN: + return "Unknown"; + default: + return "Invalid"; + } +} + /** * Parse a Trainer message to populate config. Returns a bool * indicating if the struct was correctly parsed. -- 2.24.1