// Othello_game.java
// Last modified: 7-1-96
//
// Copyright (c) 1996 Roxanne Canosa.  All Rights Reserved

// Principal Contributors: Roxanne Canosa, Dr. Sandeep Mitra, 
//                         Dr. Leslie Lander
// SUNY-Brockport Java Interest Group members: Lalit Bajaj, Nick Kraft, 
//                                             Eric Litteer, Tom McDermott
//
// This program is available for distribution and may be used, copied or
// modified on the condition that the copyright notice is not modified.
// The contributors are not responsible for any problems or damage caused
// by this program.
//
// This applet is an implementation of an Othello game - an interactive game
// between the user(black), and the computer(white).  The game starts with an
// 8x8 grid, and a starting configuration.  The object of the game is to cover
// as much of the grid with your color pieces as possible, by making certain
// strategic moves.  A move consists of "outflanking" your opponent's disc(s),
// then flipping the outflanked disc(s) to your color.  The game is over when
// it is no longer possible for either player to move.

import java.awt.*;
import java.applet.*;

public class Othello_game extends Applet implements Runnable
{
   Thread runner;                // declare a thread for this game

   boolean black_shown=false;    // flag to signal pause
   boolean show_em=false;

   final int BLACK = 1;          // declare state of each square
   final int WHITE = 2;
   final int EMPTY = 0;
   final int OFFBOARD = -1;

   final static int Game[][] = new int[10][10];    //10x10 matrix of squares

   protected int black_count = 0;        
   protected int white_count = 0;

   Event evt;
   int   x,y;



   public void start()                     // create a thread and start it
      {
      if (runner == null)
         {
         black_shown=false;
         runner = new Thread(this);
         runner.start();
         }
      }

   public void stop()                     // stop the thread
      {
      if (runner != null)
         {
         runner.stop();
         runner = null;
         black_shown=false;
         }
      }


   public synchronized void run()                // initialize screen
      {
      setBackground(Color.green);

      for (int i=0; i<10; i++)      // initialize off-board squares
         {
            Game[i][0] = OFFBOARD;
            Game[i][9] = OFFBOARD;
            Game[0][i] = OFFBOARD;
            Game[9][i] = OFFBOARD;
         }

      for (int i=1; i<9; i++)       // initialize game board to be empty
         for (int j=1; j<9; j++)
            Game[i][j] = EMPTY;

      Game[4][4] = WHITE;          // except for initial set up
      Game[5][4] = BLACK;
      Game[4][5] = BLACK;
      Game[5][5] = WHITE;

      while (runner!=null)         // signal thread to wait after painting
         {                         // black and before white responds
         while (!black_shown)
            {
            try {
                wait();
            } catch (InterruptedException e){ }
            black_shown=false;
            showStatus("Good move!");
            pause(1000);
            whiteResponds();
            }
         }
      }
               
 
   // BLACK clicked on a square - update screen
   public synchronized boolean mouseUp(Event evt, int x, int y)
   {
      Dimension d = size();             // find out which square was clicked
      int c = (x*8)/d.width + 1;        // column
      int r = (y*8)/d.height + 1;       // row
      boolean black_done;               // true if black cannot move anywhere

      if (legalMove(r,c,BLACK,WHITE,true))
        {
        Game[r][c] = BLACK;             // set that square to black
        repaint();
        black_shown=true;
        notify();
        }
      else showStatus("Not a legal move");
      black_done=true;                 // check if black can move anywhere
      for (int i=1; i<9; i++)
         for (int j=1; j<9; j++)
            if (legalMove(i,j,BLACK,WHITE,false) )
               black_done=false;
      
      if (black_done)                 // black cannot move - white finishes up
         for (int i=1; i<65; i++)
            whiteResponds();

      return true;
   } 


   // computer responds with a move
   public void whiteResponds()
      {
      boolean found;   	                 // true if a legal square is found
      int i, j;				// indices for loops
  
      found=false;
      if (legalMove(1,1,WHITE,BLACK,true))      // first check corners
         {
         Game[1][1]=WHITE;
         found=true;
         }
      if ( (!found) && (legalMove(8,8,WHITE,BLACK,true)) )
         {
         Game[8][8]=WHITE;
         found=true;
         }
      if ( (!found) && (legalMove(1,8,WHITE,BLACK,true)) )
         {
         Game[1][8]=WHITE;
         found=true;
         }
      if ( (!found) && (legalMove(8,1,WHITE,BLACK,true)) )
         {
         Game[8][1]=WHITE;
         found=true;
         }

	i=3;				// check center squares
	while ((!found) && (i < 7))
	{
	    j=3;
            while ( (!found) && (j < 7))
	    {
	    if	(legalMove(i,j,WHITE,BLACK,true)) 
               {
               Game[i][j]=WHITE;
               found=true;
               }
	       j++;
	     }
	     i++;
	}

	i=3;
	while ((!found) && (i < 7))    // then check edges except for those
         {                           // surrounding a corner
         if (legalMove(1,i,WHITE,BLACK,true))
            {
            Game[1][i]=WHITE;
            found=true;
            }
         if ( (!found) && (legalMove(8,i,WHITE,BLACK,true)))
              {
            Game[8][i]=WHITE;
            found=true;
            }
         if ( (!found) && (legalMove(i,1,WHITE,BLACK,true)))
            {
            Game[i][1]=WHITE;
            found=true;
            }
         if ( (!found) && (legalMove(i,8,WHITE,BLACK,true)))
            {
            Game[i][8]=WHITE;
            found=true;
            }
	    i++;
         }
      

      i=3;             
      while ((!found) && (i < 7))		// next check inner edges
         {
         if (legalMove(2,i,WHITE,BLACK,true))
            {
            Game[2][i]=WHITE;
            found=true;
            }
         if ( (!found) && (legalMove(7,i,WHITE,BLACK,true)))
            {
            Game[7][i]=WHITE;
            found=true;
            }
         if ( (!found) && (legalMove(i,2,WHITE,BLACK,true)))
            {
            Game[i][2]=WHITE;
            found=true;
            }
         if ( (!found) && (legalMove(i,7,WHITE,BLACK,true)))
            {
            Game[i][7]=WHITE;
            found=true;
            }
	    i++;
         }
   
	 i=1;		// finally squares surrounding a corner
	 while ((!found) && (i < 9))
	 {
	   j=1;
	   while ((!found) && (j < 9))
	   {	
            if (legalMove(i,j,WHITE,BLACK,true)) 
               {
               found=true;
               Game[i][j]=WHITE;
               }
	       j++;
	   }
	   i++;
	}
     
      repaint();
      }


