Пример #1
0
        public void ProcessHit(ASurfaceExpression surface, double horizontalHitCoeff, double verticalHitCoeff)
        {
            var surfaceNormal = surface.Normal;
            var projection    = ProjectToSurface(surface);

            projection.Position.Vertical = 2 * Constants.BallRadius * surfaceNormal - projection.Position.Vertical;
            projection.Speed.Vertical   *= -verticalHitCoeff;
            var ballPoint = -Constants.BallRadius * surfaceNormal;
            var fullPerpendicularSpeed = projection.Speed.Horizontal + Point3DExpression.VectorMult(ballPoint, AngularSpeed);
            var force = -horizontalHitCoeff * fullPerpendicularSpeed;

            projection.Speed.Horizontal += force;
            AngularSpeed += Point3DExpression.VectorMult(force, ballPoint.Normal) / Constants.BallRadius;
            RestoreFromSurfaceProjection(surface, projection);
        }
Пример #2
0
        public bool Initialize(State state, Player player)
        {
            initialState = state;
            state        = state.Clone(false);
            this.player  = player.Clone();

            isServing           = state.GameState == GameState.Serving;
            maxHeightLimitation = isServing ? Constants.MaxBallServeMaxHeight : Constants.MaxBallMaxHeight;
            playerSide          = player.Side;

            if (state.GameState == GameState.Failed || player.Index != state.HitSide)
            {
                return(false);
            }

            var states = new List <State>();

            if (isServing)
            {
                while (state.Ball.Speed.Y >= 0 || state.Ball.Position.Y >= Constants.MaxBallServeY)
                {
                    state.DoStep();
                }

                var attemptState = state.Clone(false);
                while (attemptState.Ball.Position.Y >= Constants.MinBallServeY)
                {
                    states.Add(attemptState.Clone(false));
                    attemptState.DoStep();
                }

                states.Add(attemptState.Clone(false));

                hitTimeVar.MinValue = state.Time;
                hitTimeVar.MaxValue = attemptState.Time;
            }
            else
            {
                if (!state.DoStepsUntilGameState(GameState.FlyingToBat))
                {
                    return(false);
                }

                var attemptState = state.Clone(false);

                // Calculate time till max height
                while (attemptState.GameState != GameState.Failed)
                {
                    states.Add(attemptState.Clone(false));
                    if (attemptState.DoStep().HasOneOfEvents(Event.MaxHeight))
                    {
                        break;
                    }
                }
                double ballMaxHeightTime = attemptState.Time - state.Time;

                // Calculate time till ball fall
                while (attemptState.GameState != GameState.Failed)
                {
                    states.Add(attemptState.Clone(false));
                    if (attemptState.DoStep().HasOneOfEvents(Event.LowHit))
                    {
                        break;
                    }
                }
                double ballFallTime = attemptState.Time - state.Time;

                states.Add(attemptState.Clone(false));

                hitTimeVar.MinValue = state.Time + player.Strategy.GetMinBackHitTime(ballMaxHeightTime, ballFallTime);
                hitTimeVar.MaxValue = state.Time + player.Strategy.GetMaxBackHitTime(ballMaxHeightTime, ballFallTime);
            }

            var statesCount = states.Count;

            if (statesCount < 2)
            {
                return(false);
            }

            var ballPositions     = new Point3D[statesCount];
            var ballSpeeds        = new Point3D[statesCount];
            var ballForces        = new Point3D[statesCount];
            var ballAngularSpeeds = new Point3D[statesCount];
            var ballAngularForces = new Point3D[statesCount];

            for (var index = 0; index < statesCount; index++)
            {
                var ball = states[index].Ball;
                ballPositions[index]     = ball.Position;
                ballSpeeds[index]        = ball.Speed;
                ballForces[index]        = ball.Force;
                ballAngularSpeeds[index] = ball.AngularSpeed;
                ballAngularForces[index] = ball.AngularForce;
            }

            optimizationVariables      = new Variable[] { hitTimeVar, hitSpeedVar, attackPitchVar, attackYawVar, velocityAttackPitchVar, velocityAttackYawVar };
            optimizationVariablesCount = optimizationVariables.Length;

            var ballForceExpression        = FunctionByPoints.Create3DFunctionByPoints("BallForce", hitTimeVar, ballForces, state.Time, Constants.SimulationFrameTime);
            var ballSpeedExpression        = FunctionByPoints.Create3DFunctionByPoints("BallSpeed", hitTimeVar, ballSpeeds, state.Time, Constants.SimulationFrameTime, ballForceExpression);
            var ballPositionExpression     = FunctionByPoints.Create3DFunctionByPoints("BallPosition", hitTimeVar, ballPositions, state.Time, Constants.SimulationFrameTime, ballSpeedExpression);
            var ballAngularForceExpression = FunctionByPoints.Create3DFunctionByPoints("BallAngularForce", hitTimeVar, ballAngularForces, state.Time, Constants.SimulationFrameTime);
            var ballAngularSpeedExpression = FunctionByPoints.Create3DFunctionByPoints("BallAngularSpeed", hitTimeVar, ballAngularSpeeds, state.Time, Constants.SimulationFrameTime, ballAngularForceExpression);

            initialBallExpression = new BallExpression(ballPositionExpression, ballSpeedExpression, ballAngularSpeedExpression);

            var ballReverseSpeed      = -initialBallExpression.Speed;
            var reverseBallSpeedPitch = ballReverseSpeed.Pitch;
            var reverseBallSpeedYaw   = ballReverseSpeed.Yaw;

            if (isServing)
            {
                // Yaw for vertical vector is undefined, so use default bat direction instead
                reverseBallSpeedYaw = player.DefaultNormal.Yaw;
            }

            Expression minVelocityAttackPitch, maxVelocityAttackPitch;
            double     minHitSpeed, maxHitSpeed, minAttackPitch, maxAttackPitch, maxAttackYaw, maxVelocityAttackYaw;

            if (isServing)
            {
                var ballX = Math.Abs(state.Ball.Position.X);
                minHitSpeed            = Constants.MaxPlayerSpeed * player.Strategy.GetMinServeHitSpeed(ballX);
                maxHitSpeed            = Constants.MaxPlayerSpeed * player.Strategy.GetMaxServeHitSpeed(ballX);
                minAttackPitch         = player.Strategy.GetMinServeAttackAngle();
                maxAttackPitch         = player.Strategy.GetMaxServeAttackAngle();
                minVelocityAttackPitch = player.Strategy.GetMinServeVelocityAttackAngle();
                maxVelocityAttackPitch = player.Strategy.GetMaxServeVelocityAttackAngle();
                maxAttackYaw           = Misc.FromDegrees(40);
                maxVelocityAttackYaw   = Misc.FromDegrees(70);
            }
            else
            {
                minHitSpeed            = Constants.MaxPlayerSpeed * player.Strategy.GetMinHitSpeed();
                maxHitSpeed            = Constants.MaxPlayerSpeed * player.Strategy.GetMaxHitSpeed();
                minAttackPitch         = player.Strategy.GetMinAttackAngle();
                maxAttackPitch         = player.Strategy.GetMaxAttackAngle();
                minVelocityAttackPitch = player.Strategy.GetMinVelocityAttackAngle();
                maxVelocityAttackPitch = player.Strategy.GetMaxVelocityAttackAngle();
                maxAttackYaw           = Misc.FromDegrees(50);
                maxVelocityAttackYaw   = Misc.FromDegrees(60);
            }
            //maxAttackYaw = maxVelocityAttackYaw = 0.0001;

            var hitSpeed    = minHitSpeed + hitSpeedVar * (maxHitSpeed - minHitSpeed);
            var attackPitch = minAttackPitch + attackPitchVar * (maxAttackPitch - minAttackPitch);

            if (!isServing)
            {
                minVelocityAttackPitch = Expression.Max(minVelocityAttackPitch, attackPitch - Constants.MaxAttackAngleDifference);
                maxVelocityAttackPitch = Expression.Min(maxVelocityAttackPitch, attackPitch + Constants.MaxAttackAngleDifference);
            }
            var velocityAttackPitch = minVelocityAttackPitch + velocityAttackPitchVar * (maxVelocityAttackPitch - minVelocityAttackPitch);
            var attackYaw           = attackYawVar * maxAttackYaw;
            var velocityAttackYaw   = velocityAttackYawVar * maxVelocityAttackYaw;

            playerExpression = new PlayerExpression()
            {
                Index      = player.Index,
                AnglePitch = reverseBallSpeedPitch + attackPitch,
                AngleYaw   = reverseBallSpeedYaw + attackYaw,
                Speed      = hitSpeed * Point3DExpression.FromAngles(reverseBallSpeedPitch + velocityAttackPitch, reverseBallSpeedYaw + attackYaw + velocityAttackYaw)
            };
            playerExpression.Position = initialBallExpression.Position - Constants.BallRadius * playerExpression.Normal;
            playerExpression.Alias    = "Bat";

            initialBallExpression.ProcessHit(playerExpression, Constants.BallHitHorizontalCoeff, Constants.BallHitVerticalCoeff);

            initialBallExpressionDerivatives = new BallExpression[optimizationVariablesCount];
            playerExpressionDerivatives      = new PlayerExpression[optimizationVariablesCount];
            for (var i = 0; i < optimizationVariablesCount; i++)
            {
                initialBallExpressionDerivatives[i] = initialBallExpression.Derivate(optimizationVariables[i]);
                playerExpressionDerivatives[i]      = playerExpression.Derivate(optimizationVariables[i]);
            }

            return(true);
        }
Пример #3
0
 public void RestoreFromSurfaceProjection(ASurfaceExpression surface, ProjectionToSurfaceExpression projection)
 {
     Position = surface.Position + projection.Position.Full;
     Speed    = surface.Speed + projection.Speed.Full;
 }
Пример #4
0
 public BallExpression(Point3DExpression position, Point3DExpression speed, Point3DExpression angularSpeed)
 {
     Position     = position;
     Speed        = speed;
     AngularSpeed = angularSpeed;
 }