// AI for playing: http://www.brainbashersgames.com/games/particles.asp // no longer here!
// new website: http://www.ragdollsoft.com/particles/
// new new website: http://www.gamingdelight.com/games/particles.php
// NOTE: the findPlayArea() method no longer works, and you may have to modify line 167 to work on your screen (defining the game rectangle)
// Currently only runs at 800x600 resolution and need to get top of game board at top of chrome browser (might need to adjust findPlayArea() to get correct starting height of game)
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.Calendar;

public class Particles {

    
    // 204, 204, 204 - bot of screen    
    private static int RES_X, RES_Y; // screen resolution
    private static int INCREMENT = 10; // don't need to process every pixel (normally) since balls are rather large

    //ball is technically 35x35 pixels... but we have to make it larger due to computer delay and some coding approximations
    private static int playerX, playerY, playerSize = 155; // size of square to play in the center of (larger = less chance of dying, but fewer available spots)
    private static Rectangle playZone; // finds the blueish boarder of the game
    private static Robot robbie; // i love robbie
    private static BufferedImage screen; // create a temporary buffer to store each screen capture (efficiency)
    private static boolean seenRedBall = false; // have we seen a red ball yet? (i.e. red color in the playZone)

    // everyone likes main
    public static void main(String[] args) throws Throwable {
        robbie = new Robot(); // robbie sends all the mouse movement commands (and captures the screen)
        // Robot can also do keyboard commands, such as "robbie.keyPress(KeyEvent.VK_A);" for the "a" key

        // size of screen....
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        System.out.println("Detected screen size: (" + screenSize.getWidth() + ", " + screenSize.getHeight() + ")");

        RES_X = (int)screenSize.getWidth();
        RES_Y = (int)screenSize.getHeight();

        // wait 3 seconds... my screen is small so I needed this time to alt-tab back to browser
        Thread.sleep(3000);

     
//        // wait until it finds a valid play area
//        while(playZone == null || seenRedBall == false)
//        {
//            screen=robbie.createScreenCapture	(new Rectangle(RES_X,RES_Y));
//            findPlayArea();
//            if(playZone != null)
//            {
//                noRedHere(playZone); // this is run to update
//            }
//        }

           long start = Calendar.getInstance().getTimeInMillis();
        while(true)
        {
            // see how fast my code is doing a loop? (if slow you lose easier)
//            System.out.printf("Duration = %.3f\n", (Calendar.getInstance().getTimeInMillis()-start)/1000.0);
//            start = Calendar.getInstance().getTimeInMillis();

            //it is much more efficient to just do one screen caputre and work off a temp copy
            // (more like horribly slow otherwise... createScreenCapture() is a very expensive method)
            screen=robbie.createScreenCapture	(new Rectangle(RES_X,RES_Y));

            // if we haven't seen a red ball yet, look for the play area (otherwise don't waste computation time on it)
            if(seenRedBall == false)
            {
                findPlayArea();
            }

            // scan for an open area (playerSize by playerSize square with no red balls)
            moveToSafety();

            // if we've seen atleast one red ball and there are no more left in the play zone, we lost so stop the program
            if(seenRedBall == true && noRedHere(playZone) == 1)
            {
                break;
            }
        }
    }

    
    /**
     * This method finds an open space on the board to move your ball to
     */
    public static void moveToSafety()
    {
        // scan all possible spots on the playZone (2 for loops since 2 dimensional)
        for(int y = playZone.y; y < playZone.y + playZone.height - playerSize; y+=INCREMENT)
        {
            for(int x = playZone.x; x < playZone.x + playZone.width - playerSize; x+=INCREMENT)
            {
                // if there were no red balls in this square, play here!
                if(noRedHere(new Rectangle(x, y, playerSize, playerSize)) == 1)
                {
                    robbie.mouseMove(x + playerSize/2, y + playerSize/2); // moves the mouse to the center of the circle
                    return;
                }
            }
        }
    }

    /**
     * Scans the Rectangle r to see if a red color appears anywhere
     * @param r is the rectangle you want scanned
     * @return 1 if no red in r, 0 otherwise
     */
    public static int noRedHere(Rectangle r)
    {
        // scan rectangle (2 for loops since again, 2d)
        for(int y = r.y; y < r.y + r.height; y+=INCREMENT)
        {
            for(int x = r.x; x < r.x + r.width; x+=INCREMENT)
            {
                // is this pixel red?
                if(isRedBall(new Color(screen.getRGB(x, y))) == 1)
                {
//                    System.out.printf("Red ball detected at (%d,%d)\n",x,y); // i used this for debugging
                    seenRedBall=true;
                    return 0; // this square is not good to play in
                }
            }
        }

        return 1; // play here!
    }


