// This is the star game using Node.java as well.

import java.util.* ;
import java.awt.* ;
import java.awt.event.* ;
import java.applet.Applet ;



class GamePanel extends Panel implements Runnable, MouseListener, MouseMotionListener {

       Star game ;
       String turn  ;
       Dimension d ;
       
       DPoint center  ;     
       Color winner ;
       int winFrom, winTo ;
       Color boardColor =  Color.black ;
       Color playerColor = new Color(191,62,255) ;
       Color computeColor = new Color(255,127,36) ;
       Integer lines[][]   = new Integer[9][4]   ;
       int frame = 0 ;
       int animateFrom , animateTo ;
       double animateSize ;
       int noFrames =  20 ;
       Color animateColor ;
       Color ToColor ;
       Thread relaxer ;
       Node poston[] = new Node[9] ; 
       Node counter [] = new Node[9] ;
       GamePanel(Star game) {
         this.game = game ;
	 addMouseListener(this);
	 addMouseMotionListener(this);
	 d = game.getSize() ;
         
	 center = new DPoint(((double)d.width)/2.0, ((double)d.height)/2.0 -20.0) ;
         //Define each of the posistions as poston
	 double angle = Math.PI/6.0 ;
	 double radius = ((double)d.width) * 0.4 ;
	 double size =  radius * 0.1 ;
	 boardColor = Color.black ;
	 for (int i = 0 ; i <= 5 ; i++){
	   poston[i] = new Node() ;
	   poston[i].x = center.x + (radius * Math.sin(angle)) ;
	   poston[i].y = center.y - (radius * Math.cos(angle)) ;
	   poston[i].color =  boardColor;
	   poston[i].r = size ;
	   angle = angle + ((1.0/3.0) * Math.PI) ;
         }
	 angle = 0.0 ;
	 radius = 0.6 * radius ;
         for ( int i = 6 ; i <= 8 ; i++ ) {
           poston[i] = new Node() ;
	   poston[i].x = center.x + (radius * Math.sin(angle)) ;
	   poston[i].y = center.y - (radius * Math.cos(angle)) ;
	   poston[i].color =  boardColor;
	   poston[i].r = size ;
	   angle = angle + ((2.0/3.0) * Math.PI) ;
	 }
	 // Now set up the counters .
	 for (int i = 0 ; i <= 8 ; i++) {
	   counter[i] = new Node() ;
	   counter[i].x = poston[i].x ;
           counter[i].y = poston[i].y ;
	   counter[i].color = null ;
	   counter[i].r = 2.0 * size ;
         }
	 // Now add the winning lines
	 lines[0][0] = new Integer(6) ; 
	 lines[0][1] = new Integer(4) ;
	 lines[0][2] = new Integer(7) ;
	 lines[0][3] = new Integer(2) ;
	 
         lines[1][0] = new Integer(6) ; 
	 lines[1][1] = new Integer(5) ;
	 lines[1][2] = new Integer(7) ;
	 lines[1][3] = new Integer(3) ;
	 
         lines[2][0] = new Integer(7) ; 
	 lines[2][1] = new Integer(0) ;
	 lines[2][2] = new Integer(8) ;
	 lines[2][3] = new Integer(4) ;
	
         lines[3][0] = new Integer(7) ; 
	 lines[3][1] = new Integer(1) ;
	 lines[3][2] = new Integer(8) ;
	 lines[3][3] = new Integer(5) ;

         lines[4][0] = new Integer(8) ; 
	 lines[4][1] = new Integer(2) ;
	 lines[4][2] = new Integer(6) ;
	 lines[4][3] = new Integer(0) ;

	 lines[5][0] = new Integer(6) ; 
	 lines[5][1] = new Integer(1) ;
	 lines[5][2] = new Integer(8) ;
	 lines[5][3] = new Integer(3) ;
	 
         lines[6][0] = new Integer(5) ; 
	 lines[6][1] = new Integer(1) ;
	 lines[6][2] = new Integer(0) ;
	 lines[6][3] = new Integer(4) ;
	 
         lines[7][0] = new Integer(1) ; 
	 lines[7][1] = new Integer(3) ;
	 lines[7][2] = new Integer(2) ;
	 lines[7][3] = new Integer(0) ;
	
         lines[8][0] = new Integer(2) ; 
	 lines[8][1] = new Integer(4) ;
	 lines[8][2] = new Integer(3) ;
	 lines[8][3] = new Integer(5) ;
     }


       Image offscreen ;
       Dimension offscreensize ;
       Graphics offgraphics ;
       Node animateNode = new Node() ;

