/*
     * acc specifies how much to accelerate, or break if it is negative.
     * It may not have absolute value larger than the acc parameter given to init
     *
     * da specifies how much to turn right or left.
     * It may not have absolute value larger than the turn parameter given to init
     *
     * x, y, dx, dy, alpha, dalpha, wp, and skidding are all global variables
     * x and y give the location of the car, while dx and dy give the velocity
     * alpha gives the angle the car is facing, while dalpha gives the rotational momentum when skidding
     * skidding indicates if the car was skidding in the previous time step
     * wp gives the current waypoint index
     *
     * The most complicated part of the code is dealing with friction and air resistance
     * Most importantly, when accelerating forward, the air resistance is removed from the forward
     * force before friction is checked (more as if the car were propelled by rockets than wheels).
     * In the cross direction, the forces of friction and air resistance are added to see if the car
     * can make the turn.
     */


void step(double acc, double da){
        if (!skidding) {
            //not skidding, so reset
            dalpha = 0;
        }
        if(acc < -friction){
            acc = -friction;
        }

        dalpha += da; 
        alpha += dalpha; //adjust the direction we're facing
        if (alpha > Math.PI) alpha -= 2 * Math.PI;
        else if (alpha < -Math.PI) alpha += 2 * Math.PI; 

        dalpha /= 2;     //dampen the rotational momentum

        double cross = (dx * Math.sin(alpha) - dy * Math.cos(alpha));   //signed magnitude of velocity which is across direction we're facing
        double forward = (dx * Math.cos(alpha) + dy * Math.sin(alpha)); //signed magnitude of velocity which is in direction we're facing
        //now compute the forward and cross components of air resistance.  Resistance is proportional to velocity squared
        double crossair = cross / Math.hypot(cross, forward) * air * Math.hypot(dx, dy) * Math.hypot(dx, dy);          //signed
        double forwardair = Math.abs(forward / Math.hypot(cross, forward) * air * Math.hypot(dx, dy) * Math.hypot(dx, dy)); //unsigned
        if (cross == 0 && forward == 0) crossair = forwardair = 0;     //avoid NaN
        acc -= forwardair; //remove some forward power due to air resistance

        if (acc < 0 && Math.abs(acc) > Math.abs(forward)) acc = -forward;//can only stop as much as we're moving
        else if (acc < 0 && forward < 0) acc = -acc;//breaking while going backwards results in positive force
        
        double mcross = 0, macc = 0;

        //next we have to compute how much of the force of friction goes in the forward direction, and how much goes in the cross direction
        mcross = friction * cross / Math.hypot(cross, acc); 
        macc = friction * acc / Math.hypot(cross, acc);
        if (cross == 0 && acc == 0) { //avoid NaN when stopped
            mcross = 0;
            macc = 0;
        }

        mcross += crossair;  //the air resistance slows us down in the cross direction

        //detect skidding.  The cross velocity is the current cross velocity, minus the cross air resistance
        //the forward velocity used is either the acceleration, or the acceleration minus the air resistance
        //we do the second to avoid thinking that we are skidding when we are really just slowing rapidly due to air resistance
        skidding = Math.hypot(cross - crossair, acc) >= friction && Math.hypot(cross - crossair, acc + forwardair) > friction;

        //finally we check to see if the cross force or forward force on the car exceed the frictional allowance, and adjust accordingly
        if (cross > mcross && cross >= 0) {
            cross = mcross;
        } else if (cross < mcross && cross <= 0) {
            cross = mcross;
        }
        if (acc > macc && acc >= 0) {
            acc = macc;
        } //else case intentionally omitted

        //calculations all done, adjust velocity and position
        dx += cross * Math.cos(alpha + Math.PI / 2);
        dy += cross * Math.sin(alpha + Math.PI / 2);
        dx += acc * Math.cos(alpha);
        dy += acc * Math.sin(alpha);
        x += dx;
        y += dy;

        finally, check the waypoints.  wx and wy give the locations
        while(wp < wx.length && Math.hypot(x-wx[wp],y-wy[wp]) < 1000){
            wp++;
        }
    }