/// <summary> /// Activate delay stoppers per current rod before next action /// </summary> /// <param name="action">Action to be perfomed</param> private void ActivateDelay(RodAction action) { if (action.Linear != eLinearMove.NA || action.Rotation != eRotationalMove.NA) { _sectorWatch[action.RodType] = Stopwatch.StartNew(); } }
/// <summary> /// Main Decision Flow Method decides on action and sets property of responding player /// </summary> /// <param name="rod">Rod to use for decision</param> /// <param name="bfc">Ball Future coordinates</param> /// <returns>Rod Action to perform</returns> public override RodAction Decide(IRod rod, BallCoordinates bfc) { RodAction action = new RodAction(rod.RodType); //Action will be ignored if not enough time passed since last request was made inside sector if (!IgnoreDecision(rod.RodType)) { //Get relative Y position and set Responding Player eYPositionPlayerRelative relativeY = BallYPositionToPlayerYCoordinate(bfc.Y, rod); //Get relative X position eXPositionRodRelative relativeX = BallXPositionToRodXPosition(bfc.X, rod); /* * Beta Version of inner DECISION TREE */ switch (relativeX) { case eXPositionRodRelative.FRONT: switch (relativeY) { case eYPositionPlayerRelative.RIGHT: case eYPositionPlayerRelative.LEFT: switch (rod.State.ServoPosition) { case eRotationalMove.RISE: case eRotationalMove.DEFENCE: action = new RodAction(rod.RodType, eRotationalMove.DEFENCE, eLinearMove.BALL_Y); break; case eRotationalMove.KICK: action = new RodAction(rod.RodType, eRotationalMove.DEFENCE, eLinearMove.NA); break; } break; case eYPositionPlayerRelative.CENTER: switch (rod.State.ServoPosition) { case eRotationalMove.RISE: case eRotationalMove.DEFENCE: action = new RodAction(rod.RodType, eRotationalMove.KICK, eLinearMove.NA); break; case eRotationalMove.KICK: if (_helper.IsEnoughSpaceToMove(rod, rod.State.DcPosition, BALL_RADIUS)) { action = new RodAction(rod.RodType, eRotationalMove.NA, eLinearMove.RIGHT_BALL_DIAMETER); } else { action = new RodAction(rod.RodType, eRotationalMove.NA, eLinearMove.LEFT_BALL_DIAMETER); } break; } break; } break; case eXPositionRodRelative.CENTER: case eXPositionRodRelative.BACK: switch (relativeY) { case eYPositionPlayerRelative.RIGHT: case eYPositionPlayerRelative.LEFT: switch (rod.State.ServoPosition) { case eRotationalMove.RISE: action = new RodAction(rod.RodType, eRotationalMove.RISE, eLinearMove.BALL_Y); break; case eRotationalMove.DEFENCE: action = new RodAction(rod.RodType, eRotationalMove.RISE, eLinearMove.NA); break; case eRotationalMove.KICK: action = new RodAction(rod.RodType, eRotationalMove.DEFENCE, eLinearMove.NA); break; } break; case eYPositionPlayerRelative.CENTER: switch (rod.State.ServoPosition) { case eRotationalMove.RISE: action = new RodAction(rod.RodType, eRotationalMove.KICK, eLinearMove.NA); break; case eRotationalMove.DEFENCE: case eRotationalMove.KICK: if (_helper.IsEnoughSpaceToMove(rod, rod.State.DcPosition, BALL_RADIUS)) { action = new RodAction(rod.RodType, eRotationalMove.NA, eLinearMove.RIGHT_BALL_DIAMETER); } else { action = new RodAction(rod.RodType, eRotationalMove.NA, eLinearMove.LEFT_BALL_DIAMETER); } break; } break; } break; } Log.Print(String.Format("Defined action for {0}: [{1}] [{2}]", rod.RodType, action.Rotation, action.Linear), eCategory.Info, LogTag.DECISION); ActivateDelay(action); //Define actual desired rod coordinate to move to int startStopperDesiredY = CalculateNewRodCoordinate(rod, RespondingPlayer, bfc, action.Linear); action.DcCoordinate = rod.NearestPossibleDcPosition(startStopperDesiredY); } else { Log.Print(String.Format("Ignoring inner tree of {0} for {1} milliseconds", rod.RodType, (ACTION_DELAY - _sectorWatch[rod.RodType].Elapsed).TotalMilliseconds), eCategory.Debug, LogTag.DECISION); } //Set last decided rod and player coordinates if it was defined if (action.Linear!=eLinearMove.NA) rod.State.DcPosition = action.DcCoordinate; if (_helper.ShouldSetServoStateFromTree(rod.RodType)) if (action.Rotation != eRotationalMove.NA) rod.State.ServoPosition = action.Rotation; return action; }
/// <summary> /// Choose player to respond on current rod and action to perform /// </summary> /// <param name="rod">Current rod</param> /// <param name="bfc">Ball Future Coordinates</param> /// <param name="respondingPlayer">Responding Player index (1 based) on current rod [out]</param> /// <returns>Rod Action to be performed</returns> protected RodAction DefineActionAndRespondingPlayer(IRod rod, BallCoordinates bfc, out int respondingPlayer) { if (rod == null) throw new ArgumentException(String.Format( "[{0}] Unable to define action and responding player while rod argument is NULL!", MethodBase.GetCurrentMethod().Name)); if (bfc == null || !bfc.IsDefined) throw new ArgumentException(String.Format( "[{0}] Unable to define action and responding player while ball coordinates are NULL or UNDEFINED!", MethodBase.GetCurrentMethod().Name)); RodAction action = null; respondingPlayer = -1; switch (_helper.IsBallInSector(bfc.X, rod.RodXCoordinate, rod.DynamicSector)) { //Ball is in Current Rod Sector case eXPositionSectorRelative.IN_SECTOR: action = SubTree.Decide(rod, bfc); respondingPlayer = SubTree.RespondingPlayer; break; /* OLD : * //The Big Sub Tree * action = EnterDecisionTreeBallInSector(rod, bfc, out respondingPlayer); */ //Ball is ahead of Current Rod Sector case eXPositionSectorRelative.AHEAD_SECTOR: //Ball Vector Direction is TO Current Rod and we have intersection point if (_helper.IsBallVectorToRod(bfc.Vector) && rod.Intersection.IsDefined) { action = new RodAction(rod.RodType, eRotationalMove.DEFENCE, eLinearMove.VECTOR_BASED); //Define responding player index BallYPositionToPlayerYCoordinate(bfc.Y, rod); respondingPlayer = this.RespondingPlayer; } else { //Ball Vector Direction is FROM Current Rod action = new RodAction(rod.RodType, eRotationalMove.DEFENCE, eLinearMove.BEST_EFFORT); } break; //Ball is behind Current Rod Sector case eXPositionSectorRelative.BEHIND_SECTOR: action = new RodAction(rod.RodType, eRotationalMove.RISE, eLinearMove.BEST_EFFORT); break; } return action; }