public void InitialPieceLocationSetToBottomOfBoardFacingNorth() { PieceClass Result = new PieceClass(); Assert.That(Result.getX(), Is.EqualTo(0)); Assert.That(Result.getY(), Is.EqualTo(0)); Assert.That(Result.getFDS(), Is.EqualTo("N")); }
public void ShouldDisplayInitialPieceLocation() { PieceClass TestPiece = new PieceClass(); var Result = TestPiece.Output(); Assert.That(Result, Contains.Substring("0 0 N")); }
public int EvalClassBench() { PieceClass[] boardClass = new PieceClass[64]; for (int i = 0; i < boardClass.Length; i++) { boardClass[i] = new PieceClass(i, 'p'); } return(SearchClass(boardClass, targetDepth)); }
/// <summary> /// Invoked when the chess engine has responded with a move to apply to the /// local board /// </summary> private void OnEngineBestMoveResponse() { thinkingIndex = 0; // reset index counter for simple progress text // Get the best move from the engine string bestMove = engine.BestMove; if ((String.Compare(bestMove, "(none)") == 0) || // Stockfish (and converted ones) (String.Compare(bestMove, "a1a1") == 0) || // Rybka (board.HalfMoveCount >= HalfMovesUntilDraw)) // Propably spinning on self play or just a draw { if (board.HalfMoveCount >= HalfMovesUntilDraw) { Debug.WriteLine("Draw by 50 moves rule..."); } GameOverHandler(); } else if (GetInputState() == InputState.WaitingOnOpponentMove) { // Extract the board location from the move string PieceFile startFile = new PieceFile(bestMove[0]); int startRank = Convert.ToInt16(bestMove[1]) - Convert.ToInt16('0'); PieceFile destFile = new PieceFile(bestMove[2]); int destRank = Convert.ToInt16(bestMove[3]) - Convert.ToInt16('0'); ChessPiece foundPiece = board.FindPieceAt(startFile, startRank); MoveInformation moveInfo = new MoveInformation( new BoardSquare(startFile, startRank), new BoardSquare(destFile, destRank), foundPiece.Deployed, board.CurrentFEN); moveInfo.Color = foundPiece.Color; moveInfo.CastlingRights = board.ActivePlayerCastlingRights; // When coming from the engine, we get the promotion detection for free if (bestMove.Length == 5) { // Applied on the next move PieceClass promotionJob = ChessBoard.PieceClassFromFen(bestMove[4]); board.PromotePiece(startFile, startRank, destFile, destRank, promotionJob, ref moveInfo); } // Move the piece on the board, and add it to the official moves list board.MovePiece(ref moveInfo); // trigger a redraw view.Invalidate(); // Apply the move the engine just gave us with the engine (update it's own move) UpdateEnginePosition(); } }
/// <summary> /// Load piece images from a bitmap sheet. This overrides the unicode /// text drawing for the pieces /// </summary> /// <param name="pieceImages">Bitmap image that contains the piece data. /// It is assumed the pieces are arranged in 2 rows, with white on top /// and black on bottom. The piece order should be K Q R B N P</param> /// <param name="pieceSize">The size of a single piece</param> void IChessBoardView.SetBitmapImages(Bitmap pieceImages, Size pieceSize) { // Extract each image from the bitmap and store it in a map (job+color:image) chessPieceImageMap = new Dictionary <string, Bitmap>(); // This will not change in the loop (all destinations are the same size) Rectangle destRect = new Rectangle(0, 0, pieceSize.Width, pieceSize.Height); // This one will based on where we are in the image loop Rectangle srcRect = new Rectangle(0, 0, pieceSize.Width, pieceSize.Height); // Array of jobs in the order we expect to find them in the image // This is the same for each row (top white, bottom black) PieceClass[] jobs = new PieceClass[] { PieceClass.King, PieceClass.Queen, PieceClass.Rook, PieceClass.Bishop, PieceClass.Knight, PieceClass.Pawn }; // Init loop variables int jobIndex = 0; PieceColor pieceColor = PieceColor.White; // Loop over the assumed layout (2x6) for (int imageRow = 0; imageRow < 2; imageRow++) { for (int imageCol = 0; imageCol < 6; imageCol++) { // Create a new bitmap of the reequired size Bitmap b = new Bitmap(pieceSize.Width, pieceSize.Height); using (Graphics g = Graphics.FromImage(b)) { // Draw the portion of the larger image into the smaller one // we just created for the piece g.DrawImage(pieceImages, destRect, srcRect, GraphicsUnit.Pixel); } // Add the image to the map (mangle the color and the job for the key) chessPieceImageMap.Add(GetPieceImageKey(jobs[jobIndex++], pieceColor), b); // Shift over to the right by one piece width srcRect.X += pieceSize.Width; } // Reset row variables jobIndex = 0; srcRect.X = 0; srcRect.Y += pieceSize.Height; // Switch colors pieceColor = PieceColor.Black; } }
public string GetPieceType(int[] PiecePosition) { int i = 0; while (i < Pieces.Count) { PieceClass piece = Pieces.ToArray()[i]; if (piece.GetLocation() == PiecePosition) { return(piece.GetName()); } } return(null); }
/// <summary> /// Create a new ChessPiece /// </summary> /// <param name="pieceColor">Color</param> /// <param name="pieceClass">King, Queen, Rook, etc</param> /// <param name="pieceFile">file location</param> /// <param name="pieceRank">rank location</param> public ChessPiece(PieceColor pieceColor, PieceClass pieceClass, PieceFile pieceFile, int pieceRank) { if (pieceClass == PieceClass.EnPassantTarget) { throw new ArgumentException(); } // Save the parameters as fields color = pieceColor; job = pieceClass; rank = pieceRank; file = pieceFile; deployed = false; captured = false; isReadyForPromotion = false; }
/// <summary> /// Process the input when waiting for the current player to select a move /// </summary> /// <param name="x">x coordinate in form</param> /// <param name="y">y coordinate in form</param> private void OnWaitingForMoveSelection(int x, int y) { BoardSquare square = ((IChessBoardView)view).GetSquare(x, y); foreach (BoardSquare move in legalMoves) { if (move == square) { // Done - this is the move MoveInformation moveInfo = new MoveInformation( new BoardSquare(selectedPiece.File, selectedPiece.Rank), move, selectedPiece.Deployed, board.CurrentFEN); moveInfo.Color = selectedPiece.Color; moveInfo.CastlingRights = board.ActivePlayerCastlingRights; Debug.WriteLine("Valid Move Detected: [{0},{1}]=>[{2},{3}]", selectedPiece.File, selectedPiece.Rank, move.File, move.Rank); // Need to detect promotion and launch dialog for it... bool isPawnMovingToBackRank = (selectedPiece.Color == PieceColor.White) ? (moveInfo.End.Rank == 8) : (moveInfo.End.Rank == 1); if ((selectedPiece.Job == PieceClass.Pawn) && isPawnMovingToBackRank) { PieceClass promotionJob = view.ChoosePromotionJob(); board.PromotePiece(moveInfo.Start.File, moveInfo.Start.Rank, moveInfo.End.File, moveInfo.End.Rank, promotionJob, ref moveInfo); } // Always returns true now board.MovePiece(ref moveInfo); view.Invalidate(); Debug.WriteLine(String.Format("Fullmoves: {0}", board.FullMoveCount)); Debug.WriteLine(String.Format("Halfmoves: {0}", board.HalfMoveCount)); Debug.WriteLine(String.Format("WhCastle: {0}", board.WhiteCastlingRights.ToString())); Debug.WriteLine(String.Format("BlCastle: {0}", board.BlackCastlingRights.ToString())); // Update the position with the engine UpdateEnginePosition(); break; } } // Either way this gets cleared legalMoves.Clear(); ((IChessBoardView)view).ClearHiglightedSquares(); selectedPiece = null; }
/// <summary> /// Helper to return a FEN char for a job, color matters /// </summary> /// <param name="pieceClass">Class to convert</param> /// <param name="color">PieceColor Black is lowercase</param> /// <returns></returns> public static char FenCharFromPieceClass(PieceClass pieceClass, PieceColor color) { char result; switch (pieceClass) { case PieceClass.King: result = 'k'; break; case PieceClass.Queen: result = 'q'; break; case PieceClass.Rook: result = 'r'; break; case PieceClass.Bishop: result = 'b'; break; case PieceClass.Knight: result = 'n'; break; case PieceClass.Pawn: result = 'p'; break; default: throw new ArgumentOutOfRangeException(); } if (color == PieceColor.White) { result = Char.ToUpper(result); } return(result); }
/// <summary> /// Converts a class to its character. This does not need to differentiate /// case for color like FEN does, it's just needed to update the engine. /// The starting position or FEN for the engine determines the active player /// </summary> /// <param name="job">Job to convert</param> /// <returns></returns> public static char PieceClassToPromotionChar(PieceClass job) { if (job == PieceClass.Queen) { return('q'); } if (job == PieceClass.Rook) { return('r'); } if (job == PieceClass.Knight) { return('n'); } if (job == PieceClass.Bishop) { return('b'); } // King and Pawn are missing from the normal list, as this is only // used in promotion, and you cannot promote to yourself or to the king throw new ArgumentOutOfRangeException(); }
public void BasicTests() { // Valid: { k, q, r, b, n, p } // Others: ArgumentOutOfRangeException Tuple <char, PieceClass>[] testDataValid = { new Tuple <char, PieceClass>('k', KING), new Tuple <char, PieceClass>('q', QUEN), new Tuple <char, PieceClass>('r', ROOK), new Tuple <char, PieceClass>('b', BISH), new Tuple <char, PieceClass>('n', KNHT), new Tuple <char, PieceClass>('p', PAWN), }; foreach (Tuple <char, PieceClass> tuple in testDataValid) { Trace.WriteLine(String.Format("Verifying {0} == {1}", tuple.Item1, tuple.Item2.ToString())); Assert.AreEqual(ChessBoard.PieceClassFromFen(tuple.Item1), tuple.Item2); } // Not a complete list, but the rest of [a-z][A-Z] that isn't valid plus some others string testDataInvalid = "acdefghijlmostuvwxyzACDEFGHIJLMOSTUVWXYZ0123456789!@#$%^&*"; foreach (char c in testDataInvalid) { bool caught = false; try { Trace.WriteLine(String.Format("Verifying {0} throws ArgumentOutOfRangeException", c)); PieceClass neverGetsAssigned = ChessBoard.PieceClassFromFen(c); } catch (ArgumentOutOfRangeException) { caught = true; } Assert.IsTrue(caught); } }
public void Move(GameObject Piece, int[] newPosition) { int i = 0; GameObject[] pieces = InGamePieces.ToArray(); while (i < InGamePieces.Count) { if (pieces[i] == Piece) { break; } } int[] PiecePosition = Pieces.ToArray()[i].GetLocation(); i = 0; while (i < Pieces.Count) { PieceClass piece = Pieces.ToArray()[i]; if (piece.GetLocation() == PiecePosition) { piece.SetPiece(newPosition); } } }
/// <summary> /// Small helper to get the mangled key for an image /// </summary> /// <param name="job"></param> /// <param name="color"></param> /// <returns></returns> private static string GetPieceImageKey(PieceClass job, PieceColor color) { return(String.Concat(job.ToString(), color.ToString())); }
/// <summary> /// When a pawn has made it to the back rank, it can be promoted. This method /// will mark a piece as needing promotion on the next move. We don't want to /// change the job until it has moved to keep inline with the rest of the logic /// </summary> /// <param name="startFile"></param> /// <param name="startRank"></param> /// <param name="targetFile"></param> /// <param name="targetRank"></param> /// <param name="promotionClass"></param> /// <param name="moveInfo">Detailed move info</param> public void PromotePiece(PieceFile startFile, int startRank, PieceFile targetFile, int targetRank, PieceClass promotionClass, ref MoveInformation moveInfo) { ChessPiece piece = FindPieceAt(startFile, startRank); int validRank = (piece.Color == PieceColor.White) ? 8 : 1; if (targetRank != validRank) { throw new ArgumentOutOfRangeException(); } // Find the pawn and mark it if (piece.Job != PieceClass.Pawn) { // Logic check throw new InvalidOperationException(); } moveInfo.PromotionJob = promotionClass; piece.PromoteOnNextMove(promotionClass); }
public void BasicPropertiesTests() { BoardSquare startSquare = new BoardSquare(new PieceFile('b'), 6); BoardSquare endSquare = new BoardSquare(new PieceFile('e'), 3); bool previouslyDeployed = true; Trace.WriteLine(String.Format("Constucting default MoveInformation[{0}:{1}->{2}:{3}] Deployed: {4}", startSquare.File.ToString(), startSquare.Rank, endSquare.File.ToString(), endSquare.Rank, previouslyDeployed)); MoveInformation testMove = new MoveInformation(startSquare, endSquare, previouslyDeployed, ChessBoard.InitialFENPosition); // First verify the basic properties set on creation Trace.WriteLine(String.Format("Verifying start and end squares...")); Assert.AreEqual(testMove.Start, startSquare); Trace.WriteLine(String.Format("Verifying FirstMove...")); Assert.IsFalse(testMove.FirstMove); // Now set some extraneous properties Trace.WriteLine(String.Format("Verifying Color set/get...")); PieceColor testColor = PieceColor.Black; testMove.Color = testColor; Assert.AreEqual(testMove.Color, testColor); // CastlingRights Trace.WriteLine(String.Format("Verifying CastlingRights set/get...")); BoardSide testCastlingRights = BoardSide.Queen; testMove.CastlingRights = testCastlingRights; Assert.AreEqual(testMove.CastlingRights, testCastlingRights); // PromotionClass Trace.WriteLine(String.Format("Verifying PromotionJob set/get...")); PieceClass testPromotionClass = PieceClass.Knight; Assert.IsFalse(testMove.IsPromotion); testMove.PromotionJob = testPromotionClass; Assert.AreEqual(testMove.PromotionJob, testPromotionClass); Assert.IsTrue(testMove.IsPromotion); // CapturedPiece and CastlingRook are mutually exclusive Properties // neither can be checked without first being set or an exception is // thrown. Also, if one is set and you check the other, an exception // is thrown // IsCapture and IsCastle can be used to check if either is set // without the exception Trace.WriteLine(String.Format("Verifying IsCapture and IsCastle initially false...")); Assert.IsFalse(testMove.IsCapture); Assert.IsFalse(testMove.IsCastle); Trace.WriteLine(String.Format("Set a capture piece and verify IsCapture and CapturedPiece...")); ChessPiece testPiece = new ChessPiece(PieceColor.White, PieceClass.Pawn, new PieceFile('c'), 2); testMove.CapturedPiece = testPiece; Assert.IsTrue(testMove.IsCapture); Assert.AreEqual(testMove.CapturedPiece, testPiece); try { Trace.WriteLine(String.Format("Attempting to get the CastlingRook (invalid)...")); ChessPiece rook = testMove.CastlingRook; } catch (InvalidOperationException) { Trace.WriteLine(String.Format("Caught InvalidOperationException...")); } // Recreate the test move to clear the captured piece testMove = new MoveInformation(startSquare, endSquare, previouslyDeployed, ChessBoard.InitialFENPosition); Trace.WriteLine(String.Format("Set a castling rook and verify IsCastle and CsatlingRook...")); ChessPiece testRook = new ChessPiece(PieceColor.White, PieceClass.Rook, new PieceFile('a'), 1); testMove.CastlingRook = testRook; Assert.IsTrue(testMove.IsCastle); Assert.AreEqual(testMove.CastlingRook, testRook); try { Trace.WriteLine(String.Format("Attempting to get the CapturedPiece (invalid)...")); ChessPiece capture = testMove.CapturedPiece; } catch (InvalidOperationException) { Trace.WriteLine(String.Format("Caught InvalidOperationException...")); } // Setting a non-Rook to a castling rook will throw testMove = new MoveInformation(startSquare, endSquare, previouslyDeployed, ChessBoard.InitialFENPosition); try { testMove.CastlingRook = testPiece; } catch (ArgumentException) { Trace.WriteLine(String.Format("Caught ArgumentException...")); } }
/// <summary> /// Promote the piece to a new class /// </summary> /// <param name="newLotInLife">PieceClass after promotion e.g. Queen /// 99.99999% of the time</param> public void PromoteOnNextMove(PieceClass newLotInLife) { isReadyForPromotion = true; promotionClass = newLotInLife; }