Thursday, March 27, 2014

A Chess Project, Part 10

Intro

We got a good start on our unit testing in the Chess Project Part 9 posting last week. We unit tested every possible move for white pieces, created a spiffy new html format for chess boards to ease our unit testing, and we tested many of our helper methods in other classes as well. This time around we will finish up unit testing the current suite of functionality. We have to add unit tests for some of the valid black piece moves (I only deem it worth our time to create tests for moves unique to black; his pawns and king castling moves, make sure black pieces can't put their own king in check) and we have just a few helper methods within ChessValidMoveCalculator to test out. Then we're green to move on to the super-fun part (next week), starting to figure out what the "best" move is for a given chess board!

The Code

Like last week, I think it best to start off by giving you this link to the code. There are too many new unit tests forming too much code to paste it in the blog, so at your leisure please download it from the link, open it up, build it, and take a look at the new unit tests. Then come on back so we can discuss them.

Unit Tests

We'll start with pawn moves. Obviously black's pawns move down the board while white's pawns move up the board, so their move calculations are different. This is why I decided to unit test black pawns separately from white pawns. You can see by looking at the unit test file that I mirrored all the white unit tests with black as far as pawns are concerned, so we should have full coverage.

I'm going to skip unit testing of black Knight, Bishop, Rook, and Queen moves. Why? These pieces move exactly the same whether they are white or black. The only difference is that white pieces can't put the white king in check, and black pieces can't put the black king in check, but I don't have to duplicate all my tests to check 1 situation per color. I did however recreate the majority of the king's unit tests as castling is different (white castles on row 7, black on row 0), so you can see in our unit test code that most but not all of the king testing is duplicated from white to black. I also renamed some of the unit tests to better denote color and direction.

We also added 8 more unit tests (4 each) for ColorThreatensSquare and IsKingInCheck, testing the positive and negative and black/white of each method.

You may have also noticed I had to fix more code. This just reaffirms my love of unit tests. See if you can find the code I had to fix. Here's a hint: it had to do with checking if a move would put the same-color king in check.

What's Next?

That's it for this week folks! We have 1 solution, 4 projects, dozens of classes, 80 unit tests, 1 web API, etc etc. Next week we'll FINALLY get to the whole point of this project, calculating the "best" move. I haven't a clue how long that will take us to do, it could be 1 post or 5, we'll just have to wait and see. 

Thursday, March 20, 2014

A Chess Project, Part 9

Intro

As promised last week in Part 8, this week is all about the unit tests. We've got a pretty sizable chunk of code going in this project and so far we have no way to test any of it. I don't plan on creating a GUI for this solution (at least not in this series of blog posts), so unit testing is the way to go. Please view my unit testing series of blog posts (UT1, UT2, UT3, UT4) for a quick refresher on unit testing if necessary.

The Code

I think it will be easier to understand what's going on if I give you a link to the code at the top of the article this time, so here you go. Once you have it pulled down, extracted and compiled come on back for the remainder of the article.

Unit Tests

As you can see in the screenshot below, I created a new unit test project in the solution named BlogChess.Backend.Test.
This is where all our unit tests for the project are going. As of the time I am writing this, there are 57 unit tests in the solution. That is a bit too many for us to walk through in the blog, so at your leisure please dig through the code and see what's going on. The unit tests at this point cover the vast majority of our functionality from the backend dll. We are testing the validation code, board size, and all the valid moves for white. The only things left to test are the black piece move validation methods, and we'll do that in the next blog post.

As a result of all this unit testing, I found 2 other things necessary. First, I had to fix some bugs. I know what you're thinking: "But Pete, you don't make mistakes!". Well I appreciate the kind words (you were thinking them, admit it!), but yes I actually do make mistakes. I bet I fixed a half-dozen of them thanks to the unit tests. I won't detail all of them (mostly because I don't remember what they were at this point), but suffice it to say they would have made this project rather useless if they had been left to fester. The second thing I found necessary while creating unit tests was to have a way to visualize a chess board so that I could set up specific positions in the unit tests, and validate piece movement. Cue dramatic new bold sub-heading...

New Format, New Formatter/Parser (use of html agility pack)

...So, I created a new chess format. Sure arrays are great for representing a chess board, but which is easier to work with when creating a unit test? This...

{ {-4, -2, -3, -5, -6, -3, -2, -4}, {-1, -1, -1, -1, -1, -1, -1, -1}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {4, 2, 3, 5, 6, 3, 2, 4} }


or this?

So, I invented a new chess format (it sounds a lot more impressive than it really is) and created a class to import the new format. Believe it or not, the above screenshot is pure html/css. There are no images in that. Well the screenshot itself is an image obviously, but it's showing just html/css.

How did we accomplish this? If you're moderately familiar with html/css, it's easier than you might think. It turns out that unicode defines special characters for each of the chess pieces, so as long as the font you are using supports these values, then you can use plain-old-text to represent the pieces. After that it's just a simple matter of putting a board around the pieces you want, and voila! You can look at some of the many samples I put in the solution, using the screenshot below as a guide to finding the files. The essence of the export format though is much simpler than these files allude to. All you need is elements on the page that have a data-col attribute of "a" through "h", and those same elements should have a data-row attribute of "1" through "8". These of course represent the 64 squares of the chess board. For ease of formatting I've elected to use a table (you could use div's, span's, or whatever other html element you feel like using), a modified sample of which you can see below.

    <table>
        <tbody>
<tr>
            <td>8</td>
            <td data-col="a" data-row="8"></td>
            <td data-col="b" data-row="8"></td>
            <td data-col="c" data-row="8"></td>
            <td data-col="d" data-row="8"></td>
            <td data-col="e" data-row="8">♚</td>
            <td data-col="f" data-row="8"></td>
            <td data-col="g" data-row="8"></td>
            <td data-col="h" data-row="8"></td>
        <tr>
</tbody></table>

For some more thorough and much cleaner looking samples with css to format them nicely, take a look at any of the unit test files in the solution as you see highlighted below. These samples all import perfectly fine using our new formatter object, and are also very easy to use the mark-1 eyeball to see what's going on with the board itself by just viewing the file in any modern web browser. Again the above html table is just a sample; obviously you'd need the other 56 squares to make a full board :)




