//Test to see if the king is currently in check public bool isInCheck(int kingX, int kingY, ChessPiece[,] chessBoard) { chessColour kingColour = chessBoard[kingX, kingY].Colour; //CHECK KNIGHT LOCATIONS if (searchForKnightAttacks(kingX, kingY, chessBoard, kingColour)) { return(true); } //CHECK FOR LINEAR ATTACKS - eight possible locations if (searchForLinearAttacks(1, 0, kingX, kingY, chessBoard, kingColour) || //horizontal attack searchForLinearAttacks(0, 1, kingX, kingY, chessBoard, kingColour) || //vertical attack searchForLinearAttacks(1, -1, kingX, kingY, chessBoard, kingColour) || //diagonal right searchForLinearAttacks(1, 1, kingX, kingY, chessBoard, kingColour)) //diagonal left { return(true); } //CHECK FOR PAWN ATTACKS if (searchForPawnAttacks(kingX, kingY, chessBoard, kingColour)) { return(true); } //If we got here, nothing is putting the king in check! return(false); }
//constructor public ChessPiece(int xPos, int yPos) { _positionX = xPos; _positionY = yPos; _canCastle = true; _colour = chessColour.BLACK; }
private void updateTime() { //if the player has changed, update the main window with the player colour and the other player's time if (activePlayer != _mainWindowHandle.currentGame.Turn) { activePlayer = _mainWindowHandle.currentGame.Turn; if (activePlayer == chessColour.WHITE) { label_turn.Text = "White Move:"; label_othTime.Text = "BLK - " + _mainWindowHandle.currentGame.getTime(chessColour.BLACK); } else { label_turn.Text = "Black Move:"; label_othTime.Text = "WHT - " + _mainWindowHandle.currentGame.getTime(chessColour.WHITE); } } //Update the chessclock every tick if (_mainWindowHandle.currentGame.Turn == chessColour.WHITE) { label_curTime.Text = _mainWindowHandle.currentGame.getTime(_mainWindowHandle.currentGame.Turn); } else { label_curTime.Text = _mainWindowHandle.currentGame.getTime(_mainWindowHandle.currentGame.Turn); } }
//parameterless constructor - required for serialization public ChessPiece() { _positionX = 0; _positionY = 0; _canCastle = true; _colour = chessColour.BLACK; }
public static bool isEnPassant(int oldX, int oldY, int finalX, int finalY, ChessPiece[,] chessBoard) { chessColour colour = chessBoard[oldX, oldY].Colour; //EnPassant move is up one and across one from the initial pawn position if (colour == chessColour.WHITE && oldY != BLK_PAWN_DBLMV) //White pawns can attack enPassent only from row4 { return(false); } else if (colour == chessColour.BLACK && oldY != WHT_PAWN_DBLMV) //black can only attack enpassent from position 3 { return(false); } //Check that the defending pawn is the same as the last pawn moved up two squares if (_doubleMove != null && chessBoard[finalX, oldY].Colour == _doubleMove.Colour && chessBoard[finalX, oldY].PositionX == _doubleMove.PositionX && chessBoard[finalX, oldY].PositionY == _doubleMove.PositionY) { //Yes! This is an enPassent move, giv'er. return(true); } return(false); }
//Moves chess piece from old to new location on the board public void movePiece(int oldCol, int oldRow, int newCol, int newRow) { //Finds the type and colour of piece that we're moving chessPieces selectedType = chessBoard[oldCol, oldRow].Type(); chessColour selectedColour = chessBoard[oldCol, oldRow].Colour; //You can't move a piece if it doesn't exist if (selectedType != chessPieces.CLEAR) { //Variables to update display after enPassent move bool enPassant = false; Pawn enPassantPawn = null; if (ChessPiece.DblMovePawn != null && chessBoard[oldCol, oldRow].Type() == chessPieces.PAWN) { enPassant = ChessPiece.isEnPassant(oldCol, oldRow, newCol, newRow, chessBoard); enPassantPawn = (Pawn)(ChessPiece.DblMovePawn).Clone(); } //Variables to update display after castling move bool castling = false; if (chessBoard[oldCol, oldRow].CanCastle && chessBoard[newCol, newRow].CanCastle) { castling = ChessPiece.isCastling(chessBoard[oldCol, oldRow], chessBoard[newCol, newRow], chessBoard); } //move the piece ChessPiece.Move(oldCol, oldRow, newCol, newRow, chessBoard); selectedType = chessBoard[newCol, newRow].Type(); //type may have changed (pawn->queen), so update //Every time a valid move is made, switch turns currentGame.changeTurns(); //DISPLAY - Special case: If we are castling, just update the whole row that the king is on if (castling) { for (int i = 0; i < MAX_CHESS_SQUARES; i++) { displayPieceAt(i, newRow, chessBoard[i, newRow].Type(), chessBoard[i, newRow].Colour); updateSelectionSquare(); } } else { //DISPLAY - Regular Move: Update only the piece that just moved: displayPieceAt(newCol, newRow, selectedType, selectedColour); //DISPLAY - Special case: If the move was enPassent, update the possible pawn locations (+/- one from the pawn that just moved if (enPassant) { displayPieceAt(enPassantPawn.PositionX, enPassantPawn.PositionY, chessBoard[enPassantPawn.PositionX, enPassantPawn.PositionY].Type(), chessBoard[enPassantPawn.PositionX, enPassantPawn.PositionY].Colour); } } } }
private void playAsBlackToolStripMenuItem_Click(object sender, EventArgs e) { if (playAsBlackToolStripMenuItem.Checked == true) { firstPlayerColour = chessColour.BLACK; } else { firstPlayerColour = chessColour.WHITE; } newGame(); }
//Handles the ending of the current player's turn public void changeTurns() { if (_turn == chessColour.BLACK) { _blackSW.Stop(); _turn = chessColour.WHITE; _whiteSW.Start(); } else { _whiteSW.Stop(); _turn = chessColour.BLACK; _blackSW.Start(); } }
//Sets all chess pieces to display in the startup positions public void updateDisplay() { updateTitleBar(); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { chessColour tmpColour = chessBoard[i, j].Colour; chessPieces tmpType = chessBoard[i, j].Type(); displayPieceAt(i, j, tmpType, tmpColour); } } updateSelectionSquare(); }
public string getTime(chessColour colour) { TimeSpan ts; if (colour == chessColour.BLACK) { ts = _blackSW.Elapsed; } else { ts = _whiteSW.Elapsed; } String retVal = String.Format("{0:00}:{1:00}:{2:00}", ts.Hours, ts.Minutes, ts.Seconds); return(retVal); }
//Load a saved game private void loadGameToolStripMenuItem_Click(object sender, EventArgs e) { //Create object to read in all gameplay data ChessData loadData = new ChessData(); Stream loadStream = null; OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Filter = "chs files (*.chs)|*.chs|All files (*.*)|*.*"; openFileDialog1.FilterIndex = 1; //default to loading .chs files openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { try { if ((loadStream = openFileDialog1.OpenFile()) != null) { using (loadStream) { // Deserialize data from file: IFormatter formatter = new BinaryFormatter(); loadData = (ChessData)formatter.Deserialize(loadStream); //load the all the gameplay data chessBoard = loadData.chessBoard; currentGame = loadData.currentGame; firstPlayerColour = loadData.firstPlayerColour; //Update chessboard display with new data updateDisplay(); } } } catch (Exception ex) { MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message); } } }
public void reset() { _turn = chessColour.WHITE; //Default player is white }
//Takes in the expected position of the king, the chessBoard, and the colour of the king. //Checks all eight positions that a knight could possibly attack from. private bool searchForKnightAttacks(int kingX, int kingY, ChessPiece[,] chessBoard, chessColour kingColour) { int xAdd, yAdd, tmpX, tmpY; //Loop through -2,-1, 0, 1, 2 for (int i = -KNT_BIG_INC; i <= KNT_BIG_INC; i++) { //ignore zero if (i != 0) { xAdd = i; tmpX = kingX + xAdd; //Check validity of the position if (tmpX <= MAX_CHESS_VALUE && tmpX >= MIN_CHESS_VALUE) { //Good x value, now let's find corresponding y values //Loop through -2,-1, 0, 1, 2 for (int j = -KNT_BIG_INC; j <= KNT_BIG_INC; j++) { //ignore zero if (j != 0) { yAdd = j; tmpY = kingY + yAdd; //Check validity of y position if (tmpY <= MAX_CHESS_VALUE && tmpY >= MIN_CHESS_VALUE) { // Knights always move two spaces in one direction and one space in another. // yAdd and xAdd cannot be the same value if the move is valid if (Math.Abs(yAdd) != Math.Abs(xAdd)) { //if the colour of the chesspiece at this location is attacking, and //it is a knight if (chessBoard[tmpX, tmpY].Colour != kingColour && chessBoard[tmpX, tmpY].Type() == chessPieces.KNIGHT) { //we are in check return(true); } } } } } } } } //No knight putting the king in check! return(false); }
//Displays the chess piece at the given position private void displayPieceAt(int newPosX, int newPosY, chessPieces type, chessColour colour) { //update title bar whenever you move a piece updateTitleBar(); switch (type) { case chessPieces.KING: if (colour == chessColour.WHITE) //Display White King { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteKingW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteKingB; } } else //Display Black King { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackKingW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackKingB; } } break; case chessPieces.QUEEN: if (colour == chessColour.WHITE) //Display White Queen { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteQueenW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteQueenB; } } else //Display Black Queen { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackQueenW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackQueenB; } } break; case chessPieces.BISHOP: if (colour == chessColour.WHITE) //Display White Bishop { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteBishopW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteBishopB; } } else //Display Black Bishop { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackBishopW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackBishopB; } } break; case chessPieces.KNIGHT: if (colour == chessColour.WHITE) //Display White Knight { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteKnightW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteKnightB; } } else //Display Black Knight { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackKnightW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackKnightB; } } break; case chessPieces.ROOK: if (colour == chessColour.WHITE) //Display White Rook { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteRookW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhiteRookB; } } else //Display Black Rook { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackRookW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackRookB; } } break; case chessPieces.PAWN: if (colour == chessColour.WHITE) //Display White Pawn { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhitePawnW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.WhitePawnB; } } else //Display Black Pawn { if (squareIsWhite[newPosX, newPosY]) { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackPawnW; } else { dgv_chessBoard[newPosX, newPosY].Value = Chess.Properties.Resources.BlackPawnB; } } break; case chessPieces.CLEAR: blankSquareAt(newPosX, newPosY); break; } }
//Moves a piece from one location to another on the chess board public static void Move(int oldX, int oldY, int newX, int newY, ChessPiece[,] chessBoard) { //You can't move a piece if it doesn't exist if (chessBoard[oldX, oldY].Type() != chessPieces.CLEAR) { chessColour pieceColor = chessBoard[oldX, oldY].Colour; //Special cases for pawns if (chessBoard[oldX, oldY].Type() == chessPieces.PAWN) { //We must remove the enemy pawn killed via enPassent if applicable if (isEnPassant(oldX, oldY, newX, newY, chessBoard)) { chessBoard[newX, oldY] = new ChessPiece(newX, newY - 1); } //When a white pawn moves to the bottom (8) or a black pawn moves to the top (0) it is promoted if ((pieceColor == chessColour.BLACK && newY == MIN_CHESS_VALUE) || (pieceColor == chessColour.WHITE && newY == MAX_CHESS_VALUE)) { //replace the pawn with a queen King oldKing = chessBoard[oldX, oldY]._king; chessBoard[oldX, oldY] = new Queen(oldX, oldY); chessBoard[oldX, oldY].Colour = pieceColor; chessBoard[oldX, oldY]._king = oldKing; } //Whenever a pawn moves two spaces, we record this for processing later if (Math.Abs(newY - oldY) > 1) { ChessPiece.DblMovePawn = (Pawn)chessBoard[oldX, oldY]; } else { //if the pawn didn't move two spaces, then clear DblMove ChessPiece.DblMovePawn = null; } } //Special case - If castling, we move the pieces to a different location if (isCastling(chessBoard[oldX, oldY], chessBoard[newX, newY], chessBoard)) { //Find the king and rook ChessPiece king; ChessPiece rook; if (chessBoard[oldX, oldY].Type() == chessPieces.KING) { king = chessBoard[oldX, oldY]; rook = chessBoard[newX, newY]; } else { rook = chessBoard[oldX, oldY]; king = chessBoard[newX, newY]; } //Move the king two spaces X towards the rook //Move the rook next to the king, on the opposite side if (king.PositionX < rook.PositionX) { king.PositionX = king.PositionX + 2; rook.PositionX = king.PositionX - 1; } else { king.PositionX = king.PositionX - 2; rook.PositionX = king.PositionX + 1; } //Update positions on chessboard - put pieces in new spots, clear old spots chessBoard[king.PositionX, king.PositionY] = king; chessBoard[rook.PositionX, rook.PositionY] = rook; chessBoard[oldX, oldY] = new ChessPiece(oldX, oldY); chessBoard[newX, newY] = new ChessPiece(newX, newY); //Once moved, the king and rook can never castle again king.CanCastle = false; rook.CanCastle = false; } else // regular move takes place { //move the piece to the new location chessBoard[newX, newY] = chessBoard[oldX, oldY]; //record the new location in the piece chessBoard[newX, newY].PositionX = newX; chessBoard[newX, newY].PositionY = newY; //replace the piece you moved chessBoard[oldX, oldY] = new ChessPiece(oldX, oldY); } //If the king or roook have moved, they can never castle again if (chessBoard[newX, newY].Type() == chessPieces.KING || chessBoard[newX, newY].Type() == chessPieces.ROOK) { chessBoard[newX, newY].CanCastle = false; } } }
//Event driven logic - user clicking on a chess piece drives the whole program private void dgv_chessBoard_CellContentClick(object sender, DataGridViewCellEventArgs e) { //We can only move a piece if we've selected one to move if (selectionMade) { ChessPiece selectedPiece = chessBoard[selectedX, selectedY]; chessColour selectedColour = chessBoard[selectedX, selectedY].Colour; // check that the move is legal for the piece selected, // and that the piece is the correct colour to move, if (currentGame.Turn == selectedColour && selectedPiece.isValidMove(e.ColumnIndex, e.RowIndex, chessBoard)) { //If we're playing single player with no networking we can move black or white pieces if (!isNetworked) { movePiece(selectedX, selectedY, e.ColumnIndex, e.RowIndex); } else if (thisPlayerColour == currentGame.Turn) //If we're playing a networked game, we can only move our own pieces { movePiece(selectedX, selectedY, e.ColumnIndex, e.RowIndex); // Use an event to call the networkingWindow to record and send the move to other player if (isNetworked) { //"MOVE|oldCol,oldRow|newCol,newRow\n" chessMoveArgs args = new chessMoveArgs(); args.oldX = selectedX; args.oldY = selectedY; args.newX = e.ColumnIndex; args.newY = e.RowIndex; OnChessMoveEvent(args); } } } //if the move wasn't valid, clear selection for next use selectionMade = false; //report selection to other player if (isNetworked) { selectionMadeArgs args = new selectionMadeArgs(); args.selection = selectionMade; args.intX = selectedX; args.intY = selectedY; OnSelectionMadeEvent(args); } } else { selectionMade = true; //saves the selection selectedX = e.ColumnIndex; selectedY = e.RowIndex; //report selection to other player if (isNetworked) { selectionMadeArgs args = new selectionMadeArgs(); args.selection = selectionMade; args.intX = selectedX; args.intY = selectedY; OnSelectionMadeEvent(args); } } updateSelectionSquare(); //updates the gameboard if a square has been selected/released }
// Takes in the expected position of the king, the chessBoard, and the colour of the king. // The incY or incX values passed to this function determine which direction to seach in. // You can pass in either a -1 (negative direction), 0, or 1 (positive direction) // One of either incY or incX must always be set to a value, or this function will never exit the while loop private bool searchForLinearAttacks(int incX, int incY, int kingX, int kingY, ChessPiece[,] chessBoard, chessColour kingColour) { int tmpY, tmpX; for (int i = 0; i <= 1; i++) { tmpY = kingY; tmpX = kingX; bool bPieceFound = false; //First time through we check for vertical attacks going up if (i % 2 == 0) { //incY and incX should be initially set by caller } else //Second time through we check for vertical going down { incY = -incY; incX = -incX; } //Check that the values are all on the chessboard while ((tmpY + incY) <= MAX_CHESS_VALUE && (tmpY + incY) >= MIN_CHESS_VALUE && (tmpX + incX) <= MAX_CHESS_VALUE && (tmpX + incX) >= MIN_CHESS_VALUE && bPieceFound != true) { tmpY += incY; tmpX += incX; //Stop looping when we've found something. Ignore clear squares //and squares that contain the king we're currently moving. if (chessBoard[tmpX, tmpY].Type() != chessPieces.CLEAR) { //is the piece an attacking colour? if (chessBoard[tmpX, tmpY].Colour != chessBoard[kingX, kingY].Colour) { //Rooks can only attack in straight lines if (chessBoard[tmpX, tmpY].Type() == chessPieces.ROOK) { //Either incY or incX must be zero for a straight line if (incY == 0 || incX == 0) { return(true); } } //Bishops can only attack in diagonals else if (chessBoard[tmpX, tmpY].Type() == chessPieces.BISHOP) { //Both incY and incX must be one for a diagonal attack if (Math.Abs(incY) == Math.Abs(incX)) { return(true); } } else if (chessBoard[tmpX, tmpY].Type() == chessPieces.QUEEN) { //Any linear attack is valid for the queen return(true); } else if (chessBoard[tmpX, tmpY].Type() == chessPieces.KING) { //king only attacks from one space away in any direction if ((Math.Abs(Math.Abs(tmpX) - Math.Abs(kingX)) < 1) && (Math.Abs(Math.Abs(tmpY) - Math.Abs(kingY)) < 1)) { return(true); } } } //We found a blocking piece, so no need to further check positions bPieceFound = true; } } } return(false); }
//Takes in the expected position of the king, the chessBoard, and the colour of the king. //Checks both positions a pawn could attack from. private bool searchForPawnAttacks(int kingX, int kingY, ChessPiece[,] chessBoard, chessColour kingColour) { int tmpX, tmpY, incY; //White is at the top, so always attacked by pawns below if (chessBoard[kingX, kingY].Colour == chessColour.WHITE) { incY = 1; } else //Black king, always attacked by pawns above { incY = -1; } //There are two pawn locations that the king could be attacked from, start //by checking the right, then loop through to check the left tmpX = kingX + 1; for (int i = 0; i <= 1; i++) { //Check that the pawn is in a valid location if (tmpX <= MAX_CHESS_VALUE && tmpX >= MIN_CHESS_VALUE) { tmpY = kingY + incY; if (tmpY <= MAX_CHESS_VALUE && tmpY >= MIN_CHESS_VALUE) { //Check for attacking colour, and that the piece is a pawn if (chessBoard[tmpX, tmpY].Colour != kingColour && chessBoard[tmpX, tmpY].Type() == chessPieces.PAWN) { //This pawn is attacking return(true); } } } //Once we've checked one side, check the other tmpX = kingX - 1; } //no attacking pawns return(false); }