public static Board Parse(string board) { var rows = board.Split('\r', '\n').Where(r => !string.IsNullOrEmpty(r)).ToArray(); if (rows.Length != 8) { throw new ArgumentException($"Should be 8 rows! (got {rows.Length})"); } var boardRows = new List <Square[]>(); for (int rowIndex = 0; rowIndex < 8; rowIndex++) { var row = rows[rowIndex]; var boardRow = new List <Square>(); if (row.Length != (8 * 3) - 1) { throw new ArgumentException($"Rows must be 23 chars. Row {rowIndex} was {row.Length}"); } for (int columnIndex = 0; columnIndex < 8; columnIndex++) { string pieceString = row.Substring(columnIndex * 3, 2); var square = new Square( SquareReference.FromRowColumn(rowIndex, columnIndex), ParsePiece(pieceString) ); boardRow.Add(square); } boardRows.Add(boardRow.ToArray()); } return(new Board { Squares = boardRows.ToArray() }); }
public static IEnumerable <SquareReference> MovesUntilPiece( this Board board, SquareReference start, int rowDelta, int columnDelta, Color opponentColor) { SquareReference?move = start; while (true) { move = move.Value.Move(rowDelta, columnDelta); if (move == null) { yield break; } var piece = board[move.Value].Piece; if (piece.Color == opponentColor) { yield return(move.Value); yield break; } else if (piece.Color == Color.Empty) { yield return(move.Value); // yield and continue } else { // own color yield break; } } }
public Move(DateTime moveTimeUtc, Piece piece, SquareReference start, SquareReference end, Piece capturedPiece) { MoveTimeUtc = moveTimeUtc; Piece = piece; Start = start; End = end; CapturedPiece = capturedPiece; }
public Board MovePiece(SquareReference from, SquareReference to) { var newBoard = Clone(); var piece = Squares[from.Row][from.Column].Piece; newBoard.Squares[from.Row][from.Column].Piece = Piece.Empty; newBoard.Squares[to.Row][to.Column].Piece = piece; return(newBoard); }
public static SquareReference?Move(this SquareReference start, int rowDelta, int columnDelta) { int newRow = start.Row + rowDelta; int newColumn = start.Column + columnDelta; if (newRow < 0 || newRow > 7 || newColumn < 0 || newColumn > 7) { return(null); } return(SquareReference.FromRowColumn(newRow, newColumn)); }
public static Board CreateEmptyBoard() { return(new Board { Squares = new Square[8][] { Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(0, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(1, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(2, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(3, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(4, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(5, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(6, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(7, i), Piece.Empty)).ToArray(), } }); }
public static Board CreateStartingBoard() { return(new Board { Squares = new Square[8][] { (new [] { 2, 3, 4, 5, 6, 4, 3, 2 }) .Select( (i, index) => new Square( SquareReference.FromRowColumn(0, index), new Piece(Color.Black, (PieceType)i) ) ).ToArray(), Enumerable.Range(0, 8) .Select( i => new Square( SquareReference.FromRowColumn(1, i), new Piece(Color.Black, PieceType.Pawn) ) ).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(2, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(3, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(4, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8).Select(i => new Square(SquareReference.FromRowColumn(5, i), Piece.Empty)).ToArray(), Enumerable.Range(0, 8) .Select( i => new Square( SquareReference.FromRowColumn(6, i), new Piece(Color.White, PieceType.Pawn) ) ).ToArray(), (new [] { 2, 3, 4, 5, 6, 4, 3, 2 }) .Select( (i, index) => new Square( SquareReference.FromRowColumn(7, index), new Piece(Color.White, (PieceType)i) ) ).ToArray() } }); }
public IEnumerable <SquareReference> GetAvailableMoves(SquareReference from) { var initialMoves = GetAvailableMoves_NoCheckTest(this, from); var square = Board[from]; var piece = square.Piece; // filter out moves that result in check // brute force approach ;-) // for each move, check whether there are any moves for any opponent piece after that // which would end on the current player's king's square // if so then we have a move that puts the player into check, so filter out var nonCheckMoves = initialMoves.Where(move => { var newGame = MakeMove_Internal(from: square.Reference, to: move, suppressValidityCheck: true); return(!IsInCheck(newGame, piece.Color)); }); return(nonCheckMoves); }
private Game MakeMove_Internal(SquareReference from, SquareReference to, bool suppressValidityCheck) { if (!suppressValidityCheck) // GetAvailable moves calls this, so this flag avoids StackOverflowException ;-) { if (Board[from].Piece.Color != CurrentTurn || !GetAvailableMoves(from).Contains(to)) { throw new ArgumentException("Invalid move"); } } var capturedPiece = Board[to].Piece; Square square = Board[from]; var newGame = new Game( id: Id, currentTurn: (CurrentTurn == Color.Black) ? Color.White : Color.Black, board: Board.MovePiece(from, to), moves: _moves.Concat(new[] { new Move(DateTime.UtcNow, square.Piece, from, to, capturedPiece) }).ToList() ); return(newGame); // TODO - add a flag for whether the current player is in check }
public Game MakeMove(SquareReference from, SquareReference to) { return(MakeMove_Internal(from, to, suppressValidityCheck: false)); }
private IEnumerable <SquareReference> GetAvailableMoves_NoCheckTest(Game game, SquareReference from) { var square = game.Board[from]; var pieceType = square.Piece.PieceType; switch (pieceType) { case PieceType.Pawn: return(GetAvailableMoves_Pawn(game, square)); case PieceType.Rook: return(GetAvailableMoves_Rook(game, square)); case PieceType.Knight: return(GetAvailableMoves_Knight(game, square)); case PieceType.Bishop: return(GetAvailableMoves_Bishop(game, square)); case PieceType.Queen: return(GetAvailableMoves_Queen(game, square)); case PieceType.King: return(GetAvailableMoves_King(game, square)); default: throw new InvalidOperationException($"Unhandled piece type!! {pieceType}"); } }
} // TODO - should we make this immutable? public Square(SquareReference reference, Piece piece) { Reference = reference; Piece = piece; }
public Square this[SquareReference reference] { get { return(Squares[reference.Row][reference.Column]); } }