public move(piece p, square s) { movablePiece = p; targetSquare = s; }
//function that handles end of turn and calculation of the new turn //called after a player has made his move => switch sides //TODO private void endTurn() { var colorDark = Color.DarkGray; var colorLight = Color.White; var colorSelected = Color.OrangeRed; var colorMovable = Color.DarkSeaGreen; turnCount++; //change turn owner if (turn == "white") { turn = "black"; } else { turn = "white"; } legalMoves = new List <move>(); //this handles the mask calculation masks.calculateCheckers(); //deselect piece and reset the board colors selectedPiece = null; foreach (square s in squareArray) { Panel workingPanel = _chessBoardPanels[s.xPosition, s.yPosition]; if ((workingPanel.Location.X / tileSize) % 2 == 0) { workingPanel.BackColor = (workingPanel.Location.Y / tileSize) % 2 != 0 ? colorDark : colorLight; } else { workingPanel.BackColor = (workingPanel.Location.Y / tileSize) % 2 != 0 ? colorLight : colorDark; } } //calculate new move list pins.calculatePins(); core.calculateMoves(); //conditions for end of the game if (legalMoves.Count == 0 && masks.checkerCount == 0) { //game ends in a draw gameOver("draw"); } else if (legalMoves.Count == 0 && masks.checkerCount > 0) { //the opponent wins if (turn == "white") { gameOver("black"); } else { gameOver("white"); } } //uncomment for debugging of masks - currently works(maybe?) /*for(int i = 0; i < 8; i++) * { * for(int j = 0; j < 8; j++) * { * if (masks.kingDangerMask[i, j]) _chessBoardPanels[i, j].BackColor = Color.Blue; * } * }*/ }
public square(int x, int y) { this.xPosition = x; this.yPosition = y; here = null; }
//TODO //handler of the player clicking a square on the board private void boardClickHandler(object sender, EventArgs e) { var colorDark = Color.DarkGray; var colorLight = Color.White; var colorSelected = Color.OrangeRed; var colorMovable = Color.DarkSeaGreen; Panel clickedPanel = (Panel)sender; //the piece the player tried to click (can be null! = clicked an empty square) piece clickedPiece = squareArray[clickedPanel.Location.X / tileSize, clickedPanel.Location.Y / tileSize].here; square clickedSquare = squareArray[clickedPanel.Location.X / tileSize, clickedPanel.Location.Y / tileSize]; //selecting squares works //TODO - check for present pieces //TODO - check of other selected squares - global variable? //dummy for debugging the game board - uncomment to use /*if(clickedPanel.BackColor == colorSelected) * { * if ((clickedPanel.Location.X / tileSize) % 2 == 0) * clickedPanel.BackColor = (clickedPanel.Location.Y / tileSize) % 2 != 0 ? colorDark : colorLight; * else * clickedPanel.BackColor = (clickedPanel.Location.Y / tileSize) % 2 != 0 ? colorLight : colorDark; * } * else clickedPanel.BackColor = colorSelected;*/ //if it's the first turn of the game, end turn to evaluate moves for pieces if (firstMove) { firstMove = false; endTurn(); if (board.mode == "Play versus A.I." && turn != playerfaction) { move aiMove = ai_core.getMove(); //simulate the ai clicking on the board to make the move boardClickHandler(_chessBoardPanels[aiMove.movablePiece.xPosition, aiMove.movablePiece.yPosition], null); boardClickHandler(_chessBoardPanels[aiMove.targetSquare.xPosition, aiMove.targetSquare.yPosition], null); } } if (clickedPiece == null && selectedPiece == null) //player clicked meaninglessly { //do nothing } //the player attempted to select a piece while not having one selected else if (selectedPiece == null) //clicked piece can NOT be null { if (clickedPiece.pieceColor == turn) //the player clicked his own piece (selected) { selectedPiece = clickedPiece; movableSquares = new List <square>(); foreach (move m in legalMoves) { if (m.movablePiece == selectedPiece) { movableSquares.Add(m.targetSquare); } } //update the gameboard with movable squares (in green) _chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].BackColor = colorSelected; foreach (square s in movableSquares) { _chessBoardPanels[s.xPosition, s.yPosition].BackColor = colorMovable; } } //else do nothing - the player tried to select the enemy piece } //the player attempted to deselect a piece else if ((clickedPiece == null && !(movableSquares.Contains(clickedSquare))) || (clickedPiece == selectedPiece)) { //deselect the selected piece if ((_chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].Location.X / tileSize) % 2 == 0) { _chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].BackColor = (_chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].Location.Y / tileSize) % 2 != 0 ? colorDark : colorLight; } else { _chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].BackColor = (_chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].Location.Y / tileSize) % 2 != 0 ? colorLight : colorDark; } selectedPiece = null; //update the board to deselect the pieces in color foreach (square s in movableSquares) { Panel workingPanel = _chessBoardPanels[s.xPosition, s.yPosition]; if ((workingPanel.Location.X / tileSize) % 2 == 0) { workingPanel.BackColor = (workingPanel.Location.Y / tileSize) % 2 != 0 ? colorDark : colorLight; } else { workingPanel.BackColor = (workingPanel.Location.Y / tileSize) % 2 != 0 ? colorLight : colorDark; } } movableSquares = null; } //the player selected one of his other pieces while having one selected already else if (selectedPiece != null && clickedPiece != null && clickedPiece.pieceColor == turn) { //deselect the selected piece if ((_chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].Location.X / tileSize) % 2 == 0) { _chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].BackColor = (_chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].Location.Y / tileSize) % 2 != 0 ? colorDark : colorLight; } else { _chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].BackColor = (_chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].Location.Y / tileSize) % 2 != 0 ? colorLight : colorDark; } selectedPiece = null; //update the board to deselect the pieces in color foreach (square s in movableSquares) { Panel workingPanel = _chessBoardPanels[s.xPosition, s.yPosition]; if ((workingPanel.Location.X / tileSize) % 2 == 0) { workingPanel.BackColor = (workingPanel.Location.Y / tileSize) % 2 != 0 ? colorDark : colorLight; } else { workingPanel.BackColor = (workingPanel.Location.Y / tileSize) % 2 != 0 ? colorLight : colorDark; } } movableSquares = null; //now select the new piece selectedPiece = clickedPiece; movableSquares = new List <square>(); foreach (move m in legalMoves) { if (m.movablePiece == selectedPiece) { movableSquares.Add(m.targetSquare); } } //update the gameboard with movable squares (in green) _chessBoardPanels[selectedPiece.xPosition, selectedPiece.yPosition].BackColor = colorSelected; foreach (square s in movableSquares) { _chessBoardPanels[s.xPosition, s.yPosition].BackColor = colorMovable; } } //the player performed a move (or a take) else if (selectedPiece != null && movableSquares.Contains(clickedSquare)) { selectedPiece.move(clickedSquare); endTurn(); //handler for the A.I. to make a move if (board.mode == "Play versus A.I." && turn != playerfaction) { move aiMove = ai_core.getMove(); //simulate the ai clicking on the board to make the move boardClickHandler(_chessBoardPanels[aiMove.movablePiece.xPosition, aiMove.movablePiece.yPosition], null); boardClickHandler(_chessBoardPanels[aiMove.targetSquare.xPosition, aiMove.targetSquare.yPosition], null); } } }
public static void calculateMoves() { //king moves are calculated first - if there is a double check, the rest doesn't need to be calculated piece playerKing = null; if (board.turn == "white") { playerKing = board.whitePieces.Find(p => p.pieceType == "king"); } else { playerKing = board.blackPieces.Find(p => p.pieceType == "king"); } bool currentPinned = false; pin currentPin = null; List <square> kingSquares = playerKing.getLegalMoves(); foreach (square s in kingSquares) { board.legalMoves.Add(new move(playerKing, s)); } //double check - only legal moves are to move the king if (masks.checkerCount >= 2) { return; } //single check - can move, block or capture checker //TODO: pinned pieces else if (masks.checkerCount == 1) { List <piece> pcs = null; if (board.turn == "white") { pcs = board.whitePieces; } else { pcs = board.blackPieces; } List <square> consideredMoves = null; foreach (piece p in pcs) { //if the piece is pinned, give it special treatment if (pins.existingPins.Exists(pi => pi.pinnedPiece == p)) { currentPinned = true; currentPin = pins.existingPins.Find(pi => pi.pinnedPiece == p); } consideredMoves = p.getLegalMoves(); foreach (square s in consideredMoves) { //if the piece is not pinned, proceed normally if (!currentPinned) { //move is only valid in check if it conincides with the pushmask or the capturemask if (masks.captureMask[s.xPosition, s.yPosition] || masks.pushMask[s.xPosition, s.yPosition]) { board.legalMoves.Add(new move(p, s)); } } else { //move has to coincide with the pin rules in addition to the pushmask or capturemask if ((masks.captureMask[s.xPosition, s.yPosition] || masks.pushMask[s.xPosition, s.yPosition]) && (currentPin.pushSquares.Exists(sq => sq == s) || currentPin.takeSquares.Exists(sq => sq == s))) { board.legalMoves.Add(new move(p, s)); } } } currentPin = null; currentPinned = false; } //no other moves are valid except for king moves, blocks or checker captures return; } //no check is in play - calculate moves like normal //pins.cs handles the calculation of pins //TODO: pinned pieces(separately) else { List <piece> pcs = null; if (board.turn == "white") { pcs = board.whitePieces; } else { pcs = board.blackPieces; } List <square> consideredMoves = null; foreach (piece p in pcs) { //separate behavior for pinned pieces if (pins.existingPins.Exists(pi => pi.pinnedPiece == p)) { currentPinned = true; currentPin = pins.existingPins.Find(pi => pi.pinnedPiece == p); } consideredMoves = p.getLegalMoves(); foreach (square s in consideredMoves) { //normal behavior if (!currentPinned) { board.legalMoves.Add(new move(p, s)); } else { if (currentPin.pushSquares.Exists(sq => sq == s) || currentPin.takeSquares.Exists(sq => sq == s)) { board.legalMoves.Add(new move(p, s)); } } } currentPin = null; currentPinned = false; } } }
public pin(piece p, List <square> take, List <square> push) { pinnedPiece = p; takeSquares = take; pushSquares = push; }
//figures out which pieces are pinned and puts them in pinnedPieces list public static void calculatePins() { existingPins = new List <pin>(); //reference to the player's king piece playerKing = null; if (board.turn == "white") { playerKing = board.whitePieces.Find(p => p.pieceType == "king"); } else { playerKing = board.blackPieces.Find(p => p.pieceType == "king"); } //pins are calculates in 8 directions //a search starts in a direction from the king - it "xrays" a friendly piece once and marks it as a candidate for a pin //if the search finds an enemy candidate for a pinner after the xray, the pinned piece is marked //the search ends unsuccesfully if multiple friendly pieces are hit in a row, if an unfit pinner candidate is found or if the edge of the board is hit int i = playerKing.xPosition; int j = playerKing.yPosition; bool xrayed = false; bool foundPin = false; List <square> potentialPush = new List <square>(); List <square> potentialTake = new List <square>(); piece pinCandidate = null; //up j = playerKing.yPosition - 1; while (j >= 0) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "rook" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } j--; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } //right i = playerKing.xPosition; j = playerKing.yPosition; xrayed = false; foundPin = false; potentialPush = new List <square>(); potentialTake = new List <square>(); pinCandidate = null; i = playerKing.xPosition + 1; while (i < 8) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "rook" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } i++; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } //down i = playerKing.xPosition; j = playerKing.yPosition; xrayed = false; foundPin = false; potentialPush = new List <square>(); potentialTake = new List <square>(); pinCandidate = null; j = playerKing.xPosition + 1; while (j < 8) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "rook" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } j++; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } //left i = playerKing.xPosition; j = playerKing.yPosition; xrayed = false; foundPin = false; potentialPush = new List <square>(); potentialTake = new List <square>(); pinCandidate = null; i = playerKing.xPosition - 1; while (i >= 0) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "rook" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } i--; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } //"rook" pins are done(working properly), now the diagonal "bishop" pins //TODO //top right i = playerKing.xPosition; j = playerKing.yPosition; xrayed = false; foundPin = false; potentialPush = new List <square>(); potentialTake = new List <square>(); pinCandidate = null; i = playerKing.xPosition + 1; j = playerKing.yPosition - 1; while (i < 8 && j >= 0) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "bishop" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } i++; j--; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } //bottom right i = playerKing.xPosition; j = playerKing.yPosition; xrayed = false; foundPin = false; potentialPush = new List <square>(); potentialTake = new List <square>(); pinCandidate = null; i = playerKing.xPosition + 1; j = playerKing.yPosition + 1; while (i < 8 && j < 8) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "bishop" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } i++; j++; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } //bottom left i = playerKing.xPosition; j = playerKing.yPosition; xrayed = false; foundPin = false; potentialPush = new List <square>(); potentialTake = new List <square>(); pinCandidate = null; i = playerKing.xPosition - 1; j = playerKing.yPosition + 1; while (j < 8 && i >= 0) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "bishop" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } i--; j++; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } //top left i = playerKing.xPosition; j = playerKing.yPosition; xrayed = false; foundPin = false; potentialPush = new List <square>(); potentialTake = new List <square>(); pinCandidate = null; i = playerKing.xPosition - 1; j = playerKing.yPosition - 1; while (i >= 0 && j >= 0) { //nothing there - add to potential moves for pinned piece on this line if (board.squareArray[i, j].here == null) { potentialPush.Add(board.squareArray[i, j]); } else { //xray the friendly piece and make it a candidate if (!xrayed && board.squareArray[i, j].here.pieceColor == board.turn) { xrayed = true; pinCandidate = board.squareArray[i, j].here; } //we found the pinning piece else if (xrayed && (board.squareArray[i, j].here.pieceType == "bishop" || board.squareArray[i, j].here.pieceType == "queen") && board.squareArray[i, j].here.pieceColor != board.turn) { potentialTake.Add(board.squareArray[i, j]); foundPin = true; break; } //we found something else => the search was not successful, there is no pin here else { break; } } i--; j--; } //if we found a pin, save it if (foundPin) { existingPins.Add(new pin(pinCandidate, potentialTake, potentialPush)); } }
//calculates how many pieces are in check for the player and creates the masks public static void calculateCheckers() { //init of masks for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { kingDangerMask[i, j] = false; captureMask[i, j] = false; pushMask[i, j] = false; checkingMask[i, j] = false; } } checkerCount = 0; //pointer to the player's king (for ease of reading) piece playerKing; if (board.turn == "white") { playerKing = board.whitePieces.Find(p => p.pieceType == "king"); } else { playerKing = board.blackPieces.Find(p => p.pieceType == "king"); } //first calculate the danger squares if (board.turn == "white") { foreach (piece p in board.blackPieces) { if (p.pieceType == "pawn") { if (p.xPosition - 1 >= 0) { kingDangerMask[p.xPosition - 1, p.yPosition + 1] = true; if (board.squareArray[p.xPosition - 1, p.yPosition + 1].here != null && board.squareArray[p.xPosition - 1, p.yPosition + 1].here.pieceType == "king" && board.squareArray[p.xPosition - 1, p.yPosition + 1].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } if (p.xPosition + 1 < 8) { kingDangerMask[p.xPosition + 1, p.yPosition + 1] = true; if (board.squareArray[p.xPosition + 1, p.yPosition + 1].here != null && board.squareArray[p.xPosition + 1, p.yPosition + 1].here.pieceType == "king" && board.squareArray[p.xPosition + 1, p.yPosition + 1].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "knight") { List <square> m = utils.knightMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "bishop") { List <square> m = utils.bishopDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "rook") { List <square> m = utils.rookDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "queen") { //treat the queen like a rook + bishop List <square> m = utils.bishopDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } m = utils.rookDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "king") { List <square> m = utils.kingDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; } } } } else if (board.turn == "black") { foreach (piece p in board.whitePieces) { if (p.pieceType == "pawn") { if (p.xPosition - 1 >= 0) { kingDangerMask[p.xPosition - 1, p.yPosition - 1] = true; if (board.squareArray[p.xPosition - 1, p.yPosition - 1].here != null && board.squareArray[p.xPosition - 1, p.yPosition - 1].here.pieceType == "king" && board.squareArray[p.xPosition - 1, p.yPosition - 1].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } if (p.xPosition + 1 < 8) { kingDangerMask[p.xPosition + 1, p.yPosition - 1] = true; if (board.squareArray[p.xPosition + 1, p.yPosition - 1].here != null && board.squareArray[p.xPosition + 1, p.yPosition - 1].here.pieceType == "king" && board.squareArray[p.xPosition + 1, p.yPosition - 1].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "knight") { List <square> m = utils.knightMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "bishop") { List <square> m = utils.bishopDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "rook") { List <square> m = utils.rookDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "queen") { //treat the queen like a rook + bishop List <square> m = utils.bishopDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } m = utils.rookDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; if (board.squareArray[s.xPosition, s.yPosition].here != null && board.squareArray[s.xPosition, s.yPosition].here.pieceType == "king" && board.squareArray[s.xPosition, s.yPosition].here.pieceColor == board.turn) { checkingMask[p.xPosition, p.yPosition] = true; checkerCount++; } } } else if (p.pieceType == "king") { List <square> m = utils.kingDangerMoves(board.squareArray[p.xPosition, p.yPosition]); foreach (square s in m) { kingDangerMask[s.xPosition, s.yPosition] = true; } } } } //now the king danger squares are calculated - we know where the king can't move because that square is attacked //we know which squares have pieces that are GIVING CHECK to the player's king //we also know the number of pieces giving check to the player's king //if checkerCount >= 2 then the only legal moves are king moves to safe squares //if checkerCount == 1 then we have 3 options // -move the king out of check // -capture the checking piece // -block the checking piece //we have to move the king => no capture is valid if (checkerCount >= 2) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { captureMask[i, j] = false; } } } //we can evade the single check by capturing the piece if (checkerCount == 1) { captureMask = checkingMask; } //now the push mask - will include squares that we can move a piece to in order to block a single check //with double checks, check can't be blocked => mask is false if (checkerCount >= 2) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { pushMask[i, j] = false; } } } piece checkingPiece = null; //if single check, then there is only one "true" on the checkingMask - find it to find the checking piece if (checkerCount == 1) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (checkingMask[i, j] == true) //we found the only checking piece { checkingPiece = board.squareArray[i, j].here; } } } //if it's a "slider" piece, find squares where we can block the check - between the piece and the king if (checkingPiece.pieceType == "rook" || checkingPiece.pieceType == "queen" || checkingPiece.pieceType == "bishop") { List <square> pieceSlider = null; List <square> kingSlider = null; if (checkingPiece.pieceType == "rook" || checkingPiece.pieceType == "queen") { pieceSlider = utils.rookSliderMoves(board.squareArray[checkingPiece.xPosition, checkingPiece.yPosition]); kingSlider = utils.rookSliderMoves(board.squareArray[playerKing.xPosition, playerKing.yPosition]); //overlap the two sliders in a 2 dimensional array to get the squares where blocking is possible int[,] overlap = new int[8, 8]; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { overlap[i, j] = 0; } } foreach (square s in kingSlider) { overlap[s.xPosition, s.yPosition]++; } foreach (square s in pieceSlider) { overlap[s.xPosition, s.yPosition]++; } //if both pieces "saw" the square => add it to the pushMask for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (overlap[i, j] == 2) { pushMask[i, j] = true; } } } } if (checkingPiece.pieceType == "bishop" || checkingPiece.pieceType == "queen") { pieceSlider = utils.bishopSliderMoves(board.squareArray[checkingPiece.xPosition, checkingPiece.yPosition]); kingSlider = utils.bishopSliderMoves(board.squareArray[playerKing.xPosition, playerKing.yPosition]); //overlap the two sliders in a 2 dimensional array to get the squares where blocking is possible int[,] overlap = new int[8, 8]; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { overlap[i, j] = 0; } } foreach (square s in kingSlider) { overlap[s.xPosition, s.yPosition]++; } foreach (square s in pieceSlider) { overlap[s.xPosition, s.yPosition]++; } //if both pieces "saw" the square => add it to the pushMask for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (overlap[i, j] == 2) { pushMask[i, j] = true; } } } } } } //now both the push mask and the capture mask is DONE //TODO: pinned pieces }