Now, on to the design and code of the formatter. In the future I can see myself wanting to import and export various other chess formats/notations (there are plenty of them), so let's use an interface to represent any type of formatter. We'll call the interface IChessBoardFormatter. Then, because the format we want right now is html based, we'll just call the class HtmlChessBoardFormatter and have the class implement the new interface.


IChessBoardFormatter defines 4 methods: Import, Export, ExternalPieceToNative, NativePieceToExternal. Import and Export should be pretty self-explanatory. ExternalPieceToNative converts an external representation of a piece (in whatever format) to a native piece (a short value from -6 (black king) to +6 (white king). NativePieceToExternal just goes the other direction.

HtmlChessBoardFormatter is the class we'll use to translate boards between our internal representation(arrays of short) and the new human-friendly format (html). For the moment I didn't implement the capability to export; just import. For now I only need this class in order to read in html files for unit testing. It's too much code to put in this blog post, so open up HtmlChessBoardFormatter and take a look at the Import and ExternalPieceToNative methods; they're where the magic is.

If you've never used the Html Agility Pack I highly recommend it for your HTML parsing needs in .net. I've used it in the Import method of the formatter class in order to find html elements with a data-row and data-col attribute, as they are the elements that contain our chess pieces. Here's a sample of it:

            var document = new HtmlDocument();
            document.LoadHtml(sourceBoard);
            foreach (var node in document.DocumentNode.SelectNodes("//*[@data-row]"))
            {
                var sourceRow = node.Attributes["data-row"].Value;
                var sourceCol = node.Attributes["data-col"].Value;


Spiffy huh? Resilient html parsing made easy in .net.

What's Next?

As you may have guessed, we'll have to hit up the unit tests for black pieces/movement and any other public methods of the valid move calculator next week. I can finally see the light at the end of the space-time continuum though, we're almost ready to start coding our "best move" logic! And, thanks to these unit tests, we'll actually be able to suggest valid moves.

Resources

Wikipedia Chess
Wikipedia en Passant
Wikipedia Chess Symbols in UnicodeHtml Agility Pack

Thursday, March 13, 2014

A Chess Project, Part 8

Intro

We're moving right along with this sizable project, a Web API that will tell you the "best" move to make for a given chess position/game. We've created a test page, a Web API for clients to call, and we're still in the middle of calculating valid moves. If you need a refresher, look back through the history of this blog and find parts 1-7; they'll give you the info you need. On to part 8!

Can't Put Your Own King in Check

As I mentioned last week, there is still one major restriction we need to code: you cannot make a move that puts your own king in check. Here is an illustration of such an illegal move:

(white's turn)


Normally the white pawn at d2 (the one with the red arrow pointing at it) could move forward/up one square to d3, or two squares to d4. However, because the black bishop on b4 would threaten the king if the pawn moved out of the way, the pawn cannot in fact move from its current location. This is the type of move we are trying to prevent, so let's figure out how to do that.

Logically speaking, the best thing I can come up with is to pretend that the white piece has moved, and then check the valid moves of all the black pieces. If a black piece would be capable of "taking" the white king, then the previous move was invalid. Keep in mind that this invalidity could count for any type of piece; a pawn move can't put your king in danger, a rook move can't, and so on. This means a logical place to put the code would be in AddMoveToList, as it's already called every single time we add a move to, well, the list.

This isn't where we'll start though. We'll first create a method that tells us if the king is in check. We'll be creative and call it IsKingInCheck. Here's the code for it:

        protected bool IsKingInCheck(bool colorIsWhite, ChessBoard board)
        {
            var kingPosition = FindKing(colorIsWhite, board);
            return ColorThreatensSquare(!colorIsWhite, board, kingPosition.Item1, kingPosition.Item2);
        }


Pretty short and sweet; we find the king, and then return a boolean telling us if the opposite color threatens the square that the king is on. We haven't yet created the FindKing function though, so let's do that now:

        protected Tuple<short, short> FindKing(bool colorIsWhite, ChessBoard board)
        {
            short kingPieceValue = (short)(Constants.King * (colorIsWhite ? Constants.WhiteTransform : Constants.BlackTransform));
            for (short row = 0; row < 8; row++)
            {
                for (short col = 0; col < 8; col++)
                {
                    if (board.Board[row, col] == kingPieceValue)
                        return new Tuple<short, short>(row, col);
                }
            }
            throw new Exception("King not found");
        }


This method determines what the short constant value is for the king based on the color we are looking for, then loops through the board to find the king on it. If there is no king we throw an exception.

It's worth pointing out now that we only need to traverse 1 branch into the tree to check for checks; after all, when you're checking if a piece threatens the king, you don't really care if the piece can actually make the move; you only care if the square is threatened. Because of this we now need to create a new field of class ChessValidMoveCalculator that tells us whether we should allow multi-layer traversal of the tree:

protected bool m_allowCheckSubTrees = true;


If you'll recall, IsKingInCheck calls the pre-existing function ColorThreatensSquare. It is in this function that we calculate the next color's valid moves to see if a square is threatened, so it's in this method that we need to set m_allowCheckSubTrees to false. Here's the updated version of this function:

        public bool ColorThreatensSquare(bool colorIsWhite, ChessBoard board, short row, short col)
        {
            var game = new ChessGame();
            var positions = new List<ChessBoard>();
            positions.Add(new ChessBoard(true) { Board = (short[,])board.Board.Clone() });
            game.Positions = positions.ToList();
            game.GameStatus = colorIsWhite ? GameStatus.WhitesTurn : GameStatus.BlacksTurn;
            var futureCalculator = new ChessValidMoveCalculator(game);
            futureCalculator.m_allowCheckSubTrees = false;
            var futurePositions = futureCalculator.CalculateValidMoves();
            var colorSign = colorIsWhite ? Constants.WhiteTransform : Constants.BlackTransform;
            foreach (var position in futurePositions)
                if (Math.Sign(position.Board[row, col]) == colorSign)
                    return true;
            return false;
        }


What did we do to this method? We first set the game.GameStatus to the turn of the appropriate color, based on who we are checking using the parameter colorIsWhite. I realized when I opened up this unit that I had never set whose turn it is in this "future" game, so I needed to do that in order to keep things from splodin. I then set futureCalculator.m_allowCheckSubTrees to false, so that we don't check to make sure the piece can actually move to determine if it threatens a square, as we don't want a nigh-infinite traversal of our logic tree.

The last thing we need to do is call our new method IsKingInCheck. As I said a few paragraphs ago, the best place to do this is in AddMoveToList.

        protected IList<ChessBoard> AddMoveToList(ChessBoard startingBoard, IList<ChessBoard> boards, short oldRow, short oldCol, short newRow, short newCol)
        {
            var resultArray = new ChessBoard[boards.Count];
            boards.CopyTo(resultArray, 0);
            var result = resultArray.ToList();
            if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8)
            {
                //check the sign (color) of the current square and future square; if same, don't allow the move
                var startingPieceSign = Math.Sign(startingBoard.Board[oldRow, oldCol]);
                var futurePieceSign = Math.Sign(startingBoard.Board[newRow, newCol]);
                if (startingPieceSign != futurePieceSign)
                {
                    var futureBoard = (short[,])startingBoard.Board.Clone();
                    var piece = futureBoard[oldRow, oldCol];
                    futureBoard[oldRow, oldCol] = Constants.Empty;
                    futureBoard[newRow, newCol] = piece;
                    var newBoard = new ChessBoard(true);
                    newBoard.Board = futureBoard;
                    //check if new board and starting board are the same; if so don't add to valid moves list
                    var equal = futureBoard.Rank == startingBoard.Board.Rank &&
                        Enumerable.Range(0, futureBoard.Rank).All(dimension => futureBoard.GetLength(dimension) == startingBoard.Board.GetLength(dimension)) &&
                        futureBoard.Cast<short>().SequenceEqual(startingBoard.Board.Cast<short>());
                    //make sure the move wouldn't put the current color's king in check
                    var wouldPutSameColorKingInCheck = false;
                    if (m_allowCheckSubTrees)
                    {
                        var futureBoardContainer = new ChessBoard(true);
                        futureBoardContainer.Board = futureBoard;
                        wouldPutSameColorKingInCheck = IsKingInCheck(m_game.GameStatus == GameStatus.BlacksTurn, futureBoardContainer);
                    }
                    //add move to list of valid moves
                    if (!equal && !wouldPutSameColorKingInCheck)
                        result.Add(newBoard);
                }
            }
            return result;
        }


The addition to this function starts with the comment "make sure the move wouldn't put the current color's king in check". Here we first determine if we're supposed to check sub-trees, because if not then we don't care if the move would put the king in check. If we are allowed to check sub-trees we set a local variable wouldPutSameColorKingInCheck to the appropriate value by calling IsKingInCheck, passing in the potential future board. Lastly we add the move to our list of valid moves only if it would not put the king in check.

What's Next?

We're moving right along. Next week we'll create our unit tests. We won't make any actual progress on the "best" move calculation while creating our tests, but we'll give ourselves better confidence that what we've done so far is actually correct and most likely we'll be able to find and fix some bugs.

Here's the link to the current source code.

Resources

  • Online chess board editor "Apronus"

Thursday, March 6, 2014

A Chess Project, Part 7

Intro

Here we are in part 7 of the chess project. Last week we coded most of the valid moves available to our chess pieces. This week we'll tackle the remainder. What's left? En passant pawn captures and castling.


En Passant

I'm going to try not to plagiarize here, but I'm sure quite a bit has been written about en-passant so if you recognize these words, sorry. An en-passant capture is a pawn move where it captures an enemy pawn that has just moved two squares forward, pretending the target pawn has moved only a single square forward. The capturer must be on it's color's 5th rank. It's kind of hard to picture so let me refer you to this Wikipedia article which has some nice pictures.

Open up ChessValidMoveCalculator. Skip down to CalculatePawnValidMoves, as this is where we'll be doing our work. We already have calculations in there for moving forward-left and forward-right, and an en passant capture is a special case of these 2 moves. I won't bore you with too much detail, nor will I claim that this code is 100% perfect (darn my lack of unit testing!). Below you will see the modified portion ChessValidMoveCalculator.

                //forward-left diagonal (only if capturing opponent's piece)
                rowMovementAmount = (short)(1 * rowModifier);
                newRow = (short)(currentRow + rowMovementAmount);
                newCol = (short)(currentCol - 1);
                if (newRow >= 0 && newRow <= 7 && newCol >= 0 && newCol <= 7)
                {
                    if (Math.Sign(m_game.Positions.Last().Board[newRow, newCol]) == -Math.Sign(m_game.Positions.Last().Board[currentRow, currentCol]))
                    {
                        if (newRow == 0 || newRow == 7) //back rank promotions
                        {
                            for (short promotionPieceIndex = Constants.Knight; promotionPieceIndex <= Constants.Queen; promotionPieceIndex++)
                            {
                                short promotionPiece = (short)(promotionPieceIndex * rowModifier);
                                boards = AddMoveToList(m_game.Positions.Last(), boards, currentRow, currentCol, newRow, newCol);
                            }
                        }
                        else
                            boards = AddMoveToList(m_game.Positions.Last(), boards, currentRow, currentCol, newRow, newCol);
                    }
                    else if (m_game.Positions.Count() > 1) //big chunk of logic to see if en passant is possible
                    {
                        if ((currentRow == 3 && currentStatus == GameStatus.WhitesTurn) || (currentRow == 4 && currentStatus == GameStatus.BlacksTurn))
                        {
                            var priorPosition = m_game.Positions.ToArray()[m_game.Positions.Count() - 1].Board;
                            //pawn of opposite color moved up 2 squares next to the current piece
                            if (priorPosition[newRow + rowModifier, newCol] == Constants.Pawn * rowModifier && m_game.Positions.Last().Board[currentRow, newCol] == Constants.Pawn * rowModifier) 
                            {
                                boards = AddMoveToList(m_game.Positions.Last(), boards, currentRow, currentCol, newRow, newCol);
                            }
                        }
                    }
                }
                //forward-right diagonal (only if capturing opponent's piece)
                rowMovementAmount = (short)(1 * rowModifier);
                newRow = (short)(currentRow + rowMovementAmount);
                newCol = (short)(currentCol + 1);
                if (newRow >= 0 && newRow <= 7 && newCol >= 0 && newCol <= 7)
                {
                    if (Math.Sign(m_game.Positions.Last().Board[newRow, newCol]) == -Math.Sign(m_game.Positions.Last().Board[currentRow, currentCol]))
                    {
                        if (newRow == 0 || newRow == 7) //back rank promotions
                        {
                            for (short promotionPieceIndex = Constants.Knight; promotionPieceIndex <= Constants.Queen; promotionPieceIndex++)
                            {
                                short promotionPiece = (short)(promotionPieceIndex * rowModifier);
                                boards = AddMoveToList(m_game.Positions.Last(), boards, currentRow, currentCol, newRow, newCol);
                            }
                        }
                        else
                            boards = AddMoveToList(m_game.Positions.Last(), boards, currentRow, currentCol, newRow, newCol);
                    }
                    else if (m_game.Positions.Count() > 1) //big chunk of logic to see if en passant is possible
                    {
                        if ((currentRow == 3 && currentStatus == GameStatus.WhitesTurn) || (currentRow == 4 && currentStatus == GameStatus.BlacksTurn))
                        {
                            var priorPosition = m_game.Positions.ToArray()[m_game.Positions.Count() - 1].Board;
                            //pawn of opposite color moved up 2 squares next to the current piece
                            if (priorPosition[newRow + rowModifier, newCol] == Constants.Pawn * rowModifier && m_game.Positions.Last().Board[currentRow, newCol] == Constants.Pawn * rowModifier)
                            {
                                boards = AddMoveToList(m_game.Positions.Last(), boards, currentRow, currentCol, newRow, newCol);
                            }
                        }
                    }
                }


There are 2 additions, and both are else chunks that have a comment with "en passant" in it. If the current piece is a pawn, and the pawn is on the 5th rank for it's appropriate color, and if the prior move saw a pawn move 2 squares to get next to the current pawn, then en passant is available.


Castling

Castling is an important defensive maneuver in chess whereby the king gets to move 2 squares towards the edge of the board and the rook to that same side jumps 1 square to the opposite side of the king. In the early part of the game this has 2 important purposes: the first part is this gets the king nestled into the easily-defensible corner, usually behind a shield of protective pawns. This gives the king disposable cover that is tough to break through cheaply. The second purpose is it brings the rook closer into play. Rooks are more valuable in the center of the board where they have more room to roam.

 The king can castle in either direction (left and right), but with these limitations:
  1. there can be no other pieces between the king and the rook.
  2. the king and rook must still be on their starting square (they cannot have moved yet during the game).
  3. None of the opponents pieces may threaten squares that the king has to move through, to, or from.
  4. And of course you can't make any move that puts your king in check, including castling.

As you've guessed, the logic for this maneuver will go into the method CalculateKingValidMoves. As you can see below, I've split the castling logic out into 2 sections: 1 for black and 1 for white. It just looks a little cleaner this way:

        protected IList<ChessBoard> CalculateKingValidMoves(short currentRow, short currentCol, IList<ChessBoard> boards, GameStatus currentStatus)
        {
            short newRow;
            short newCol;
            short rowMovementAmount;
            short colMovementAmount;
            bool isWhitePiece = m_game.Positions.Last().Board[currentRow, currentCol] > 0;
            bool isBlackPiece = m_game.Positions.Last().Board[currentRow, currentCol] < 0;
            if ((currentStatus == GameStatus.BlacksTurn && isBlackPiece) || (currentStatus == GameStatus.WhitesTurn && isWhitePiece))
            {
                //+1+1,+1-1,-1+1,-1-1
                for (rowMovementAmount = -1; rowMovementAmount <= 1; rowMovementAmount++)
                {
                    for (colMovementAmount = -1; colMovementAmount <= 1; colMovementAmount++)
                    {
                        newRow = (short)(currentRow + rowMovementAmount);
                        newCol = (short)(currentCol + colMovementAmount);
                        boards = AddMoveToList(m_game.Positions.Last(), boards, currentRow, currentCol, newRow, newCol);
                    }
                }
                //black castle
                if (currentStatus == GameStatus.BlacksTurn && isBlackPiece && currentCol == 4 && currentRow == 0)
                {
                    //castle west
                    if (m_game.Positions.Last().Board[0, 0] == Constants.Rook * Constants.BlackTransform &&
                        m_game.Positions.Last().Board[0, 1] == Constants.Empty &&
                        m_game.Positions.Last().Board[0, 2] == Constants.Empty &&
                        m_game.Positions.Last().Board[0, 3] == Constants.Empty)
                    {
                        var futureBoard = (short[,])m_game.Positions.Last().Board.Clone();
                        futureBoard[0, 2] = Constants.King * Constants.BlackTransform;
                        futureBoard[0, 3] = Constants.Rook * Constants.BlackTransform;
                        boards = boards.ToList();
                        bool anySquareThreatened = false;
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 0);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 1);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 2);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 3);
                        if (!anySquareThreatened)
                            boards.Add(new ChessBoard(true) { Board = futureBoard });
                    }
                    //castle east
                    if (m_game.Positions.Last().Board[0, 7] == Constants.Rook * Constants.BlackTransform &&
                        m_game.Positions.Last().Board[0, 6] == Constants.Empty &&
                        m_game.Positions.Last().Board[0, 5] == Constants.Empty)
                    {
                        var futureBoard = (short[,])m_game.Positions.Last().Board.Clone();
                        futureBoard[0, 6] = Constants.King * Constants.BlackTransform;
                        futureBoard[0, 5] = Constants.Rook * Constants.BlackTransform;
                        boards = boards.ToList();
                        bool anySquareThreatened = false;
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 7);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 6);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 5);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(true, m_game.Positions.Last(), 0, 4);
                        if (!anySquareThreatened)
                            boards.Add(new ChessBoard(true) { Board = futureBoard });
                    }
                }
                //white castle
                if (currentStatus == GameStatus.WhitesTurn && isWhitePiece && currentCol == 4 && currentRow == 7)
                {
                    //castle west
                    if (m_game.Positions.Last().Board[7, 0] == Constants.Rook &&
                        m_game.Positions.Last().Board[7, 1] == Constants.Empty &&
                        m_game.Positions.Last().Board[7, 2] == Constants.Empty &&
                        m_game.Positions.Last().Board[7, 3] == Constants.Empty)
                    {
                        var futureBoard = (short[,])m_game.Positions.Last().Board.Clone();
                        futureBoard[7, 2] = Constants.King;
                        futureBoard[7, 3] = Constants.Rook;
                        boards = boards.ToList();
                        bool anySquareThreatened = false;
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 0);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 1);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 2);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 3);
                        if (!anySquareThreatened)
                            boards.Add(new ChessBoard(true) { Board = futureBoard });
                    }
                    //castle east
                    if (m_game.Positions.Last().Board[7, 7] == Constants.Rook &&
                        m_game.Positions.Last().Board[7, 6] == Constants.Empty &&
                        m_game.Positions.Last().Board[7, 5] == Constants.Empty)
                    {
                        var futureBoard = (short[,])m_game.Positions.Last().Board.Clone();
                        futureBoard[7, 6] = Constants.King;
                        futureBoard[7, 5] = Constants.Rook;
                        boards = boards.ToList();
                        bool anySquareThreatened = false;
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 7);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 6);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 5);
                        anySquareThreatened = anySquareThreatened || ColorThreatensSquare(false, m_game.Positions.Last(), 7, 4);
                        if (!anySquareThreatened)
                            boards.Add(new ChessBoard(true) { Board = futureBoard });
                    }
                }
            }
            return boards;
        }

It's a pretty fair amount of code here; we have to check both directions since the kings and rooks can castle both left and right. We also checked to make sure no pieces are between king and rook, and made sure no opposing pieces threaten the squares they are on or that they will be passing through.

Summary and What's Next

That's it for this week folks. This stuff is getting harder each week! The good news is that there are no more movement types left to code. The bad news is we still have one major restriction to code, and that being that you cannot make a move which puts your own king in check. We will code this one in the next blog post and apply it to all of the move calculations that we have done so far. I'm also becoming more and more wary of how complicated the code is getting; I'm not really trusting the accuracy of the code. We will need to start unit testing this stuff pretty soon, possibly even in the next post. Normally I would do the unit testing alongside the actual coding, but for the sake of keeping these posts reasonable and focused I have foregone unit testing to date.

And finally, here is the code

Resources

Castling