<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
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];
		gbc.fill= GridBagConstraints.BOTH;	
		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(true);
	}

// 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  &amp;&amp;
		e.target instanceof CheckersSquare  &amp;&amp;  clickflag == 0) {
		processSquareClick((CheckersSquare)e.target);
		return true;
		}
	if (e.id == Event.MOUSE_DOWN  &amp;&amp;
		e.target instanceof CheckersSquare  &amp;&amp;  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&lt;=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
			board[i]  [5].placePiece(CheckersSquare.BLACK);// row 5
			board[i+1][6].placePiece(CheckersSquare.BLACK);// row 6
			board[i]  [7].placePiece(CheckersSquare.BLACK);// row 7
			}

	// 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&gt;0; 0 if v=0; -1 if v&lt;0)
private int sign(int v) {
    if (v &gt; 0)
		return 1;
    if (v &lt; 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) {
 	// 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;
            
    // 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();
			oldSq.pickUpPiece();
			newSq.placePiece(piece);
			promoteToKing(newSq);
			return true;
			}
			
	// 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();
			oldSq.pickUpPiece();
			newSq.placePiece(piece);
			// Pick up the piece that was jumped over
				int x= (oldSq.col+newSq.col)/2; //col no of jumped piece
				int y= (oldSq.row+newSq.row)/2; //row no of jumped piece
				board[x][y].pickUpPiece();
				if (otherColor==CheckersSquare.RED)
					redCount.setInt(redCount.getInt()-1);
				else blackCount.setInt(blackCount.getInt()-1);
			promoteToKing(newSq);
			return true;
			}
			
	// 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,
		if (Math.abs(dx) != 1) return false;
    	if (Math.abs(dy) != 1) return false;
    
    // Return true if this is a King (which can go in any direction)
    	if (oldSq.isKing()) return true;
    
    // The piece is not a king. Return value of "the piece moves
    // forward (and not backward)"
    	return (oldSq.containsRed()   &amp;&amp; dy&gt;0) ||
    		   (oldSq.containsBlack() &amp;&amp; dy&lt;0);
 	}
 	
// 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
		if (Math.abs(dx) != 2) return false;
    	if (Math.abs(dy) != 2) return false;
    	
    // Return false if there is not a piece of the other color
    // between oldSq and newSq.
    	// Set s to the square between oldSq and newSq --remembering
    	// that the rows and cols differ by an absolute value of 2
    		CheckersSquare s=
    			board[oldSq.col + sign(dx)][oldSq.row+sign(dy)];
    		if  (!s.isSameColor(otherColor))
    			return false;
    
    // Return true if this is a King (which can go in any direction)
    	if (oldSq.isKing()) return true;
    
    // The piece is not a king. Return value of "the piece moves
    // forward (and not backward)"
    	return (oldSq.containsRed()   &amp;&amp; dy&gt;0) ||
    		   (oldSq.containsBlack() &amp;&amp; dy&lt;0);
 	}

// 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) {
	enableBoard(false);
	if (sq.contents() == CheckersSquare.EMPTY ||
	    !sq.isSameColor(colorToPlay)) {
			enableBoard(true);
			nextTask.setText("Invalid choice. Choose");
			if (colorToPlay==CheckersSquare.RED)
				nextTask1.setText("a red piece to move");
			else
				nextTask1.setText("a black piece to move");
			return;
			}
	oldSq= sq;
	sq.setToBeMoved(true);
	clickflag = 1;
	nextTask.setText("Select destination");
	nextTask1.setText("");
	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) &amp;&amp; sq.contents()==CheckersSquare.RED) {
		sq.pickUpPiece();
		sq.placePiece(CheckersSquare.REDKING);
		return;
		}
	if ((sq.row==0) &amp;&amp; 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;
	}
}
</pre></body></html>