    /** this method locates the blueish boarder around the game
     *  it checks for the following color pattern (3x3)
     *  W W W
     *  W B B
     *  W B W
     */
    public static void findPlayArea()
    {
    	// NOTE: method is now obsolete as the current website does not have a blue bounding box around the play area
    	// NOTE: instead a terrible hack is used that assumes it is magically positioned right

        int offset = 10; // offset is the spacing between the color checks
/*
        // scans every pixel in the screen (expensive, but the boarder is small)
        for(int y=offset; y < RES_Y-offset; y++)
        {
            for(int x=offset; x < RES_X-offset; x++)
            {
                // if this x,y (center of the pattern) matches....
                if(isBlueEdge(new Color(screen.getRGB(x, y))) == 1 // center = blue
                        && isBlueEdge(new Color(screen.getRGB(x+offset, y))) == 1 // right = blue
                        && isBlueEdge(new Color(screen.getRGB(x, y + offset))) == 1 // down = blue
                        && isBalancedColor(new Color(screen.getRGB(x+offset, y + offset))) == 1 // down right = white
                        && isBalancedColor(new Color(screen.getRGB(x-offset, y + offset))) == 1 // down left = white
                        && isBalancedColor(new Color(screen.getRGB(x-offset, y))) == 1 // left = white
                        && isBalancedColor(new Color(screen.getRGB(x-offset, y - offset))) == 1 // left up = white
                        && isBalancedColor(new Color(screen.getRGB(x, y - offset))) == 1 // up = white
                        && isBalancedColor(new Color(screen.getRGB(x+offset, y - offset))) == 1) // up right = white
                {
                    //  play area is 599x599
                    // this min is to limit it onto the screen (prevents crashes elsewhere if you only have half the playzone open)
                    playZone = new Rectangle(x, y, Math.min(599, RES_X - x), Math.min(599, RES_X - x));

//                    System.out.printf("Found player area at (%d,%d)\n", playZone.x, playZone.y);
                    /// then stop looping
                    break;
                }
            }
        }
        */
        
//        playZone = new Rectangle(65, 100, 852-65, 900-100);
        playZone = new Rectangle(200, 132, 648-200, 576-132);

    }



    /**
     * Is this white? (also detects grey/black...)
     * @param col = pixel color
     * @return 1 if all primary colors equal, 0 otherwise
     */
            public static int isBalancedColor(Color col)
	 {
		 int ret = -1;

		 if(Math.abs(col.getRed() - col.getBlue())<50 && Math.abs(col.getBlue() - col.getGreen())<50 && (col.getGreen() - col.getRed())<50)
		 {
			 ret = 1;
		 }
		 else
		 {
			 ret = 0;
		 }

		 return ret;
	 }

    // 29, 29, 156 - RGB of blue ball point
            /**
             * is this a blue ball color?
             * @param col = color
             * @return 1 if blue, 0 otherwise
             */
    public static int isBlueBall(Color col)
	 {
		 int ret = -1;

		 if(col.getRed()<60 && col.getGreen()<60 && col.getBlue()>100)
		 {
			 ret = 1;
		 }
		 else
		 {
			 ret = 0;
		 }

		 return ret;
	 }

    // 0, 51, 156 - blue edge
    /**
     * Is this a blue boarder color?
     * @param col = pixel color
     * @return 1 if it is blue boarder color, 0 otherwise
     */
    public static int isBlueEdge(Color col)
	 {
		 int ret = -1;

		 if(col.getRed()<50 && col.getGreen()<80 && col.getBlue()>100)
		 {
			 ret = 1;
		 }
		 else
		 {
			 ret = 0;
		 }

		 return ret;
	 }


    // 117, 20, 20 - red ball
    /**
     * Is this the red ball's color?
     * @param col = pixel color
     * @return 1 if red, 0 otherwise
     */

    public static int isRedBall(Color col)
	 {
		 int ret = -1;

		 if(col.getRed()>100 && col.getGreen()<50 && col.getBlue()<50)
		 {
			 ret = 1;
		 }
		 else
		 {
			 ret = 0;
		 }

		 return ret;
	 }

}