       public synchronized void update(Graphics g) {
	 d = game.getSize() ;
	 frame++ ;
         if ((offscreen == null) || ( d.width != offscreensize.width ) 
	                          || (d.height != offscreensize.height)) {
	    offscreen = createImage(d.width,d.height);
	    offscreensize = d ;
	    offgraphics = offscreen.getGraphics();
	 }
	 offgraphics.setColor(getBackground());
	 offgraphics.fillRect(0,0,d.width,d.height);

         int j ;
         
         for (int  i = 0 ; i <= 5 ; i++) {
	   j = (i+2)%6 ;
	   joinNodes(offgraphics,poston[i],poston[j],boardColor,5) ;
	 }
	 if ( frame <= 0 ) {
	    counter[animateTo].color = null ;
	    counter[animateFrom].color = null ;
	    animateNode = slideNode(counter,animateFrom,animateTo,-1 * frame) ;
	    animateNode.r = animateSize ;
	    animateNode.color = animateColor ;
         }
	 if ( frame == 0 ) {
	    counter[animateTo].color = ToColor ;
	    animateNode.color = null ;
	    winner = aWinner() ;
         }
	 
	 for ( int i = 0 ; i <= 8 ; i++) 
           drawNode(offgraphics,poston[i]) ;
	 for ( int i = 0 ; i <= 8 ; i++ ) {   
	   drawNode(offgraphics,counter[i]) ;
	   //
           offgraphics.setColor(Color.red) ;
           //offgraphics.drawString("Node "+i,(int)poston[i].x,(int)poston[i].y) ;
           //
         }
	 if ( frame < 0 ) {
           drawNode(offgraphics,animateNode) ;
	 }
	 if ( ( winner != null ) && ( frame > 0 ) ){
	   turn = null;
           joinNodes(offgraphics, poston[winFrom],poston[winTo],Color.red,10) ;
	 }

	 g.drawImage(offscreen, 0 , 0 , null );
       }
       public Node slideNode(Node n[], int from , int to , int frame ) {
         Node m = new Node() ;
	 int no ;
	 double dx,dy ;
	 no = noFrames - frame ;
	 dx = (n[to].x - n[from].x)/(double)noFrames ;
	 dy = (n[to].y - n[from].y)/(double)noFrames ;
	 m.x = n[from].x + ((double)no * dx) ;
	 m.y = n[from].y + ((double)no * dy) ;
	 return(m) ;

       }
       public void drawNode(Graphics g, Node n) {
          int x, y, diameter ;
	  if ( n.color != null ) {
            x = (int)( n.x - n.r + 1.0 ) ;
            y = (int)( n.y - n.r + 1.0 )  ;
            diameter = (int)( n.r + n.r + 1.0 ) ;
            g.setColor(n.color) ;
            g.fillOval(x,y,diameter,diameter);
          }
       }
       public void joinNodes(Graphics g,Node n, Node m,Color boardColor,int width) {
	  int x1,y1,x2,y2 ;
          double h ;
	  double  down, right ;
	  Polygon poly  = new Polygon() ;
	  h = Math.pow(m.x - n.x, 2.0 ) + Math.pow(m.y - n.y, 2.0 ) ;
	  h = Math.sqrt(h) ;
	  down = width * Math.cos((m.x - n.x)/h) ;
	  right = width * Math.sin((m.y - n.y)/h) ;
	  poly.addPoint((int)(m.x + right ),(int)(m.y + down)) ;
	  poly.addPoint((int)(m.x - right ),(int)(m.y - down)) ;
	  poly.addPoint((int)(n.x - right ),(int)(n.y - down)) ;
          poly.addPoint((int)(n.x + right ),(int)(n.y + down)) ;
          g.setColor(boardColor) ;
	  //g.drawLine(x1,y1,x2,y2) ;
	  g.fillPolygon(poly) ;
       }
       int nodeSelected = -1 ;
       public void mousePressed(MouseEvent e) {
         int x = e.getX() ;
	 int y = e.getY() ;
	 if ( ( turn == "player" )
	      && ( numberCounters(counter, 9 , playerColor) >= 4 )
	      && ( insideNode(counter , 9 , x , y ,playerColor ) != -1 )
	      && ( frame > 0 )){
	         nodeSelected = insideNode(counter,9,x,y,playerColor) ;
         }
	 repaint();
	 e.consume() ;
       }
       public void mouseDragged(MouseEvent e) {
         int x = e.getX() ;
	 int y = e.getY() ;
	 if ( nodeSelected != -1 ) {
           counter[nodeSelected].x = (double)x ;
	   counter[nodeSelected].y = (double)y ;
         }
	 repaint() ;
	 e.consume() ;
       }
       public void mouseReleased(MouseEvent e) {
         int x = e.getX() ;
	 int y = e.getY() ;
	 int to ;
	 if ( nodeSelected != -1 ) {
            if ( insideNode(counter,9,x,y, null ) != -1 ) {
	       to = insideNode(counter, 9 , x, y, null ) ;
	       counter[to].color = playerColor ;
	       counter[nodeSelected].x = poston[nodeSelected].x ;
	       counter[nodeSelected].y = poston[nodeSelected].y ;
	       counter[nodeSelected].color = null ;
	       winner = aWinner() ;
	       if ( winner == null ) {
	         turn = "computer" ;
	         computersTurn() ;
               }
            }
	    else {
	      counter[nodeSelected].x = poston[nodeSelected].x ;
	      counter[nodeSelected].y = poston[nodeSelected].y ;
            }
	 }
	 nodeSelected = -1 ;
	 repaint() ;
	 e.consume() ;
       }
       public Color  aWinner() {
	   int first , second  ;
           for ( int i = 0 ; i <= 9 - 1 ; i++ ) {
             if ( counter[i].color != null ) {
               for (int j = 0 ; j <= 3 ; j=j+2) {
	         first = lines[i][j].intValue() ;
		 second = lines[i][j+1].intValue() ;
                 if ( (counter[i].color == counter[first].color ) 
		       && ( counter[i].color == counter[second].color )) {
                   if ( i >= 6 ) {
		     winFrom = first ;
		     winTo = second ;
                   }
		   if ( first >= 6 ) {
		     winFrom = i ;
		     winTo  = second ;
                   }
		   if ( second >= 6 ) {
		     winFrom = i ;
		     winTo  = first ;
                   }

		   return(counter[i].color) ;
                    
		 }
	       }
	     }
	   }
           return(null) ;
       }
       public void mouseClicked(MouseEvent e) {
          int x = e.getX() ;
	  int y = e.getY() ;
	  int iselect ;
	  if ( ( turn == "player" ) 
              && ( numberCounters(counter, 9, playerColor) < 4)
	      && (  insideNode(counter, 9 , x, y, null) != -1 )
	      && ( frame > 0 )) {
	        iselect = insideNode(counter, 9 , x, y, null) ;
                counter[iselect].color = playerColor ;
		repaint();
		winner = aWinner() ;
		if ( winner == null ) {
		  turn = "computer" ;
                  computersTurn() ;
                }
	  }
	  else 
	    repaint() ;
	  e.consume() ;
	  repaint() ;
       }
       
