Check out Modern Chess, our featured variant for January, 2025.

Pixelpusher - sourcecode


// Copyright by Hans Bodlaender and Eli Bachmutsk (c) 1998.
// Non-commercial or educational use permitted. 

import java.awt.*;
import java.net.*;

public class ChessCanvas extends  java.applet.Applet 
{
  // 0     = empty square  
  // 1,2   = white & black king         3,4   = white & black queen
  // 5,6   = white & black rook         7,8   = white & black knight
  // 9,10  = white & black bishop       11,12 = white & black pawn
  Image img[] = new Image[13];   // Piece images - null as default
  int board [][]; // position (i,j)  (a1 = 0,0; b3= 2,3; h8 = 7,7, etc.)
  ChessMoveChecker control;
  int sqsize = 32;               // square size in pixels
  int rows = 8, columns = 8 ;    // Number of rows and columns on the board 
  int rowClicked, colClicked;    // Clicked row & column,-1 if not clicked
  int computercolor = 1;         // Computer always played black
  int moveNumber;
  String setup = "rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR" ; // Board setup
  Panel links;
  MediaTracker tracker = new MediaTracker(this);
  String version = "PIXELPUSHER V0.3";
  TextField ta = new TextField(50);

  public void init()
  {
    reset();
    resize  (sqsize*columns, sqsize*rows+40); // + TextArea on south
    links   = new Panel();
    links.setLayout( new BorderLayout ());
    setLayout( new BorderLayout ());
    add ("West", links);
    LoadImages();
          // Area for messages
    ta.setFont( new Font ("Helvetica", Font.BOLD, 12)); 
    ta.setEditable(false);  
    ta.setBackground( Color.white);  
    add("South", ta);
  }
 public void reset ()
  {     moveNumber = 0;
        rowClicked = -1;
        board   = new int [columns][rows];         // default is 0 - empty
        ForsytheToBoard();
        control =  new ChessMoveChecker(this);
        ta.setText(version);
  }
 public void setText (String text) { ta.setText(moveNumber+". "+text);}
 public boolean mouseDown (Event e, int x, int y) 
  {     
        if (e.modifiers != 0)       // right mouse button - reset 
              reset();
         else 
              clickProcessing ( x/sqsize, rows - y/sqsize - 1);
        repaint();
        return true;
 }
 void clickProcessing (int i, int j)    // i - column, j - row
 {
  if (rowClicked == -1) // First click : from where the player should move ?
   {
     if ( (board[i][j] > 0) &&  control.RightPlayer(i,j)) // not empty and ...
       { colClicked = i;
         rowClicked = j;
       }
   }else // Second click : to which squre player should move
   {
     if (i == colClicked && j == rowClicked)
          rowClicked = -1; // if clicked on same square, clicking undone
     else if ( control.LegalMove   (colClicked,rowClicked,i,j) &&
               control.RightPlayer (colClicked,rowClicked) )
        { 
          control.DoMove (colClicked,rowClicked,i,j);
          rowClicked = -1;
	  MakeComputerMove();
        }
   }
 }
 public void paint (Graphics g)
 {
    for (int i = 0; i<columns ; i++)
     for (int j = 0; j<rows ; j++)
            drawsquare (g,i,j);     // draw colored square
    for (int i = 0; i<columns ; i++)
      for (int j = 0; j<rows ; j++)
            drawpiece (g,i,j);      // draw pieces
 }
 public void drawsquare (Graphics g,int i,int j) 
  {       // draw color square at the beginning
     Color c = ((i+j) % 2 == 0) ? Color.gray : Color.yellow;
     if (i==colClicked && j==rowClicked)  c = Color.red ;
     g.setColor(c);
     g.fillRect(i*sqsize, (rows-j-1)* sqsize, sqsize, sqsize);
  }
 public void drawpiece (Graphics g,int i,int j) // drawpiece on position (i,j)
  {       
     Image image = img [ board [i][j] ];
     if (image != null) 
        g.drawImage (image, i*sqsize, (rows-j-1)*sqsize,sqsize,sqsize,this); 
  }
 public void LoadImages ()
  { String inames[] = { "kingw","kingb","queenw","queenb","rookw","rookb",
                     "knightw","knightb","bishopw","bishopb","pawnw","pawnb"};
   for (int i=0; i< 12; i++)
      try { img[i+1] = getImage(new URL(getDocumentBase(),inames[i]+".gif"));
            tracker.addImage( img[i+1], 0);
      } catch (Exception e){}
   try {tracker.waitForAll();} catch (Exception e) {}; // Wait to image loading
 }
 public void ForsytheToBoard () // Gets a board string in Forsythe notation 
 {
  int x = 0, y = rows-1;
  for( int place = 0; place < setup.length(); place++) 
   { char c = setup.charAt(place);
     if      (c == '/')          {x=0; y--;}
     else if (x<columns && y>-1) {board[x][y]=" KkQqRrNnBbPp".indexOf(c);x++;}
   }
 }
 public void MakeComputerMove()
 {
  moveNumber++;
  setText("Black move");
  Move computermove = ComputerPlayer.findmove(control,computercolor);
  if (!computermove.isvoid())	    control.DoMove(computermove);

 if(control.Mated(1-computercolor))          setText("BLACK WIN: MATE!!!");
 else if(control.InCheck(1-computercolor))   setText("White in check!!!"); 
 else if(control.Stalemated(1-computercolor))setText("STALEMATE !!!");
 else if(control.Mated(computercolor))       setText("WHITE WIN: MATE!!!"); 
 else if(control.Stalemated(computercolor))  setText("STALEMATE  !!!");
 else                                        setText("White move");
 }
}
///////////////////////////////////////////////////////////////////////
class Move
{
  public int startrow, endrow, startcol, endcol;
  Move()
  {  startrow = endrow = startcol = endcol = 0; }
  Move(int k1, int r1, int k2, int r2)
  {  startcol = k1; startrow = r1; endcol = k2; endrow = r2;  }
  boolean isvoid()   // Return true if void move (all zeros)
  {  return (startrow+endrow+startcol+endcol)==0 ?  true : false; }
}
///////////////////////////////////////////////////////////////////////
class ComputerPlayer
{
 static int plydepth=2;
 // Overloading: findmove tries to find the best move for given position
 // ChessMoveChecker and Move: evaluate how good this particular move is.
 public static Move findmove (ChessMoveChecker position, int player)
 {
  Move themove = new Move();
  int bestmove = -50000;
  for (int i1=0; i1< position.columns; i1++)
   for (int j1=0; j1 <  position.rows; j1++)
    if (!position.EmptySquare(i1,j1))
     if (position.PieceOwner(i1,j1)==player)
      for (int i2=0; i2< position.columns; i2++)
       for (int j2=0; j2< position.rows; j2++)
	if (position.SemiLegalMove(i1,j1,i2,j2))
	{
          ChessMoveChecker aftermove = new ChessMoveChecker(position);
          aftermove.DoMove(i1,j1,i2,j2);
          if ( aftermove.InCheck(player) ) continue;
          int tryevaluate = Evaluate(aftermove,plydepth -1);
          if (tryevaluate > bestmove)
          {   themove = new Move(i1,j1,i2,j2); 
              bestmove = tryevaluate;
          }
        }
  return themove;
 }
 // This one gives a value for the player that moved to this position.
 static int Evaluate (ChessMoveChecker position, int plies)
 {
  if (plies <=0) return Evaluate(position);
  int otherplayer = 1-position.lastplayermoved;
    // what is the best move for the other player?
  int bestmove = -50000;
  for (int i1=0; i1<position.columns; i1++)
   for (int j1=0; j1 < position.rows; j1++)
    if (!position.EmptySquare(i1,j1))
     if (position.PieceOwner(i1,j1)==otherplayer)
      for (int i2=0; i2<position.columns; i2++)
       for (int j2=0; j2<position.rows; j2++)
	if (position.SemiLegalMove(i1,j1,i2,j2))
	{
          ChessMoveChecker aftermove = new ChessMoveChecker(position);
          aftermove.DoMove(i1,j1,i2,j2);
          if ( aftermove.InCheck(otherplayer) ) continue;
          int tryevaluate = Evaluate(aftermove,plies -1);
          if (tryevaluate > bestmove)
              bestmove = tryevaluate;
        }
  return 1-bestmove;
 }
 static int Evaluate (ChessMoveChecker position)
 {
   int otherplayer = 1- position.lastplayermoved;
   if (position.Mated(otherplayer))      return 50000; // Mate : value is high
   if (position.Stalemated(otherplayer)) return 0; // Stalemate : draw is zero
       //compute the difference in value of the pieces
   int totvalue = diffvalueofpieces(position,1-otherplayer);
   int ran = 1+ (int) (Math.random() * 10);  // Random from 1 to 10
   return ran + 10*totvalue;
 }
 // what is the value of the pieces of player minus the value of its opponent?
 static int diffvalueofpieces (ChessMoveChecker position, int player)
 {
   int totvalue = 0;
   for (int k=0; k<position.columns; k++)
    for (int r=0; r<position.rows;r++)
     if (!position.EmptySquare(k,r))
     {
      if (position.PieceOwner(k,r)==player)
       totvalue += PieceValue(position.board[k][r]);
      else
       totvalue -= PieceValue(position.board[k][r]);
     }
   return totvalue;
 }
 static int PieceValue(int piece) // give value of piece, notated as integer
 {  switch (piece)
    {
     default:          return 0;
     case 1: case 2:   return 1000; // king. Who cares what value he gets.
     case 3: case 4:   return 80;   // queen
     case 5: case 6:   return 50;   // rook
     case 7: case 8:   return 30;   // knight
     case 9: case 10:  return 30;   // bishop
     case 11: case 12: return 10;   // pawn
    }
 }
}
////////////////////////////////////////////////////////////////////////////
class ChessMoveChecker
{
  int[][] board;
  static int rows, columns;
  static int kingcol = 4; // position that king starts(for castling)
       // booleans that tell which player may castle;
  boolean whiteshortcastling, blackshortcastling;
  boolean whitelongcastling,  blacklongcastling;
  int lastplayermoved; // Which player moved last : 0 - white, 1 - black
  Move lastmove;

// Constructor method
ChessMoveChecker (ChessCanvas hetboard)
  {
    board   = hetboard.board;    // Copy pointer, not board itself
    rows    = hetboard.rows;
    columns = hetboard.columns;
        // Sets the booleans whether one can castle.
    whiteshortcastling  = blackshortcastling  = true;
    whitelongcastling   = blacklongcastling   = true;
        // As white starts, that would correspond to black playing last
    lastplayermoved  = 1;
    lastmove = new Move();
}
// 2nd constructor method: copies parent's board
ChessMoveChecker (ChessMoveChecker tocopy)
{
    whiteshortcastling = tocopy.whiteshortcastling;
    blackshortcastling = tocopy.blackshortcastling;
    whitelongcastling  = tocopy.whitelongcastling;
    blacklongcastling  = tocopy.blacklongcastling;
        // As white starts, that would correspond to black playing last
    lastplayermoved  = tocopy.lastplayermoved;
    lastmove = new Move ( tocopy.lastmove.startcol, tocopy.lastmove.startrow,
                          tocopy.lastmove.endcol,   tocopy.lastmove.endrow);   
        // Initiate current board according to parent board
    board = new int[columns][rows];
    for (int i = 0; i< columns; i++)
      for (int j=0; j< rows; j++)
       board[i][j]=tocopy.board[i][j];
}
// Does move from (k1, r1) to (k2, r2) is legal ?
public boolean LegalMove (int k1, int r1, int k2, int r2)
  {
     if (!SemiLegalMove  (k1,r1,k2,r2))    return false;
     if (InCheckAfterMove(k1,r1,k2,r2))    return false;
     return true;
  }
// A move is SemiLegal if it is legal without looking for check
public boolean SemiLegalMove (int k1, int r1, int k2, int r2)
  {
    if (k1 == k2 && r1 == r2)                return false;
    if (TakingPieceOfSameColor(k1,r1,k2,r2)) return false;
    switch (board[k1][r1]) 
    {
      case 0:            return false;
      case 1:            return LegalWhiteKingMove (k1,r1,k2,r2);
      case 2:            return LegalBlackKingMove (k1,r1,k2,r2);
      case 3:  case 4:   return LegalQueenMove     (k1,r1,k2,r2);
      case 5:  case 6:   return LegalRookMove      (k1,r1,k2,r2);
      case 7:  case 8:   return LegalKnightMove    (k1,r1,k2,r2);
      case 9:  case 10:  return LegalBishopMove    (k1,r1,k2,r2);
      case 11:           return LegalWhitePawnMove (k1,r1,k2,r2);
      case 12:           return LegalBlackPawnMove (k1,r1,k2,r2);
    }
    return true;
  }
boolean LegalWhiteKingMove (int k1,int r1, int k2, int r2)
{     // check on castling.
  if (k1==kingcol && k2==kingcol+2 && r1==0 && r2==0)
    return LegalWhiteShortCastling();
  if (k1==kingcol && k2==kingcol-2 && r1==0 && r2==0)
    return LegalWhiteLongCastling();
  return LegalKingMove(k1,r1,k2,r2);
}
boolean LegalBlackKingMove (int k1,int r1,int k2,int r2)
{     // check on castling.
  if (k1==kingcol && k2==kingcol+2 && r1==rows-1 && r2==rows-1)
    return LegalBlackShortCastling();
  if (k1==kingcol && k2==kingcol-2 && r1==rows-1 && r2==rows-1)
    return LegalBlackLongCastling();
  return LegalKingMove(k1,r1,k2,r2);
}
boolean LegalKingMove (int k1,int r1,int k2,int r2)
{
   return ( (k1-k2)*(k1-k2) <=1 && (r1-r2)*(r1-r2) <= 1);
}
boolean LegalRookMove (int k1, int r1, int k2, int r2)
{
   if ( k1 == k2 )
   {  for (int i= Math.min(r1,r2)+1; i < Math.max(r1,r2); i++)
          if ( !EmptySquare(k1,i)) return false;
      return true;
   }
   else if (r1 == r2)
   {  for (int i= Math.min(k1,k2)+1; i < Math.max(k1,k2); i++)
          if ( !EmptySquare(i,r1)) return false;
      return true;
   }
   else return false;
}
boolean LegalKnightMove (int k1, int r1, int k2, int r2)
{
  return ( Math.abs((k1-k2)*(r1-r2)) ==2 ) ? true : false ; 
}
boolean LegalBishopMove (int k1, int r1, int k2, int r2)
{
   if ( Math.abs(k1-k2) == Math.abs(r1-r2) )
   {
     int kstep = (k1 < k2) ? 1 : -1;
     int rstep = (r1 < r2) ? 1 : -1;
     int i=k1+kstep; 
     int j=r1+rstep;
     while ( i != k2 )
     {
       if (!EmptySquare(i,j)) return false;
       i += kstep;
       j += rstep;
     }
     return true;
   }
   return false;
}
boolean LegalQueenMove (int k1, int r1, int k2, int r2)
{
   return (LegalRookMove(k1,r1,k2,r2) || LegalBishopMove(k1,r1,k2,r2));
}
boolean LegalWhitePawnMove (int k1, int r1, int k2, int r2)
{  
   boolean taking = (board[k2][r2] == 0 ) ? false : true;
   if (taking == true && r2 == r1 + 1 && ( (k1 == k2 +1) || (k1 == k2 -1)))
        return true;
   else if (taking == false && (r2 == r1 + 1) && k1 == k2)
	return true;
   else if (taking == false && r1 == 1 && r2 == 3 && k1 == k2 &&
	    board[k1][2] == 0 )
        return true; // white double pawn step
   else if (LegalWhitePawnEnPassantCapture (k1, r1, k2, r2))
        return true;
   return false;
}
boolean LegalBlackPawnMove (int k1, int r1, int k2, int r2)
{
  boolean taking = (board[k2][r2] == 0 ) ? false : true;
  if (taking == true && r2 == r1 - 1 && ( (k1 == k2 +1) || (k1 == k2 -1)))
        return true;
   else if (taking == false && r2 == r1 - 1 && k1 == k2)
	return true;
   else if (taking == false && r1 == rows-2 && r2 == r1-2 && k1 == k2 &&
	    board[k1][r1-1] == 0 )
        return true;  // black double pawn step
   else if (LegalBlackPawnEnPassantCapture (k1, r1, k2, r2))
        return true;
   return false;
}
public boolean LegalWhitePawnEnPassantCapture (int k1, int r1, int k2, int r2)
{
  if (board[k1][r1] != 11)  return false;  // white pawn on starting square
  if (board[k2][r2] != 0 )  return false;  // go to empty square
  // check if opponent made a pawn double step on destination column
  if (lastmove.startcol != k2) return false;
  if (lastmove.endcol != k2)   return false;
  if (lastmove.startrow != lastmove.endrow +2) return false;
  if (board[lastmove.endcol][lastmove.endrow] != 12) return false;
  if (r1 != rows-4) return false;
  if (r2 != rows-3) return false;
  if (Math.abs(k1-k2) != 1) return false;
  return true;
}
public boolean LegalBlackPawnEnPassantCapture (int k1, int r1, int k2, int r2)
{
  if (board[k1][r1] != 12)  return false;  // white pawn on starting square
  if (board[k2][r2] != 0 )  return false;  // go to empty square
  // check if opponent made a pawn double step on destination column
  if (lastmove.startcol != k2) return false;
  if (lastmove.endcol != k2)   return false;
  if (lastmove.startrow != lastmove.endrow -2)  return false;
  if (board[lastmove.endcol][lastmove.endrow] != 11) return false;
  if (r1 != 3)  return false;
  if (r2 != 2)  return false;
  if (Math.abs(k1-k2) != 1) return false;
  return true;
}
boolean EmptySquare (int col, int row) // tests if square (col,row) is empty
{
  return (board[col][row] == 0) ? true : false;
}
// true if one tries to take a piece of the same color
boolean TakingPieceOfSameColor (int k1, int r1, int k2, int r2)
{
   if (EmptySquare (k2,r2)) return false;
   return ( (board[k1][r1] % 2) == (board[k2][r2] % 2)) ? true : false ;
}
// Methods about castling
void ChangeCastlingStatus (int k1, int r1, int k2, int r2)
{    // if a square moves from a corner, one type of castling is never
     // possible anymore.
   if (k1==0 && r1 == 0)             whitelongcastling  = false;
   if (k1==columns-1 && r1 == 0)     whiteshortcastling = false;
   if (k1==0 && r1 == rows-1)        blacklongcastling  = false;
   if (k1==columns-1 && r1 ==rows-1) blackshortcastling = false;
   if (board[k1][r1] == 1) // white king moves
       whitelongcastling  = whiteshortcastling = false;
   if (board[k1][r1] == 2) // black king moves
       blacklongcastling  = blackshortcastling = false;
}
boolean LegalWhiteShortCastling()   // Is it legal for white to castle short?
{
  if (InCheck(0)) return false;
  for (int i= kingcol + 1; i < columns -1; i++)
    if (!EmptySquare(i,0) || Attacked(1,i,0))   return false;
  return whiteshortcastling;
}
boolean LegalWhiteLongCastling()    // is it legal for white to castle long?
{
  if (InCheck(0)) return false;
  for (int i= kingcol - 1; i >0; i--)
    if (!EmptySquare(i,0) || Attacked(1,i,0))    return false;
  return whitelongcastling;
}
boolean LegalBlackLongCastling()   // is it legal for black to castle long?
{
  if (InCheck(1)) return false;
  for (int i= kingcol - 1; i >0; i--)
    if ( !EmptySquare(i,rows-1) || Attacked(0,i,rows-1) )  return false;
  return blacklongcastling;
}
boolean LegalBlackShortCastling()  // is it legal for black to castle short?
{
  if (InCheck(1)) return false;
  for (int i= kingcol + 1; i < columns -1; i++)
    if (!EmptySquare(i,rows-1) || Attacked(0,i,rows-1))   return false;
  return blackshortcastling;
}
// Determine if the move is a pawn promotion.
boolean DeterminePawnPromotion (int k1, int r1, int k2, int r2)
{
  if (board[k1][r1]==11 && r2 == rows-1)  return true;
  if (board[k1][r1]==12 && r2 == 0)       return true;
  return false;
}
public void SetLastPlayerMoved(int i)
{ 
  lastplayermoved = i;
}
// returns the owner of the piece on square (k,r)
public int PieceOwner(int k, int r)
{
   return 1- (board[k][r] %2) ; // 0 if white owns the piece,1-if black
}
// checks if the right player wants to make a move
public boolean RightPlayer(int k1, int r1)
{
   return (PieceOwner(k1,r1) != lastplayermoved);
}
// Checks if player is in check
boolean InCheck (int player)
{     // first find the king piece of the player.
  int kingpiece = 1 + player;
  for (int k=0; k< columns; k++)
    for (int r=0; r < rows; r++)
       if (board[k][r]==kingpiece)
	 // crude: check if any piece could move to the kings position
	 for (int k2=0; k2<columns; k2++)
	   for (int r2=0; r2<rows; r2++)
	     if (! EmptySquare(k2,r2))
	       if (SemiLegalMove(k2,r2,k,r)) 
		 return true;
  return false;
}
// has player a semilegal move that attacks (k,r)
boolean Attacked (int player, int k, int r)
{  
 for (int k2=0; k2 < columns; k2++)
   for (int r2=0; r2 < rows; r2++)
     if (! EmptySquare(k2,r2) && (PieceOwner(k2,r2)== player))
	   if (SemiLegalMove(k2,r2,k,r))
	      return true;
 return false;
}
boolean InCheckAfterMove (int k1, int r1, int k2, int r2)
{
  ChessMoveChecker aftermove = new ChessMoveChecker(this);
  aftermove.DoMove(k1,r1,k2,r2);
  return aftermove.InCheck( PieceOwner(k1,r1) );
}
void DoMove (Move m)
  {     DoMove(m.startcol,m.startrow,m.endcol,m.endrow); }
void DoMove (int k1, int r1, int k2, int r2)
{
     // First determine if this is a promotion move
   boolean promotion = DeterminePawnPromotion(k1,r1,k2,r2);
     // determine if this is a castling move
   boolean castled =((board[k1][r1]>2) || (Math.abs(k1-k2)<2)) ? false : true;
   boolean whiteenpassant = LegalWhitePawnEnPassantCapture (k1, r1, k2, r2);
   boolean blackenpassant = LegalBlackPawnEnPassantCapture (k1, r1, k2, r2);
     // update status
   lastmove = new Move (k1,r1, k2, r2);
   SetLastPlayerMoved(PieceOwner(k1,r1));
   ChangeCastlingStatus(k1,r1,k2,r2);
     // do the move
   board[k2][r2] = board[k1][r1];
   board[k1][r1]=0;
     // additional work if promotion, castling, enpassant
   if (promotion)       board[k2][r2] = DeterminePromotionPiece(k2,r2);
   if (castled)         HandleCastling(k1,r1,k2,r2);
   if (whiteenpassant)  board[k2][r2-1]=0;  // remove captured pawn
   if (blackenpassant)  board[k2][r2+1]=0;  // remove captured pawn
}

void HandleCastling(int k1,int r1,int k2,int r2)
{
   if (k1 > k2)                           // castling to left of board
   { board[k2+1][r2] = board[0][r2];
     board[0][r2] = 0;
   }  else                                // castling to right of board
   { board[k2-1][r2] = board[columns -1][r2];
     board[columns-1][r2]=0;
   }
}
// Determinate pawn promoted piece (always queen at this stage)
int DeterminePromotionPiece (int k, int r) 
{
  return 3+PieceOwner(k,r);    // Promoted to queen 
}
boolean Mated(int player)
{
  if (lastplayermoved != player)
    if (InCheck(player))
      return (!HasALegalMove(player));
  return false;
}
boolean Stalemated(int player)
{
  if (lastplayermoved != player)
    if (!InCheck(player))
      return (!HasALegalMove(player));
  return false;
}
boolean HasALegalMove(int player)
{
  for (int k=0; k<columns; k++)
    for (int r=0; r<rows;r++)
     if ((!EmptySquare(k,r)))
      if (PieceOwner(k,r)==player)
       for (int i2=0; i2<columns; i2++)
        for (int j2=0; j2<rows; j2++)
	     if (LegalMove(k,r,i2,j2))
	        return true;
   return false;
}
}


WWW page by Hans Bodlaender. Programming by Hans Bodlaender and Eli Bachmupsky.
WWW page created: April 23, 1998. Last modified: November 13, 1998.