/// <summary> /// Performs a step in the game and notifies all associated clients using a push notification. /// </summary> /// <param name="SessionID">Identifier of the client who performed the move.</param> /// <param name="x">The X position of the move performed.</param> /// <param name="y">The Y position of the move performed.</param> /// <param name="playerLetter">Letter representing the player's move. Either "X" or "O".</param> public void GameStep(Guid SessionID, int x, int y, string player) { TicTacToeMove move = new TicTacToeMove() { X = x, Y = y, Player = player }; if (!ValidateTicTacToeMove(move)) { return; } gameState.StepsMade++; // Perform the requested move MakeMove(move); // Update the game state in light of the move performed UpdateState(move); byte[] bytes = GetBytes <TicTacToeMove>(move); // Notify all the relevant clients of the move foreach (KeyValuePair <Guid, Subscription> sub in subscribers) { if (sub.Value.SessionID != SessionID) { SendMessage(sub.Value.ChannelUri, bytes); } } }
/// <summary> /// Check if a move is legal. /// </summary> /// <param name="move">Move the validate.</param> /// <returns>True if the move is valid and false otherwise.</returns> private bool ValidateTicTacToeMove(TicTacToeMove move) { if (gameState.StepsMade == 0) { if (move.Player == ConstData.XString) { gameState.CurrentState = TicTacToeState.XPlayerTurn; } else { gameState.CurrentState = TicTacToeState.OPlayerTurn; } } bool isValid = true; // Invalidate the move if it is illegal because of the game state switch (gameState.CurrentState) { case TicTacToeState.XPlayerTurn: if (move.Player == ConstData.OString) { isValid = false; } break; case TicTacToeState.OPlayerTurn: if (move.Player == ConstData.XString) { isValid = false; } break; case TicTacToeState.XPlayerWin: case TicTacToeState.OPlayerWin: case TicTacToeState.Tie: isValid = false; break; default: break; } // Check if the requested cell is off the board if (move.X < 0 || move.X > ColumnMaxSize || move.Y < 0 || move.Y > RowMaxSize) { isValid = false; } // Checks that the cell is empty if (gameState.Board[move.X][move.Y] != string.Empty) { isValid = false; } return(isValid); }
/// <summary> /// Put a move on the board. /// </summary> /// <param name="move">Move to perform.</param> private void MakeMove(TicTacToeMove move) { gameState.Board[move.X][move.Y] = move.Player; }
/// <summary> /// Update the state of the game in light of a move performed by one of the clients. This checks whether or /// not the game has ended. If the game ended determines the game result and otherwise changes the currently /// active player. /// </summary> /// <param name="move">The move performed by one of the clients.</param> private void UpdateState(TicTacToeMove move) { bool isGameOver = false; // In order to win this game, a player must perform at least 3 steps. // Therefore, if we count 5 steps for both players it means that player "X" already made 3 steps. if (gameState.StepsMade >= MinimumStepsToCheckVictory) { int col = 0; int row = 0; int leftDiagonal = 0; int rightDiagonal = 0; // See if the player won by performing the supplied move for (int i = 0; i < RowMaxSize; i++) { // Checks the move's column if (gameState.Board[move.X][i] == move.Player) { col++; } // Checks the move's row if (gameState.Board[i][move.Y] == move.Player) { row++; } // Checks the primary diagonal if (gameState.Board[i][i] == move.Player) { leftDiagonal++; } // Checks the secondary diagonal if (gameState.Board[i][2 - i] == move.Player) { rightDiagonal++; } } // If we have a winner: change the state if (row == RowMaxSize || col == ColumnMaxSize || leftDiagonal == RowMaxSize || rightDiagonal == RowMaxSize) { if (move.Player == ConstData.XString) { gameState.CurrentState = TicTacToeState.XPlayerWin; } else { gameState.CurrentState = TicTacToeState.OPlayerWin; } isGameOver = true; } // If all the board is full and no one wins then there is a tie if (gameState.StepsMade == TotalCellCount && !isGameOver) { gameState.CurrentState = TicTacToeState.Tie; isGameOver = true; } } // If there is no winner and the board is not full, change the active player if (!isGameOver) { if (gameState.CurrentState == TicTacToeState.XPlayerTurn) { gameState.CurrentState = TicTacToeState.OPlayerTurn; } else { gameState.CurrentState = TicTacToeState.XPlayerTurn; } } move.GameFlow = gameState.CurrentState.ToString(); }