       public void run() {
         Thread me = Thread.currentThread();
	 while (relaxer == me) {
	   relax();
	   try {
	     Thread.sleep(100);
             } catch (InterruptedException e) {
	       break ;
           }
         }
       }      

       
       public void computersTurn() {
	   int layed,to = -1 ;
	   int from ;
	   layed = numberCounters(counter,9,computeColor) ;
	   if ( layed <= 3 ) {
              to = selectEntry() ;
	      counter[to].color = computeColor ;
              animateFrom = to ;
	      animateTo   = to ;
	      animateColor = boardColor ;
	      ToColor      = computeColor ;
	      animateSize = poston[to].r ;
	      frame = (-1 * noFrames)/2 ;

	   }
	   if ( layed >= 4 ) {
	       for ( int i = 0 ; i <= 9-1 ; i++) {
	         if ( counter[i].color == null ) {
		   to = i ;
                 }
               }
	       
	       from = selectToMove() ;
	       animateFrom = from ;
	       animateTo = to ;
	       animateColor = computeColor ;
	       ToColor = computeColor ;
	       animateSize = counter[from].r ;
	       frame = -1 * noFrames ;
	   }
	   winner = aWinner() ;
           if ( winner == null )
	        turn = "player" ;
	   repaint() ;
       }
       public int selectToMove() {
	  boolean canwin ;
	  int from = -1  ;
	  int first,second ;
          canwin = false ;
          for ( int i = 0 ; i <= 9 - 1 ; i++ ) {
	    if ( counter[i].color == computeColor ) {
                for ( int j = 0 ; j <= 3 ; j=j+2 ) {
                   first = lines[i][j].intValue() ;
		   second = lines[i][j+1].intValue() ;
		   if ( (counter[first].color == playerColor )
		        && (counter[second].color == playerColor ) ){
                      canwin = true ;
		      
                   }
		}
		if ( canwin == false ) {
		  from = i ;
                }
	    }
	  }
	  if ( from == -1 ){  // Play randomley then
	    from = selectPlace(counter,9,computeColor);
          }
          return(from) ;
       }
       public int selectEntry() {
          int to = -1 ;
	  int first , second ;
          for ( int i = 0 ; i <= 9 - 1 ; i++ ) {
	     if ( counter[i].color == null ) {
	       for ( int j = 0 ; j <= 3 ; j = j + 2 ) {
                 first  = lines[i][j].intValue() ;
	         second = lines[i][j+1].intValue() ;
	         if ( ( counter[first].color == playerColor )
	                 && ( counter[second].color == playerColor ) ) {
		         return(i) ;
                 }
	       }
            }
          }
	  if ( to == -1 ) 
	    to =  selectPlace(counter , 9 , null) ;
	  return (to ) ;
       }
       public int selectPlace(Node n[], int number , Color color) {
          int count = 0 ;
	  int choose ;
	  for ( int i = 0 ; i <= 9 - 1 ; i++ ) {

	  }


           // So play randomley 
           for ( int i = 0 ; i <= number - 1 ; i++ ) {
             if ( n[i].color == color ) {
	       count++ ;
             }
	   }
	   choose = (int)((double)count * Math.random()) ;
	   choose++ ;
	   count = 0 ;
           for ( int i = 0 ; i <= number - 1 ; i++ ) {
             if ( n[i].color == color ) {
	       count++ ;
	     }
             
	     if ( count == choose ) 
	       return ( i ) ;
	   }
	   return (-1) ;
       }

