
import java.awt.*;

// Frame for the game Checkers. The frame contains the game
// board and necessary buttons and information fields.
public class Checkers extends Frame {
// Components that go in the frame
	CheckersSquare[][] board; // Will contain the 8 x 8 game board
	Label redsLabel= new Label("red pieces ",Label.CENTER);
	Label blacksLabel= new Label("black pieces ",Label.CENTER);
	Label reds= new Label("0",Label.CENTER); // Number of reds pieces on board
	Label blacks= new Label("0",Label.CENTER); // Number of black pieces on board
	Label whoPlays= new Label("Red to play ",Label.CENTER);
	Label nextTask= new Label("Invalid destination. Choose  ",Label.CENTER);
	Label nextTask1= new Label("an empty square to move to  ",Label.CENTER);
	TextArea helpText= null; // To contain an explanation, when requested

// Titles for buttons
	private final String[] buttons= {"New game", "Quit", "Help"};

// The layout and constraint variables for this frame
	GridBagLayout gb;
	GridBagConstraints gbc;

// Number of red pieces and black pieces on the board
	IntLabel redCount= new IntLabel(0, reds);
	IntLabel blackCount= new IntLabel(0, blacks); 

// clickflag describes the clicks made by the user thus far in making
// a move:
//   = 0: No piece has been chosen (clicked on). For all
//		  squares, field toBeMoved is false.
//   = 1: A click, on a piece of color colorToPlay, has been made.
//        oldSq is the square of the piece to be moved, and it is
//		  highlighted (i.e. oldSq.toBeMoved=true). For all other
//        squares, field toBeMoved is false.
	int clickflag = 0;
	CheckersSquare oldSq;

// These variables have values CheckersSquare.RED or CheckersSquare.BLACK
	int colorToPlay; 	// player (i.e. color) to place next
	int otherColor;		// the other color

// Constructor: An 8 x 8 checkerboard, with three buttons and some
// pieces of information
public Checkers() {
	super("Checkers");
	gb= new GridBagLayout();
	gbc= new GridBagConstraints();
	setFont(new Font("Dialog", Font.PLAIN, 10));
	setLayout(gb);
	gbc.fill  =  GridBagConstraints.NONE;
	int i;
	int j;

	// (0) Create and place the 8*8 squares in the frame
		board= new CheckersSquare[8][8];
		for (i= 0; i != 8; i= i+1)
			for (j= 0; j != 8; j= j+1) {
				board[i][j]= new CheckersSquare(i,j);
				add(board[i][j], gb, gbc, 2*i,2*j, 2,2, 0,0);
				}
	
	// (1) Create the buttons given by String buttons. Setting gbc.fill to
	// BOTH ensures that the buttons fill their entire space; without this
	// assignment, buttons would take the minimum space possible. Comment
	// out the first statement and execute to see this.
		gbc.fill=  GridBagConstraints.BOTH;	
		for (j= 0; j != buttons.length; j= j+1)
			add(new Button(buttons[j]), gb, gbc, 2*8,2*j, 2,2, 0,0);
	
	// (2a) Place labels for the numbers of white and black pieces
		gbc.fill=  GridBagConstraints.HORIZONTAL;
		gbc.anchor= GridBagConstraints.SOUTHWEST;
		add(redsLabel,   gb, gbc, 2*8, 2*5,   2,1, 0,0);
		add(blacksLabel, gb, gbc, 2*8, 2*6,   2,1, 0,0);
		add(reds,        gb, gbc, 2*8, 2*5+1, 2,1, 0,0);
		add(blacks,      gb, gbc, 2*8, 2*6+1, 2,1, 0,0);
	
	// (2b) Place the "whose play is it" and message labels
		add(whoPlays,  gb, gbc, 2*8,2*3,    2,1, 0,0);
		add(nextTask,  gb, gbc, 2*8, 2*3+1, 2,1, 0,0);
		add(nextTask1, gb, gbc, 2*8, 2*3+2, 2,1, 0,0);
	
	pack();
	move(150,50);
	newGame();
	show();
	setResizable(false);
	}

// Add component c to gbl (with constraints gbc) at position (x,y).
// Component c takes w columns and r rows, and is weighted (wx, wy).
private void add(Component c, GridBagLayout gbl,
				GridBagConstraints gbc,
				int x, int y, int w, int h, int wx, int wy) {
	gbc.gridx= x;
	gbc.gridy= y;
	gbc.gridwidth= w;
	gbc.gridheight= h;
	gbc.weightx= wx;
	gbc.weighty= wy;
	gbl.setConstraints(c, gbc);
	add(c);
	}
	
// If a button was pressed, process it; otherwise, return false
public boolean action(Event e, Object arg) {
	if (arg.equals(buttons[0])) {
		// Handle press of "New game" and return true
			newGame();
			return true;
		}
	if (arg.equals(buttons[1])) {
		// Handle press of "Quit" and return true
			dispose();
			return true;
		}
	if (arg.equals(buttons[2])) {
		// Handle press of "Help" and return true
			if (helpText != null) {
				// Help field already exists, so remove it and return
					remove(helpText);
					helpText= null;
					pack();
					return true;
					}
			helpText= new TextArea("This is the game of checkers. We " +
				"assume you know how to play. To move a piece, first\n" +
				"click the mouse on the piece you want to move. Note " +
				"that this piece is highlighted. Then\n" +
				"click on the square to which you " +
				"want to move it. If you decide to change the piece you \n" +
				"want to move, just click on a " +
				"different piece (of the same color).\n" +
				"\n" +
				"One change in the game: You can't jump two pieces at once. " +
				"Try changing the program\nto do this --it's a big change.\n" +
				"\nA king is shown with a yellow \"K\" it.");
			helpText.setEditable(false);
			gbc.fill= GridBagConstraints.BOTH;
			add(helpText, gb, gbc, 0,17, 18,1, 0,0);
			resize(400,400);
			pack();
			return true;
		}
	return false;
	}

// Process press of WINDOW_DESTROY or mouse click in a Checkers square
public boolean handleEvent(Event e) {
	if (e.id == Event.WINDOW_DESTROY) {
		dispose();
		return true;
		}
	if (e.id == Event.MOUSE_DOWN  &&
		e.target instanceof CheckersSquare  &&  clickflag == 0) {
		processSquareClick((CheckersSquare)e.target);
		return true;
		}
	if (e.id == Event.MOUSE_DOWN  &&
		e.target instanceof CheckersSquare  &&  clickflag == 1) {
		processClickTwo((CheckersSquare)e.target);
		return true;
		}
	return super.handleEvent(e);
	}
	
// Set the board up for a new game
public void newGame() {
	// Pick up the pieces from all the squares
		for (int i= 0; i != 8; i= i+1)
			for (int j= 0; j != 8; j= j+1)
				board[i][j].pickUpPiece();
		nextTask.setText("Select a piece to move");
		nextTask1.setText("");
		clickflag = 0;
	// Place red and black pieces in the initial configuration
		for (int i= 0; i<=6; i= i+2) {
			board[i+1][0].placePiece(CheckersSquare.RED);  // row 0
			board[i]  [1].placePiece(CheckersSquare.RED);  // row 1
			board[i+1][2].placePiece(CheckersSquare.RED);  // row 2
			/* PUT ASSIGNMENTS HERE SO THAT BLACK PIECES ARE
			   PLACED AS WELL AS REDS. THEN DELETE THIS COMMENT
			*/
			}

	// Set the number of red and number of black pieces to 12
		redCount.setInt(12);
		blackCount.setInt(12);
	colorToPlay= CheckersSquare.BLACK;
	otherColor= CheckersSquare.RED;
	changeTurn();
	}

// return the sign of v (1 if v>0; 0 if v=0; -1 if v<0)
private int sign(int v) {
    if (v > 0)
		return 1;
    if (v < 0)
		return -1;
    return v;
    }
    
// Attempt to move piece from square oldSq to square newSq
// If not possible, return false.
// If possible, make the move and return true
private boolean validMove(CheckersSquare oldSq, CheckersSquare newSq) {
 	// (vm1) Return false if it's an attempt to move to a red square or
    // if it's an attempt to move to an already-occupied square
		if (newSq.isRed())
            return false;
		if (newSq.contents() != CheckersSquare.EMPTY)
            return false;
            
    // (vm2) If this is a valid non-jump move, then make the move
    // and return true. Making the move requires: (0) picking up
    // the piece, (1) putting it down on the new square, and
    // (2)promoting it to a new king if necessary.
		if (isValidNonjump(oldSq,newSq)) {
			int piece= oldSq.contents();
			/* PART I: FINISH IMPLEMENTING STATEMENT-COMMENT (vm2)
			   AND DELETE THIS COMMENT
			*/
			
			}
			
	// (vm3) If this is a valid jump move, then make the move
	// and return true. Making the move requires: (0) picking up
	// the piece, (1) putting it down on the new square, (1) picking
	// up the piece jumped (and subtracting 1 from the number of
	// pieces of that color), and (2) promoting the new piece to
	// a king if necessary 
		if (isValidjump(oldSq,newSq)) {
			int piece= oldSq.contents();
			/* PART II: FINISH IMPLEMENTING STATEMENT-COMMENT (vm3)
			   AND DELETE THIS COMMENT
			*/
			
			}
			
	// (vm4) The move is invalid, so return false
		return false;
   }
    
// Return "the move from oldSq to newSq is a valid non-jump
// move for player colorToPlay". Assume that oldSq contains a
// a piece of colorToPlay and that newSq is an empty black square
private boolean isValidNonjump(CheckersSquare oldSq,
							   CheckersSquare newSq) {
	int dx = newSq.col - oldSq.col;
    int dy = newSq.row - oldSq.row;
   
   	// Return false if the move is not a move to an adjacent
	// row and column,
		/* PLACE CODE HERE TO IMPLEMENT THE STATEMENT-COMMENT
		   AND DELETE THIS COMMENT.
		*/
    
    // Return true if this is a King (which can go in any direction)
 		/* PLACE CODE HERE TO IMPLEMENT THE STATEMENT-COMMENT
		   AND DELETE THIS COMMENT.
		*/
     
    // The piece is not a king. Return value of "the piece moves
    // forward (and not backward)"
 		/* PLACE CODE HERE TO IMPLEMENT THE STATEMENT-COMMENT
		   AND DELETE THIS COMMENT.
		*/
    	
    return false;   /* DELETE THIS STATEMENT */
 	}
 	
// Return "the move from oldSq to newSq is a valid jump
// move for player colorToPlay". Method assumes that oldSq
// contains a piece and that newSq is an empty black square
private boolean isValidjump(CheckersSquare oldSq,
							CheckersSquare newSq) {
	int dx = newSq.col - oldSq.col;
    int dy = newSq.row - oldSq.row;
   
   	// Return false if the move is not a move of 2 columns
	// and two rows
 		/* PLACE CODE HERE TO IMPLEMENT THE STATEMENT-COMMENT
		   AND DELETE THIS COMMENT.
		*/
    	
    // Return false if there is not a piece of the other color
    // between oldSq and newSq.
    	// (a)Set s to the square between oldSq and newSq --remembering
    	// that the rows and cols differ by an absolute value of 2
    		/* PLACE CODE HERE TO IMPLEMENT STATEMENT-COMMENT (a)
		   	   AND DELETE THIS COMMENT.
		    */

    	// (b)If s does not contain a piece that is the same color as
    	// variable otherColor, then return false.
    		/* PLACE CODE HERE TO IMPLEMENT STATEMENT-COMMENT (b)
		   	   AND DELETE THIS COMMENT.
		    */
    		
    
    // Return true if this is a King (which can go in any direction)
 		/* PLACE CODE HERE TO IMPLEMENT THE STATEMENT-COMMENT
		   AND DELETE THIS COMMENT.
		*/
    
    // The piece is not a king. Return value of "the move from oldSq
    // to newSq is forward (and not backward)"
		/* PLACE CODE HERE TO IMPLEMENT THE STATEMENT-COMMENT
		   AND DELETE THIS COMMENT.
		*/
		
	return false; /* Delete this statement */
 	}

// clickflag=1. If the pieces on oldSq and newSq have the same color,
// then switch to moving the piece on newSq. Otherwise, attempt to
// move the piece from oldSq to square newSq. If not possible, give
// error message; if possible, do it and switch players
public void processClickTwo(CheckersSquare newSq) {
	enableBoard(false);
	// Change the piece to move and return,if the pieces on oldSq
	// and newSq are the same color
		if (newSq.isSameColor(colorToPlay)) {
			oldSq.setToBeMoved(false);
			oldSq= newSq;
			oldSq.setToBeMoved(true);
			nextTask.setText("Select destination");
			nextTask1.setText("");
	    	enableBoard(true);
	    	return;
	    	}
	// If newSq is not empty, give error message and return
		if (newSq.contents() != CheckersSquare.EMPTY ) {
	    	enableBoard(true);
	    	nextTask.setText("Invalid destination. Choose");
	    	nextTask1.setText("another square");
	    	return;
	    	}
	if (validMove(oldSq, newSq)) {
		oldSq.setToBeMoved(false);
		clickflag = 0;
		nextTask.setText("Select a piece to move");
		nextTask1.setText("");
		changeTurn();
		enableBoard(true);
		return;                
		}
	// Move was not handled. Tell user to retry the move
	    nextTask.setText("Invalid destination. Choose");
	    nextTask1.setText("another square");
		enableBoard(true);
    }
    
// Process the first click by user in making a move --clickflag=0.
// The click is in square sq.
// If the click is on an empty square or on a piece of wrong color,
// give a message and ask user to try again.
public void processSquareClick(CheckersSquare sq) {
	// Fix it so that clicks on the checker board have no effect
		enableBoard(false);
	// If square sq contains nothing or contains a piece of color
	// colorToPlay, change a label to say the click is invalid, enable
	// the checker board, and return
		if (sq.contents() == CheckersSquare.EMPTY ||
	    	!sq.isSameColor(colorToPlay)) {
				nextTask.setText("Invalid choice. Choose");
				if (colorToPlay==CheckersSquare.RED)
					nextTask1.setText("a red piece to move");
				else
					nextTask1.setText("a black piece to move");
				enableBoard(true);
				return;
				}
	// Change the state to get ready for a second click on a destination
		oldSq= sq;
		sq.setToBeMoved(true);
		clickflag = 1;
		nextTask.setText("Select destination");
		nextTask1.setText("");
	// Fix it so that clicks on the checker board will be processed
		enableBoard(true); 
	}
	
// If en is true, enable the board squares; otherwise disable them
public void enableBoard(boolean en) {
	for (int i= 0; i != 8; i= i+1)
		for (int j= 0; j != 8; j= j+1)
			board[i][j].enable(en);
	}

// If the piece in square sq is not a king and is in the
// last row for its color, change it to a King. Changing it
// to a king should be done by picking the piece up and then
// placing a king on the square
public void promoteToKing(CheckersSquare sq) {
	if ((sq.row==7) && sq.contents()==CheckersSquare.RED) {
		sq.pickUpPiece();
		sq.placePiece(CheckersSquare.REDKING);
		return;
		}
	if ((sq.row==0) && sq.contents()==CheckersSquare.BLACK) {
		sq.pickUpPiece();
		sq.placePiece(CheckersSquare.BLACKKING);
		}	
	}
	
// Switch player (i.e. switch colorToPlay and otherColor) and
// set clickflag for a new move
public void changeTurn() {
	int temp= colorToPlay;
	colorToPlay= otherColor;
	otherColor= temp;
	if (colorToPlay == CheckersSquare.RED) {
		whoPlays.setText("Red to play");
		setCursor(MOVE_CURSOR);
		}
	else {
		whoPlays.setText("Black to play");
		setCursor(HAND_CURSOR);
		}
	clickflag= 0;
	}
}
