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.