/// <summary> /// Determine if the placement of the specified symbol on the specified square resulted in a victory. /// </summary> /// <param name="symbol"> /// Symbol that was just recently placed. /// </param> /// <param name="square"> /// Square where symbol was placed /// </param> /// <param name="victorySquares"> /// In case of victory, this out parameter will hold the set of squares that participated in this victory. /// </param> /// <returns> /// true if placement was determined to result in victory. false otherwise. /// </returns> private bool IsPlayerVictory(PlayerSymbol symbol, BoardSquare square, out IEnumerable <BoardSquare> victorySquares) { victorySquares = null; if (symbol != square.Symbol) { return(false); } var victorySet = new HashSet <BoardSquare>(); foreach (var direction in VictoryDirections) { int numSquaresMatching = 0; // Find the edge of the board, in current direction from square int beginRow = square.Row; int beginColumn = square.Column; while ((beginRow - direction[0] >= 0) && (beginColumn - direction[1] >= 0) && (beginRow - direction[0] < Board.Size) && (beginColumn - direction[1] < Board.Size)) { beginRow -= direction[0]; beginColumn -= direction[1]; } // go to the other edge of the board, looking for matching squares for (int row = beginRow, column = beginColumn; (row >= 0) && (column >= 0) && (row < Board.Size) && (column < Board.Size); row += direction[0], column += direction[1]) { if (symbol == board.GetAt(row, column).Symbol) { ++numSquaresMatching; } } // A full board length of matching squares is required for victory if (numSquaresMatching < Board.Size) { continue; } // Add the squares as victory squares, but keep iterating because there might be victory squares in other directions for (int row = beginRow, column = beginColumn; (row >= 0) && (column >= 0) && (row < Board.Size) && (column < Board.Size); row += direction[0], column += direction[1]) { victorySet.Add(board.GetAt(row, column)); } } // If victory set is non-empty, then there was victory in at least one direction if (0 == victorySet.Count) { return(false); } victorySquares = victorySet; return(true); }
/// <summary> /// Attempt to place specified symbol in specified board square. /// </summary> /// <param name="symbol"> /// Symbol to be placed. /// </param> /// <param name="square"> /// Square where placement will be attempted. /// </param> /// <returns> /// PlacementStatus indicating whether the move attempted was valid or invalid. /// </returns> public PlacingStatus PlaceSymbol(PlayerSymbol symbol, BoardSquare square) { if (null == square) { throw new ArgumentException( Properties.Resources.InvalidPlacingSquare, "square"); } // If game has already ended, let player know if (this.hasEnded) { return(PlacingStatus.GameEnded); } // If square is already occupied, let player know if (PlayerSymbol.None != square.Symbol) { return(PlacingStatus.SquareOccupied); } // If it's currently not the turn of the player that spoke, let them know if (currentSymbol != symbol) { return(PlacingStatus.OutOfTurn); } // Move was valid, so place symbol in square square.Symbol = symbol; // Check if player has won IEnumerable <BoardSquare> victorySquares; if (IsPlayerVictory(symbol, square, out victorySquares)) { foreach (BoardSquare victorySquare in victorySquares) { victorySquare.IsHighlighted = true; } this.hasEnded = true; return(PlacingStatus.Victory); } if (this.board.IsFull()) { this.hasEnded = true; return(PlacingStatus.Draw); } // If player did not win, it's the other player's turn this.currentSymbol = this.currentSymbol.Opponent(); return(PlacingStatus.Valid); }
/// <summary> /// Initializes a new instance of the <see cref="Board"/> class. /// </summary> public Board() { boardSquares = new BoardSquare[BoardSize][]; for (int row = 0; row < BoardSize; ++row) { boardSquares[row] = new BoardSquare[BoardSize]; for (int column = 0; column < BoardSize; ++column) { boardSquares[row][column] = new BoardSquare(row, column); } } }
/// <summary> /// Try to place symbol in specified board square and update game logic state and /// status display accordingly. /// </summary> /// <param name="symbol"> /// PlayerSymbol to try to place in board square. /// </param> /// <param name="square"> /// BoardSquare where symbol should be placed, if possible. /// </param> private void UpdateGameState(PlayerSymbol symbol, BoardSquare square) { // If we're in cheating mode, we place symbols on board without checking any game rules. // We also don't check for victory when in cheating mode. if (!this.rulesEnabled) { square.Symbol = symbol; return; } // Place symbol on square according to game rules var status = this.gameLogic.PlaceSymbol(symbol, square); switch (status) { case PlacingStatus.SquareOccupied: UpdateStatusDisplay(Properties.Resources.OccupiedSquare); break; case PlacingStatus.OutOfTurn: UpdateStatusDisplay(symbol.Opponent().GetTurnWarningText()); break; case PlacingStatus.Valid: UpdateStatusDisplay(null); break; case PlacingStatus.Draw: UpdateStatusDisplay(Properties.Resources.GameDraw); ShowGameEnd(); break; case PlacingStatus.Victory: UpdateStatusDisplay(symbol.GetWinAnnouncementText()); ShowGameEnd(); break; case PlacingStatus.GameEnded: this.ShowGameEnd(); break; } }
/// <summary> /// Find board square with specified ID. /// </summary> /// <param name="id"> /// ID corresponding to square to be found. /// </param> /// <returns> /// Square that has specified Id, or null if no square was found with that ID. /// </returns> public BoardSquare Find(string id) { if (null == id) { return(null); } BoardSquare match = null; foreach (var row in boardSquares) { foreach (var square in row) { if (id.Equals(square.Id)) { match = square; break; } } } return(match); }