private float GetSteer(ISensorModel model)
        {
            // steering angle is compute by correcting the actual car angle w.r.t. to track
            // axis [sensors.getAngle()] and to adjust car position w.r.t to middle of track [sensors.getTrackPos()*0.5]
            float targetAngle = (float)(model.GetAngleToTrackAxis() - model.GetTrackPosition() * 0.5f);

            // at high speed reduce the steering command to avoid loosing the control
            if (model.GetSpeed() > SteerSensitivityOffset)
            {
                return (float)(targetAngle / (SteerLock * (model.GetSpeed() - SteerSensitivityOffset) * WheelSensitivityCoeff));
            }
            else
            {
                return (targetAngle) / SteerLock;
            }
        }
        public override Action Control(ISensorModel sensorModel)
        {
            // check if car is currently stuck
            if (Math.Abs(sensorModel.GetAngleToTrackAxis()) > StuckAngle)
            {
                // update stuck counter
                stuck++;
            }
            else
            {
                // if not stuck reset stuck counter
                stuck = 0;
            }

            // after car is stuck for a while apply recovering policy
            if (stuck > StuckTime)
            {
                /* set gear and sterring command assuming car is
                 * pointing in a direction out of track */

                // to bring car parallel to track axis
                float steer = (float)(-sensorModel.GetAngleToTrackAxis() / SteerLock);
                int gear = -1; // Gear R

                // if car is pointing in the correct direction revert gear and steer
                if (sensorModel.GetAngleToTrackAxis() * sensorModel.GetTrackPosition() > 0)
                {
                    gear = 1;
                    steer = -steer;
                }
                clutch = Clutching(sensorModel, clutch);
                // build a CarControl variable and return it
                Action action = new Action();
                action.Gear = gear;
                action.Steering = steer;
                action.Accelerate = 1.0f;
                action.Brake = 0;
                action.Clutch = clutch;
                return action;
            }
            else // car is not stuck
            {
                // compute accel/brake command
                float accelAndBrake = GetAccel(sensorModel);
                // compute gear
                int gear = GetGear(sensorModel);
                // compute steering
                float steer = GetSteer(sensorModel);

                // normalize steering
                if (steer < -1)
                {
                    steer = -1;
                }
                if(steer > 1)
                {
                    steer = 1;
                }

                // set accel and brake from the joint accel/brake command
                float accel, brake;
                if(accelAndBrake > 0)
                {
                    accel = accelAndBrake;
                    brake = 0;
                }
                else
                {
                    accel = 0;
                    // apply ABS to brake
                    brake = FilterAbs(sensorModel, -accelAndBrake);
                }

                clutch = Clutching(sensorModel, clutch);

                // build a CarControl variable and return it
                Action action = new Action();
                action.Gear = gear;
                action.Steering = steer;
                action.Accelerate = accel;
                action.Brake = brake;
                action.Clutch = clutch;
                return action;
            }
        }
        private float GetAccel(ISensorModel model)
        {
            // checks if car is out of track
            if (model.GetTrackPosition() < 1 && model.GetTrackPosition() > -1)
            {
                // reading of sensor at +5 degree w.r.t. car axis
                float rxSensor = (float)model.GetTrackEdgeSensors()[10];
                // reading of sensor parallel to car axis
                float sensor = (float)model.GetTrackEdgeSensors()[9];
                // reading of sensor at -5 degree w.r.t. car axis
                float sxSensor = (float)model.GetTrackEdgeSensors()[8];

                float targetSpeed;

                // track is straight and enough far from a turn so goes to max speed
                if (sensor > MaxSpeedDist || (sensor >= rxSensor && sensor >= sxSensor))
                {
                    targetSpeed = MaxSpeed;
                }
                else
                {
                    // approaching a turn on right
                    if (rxSensor > sxSensor)
                    {
                        float h = sensor * Sin5;
                        float b = rxSensor - sensor * Cos5;
                        float sinAngle = b * b / (h * h + b * b);
                        // estimate the target speed depending on turn and on how close it is
                        targetSpeed = MaxSpeed * (sensor * sinAngle / MaxSpeedDist);
                    }
                    // approaching a turn on left
                    else
                    {
                        // computing approximately the "angle" of turn
                        float h = sensor * Sin5;
                        float b = sxSensor - sensor * Cos5;
                        float sinAngle = b * b / (h * h + b * b);
                        // estimate the target speed depending on turn and on how close it is
                        targetSpeed = MaxSpeed * (sensor * sinAngle / MaxSpeedDist);
                    }
                }
                // accel/brake command is exponentially scaled w.r.t. the difference between target speed and current one
                return (float)(2 / (1 + Math.Exp(model.GetSpeed() - targetSpeed)) - 1);
            }
            else
            {
                return 0.3f; // when out of track returns a moderate acceleration command
            }
        }