   // decide if the move is legal
   public boolean legalMove(int r, int c, int color, int othercolor,
                            boolean flip)
   {
      int i,j;                                  // position on board
      boolean legal;                            // true if legal move
      int stepcount;                            // counts the stepping
                                                // across the board

      legal = false;
  
      if (Game[r][c] == EMPTY)                  // square clicked must be empty
         {
	   for (int xdir=-1; xdir < 2; xdir++)
		for (int ydir=-1; ydir < 2; ydir++)
		{
		  stepcount = 0;
		  do
		  {
			stepcount++;
			i = r + stepcount*xdir; // so many steps along x-axis
			j = c + stepcount*ydir; // so many steps along y-axis
		   }
		  while ( (i > 0) && (i < 9) && (j > 0) && (j < 9) &&
			  (Game[i][j] == othercolor));
		  if (( i > 0) && (i < 9) && (j > 0) && (j < 9) &&
		          (stepcount > 1) && 
			// You must move more than one step for legal move
			  (Game[i][j] == color) )
			{ legal = true;
			  if (flip)
			  for (int k = 1; k < stepcount; k++)
				Game[r+xdir*k][c+ydir*k] = color;
			}
		} 
	}  
      if ( legal==true) return true;
      else return false;
   }


   void pause(int time)                     // time delay
      {
      try { runner.sleep(time); }         
      catch (InterruptedException e) { }
      }

       
   // paint the screen with the right configuartion
   public void paint(Graphics g)
   {
      Dimension d = size();
      g.setColor(Color.black);
      int xoff = d.width/8;
      int yoff = d.height/8;

      black_count=0;                        // initialize counts to 0
      white_count=0;                        
      boolean done;                         // true if game is over

      for (int i=1; i<=8; i++)              // draw the lines
      {
         g.drawLine(i*xoff, 0, i*xoff, d.height);
         g.drawLine(0, i*yoff, d.width, i*yoff);
      }

      for (int i=1; i<9; i++)              // scan board for black discs
         for (int j=1; j<9; j++)
            {
            if (Game[i][j] == BLACK)       // draw BLACK discs
               {
               g.fillOval((j*yoff+3)-yoff,(i*xoff+3)-xoff,33,33); 
               black_count++;
               }
            }
 
      g.setColor(Color.white);
      for (int i=1; i<9; i++)              // scan board for white discs
         for (int j=1; j<9; j++)
            {
            if (Game[i][j] == WHITE)       // draw WHITE discs
               {
               g.fillOval((j*yoff+3)-yoff,(i*xoff+3)-xoff,33,33);
               white_count++;
               }
            }

      g.setColor(Color.red);

      done=true;

      for (int i=1; i<9; i++)
         for (int j=1; j<9; j++)
            if ((legalMove(i,j,BLACK,WHITE,false)) ||
                (legalMove(i,j,WHITE,BLACK,false)))
               done=false;

      if (done==true) 
         {
         if (white_count>black_count)
            g.drawString("White won with "+white_count+" discs.",10,20);
         else if (black_count>white_count)
            g.drawString("Black won with "+black_count+" discs.",10,20);
         else g.drawString("Tied game",10,20);
         }
      else
         {     
         if (white_count > black_count)
            g.drawString("White is winning with "+white_count+" discs",10,20);
         else if (black_count > white_count)
            g.drawString("Black is winning with "+black_count+" discs",10,20);
         else g.drawString("Currently tied",10,20);
         }
      
      if (show_em==true)
         {
         for (int i=1; i<9; i++)
            for (int j=1; j<9; j++)
               if (legalMove(i,j,BLACK,WHITE,false))
                  g.fillOval((j*yoff+15)-yoff,(i*xoff+15)-xoff,5,5);
         }
   }
 
   public void Action()
   {
      if (show_em==false)
         {
         show_em=true;
         repaint();
         }
      else
         {
         show_em=false;
         repaint();
         }
   }

}
   