package java_example; import java.util.ArrayList; import java.util.Scanner; import java.awt.geom.Point2D; public class Eight { /** Simple representation for a puck. */ static class Puck { // Position of the puck. Point2D pos; // Puck velocity Point2D vel; // Puck color int color; }; /** Simple representation for a bumper. */ static class Bumper { // Position of the bumper. Point2D pos; // Bumper velocity Point2D vel; }; /** Simple representation for a sled. */ static class Sled { // Position of the sled. Point2D pos; // Sled direction. double dir; }; /** How much acceleration we are willing to spend on each component. */ private static final double ACCEL = Const.BUMPER_ACCEL_LIMIT / Math.sqrt( 2 ); /** Return the value of a, clamped to the [ b, c ] range */ private static double clamp( double a, double b, double c ) { if ( a < b ) return b; if ( a > c ) return c; return a; } /** Return a new vector containing the sum of a and b. */ static Point2D sum( Point2D a, Point2D b ) { return new Point2D.Double( a.getX() + b.getX(), a.getY() + b.getY() ); } /** Return a new vector containing the difference between a and b. */ static Point2D diff( Point2D a, Point2D b ) { return new Point2D.Double( a.getX() - b.getX(), a.getY() - b.getY() ); } /** Return a new vector containing a scaled by scaling factor s. */ static Point2D scale( Point2D a, double s ) { return new Point2D.Double( a.getX() * s, a.getY() * s ); } /** Return the magnitude of vector a. */ static double mag( Point2D a ) { return Math.sqrt( a.getX() * a.getX() + a.getY() * a.getY() ); } /** Return a new vector containing normalized version of a. */ static Point2D norm( Point2D a ) { double m = mag( a ); return new Point2D.Double( a.getX() / m, a.getY() / m ); } /** Return a ccw perpendicular vector for a. */ static Point2D perp( Point2D a ) { return new Point2D.Double( -a.getY(), a.getX() ); } /** Return the dot product of a and b. */ static double dot( Point2D a, Point2D b ) { return a.getX() * b.getX() + a.getY() * b.getY(); } /** Return the cross product of a and b. */ static double cross( Point2D a, Point2D b ) { return a.getX() * b.getY() - a.getY() * b.getX(); } /** * One dimensional function to help compute acceleration vectors. Return an acceleration that * can be applied to a bumper at pos and moving with velocity vel to get it to target. The alim * parameter puts a limit on the acceleration available. */ private static double moveTo( double pos, double vel, double target, double alim ) { // Compute how far pos has to go to hit target. double dist = target - pos; // Kill velocity if we are close enough. if ( Math.abs( dist ) < 0.01 ) return clamp( -vel, -alim, alim ); // How many steps, at minimum, would cover the remaining distance // and then stop. double steps = Math.ceil( (-1 + Math.sqrt( 1 + 8.0 * Math.abs( dist ) / alim )) / 2.0 ); if ( steps < 1 ) steps = 1; // How much acceleration would we need to apply at each step to // cover dist. double accel = 2 * dist / ((steps + 1) * steps); // Ideally, how fast would we be going now double ivel = accel * steps; // Return the best change in velocity to get vel to ivel. return clamp( ivel - vel, -alim, alim ); } public static void main( String[] arg ) { // List of current sled, bumper and puck locations. ArrayList<Puck> plist = new ArrayList<Puck>(); ArrayList<Bumper> blist = new ArrayList<Bumper>(); ArrayList<Sled> slist = new ArrayList<Sled>(); Scanner in = new Scanner( System.in ); int moveCount = 0; // Target for each bumper. int[] target = { -1, -1 }; // How much time the bumper has to pursue the target. int[] ttimer = { 0, 0 }; // Keep reading states until the game ends. int tnum = in.nextInt(); while ( tnum >= 0 ) { // Read all the pucks int n = in.nextInt(); plist.clear(); for ( int i = 0; i < n; i++ ) { Puck p = new Puck(); double x = in.nextDouble(); double y = in.nextDouble(); p.pos = new Point2D.Double( x, y ); x = in.nextDouble(); y = in.nextDouble(); p.vel = new Point2D.Double( x, y ); p.color = in.nextInt(); plist.add( p ); } // Read all the bumpers n = in.nextInt(); blist.clear(); for ( int i = 0; i < n; i++ ) { Bumper b = new Bumper(); double x = in.nextDouble(); double y = in.nextDouble(); b.pos = new Point2D.Double( x, y ); x = in.nextDouble(); y = in.nextDouble(); b.vel = new Point2D.Double( x, y ); blist.add( b ); } // Read the sleds and their trails. n = in.nextInt(); slist.clear(); for ( int i = 0; i < n; i++ ) { // Read the state of the sled. Sled s = new Sled(); double x = in.nextDouble(); double y = in.nextDouble(); s.pos = new Point2D.Double( x, y ); s.dir = in.nextDouble(); slist.add( s ); // Just throw away the trail information. int ts = in.nextInt(); for ( int j = 0; j < ts; j++ ) { in.nextDouble(); in.nextDouble(); } } // Just make each sled run toward the nearest grey puck. for ( int i = 0; i < 2; i++ ) { // Where do we try to send the pucks? Point2D tdest = new Point2D.Double( 100, i == 0 ? 300 : 500 ); Bumper bumper = blist.get( i ); if ( ttimer[i] <= 0 ) { // Find a target that's grey and close to the bumper. target[i] = -1; for ( int j = 0; j < plist.size(); j++ ) { // Pick a grey target that's close to the player and not too close // to the destination. if ( plist.get( j ).color == Const.GREY && plist.get( j ).pos.distance( tdest ) > 120 && Math.abs( plist.get( j ).pos.getX() - 400 ) < 340 && Math.abs( plist.get( j ).pos.getY() - 400 ) < 340 && (target[i] < 0 || plist.get( j ).pos.distance( bumper.pos ) < plist.get( target[i] ).pos.distance( bumper.pos )) ) target[i] = j; } // Give a fixed number of moves to deal with the target. if ( target[i] >= 0 ) ttimer[i] = 20; } if ( ttimer[i] > 0 ) { // Where's the target. Point2D tpos = plist.get( target[i] ).pos; // Split the bumper's veloicty into components toward the puck // and perp. double dist = tpos.distance( bumper.pos ); Point2D a1 = scale( diff( tpos, bumper.pos ), 1.0 / dist ); Point2D a2 = perp( a1 ); // Represent the velocity WRT a target-centric frame. double v1 = dot( a1, bumper.vel ); double v2 = dot( a2, bumper.vel ); // compute force in this frame. double f1 = 0; double f2 = 0; // Direction from the puck to where we want to hit it. Point2D tdir = diff( tdest, tpos ); // Should we move around the target puck? double dprod = dot( a1, norm( tdir ) ); if ( dprod < 0.8 ) { // Try to maintain a moderate distance to the target. if ( dist > 80 ) { f1 = ACCEL; } else if ( dist < 40 ) { f1 = -ACCEL; } else { f1 = clamp( -v1, -ACCEL, ACCEL ); } // How far around do we have to around the target. // double cdist = Math.acos( dprod ) * dist; // Move around the shorter way. if ( cross( tdir, a1 ) > 0 ) { f2 = ACCEL; } else { f2 = -ACCEL; } } else { // Consider the velocity WRT a frame that points from the target // puck to the destination a1 = norm( tdir ); a2 = perp( a1 ); v1 = dot( a1, bumper.vel ); v2 = dot( a2, bumper.vel ); // Position of the bumper WRT the target puck and a frame pointing // to the target's destination. Point2D bdisp = diff( bumper.pos, tpos ); double p1 = dot( a1, bdisp ); double p2 = dot( a2, bdisp ); // How hard do we have to hit the target to get it to the // destination. double tdist = mag( tdir ); double a = 0.5; double b = 0.5; double c = -tdist; // Number of steps the puck has to take to cover mag tdist. double steps = (-b + Math.sqrt( b * b - 4 * a * c )) / (2 * a); // Approximate velocity to get the puck to travel to its // destination. double vel = steps * 0.7; // Match desired velocity in the direction we want to move the puck, // line up on the other axis. f1 = clamp( vel - v1, -ACCEL, ACCEL ); f2 = moveTo( p2, v2, 0.0, ACCEL ); // If we are about to hit the target, pick a new // one the next turn. if ( p1 + v1 + f1 > -13 ) ttimer[i] = 1; } Point2D force = sum( scale( a1, f1 ), scale( a2, f2 ) ); // Tell the game what direction we want to move this bumper. System.out.printf( "%.2f %.2f ", force.getX(), force.getY() ); // Count down for how long we can chase this target. ttimer[i]--; } else { // Just move to the right. System.out.printf( "%.2f 0.0 ", Const.BUMPER_ACCEL_LIMIT ); } } // Make the sled drive in a figure eight. if ( moveCount % 80 < 40 ) { System.out.printf( "%.6f\n", Math.PI * 2.0 / 40 ); } else { System.out.printf( "%.6f\n", -Math.PI * 2.0 / 40 ); } // Try to read the next game state. tnum = in.nextInt(); moveCount++; } } }