       public int  insideNode(Node n[], int number,  int a, int b, Color color ){
          double x = (double)a;
	  double y = (double)b;
	  double r ;
          double distance, dx, dy ;
	  double maximum ;
	  for ( int i = 0 ; i <= number - 1 ; i++ ) {
	    r = 1.3 * n[i].r ;
            maximum = ( r * r ) ;
            dx = x - n[i].x ;
	    dy = y - n[i].y ;
	    distance = (dx * dx ) + (dy * dy) ;
	    if ( (distance <= maximum) && (n[i].color == color) )
	       return (i) ;
          }
	  return(-1) ;
       }


       public int numberCounters ( Node[] counter, int number , Color color ) {
         int total = 0  ;
	 for ( int i = 0 ; i <= number - 1 ; i++ ) {
	   if ( counter[i].color == color ) {
	     total++ ;
           }
         }
         return(total) ;
       }
       public void mouseEntered(MouseEvent e) {
       }
       public void mouseExited(MouseEvent e) {
       }
       
       public void mouseMoved(MouseEvent e) {
       }

       public void start() {
          for (int i = 0 ; i <= 8 ; i++ )
	    counter[i].color = null ;
          winner = null ;
	  if ( turn == "computer" ) { 
	     computersTurn() ;
	     turn = "player" ;
          }
          
          relaxer = new Thread(this);
	  relaxer.start() ;
       }
       public void stop() {
          relaxer = null ;
       }

     
       synchronized void relax(){
          repaint();
       }
}

public class Star extends Applet implements ActionListener, ItemListener {
      GamePanel game ;
      Panel buttonPanel ;
      Color backgroundColor = new Color(0,255,255) ;
      String turn = "player" ;
      Button startAgain ;
      
      Choice whoFirst ;
      public void init() {
         setLayout(new BorderLayout()) ;
         setBackground(backgroundColor) ;

         // Create the Button Panel at the foot
	 buttonPanel = new Panel() ;
	 buttonPanel.setBackground(Color.blue) ;
            // Add a start Again Button 
	 startAgain = new Button("Start Again") ;
	 startAgain.setBackground(Color.white) ;
         startAgain.addActionListener(this) ;
         buttonPanel.add(startAgain) ;
	 add("South",buttonPanel) ;
            // Add a Who First Switch 
         whoFirst = new Choice() ;
	 whoFirst.setBackground(Color.white) ;
	 whoFirst.addItem("You play first") ;
	 whoFirst.addItem("Computer plays first") ;
         whoFirst.addItemListener(this);
	 buttonPanel.add(whoFirst) ;

	 // Create the Game Panel
         game = new GamePanel(this) ;
	 game.turn = "player" ;
         add("Center",game) ;

      }
      public void start() {
        game.start() ;
      }
      public void stop() {
        game.stop() ;
      }
      public void destroy() {
        remove(game);
      }
      public void itemStateChanged(ItemEvent e){
        Object src = e.getSource() ;
	int iselected ;
	if ( src == whoFirst ) {
	  iselected = whoFirst.getSelectedIndex();
	  if ( iselected == 0 )
	    turn = "player" ;
          else 
	    turn = "computer" ;
        }
	return ;
      }
      public void actionPerformed(ActionEvent e) {
        int iselected ;
        Object src = e.getSource() ;
	if ( src == startAgain ) {
	  game.stop() ;
	  
          iselected = whoFirst.getSelectedIndex();
	  if ( iselected == 0 )
	    turn = "player" ;
          else 
	    turn = "computer" ;
	  game.turn = turn ;
          game.start() ;
        }
      }
}

