//Remove pieces tracking position public void ClearTrackerAt(int row, int column) { ChessPieceProperties piece = GetTilePiecePropertiesAt(row, column); if (piece != null) { if (piece.Team == Team.White) { wPieceLocations[(int)piece.Id] = TileIndex.Null; } else if (piece.Team == Team.Black) { bPieceLocations[(int)piece.Id] = TileIndex.Null; } else { Debug.LogError("Attempted to stop tracking piece without a team"); } } else { Debug.LogError("Attempted to stop tracking on tile with no piece"); } if (piece.Team == Team.Black) { Debug.Log("Cleared " + piece.Team + " " + piece.Id + " Tracker. Now " + bPieceLocations[(int)piece.Id].row + ", " + bPieceLocations[(int)piece.Id].col); } if (piece.Team == Team.White) { Debug.Log("Cleared " + piece.Team + " " + piece.Id + " Tracker. Now " + wPieceLocations[(int)piece.Id].row + ", " + wPieceLocations[(int)piece.Id].col); } }
private void CancelLockOn(ChessPieceProperties target) { // cancel lock on target.LockOn(false); // remove all visualization of valid move foreach (Transform validMoveVisual in validMoveVisualList) { validMoveVisual.DOMove(((Vector2)lockedOnPiece.transform.position) + lockedOnPiece.GraphicPosition, cursorMoveSpeed, false); Destroy(validMoveVisual.gameObject, cursorMoveSpeed); } // remove all visualization of threateningChess foreach (ChessPieceProperties attackingChess in threateningChess) { attackingChess.Threatened(false); } threateningChess.Clear(); // reset this list validMoveVisualList.Clear(); hoveringValidMove = null; // clear memory lockedOnPiece = null; // sound effect AudioManager.Instance.PlaySFX("cancellockon", 0.75f); }
public void ResetDoubleMoveFlag(TileIndex pieceIndex) { ChessPieceProperties piece = board.GetTilePiecePropertiesAt(pieceIndex); if (piece != null) { piece.isHasJustDoubleMoved = false; } }
private void Awake() { validMoveVisualList = new List<Transform>(); threateningChess = new List<ChessPieceProperties>(); spriteRenderer = GetComponent<SpriteRenderer>(); currentPosition = initialPosition; lockedOnPiece = null; }
//Sets the object reference held at the provided index public void SetTilePieceAt(int row, int column, GameObject obj, PieceID id = PieceID.None, bool isInitial = false) { ChessPieceProperties properties = obj.GetComponent <ChessPieceProperties>(); pieces[this.Index2DToIndex(row, column)] = properties; if (isInitial) { properties.SetId(id); } if (properties.Team == Team.White) { wPieceLocations[(int)properties.Id] = new TileIndex(row, column); } if (properties.Team == Team.Black) { bPieceLocations[(int)properties.Id] = new TileIndex(row, column); } //Debug.Log("Piece: " + obj.name + // " ID: " + properties.Id.ToString() + // " Location: " + Utils.Index2DToIndex(properties.Team==Team.White ? wPieceLocations[(int)properties.Id]:bPieceLocations[(int)properties.Id])); if (properties.Type == PieceType.King) { if (properties.Team == Team.White) { wKingIndex = new TileIndex(row, column); } else if (properties.Team == Team.Black) { bKingIndex = new TileIndex(row, column); } else { Debug.LogError("Team tag for Object named King did not match."); } } properties.isHasMoved = !isInitial; }
public void CheckDoubleMoveFlag(TileIndex pieceIndex, TileIndex end) { ChessPieceProperties piece = board.GetTilePiecePropertiesAt(pieceIndex); if (piece != null) { if (PieceType.Pawn == piece.Type) { if (!piece.isHasMoved) { if (Mathf.Abs(end.row - pieceIndex.row) == 2) { piece.isHasJustDoubleMoved = true; Debug.Log("Set double move flag for " + piece.Team + " " + piece.Id.ToString()); } } } } }
private bool IsMoveAvaliable(Team team) { bool isValidMoveFound = false; for (int i = 0; i < allMoves.Length; i++) { ChessPieceProperties tmpPiece = board.GetTilePiecePropertiesAt(Utils.IndexToTileIndex(i)); if (tmpPiece != null) { if (tmpPiece.Team == team) { if (allMoves[i].Count > 0) { isValidMoveFound = true; break; } } } } return(isValidMoveFound); }
private void LockOnChess(ChessPieceProperties piece, TileIndex index) { piece.LockOn(true); // store this piece into memory lockedOnPiece = piece; lockedOnPieceIndex = index; // get all valid move for this chess piece var validMoves = moveManager.logic.GetValidMoves(index); // visualize valid move foreach (TileIndex validMove in validMoves) { var validMoveVisual = new GameObject(lockedOnPiece.gameObject.name + "'s possible move"); validMoveVisual.transform.position = moveManager.board.GetTileCenter(index.row, index.col) + lockedOnPiece.GraphicPosition; validMoveVisual.transform.DOMove(moveManager.board.GetTileCenter(validMove.row, validMove.col) + lockedOnPiece.GraphicPosition, cursorMoveSpeed, false); var newRenderer = validMoveVisual.AddComponent<SpriteRenderer>(); var originRenderer = lockedOnPiece.SpriteRenderer; newRenderer.sprite = originRenderer.sprite; newRenderer.color = new Color(originRenderer.color.r, originRenderer.color.g, originRenderer.color.b, originRenderer.color.a / 4f); newRenderer.sortingLayerID = SpriteRenderer.sortingLayerID; // same layer with cursor newRenderer.sortingOrder = originRenderer.sortingOrder; newRenderer.transform.localScale = originRenderer.transform.localScale; validMoveVisualList.Add(validMoveVisual.transform); hoveringValidMove = null; // check if this is an attack move var attackTarget = moveManager.board.GetTilePiecePropertiesAt(validMove); if (attackTarget != null && attackTarget.Team != cursorTeam) { newRenderer.sprite = null; attackTarget.Threatened(true); threateningChess.Add(attackTarget); } } }
public void Confirm() { if (!isInTurn) // not your turn return; // check if player is trying to move locked-on chess piece to this index if (hoveringValidMove != null) { MoveChess(); // end of this function return; } // check if there is a chess piece on selected index GameObject tmp = moveManager.board.GetTilePieceAt((int)currentPosition.y, (int)currentPosition.x); if (tmp != null) { ChessPieceProperties piece = tmp.GetComponent<ChessPieceProperties>(); // check if the player have already locked on a chess piece if (lockedOnPiece != null) { // check if it is the same chess piece if (piece == lockedOnPiece) { CancelLockOn(piece); } } else if (piece.Team == cursorTeam || canMoveEnemyChess) // last condition: this chess is belong to this player { LockOnChess(piece, new TileIndex(currentPosition.y, currentPosition.x)); // sound effect AudioManager.Instance.PlaySFX("lockOn", 0.75f); } } }
private bool IsCastling(TileIndex moveOrigin, TileIndex moveTarget, ChessPieceProperties movingChess) { bool ret = false; // check on the king piece if (movingChess.Type == PieceType.King && movingChess.isHasMoved == false && Mathf.Abs(moveOrigin.col - moveTarget.col) == 2) { // check on the rook piece // determine which rook to check int targetArray; if (moveTarget.col > moveOrigin.col) { targetArray = 7; } else { targetArray = 0; } ChessPieceProperties rook; rook = moveManager.board.GetTilePiecePropertiesAt(new TileIndex(moveOrigin.row, targetArray)); if (rook != null) { if (rook.Type == PieceType.Rook && rook.isHasMoved == false) { // Conclusion : castling! ret = true; } } } return ret; }
private bool IsEnPassant(TileIndex moveOrigin, TileIndex moveTarget, ChessPieceProperties movingChess) { return (movingChess.Type == PieceType.Pawn // check if En passant is happening if it's a pawn && moveOrigin.col != moveTarget.col); // this pawn is moving diagonally }
private void MoveChess() { TileIndex moveTargetIndex = new TileIndex(currentPosition.y, currentPosition.x); // check if this is a normal move or attacking GameObject targetChess = moveManager.board.GetTilePieceAt(moveTargetIndex.row, moveTargetIndex.col); bool isAttackMove = false; if (targetChess != null) { isAttackMove = true; } else if (IsEnPassant(lockedOnPieceIndex, moveTargetIndex, lockedOnPiece)) { isAttackMove = true; targetChess = moveManager.board.GetTilePieceAt(lockedOnPieceIndex.row, moveTargetIndex.col); } else if (IsCastling(lockedOnPieceIndex, moveTargetIndex, lockedOnPiece)) { //Castling!!!!!!!!! Castling(moveTargetIndex); } if (isAttackMove) { // this is an attack targetChess.GetComponent<ChessPieceProperties>().Attacked(0.15f); Destroy(targetChess, 1f); AudioManager.Instance.PlaySFX("attack", 0.5f); AudioManager.Instance.PlaySFX("compact", 0.5f); } // move the selected chess piece to this position index Vector2 newPiecePosition = moveManager.MoveChessPiece(lockedOnPiece.gameObject, lockedOnPieceIndex, moveTargetIndex); // move the chess piece graphic lockedOnPiece.Move(newPiecePosition); // canccel the lock on lockedOnPiece.LockOn(false); // remove all visualization of valid move foreach (Transform validMoveVisual in validMoveVisualList) { // remove it immediately only if it's not the moving target. float removeTime = validMoveVisual == hoveringValidMove ? cursorMoveSpeed : 0f; Destroy(validMoveVisual.gameObject, removeTime); } // remove all visualization of threateningChess foreach (ChessPieceProperties attackingChess in threateningChess) { attackingChess.Threatened(false); } threateningChess.Clear(); // reset list validMoveVisualList.Clear(); hoveringValidMove = null; // is this a pawn promotion? if (lockedOnPiece.GetComponent<ChessPieceProperties>().Type == PieceType.Pawn && (moveTargetIndex.row == 7 || moveTargetIndex.row == 0)) { gamestate.Promotion(moveTargetIndex); } else if (moveManager.logic.IsInCheckmate(cursorTeam == Team.White ? Team.Black : Team.White)) { // checkmate detected. restart the game gamestate.GameEnd(); } else { // pass the turn to other side gamestate.Turn(); } // clear memory lockedOnPiece = null; }
public TileIndex GetPieceLocation(ChessPieceProperties properties) { return(GetPieceLocation(properties.Team, properties.Id)); }
//Calculates a list of threatened tiles and possible moves for the piece on the cell provided //Note: Excludes in King moving into check situation as enemy threats are needed //Returns (movesList, threatList) private (List <TileIndex>, List <TileIndex>) CalcThreatsAndMovesBy(int row, int col) { //TODO: Cashe Each pieces Tiles for movement calculation List <TileIndex> moveList = new List <TileIndex>(); List <TileIndex> threatList = new List <TileIndex>(); ChessPieceProperties piece = board.GetTilePiecePropertiesAt(row, col); int side = piece.CompareTag("Player Piece") ? 1 : -1; //Enemy pawns move down switch (piece.Type) { case PieceType.Pawn: AddMoveIfEnemy(new TileIndex(row + 1 * side, col - 1)); AddMoveIfEnemy(new TileIndex(row + 1 * side, col + 1)); if (AddMoveIfNotBlocked(new TileIndex(row + 1 * side, col), false)) { if (!piece.isHasMoved) { AddMoveIfNotBlocked(new TileIndex(row + 2 * side, col), false); } } //en passant move AddMoveIfEnPassant(); AddMoveIfEnPassant(); break; case PieceType.Knight: for (int i = -1; i <= 1; i += 2) { AddMoveIfNotBlocked(new TileIndex(row + 2, col + i)); AddMoveIfNotBlocked(new TileIndex(row + i, col + 2)); AddMoveIfNotBlocked(new TileIndex(row - 2, col + i)); AddMoveIfNotBlocked(new TileIndex(row - i, col - 2)); } break; case PieceType.Bishop: AddDiagonalMovesAndThreats(); break; case PieceType.Rook: AddCardinalMovesAndThreats(); break; case PieceType.Queen: AddCardinalMovesAndThreats(); AddDiagonalMovesAndThreats(); break; case PieceType.King: AddMoveIfNotBlocked(new TileIndex(row + 1, col + 1)); AddMoveIfNotBlocked(new TileIndex(row + 1, col)); AddMoveIfNotBlocked(new TileIndex(row + 1, col - 1)); AddMoveIfNotBlocked(new TileIndex(row, col + 1)); AddMoveIfNotBlocked(new TileIndex(row, col - 1)); AddMoveIfNotBlocked(new TileIndex(row - 1, col + 1)); AddMoveIfNotBlocked(new TileIndex(row - 1, col)); AddMoveIfNotBlocked(new TileIndex(row - 1, col - 1)); break; default: Debug.LogError(piece.name + " has no piece type assigned."); break; } if (piece.isPinned) { //Debug.LogError("Pin Situation Not Yet Accounted For"); TileIndex king = piece.Team == Team.White ? board.wKingIndex : board.bKingIndex; if (piece.pinningPieceIndex != TileIndex.Null) { List <TileIndex> tmpList = new List <TileIndex>(); foreach (TileIndex point in GetPointsBetween(king, piece.pinningPieceIndex, true)) { if (moveList.Contains(point)) { tmpList.Add(point); } } moveList.Clear(); moveList = tmpList; } else { Debug.LogError("Piece was flagged as pinned but no pinning piece reference was set"); } } return(moveList, threatList); void AddMoveIfEnPassant() { AddIfEnPassantConditions(new TileIndex(row, col + 1)); AddIfEnPassantConditions(new TileIndex(row, col - 1)); void AddIfEnPassantConditions(TileIndex index) { if (!IsIndexOnBoard(index)) { return; } var target = board.GetTilePiecePropertiesAt(index); if (target != null) { if (target.Type == PieceType.Pawn) { if (target.isHasJustDoubleMoved) { TileIndex tmpIndex = new TileIndex(index.row + 1 * side, index.col); if (!moveList.Contains(tmpIndex)) { AddMove(tmpIndex); } } } } } } void AddCardinalMovesAndThreats() { for (int i = row + 1; i < 8; i++) { if (!AddMoveIfNotBlocked(new TileIndex(i, col))) //If Blocked break loop { break; } } for (int i = row - 1; i >= 0; i--) { if (!AddMoveIfNotBlocked(new TileIndex(i, col))) //If Blocked break loop { break; } } for (int i = col + 1; i < 8; i++) { if (!AddMoveIfNotBlocked(new TileIndex(row, i))) //If Blocked break loop { break; } } for (int i = col - 1; i >= 0; i--) { if (!AddMoveIfNotBlocked(new TileIndex(row, i))) //If Blocked break loop { break; } } } void AddDiagonalMovesAndThreats() { int diff = 0; for (int i = col + 1; i < 8; i++)//cycle columns left { diff = i - col; TileIndex checkIndex = new TileIndex(row + diff, col + diff); if (!AddMoveIfNotBlocked(checkIndex)) //If Blocked break loop { break; } } for (int i = col + 1; i < 8; i++)//cycle columns left { diff = i - col; TileIndex checkIndex = new TileIndex(row - diff, col + diff); if (!AddMoveIfNotBlocked(checkIndex)) //If Blocked break loop { break; } } for (int i = col - 1; i >= 0; i--)//cycle columns right { diff = i - col; TileIndex checkIndex = new TileIndex(row + diff, col + diff); if (!AddMoveIfNotBlocked(checkIndex)) //If Blocked break loop { break; } } for (int i = col - 1; i >= 0; i--)//cycle columns right { diff = i - col; TileIndex checkIndex = new TileIndex(row - diff, col + diff); if (!AddMoveIfNotBlocked(checkIndex)) //If Blocked break loop { break; } } } //Adds move if enemy present, returns true when added bool AddMoveIfEnemy(TileIndex checkIndex, bool isAddThreat = true) { if (!IsIndexOnBoard(checkIndex)) { return(false); } ChessPieceProperties checkPiece; checkPiece = board.GetTilePiecePropertiesAt(checkIndex); if (isAddThreat) { AddThreat(checkIndex); //Squares Always threatened but move only valid when piece present; } if (checkPiece != null) { if (checkPiece.Team != piece.Team) //if enemy piece, add then break { AddMove(checkIndex); return(true); } } return(false); } //Adds move if not blocked by piece, Returns false if should break loop due to block bool AddMoveIfNotBlocked(TileIndex checkIndex, bool isAddThreat = true) { if (!IsIndexOnBoard(checkIndex)) { return(false); } ChessPieceProperties checkPiece; checkPiece = board.GetTilePiecePropertiesAt(checkIndex); //Can threaten squares occupied by friendly but not move there if (isAddThreat) { AddThreat(checkIndex); } if (checkPiece != null) { if (checkPiece.Team != piece.Team && isAddThreat == true) //if enemy piece blocking and can take with move, add then break { AddMove(checkIndex); } return(false); } AddMove(checkIndex); return(true); } //performs Any final checks and adds to list bool AddMove(TileIndex index) { bool isValid = true; moveList.Add(index); return(isValid); } void AddThreat(TileIndex index) { if (piece == null) { Debug.LogException(new Exception("Attempted to add threat for tile with no piece present")); } //Cashe index if piece is checking opposing king ChessPieceProperties king = board.GetTilePiecePropertiesAt(index); if (king != null) { if (king.Type == PieceType.King && king.Team != piece.Team) { piecesAttackingKing.Add(new TileIndex(row, col)); } } threatList.Add(index); } }
//Removes moves made invalid by the king being in check or king moving into check private void RemoveInvalidCheckMoves() { TileIndex wKing = board.wKingIndex; TileIndex bKing = board.bKingIndex; //Debug.Log("White King Position" + wKing.row + ", " + wKing.col); //Debug.Log("Black King Position" + bKing.row + ", " + bKing.col); isWInCheck = allThreatenedTileMaskB[wKing]; isBInCheck = allThreatenedTileMaskW[bKing]; if (isWInCheck && isBInCheck) { Debug.LogException(new Exception("Both kings flagged as in check")); } Debug.Log("Check State, White: " + isWInCheck + ", Black:" + isBInCheck); //In check logic if (isWInCheck) { FilterCheckResolvingMoves(wKing); } if (isBInCheck) { FilterCheckResolvingMoves(bKing); } PreventMoveIntoCheck(bKing, allThreatenedTileMaskW); PreventMoveIntoCheck(wKing, allThreatenedTileMaskB); //Prevent king moving into check by removing moves to threatened tiles void PreventMoveIntoCheck(TileIndex king, TileMask <bool> threats) { for (int i = allMoves[king].Count - 1; i >= 0; i--) { if (threats[allMoves[king][i]]) { allMoves[king].RemoveAt(i); } } } //Removes all moves that do not resolve check from Valid move lists void FilterCheckResolvingMoves(TileIndex king) { if (piecesAttackingKing.Count == 0) { Debug.LogException(new Exception("Attempted to resolve check where there is no attacking piece.")); } var kingProperties = board.GetTilePiecePropertiesAt(king); bool isOneThreat = piecesAttackingKing.Count == 1; //Calculate Mask for valid moves TileMask <bool> validMovesMask = new TileMask <bool>(); //-declare //-If the number of attacking pieces is 1, allow blocking or taking threat if (isOneThreat) { //Debug.Log("One King Threat Detected"); TileIndex threat = piecesAttackingKing[0]; var threatInfo = board.GetTilePiecePropertiesAt(threat); //For all single threats the attacking piece can be taken validMovesMask[threat] = true; //For Bishop queen and rook points between their line of sight are still valid if (threatInfo.Type == PieceType.Bishop || threatInfo.Type == PieceType.Rook || threatInfo.Type == PieceType.Queen) { foreach (TileIndex point in GetPointsBetween(king, threat)) { validMovesMask[point] = true; } ; //Remove king move to square behind but still inline with bishop/rook/queen TileIndex toRemove = GetPointAfter(threat, king); allMoves[king].Remove(toRemove); } //Apply mask to all team pieces other than king } for (int i = 0; i < allMoves.Length; i++) { if (Utils.IndexToTileIndex(i) != king) { ChessPieceProperties piece = board.GetTilePiecePropertiesAt(Utils.IndexToTileIndex(i)); if (piece != null) { if (piece.Team == kingProperties.Team) { if (isOneThreat) { //For one threat Apply mask to all team pieces other than king for (int j = allMoves[i].Count - 1; j >= 0; j--) { if (!validMovesMask[allMoves[i][j]]) { allMoves[i].RemoveAt(j); } } } else { //More than one threat, force move king allMoves[i].Clear(); } } } } } } }
//Sets piece flags for weather piece is pinned or not private void FlagPinnedPieces() { //-send vectors from kings position //-if hit enemy piece stop //-if hit friendly count and continue //-if hit another friendly stop //-if hit enemy queen bishop or rook get the alignment type //-set pinned if correct type TileIndex wKing = board.wKingIndex; TileIndex bKing = board.bKingIndex; FlagPinnedPieces(wKing); FlagPinnedPieces(bKing); //Flags any pieces pinned to the provided tileIndex piece void FlagPinnedPieces(TileIndex king) { Team team = board.GetTilePiecePropertiesAt(king).Team; for (int colDir = -1; colDir < 2; colDir++) { for (int rowDir = -1; rowDir < 2; rowDir++) { int checkCol = king.col + colDir; int checkRow = king.row + rowDir; int teamPieceCount = 0; TileIndex potentialPin = TileIndex.Null; //no pin state while (IsIndexOnBoard(new TileIndex(checkRow, checkCol))) { ChessPieceProperties checkPiece = board.GetTilePiecePropertiesAt(checkRow, checkCol); if (!ReferenceEquals(checkPiece, null)) { if (checkPiece.Team == team) { teamPieceCount++; //Count friendly pieces if (teamPieceCount == 2) //if a second piece is found can stop checking for pin { break; } potentialPin = new TileIndex(checkRow, checkCol); } else { //Enemy Piece found if (teamPieceCount == 1) { if (potentialPin.row != -1) //if there is a potential pin { AlignmentMode mode = GetAlignmentMode(potentialPin, king); switch (checkPiece.Type) //if aligned correctly for piece type pin the unit { case PieceType.Queen: board.GetTilePiecePropertiesAt(potentialPin).isPinned = true; board.GetTilePiecePropertiesAt(potentialPin).pinningPieceIndex = new TileIndex(checkRow, checkCol); break; case PieceType.Bishop: board.GetTilePiecePropertiesAt(potentialPin).isPinned = mode == AlignmentMode.Diagonal; board.GetTilePiecePropertiesAt(potentialPin).pinningPieceIndex = new TileIndex(checkRow, checkCol); break; case PieceType.Rook: board.GetTilePiecePropertiesAt(potentialPin).isPinned = mode == AlignmentMode.Cardinal; board.GetTilePiecePropertiesAt(potentialPin).pinningPieceIndex = new TileIndex(checkRow, checkCol); break; } } } break; //Can stop checking in direction when a opposing piece is found } } checkCol += colDir; checkRow += rowDir; } } } } }