public IReadOnlyList <CellId> ValidMovesForCell(CellId cellId, IChessBoard board)
        {
            var validMoveList = new List <CellId>();

            var source = board.GetCell(cellId);

            for (int row = 0; row < board.NumRows; row++)
            {
                for (int col = 0; col < board.NumCols; col++)
                {
                    // Figure out the status of the cell.
                    //
                    var target = board.GetCell(CellId.Create(row, col));
                    if (IsValidMove(source, target, board))
                    {
                        validMoveList.Add(CellId.Create(row, col));
                    }
                }
            }
            return(validMoveList);
        }
 private CellId keyFor(int row, int col)
 {
     return(CellId.Create(row, col));
 }
        private void setupQueenRules()
        {
            var queenRules =
                GameRule.Create().Filter(x =>
                                         x.PieceType == EChessPieceType.Queen);


            queenRules.InvalidMove((s, t, c) =>
            {
                // Can not move to our own position. This would cause an indexing issue.
                //
                if (s.ColIndex == t.ColIndex && s.RowIndex == t.RowIndex)
                {
                    return(true);
                }

                // Can not move past another piece.
                //
                int colDiff = s.ColIndex - t.ColIndex;
                int rowDiff = s.RowIndex - t.RowIndex;

                int stepRow = rowDiff > 0 ? -1 : 1;
                int stepCol = colDiff > 0 ? -1 : 1;

                if (colDiff == 0)
                {
                    stepCol = 0;
                }
                if (rowDiff == 0)
                {
                    stepRow = 0;
                }

                // Check there is no piece on the way to the target.
                //
                for (int step = 1; ; step++)
                {
                    int row = s.RowIndex + stepRow * step;
                    int col = s.ColIndex + stepCol * step;

                    if (row < 0 || row >= c.NumRows || col < 0 || col >= c.NumCols)
                    {
                        return(true);
                    }

                    // We reached the target it is not an invalid move.
                    //
                    if (row == t.RowIndex && col == t.ColIndex)
                    {
                        return(false);
                    }

                    if (row == c.NumCols - 1 && col == c.NumRows - 1)
                    {
                        return(true);
                    }

                    // We reached another piece, but it can not be the target of our move
                    // therefore this move is not valid.
                    //
                    var cell = c.GetCell(CellId.Create(row, col));
                    if (cell.PieceType != EChessPieceType.Empty)
                    {
                        return(true);
                    }
                }
            });

            queenRules.InvalidMove((s, t, c) =>
            {
                // Can not move to our own position. This would cause an indexing issue.
                //
                if (s.ColIndex == t.ColIndex && s.RowIndex == t.RowIndex)
                {
                    return(true);
                }

                // Can not move past another piece.
                //
                int colDiff = s.ColIndex - t.ColIndex;
                int rowDiff = s.RowIndex - t.RowIndex;

                if (Math.Abs(colDiff) != Math.Abs(rowDiff))
                {
                    return(false);                                        // Check its a diagonal move
                }
                int stepRow = rowDiff > 0 ? -1 : 1;
                int stepCol = colDiff > 0 ? -1 : 1;

                // Check there is no piece on the way to the target.
                //
                for (int step = 1; t.ColIndex != s.ColIndex + stepCol * step; step++)
                {
                    int row = s.RowIndex + stepRow * step;
                    int col = s.ColIndex + stepCol * step;

                    // We reached the target it is not an invalid move.
                    //
                    if (row == t.RowIndex || col == t.ColIndex)
                    {
                        return(false);
                    }

                    if (row == c.NumCols - 1 && col == c.NumRows - 1)
                    {
                        return(true);
                    }

                    // We reached another piece, but it can not be the target of our move
                    // therefore this move is not valid.
                    //
                    var cell = c.GetCell(CellId.Create(row, col));
                    if (cell.PieceType != EChessPieceType.Empty)
                    {
                        return(true);
                    }
                }
                return(false);
            });

            queenRules.ValidMove((s, t, c) =>
            {
                // Rook can move diagonally or vertically.
                //
                int colDiff = Math.Abs(s.ColIndex - t.ColIndex);
                int rowDiff = Math.Abs(s.RowIndex - t.RowIndex);

                if (colDiff == 0 || rowDiff == 0)
                {
                    return(true);
                }
                return(false);
            });

            queenRules.ValidMove((s, t, c) =>
            {
                // Bishop can move diagonally to take any piece.
                //
                int colDiff = Math.Abs(s.ColIndex - t.ColIndex);
                int rowDiff = Math.Abs(s.RowIndex - t.RowIndex);

                if (colDiff != rowDiff)
                {
                    return(false);
                }
                return(true);
            });

            _gameRules.Add(queenRules);
        }
        private void setupKingRules()
        {
            var kingRules =
                GameRule.Create().Filter(x =>
                                         x.PieceType == EChessPieceType.King);

            kingRules.InvalidMove((s, t, c) =>
            {
                if (t.PieceColor != s.PieceColor)
                {
                    return(false);
                }

                // Can not move to a piece of the same color unless it is a rook.
                // Some more castle rules are checked below.
                //
                if (t.PieceColor == s.PieceColor && t.PieceType == EChessPieceType.Rook)
                {
                    return(false);
                }

                return(true);
            });

            kingRules.ValidMove((s, t, c) =>
            {
                int colDiff = Math.Abs(s.ColIndex - t.ColIndex);
                int rowDiff = Math.Abs(s.RowIndex - t.RowIndex);

                return(colDiff <= 1 && rowDiff <= 1);
            });

            // Setup up the castle, it is only possible if the king and the rook have not been moved before and
            // there is no piece between the king and the rook.
            //
            kingRules.ValidMove((s, t, c) =>
            {
                // Check the target is a friendly rook.
                //
                if (t.PieceType != EChessPieceType.Rook || s.PieceColor != t.PieceColor)
                {
                    return(false);
                }
                // Check the rook and the king have not been moved.
                //
                if (c.HasMoved(s.Identifier) || c.HasMoved(t.Identifier))
                {
                    return(false);
                }
                // Check there is no piece between the king and the rook.
                //
                int colDiff = s.ColIndex - t.ColIndex;
                int colStep = colDiff > 0 ? -1 : 1;
                for (int step = 1; s.ColIndex + step * colStep != t.ColIndex; step++)
                {
                    int col  = s.ColIndex + step * colStep;
                    var cell = c.GetCell(CellId.Create(s.RowIndex, col));
                    if (cell.PieceType != EChessPieceType.Empty)
                    {
                        return(false);
                    }
                }

                return(true);
            });
            _gameRules.Add(kingRules);
        }
        private void setupBlackBishopRules()
        {
            var blackBishopRules =
                GameRule.Create().Filter(x => x.PieceColor == EChessPieceColor.Black && x.PieceType == EChessPieceType.Bishop);

            blackBishopRules.InvalidMove((s, t, c) =>
            {
                // Can not move to a field occupied by a black piece.
                //
                return(t.PieceColor == EChessPieceColor.Black);
            });

            blackBishopRules.InvalidMove((s, t, c) =>
            {
                // Can not move past another piece.
                //
                int colDiff = s.ColIndex - t.ColIndex;
                int rowDiff = s.RowIndex - t.RowIndex;

                if (Math.Abs(colDiff) != Math.Abs(rowDiff))
                {
                    return(false);                                        // Check its a diagonal move
                }
                int stepRow = rowDiff > 0 ? -1 : 1;
                int stepCol = colDiff > 0 ? -1 : 1;

                // Check there is no piece on the way to the target.
                //
                for (int step = 1; t.ColIndex != s.ColIndex + stepCol * step; step++)
                {
                    int row = s.RowIndex + stepRow * step;
                    int col = s.ColIndex + stepCol * step;

                    // We reached the target it is not an invalid move.
                    //
                    if (row == t.RowIndex || col == t.RowIndex)
                    {
                        return(false);
                    }

                    // We reached another piece, but it can not be the target of our move
                    // therefore this move is not valid.
                    //
                    var cell = c.GetCell(CellId.Create(row, col));
                    if (cell.PieceType != EChessPieceType.Empty)
                    {
                        return(true);
                    }
                }
                return(false);
            });

            blackBishopRules.ValidMove((s, t, c) =>
            {
                // Bishop can move diagonally to take any piece.
                //
                int colDiff = Math.Abs(s.ColIndex - t.ColIndex);
                int rowDiff = Math.Abs(s.RowIndex - t.RowIndex);

                if (colDiff != rowDiff)
                {
                    return(false);
                }
                return(true);
            });
            _gameRules.Add(blackBishopRules);
        }