/**
         * Join a game room by player's name (username)
         * @param string Username
         * @return a valid (non-null) player object
         */
        public NetworkBackgammonPlayer Enter(string _playerName, string pw)
        {
            NetworkBackgammonPlayer newPlayer = new NetworkBackgammonPlayer(_playerName);

            // Validate player
            bool goodPlayer = gamePlayerList.VerifyLogin(_playerName, pw);

            // Check the user is already in the list
            if (!connectedPlayers.Contains(newPlayer) && goodPlayer)
            {
                // Add new player object to the game room list
                connectedPlayers.Add(newPlayer);

                // Start listening to this player
                newPlayer.AddListener(this);

                // Have the player start listening to this game room
                AddListener(newPlayer);

                // Broadcast the player connected event to all registered listeners
                Broadcast(new NetworkBackgammonGameRoomEvent(NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerConnected));
            }
            else
            {
                newPlayer = null;
            }

            return(newPlayer);
        }
コード例 #2
0
        private void buttonConnect_Click(object sender, EventArgs e)
        {
            if (player == null)
            {
                if (textBoxPlayerName.Text.Trim() != "")
                {
                    if (gameRoom != null)
                    {
                        string playerName = textBoxPlayerName.Text.Trim();

                        // Register (if not already)
                        gameRoom.RegisterPlayer(playerName, "password");

                        // Enter the game room
                        player = gameRoom.Enter(playerName, "password");

                        if (player != null)
                        {
                            buttonConnect.Text               = "Disconnect";
                            textBoxPlayerName.Enabled        = false;
                            groupBoxGameRoomControls.Enabled = true;

                            player.AddListener(this);

                            UpdateConnectedPlayersList();
                        }
                        else
                        {
                            MessageBox.Show("Login failed!", "Login Error (username)!", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                        }
                    }
                    else
                    {
                        MessageBox.Show("Login failed (no game room connection)!", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    }
                }
                else
                {
                    MessageBox.Show("Login failed (no username specified)!", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
            }
            else
            {
                if (gameRoom != null)
                {
                    gameRoom.Leave(player);

                    gameRoom.RemoveListener(this);
                    player.RemoveListener(this);

                    player = null;
                }

                buttonConnect.Text               = "Connect";
                textBoxPlayerName.Enabled        = true;
                groupBoxGameRoomControls.Enabled = false;
            }
        }
コード例 #3
0
        // Show the game board display
        private void ShowBoard(bool show)
        {
            if (show)
            {
                m_backgammonBoard.TopLevel = false;
                // Set the Parent Form of the Child window.
                m_backgammonBoard.Parent = this;
                m_backgammonBoard.Top    = SystemInformation.CaptionHeight;
                // Display the new form.
                m_backgammonBoard.Show();

                m_backGammonChat.TopLevel = false;
                // Set the Parent Form of the Child window.
                m_backGammonChat.Parent = this;
                m_backGammonChat.Left   = m_backgammonBoard.Left;
                m_backGammonChat.Top    = m_backgammonBoard.Bottom;
                m_backGammonChat.Width  = this.Width - 10;
                // Display the new form.
                m_backGammonChat.Show();

                m_backGammonScoreBoardPlayer1.TopLevel = false;
                // Set the Parent Form of the Child window.
                m_backGammonScoreBoardPlayer1.Parent = this;
                m_backGammonScoreBoardPlayer1.Left   = m_backgammonBoard.Right;
                m_backGammonScoreBoardPlayer1.Top    = m_backgammonBoard.Top;
                m_backGammonScoreBoardPlayer1.Width  = 137;
                m_backGammonScoreBoardPlayer1.Height = m_backgammonBoard.Height / 2;
                // Set the title for the scoreboard
                m_backGammonScoreBoardPlayer1.Title = (NetworkBackgammonClient.Instance.Player != null ? NetworkBackgammonClient.Instance.Player.PlayerName : "?");
                // Display the new form.
                m_backGammonScoreBoardPlayer1.Show();

                m_backGammonScoreBoardPlayer2.TopLevel = false;
                // Set the Parent Form of the Child window.
                m_backGammonScoreBoardPlayer2.Parent = this;
                m_backGammonScoreBoardPlayer2.Left   = m_backgammonBoard.Right;
                m_backGammonScoreBoardPlayer2.Top    = m_backGammonScoreBoardPlayer1.Bottom;
                m_backGammonScoreBoardPlayer2.Width  = 137;
                m_backGammonScoreBoardPlayer2.Height = m_backgammonBoard.Height / 2;

                // Get the game session this player is associated with
                NetworkBackgammonPlayer oppPlayer = NetworkBackgammonClient.Instance.GameRoom.GetOpposingPlayer(NetworkBackgammonClient.Instance.Player);

                // Set the title for the scoreboard
                m_backGammonScoreBoardPlayer2.Title = (oppPlayer != null ? oppPlayer.PlayerName : "?");
                // Display the new form.
                m_backGammonScoreBoardPlayer2.Show();
            }
            else
            {
                m_backgammonBoard.Hide();
                m_backGammonChat.Hide();
                m_backGammonScoreBoardPlayer1.Hide();
                m_backGammonScoreBoardPlayer2.Hide();
            }
        }
コード例 #4
0
        /// <summary>
        /// Executes a valid move of the active player.
        /// </summary>
        /// <param name="player1">Player 1</param>
        /// <param name="player2">Player 2</param>
        /// <param name="_checker">Selected checker to be moved</param>
        /// <param name="_move">Selected move (according to one of the dice values)</param>
        /// <returns>Success (true) if the active player has won the game, otherwise false</returns>
        public static bool ExecuteMove(ref NetworkBackgammonPlayer player1,
                                       ref NetworkBackgammonPlayer player2,
                                       NetworkBackgammonChecker _checker,
                                       NetworkBackgammonDice _move)
        {
            // Determine the active player
            NetworkBackgammonPlayer activePlayer  = player1.Active ? player1 : player2;
            NetworkBackgammonPlayer waitingPlayer = player1.Active ? player2 : player1;

            bool bActivePlayerWon = true;

            // Find active player's checker that has been selected to move
            foreach (NetworkBackgammonChecker checkerAP in activePlayer.Checkers)
            {
                // Found checker, now find checker's move that has been selected
                if (checkerAP == _checker)
                {
                    foreach (NetworkBackgammonDice move in checkerAP.PossibleMoves)
                    {
                        // Found move
                        if (move == _move)
                        {
                            checkerAP.MoveChecker(_move);

                            if (checkerAP.CurrentPosition.CurrentPosition >= NetworkBackgammonPosition.GameBoardPosition.NORMAL_START &&
                                checkerAP.CurrentPosition.CurrentPosition <= NetworkBackgammonPosition.GameBoardPosition.NORMAL_END)
                            {
                                // Check whether active player kicked checker of the waiting player onto the bar
                                foreach (NetworkBackgammonChecker checkerWP in waitingPlayer.Checkers)
                                {
                                    if (checkerWP.CurrentPosition.GetOppositePosition().CurrentPosition == checkerAP.CurrentPosition.CurrentPosition)
                                    {
                                        checkerWP.CurrentPosition.Reset();
                                    }
                                }
                            }
                            break;
                        }
                    }
                    break;
                }
            }

            // Check whether active player has won the game
            foreach (NetworkBackgammonChecker checker in activePlayer.Checkers)
            {
                if (checker.CurrentPosition.CurrentPosition != NetworkBackgammonPosition.GameBoardPosition.OFFBOARD)
                {
                    bActivePlayerWon = false;
                    break;
                }
            }

            return(bActivePlayerWon);
        }
        public void TestMethod_VerifyInitialPossibleMoves()
        {
            // Configure players
            player1.Active = true;
            player2.Active = false;

            // Set reference to active player
            NetworkBackgammonPlayer activePlayer = player1.Active ? player1 : player2;

            // Loop through all possible dice combinations
            foreach (NetworkBackgammonDice.DiceValue diceValueOne in Enum.GetValues(typeof(NetworkBackgammonDice.DiceValue)))
            {
                if (diceValueOne >= NetworkBackgammonDice.DiceValue.MIN &&
                    diceValueOne <= NetworkBackgammonDice.DiceValue.MAX)
                {
                    foreach (NetworkBackgammonDice.DiceValue diceValueTwo in Enum.GetValues(typeof(NetworkBackgammonDice.DiceValue)))
                    {
                        if (diceValueTwo >= NetworkBackgammonDice.DiceValue.MIN &&
                            diceValueTwo <= NetworkBackgammonDice.DiceValue.MAX)
                        {
                            // Set (not random) dice values
                            dice[0].CurrentValue = diceValueOne;
                            dice[1].CurrentValue = diceValueTwo;

                            bool activePlayerHasPossibleMoves =
                                NetworkBackgammonGameEngine.CalculatePossibleMoves(
                                    ref player1,
                                    ref player2,
                                    dice);

                            Assert.IsTrue(activePlayerHasPossibleMoves, "Active player should always have possible moves after the winning the initial dice roll");

                            Stream stream = GetManifestResourceStreamByName("InitialCheckers_" +
                                                                            (dice[0].CurrentValueUInt32 <= dice[1].CurrentValueUInt32 ?
                                                                             dice[0].CurrentValueUInt32.ToString() :
                                                                             dice[1].CurrentValueUInt32.ToString()) +
                                                                            "_" +
                                                                            (dice[1].CurrentValueUInt32 >= dice[0].CurrentValueUInt32 ?
                                                                             dice[1].CurrentValueUInt32.ToString() :
                                                                             dice[0].CurrentValueUInt32.ToString()) +
                                                                            ".xml");

                            Assert.IsNotNull(stream, "Data (XML) for verification comparison purposes is missing");

                            List <NetworkBackgammonChecker> checkersVerified = LoadCheckersFromXMLFile(stream);

                            string checkerVerificationMessage = "";
                            bool   checkerVerificationResult  = VerifyCheckersAndPossibleMoves(activePlayer.Checkers, checkersVerified, ref checkerVerificationMessage);

                            Assert.IsTrue(checkerVerificationResult, "Possible moves of active player for initial dice roll of " + dice[0] + ", " + dice[1] + " incorrect. Detail: " + checkerVerificationMessage);
                        }
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Get a players opponent
        /// </summary>
        /// <param name="player">Backgammon player to be checked</param>
        /// <returns>null if player does not exist</returns>
        public NetworkBackgammonPlayer GetOpponent(NetworkBackgammonPlayer player)
        {
            NetworkBackgammonPlayer opp = null;

            if (ContainsPlayer(player))
            {
                opp = (player == player1 ? player2 : player1);
            }

            return(opp);
        }
コード例 #7
0
        // Send a message to the listeners of Player
        public void SendMsg(string msg)
        {
            if (IsConnected)
            {
                NetworkBackgammonPlayer recpPlayer = GameRoom.GetOpposingPlayer(Player);

                if (recpPlayer != null)
                {
                    Player.Broadcast(new NetworkBackgammonChatEvent(Player.PlayerName, recpPlayer.PlayerName, msg));
                }
            }
        }
        /// <summary>
        /// Get the player's opponent
        /// </summary>
        /// <param name="player">Backgammon player to be checked</param>
        /// <returns>null if player is not part of a game session</returns>
        public NetworkBackgammonPlayer GetOpposingPlayer(NetworkBackgammonPlayer player)
        {
            NetworkBackgammonPlayer retval = null;

            // Get the game session associated with this player
            NetworkBackgammonGameSession gameSession = GetGameSession(player);

            if (gameSession != null)
            {
                retval = gameSession.GetOpponent(player);
            }

            return(retval);
        }
コード例 #9
0
        public bool OnConnect(string playerName, string playerPassword, ref string returnMessage)
        {
            bool bRetVal = false;

            if (player == null)
            {
                if (gameRoom != null)
                {
                    // Register (if not already; ignore 'false' return value if already registered)
                    gameRoom.RegisterPlayer(playerName, playerPassword);

                    // Enter the game room
                    player = gameRoom.Enter(playerName, playerPassword);

                    if (player != null)
                    {
                        player.AddListener(this);

                        bRetVal = true;
                    }
                    else
                    {
                        if (returnMessage != null)
                        {
                            returnMessage += "\nPlayer couldn't login with name '" + playerName + "' and password '" + playerPassword + "'.";
                        }
                    }
                }
                else
                {
                    if (returnMessage != null)
                    {
                        returnMessage += "\nNo game room available to connect to!";
                    }
                }
            }
            else
            {
                if (returnMessage != null)
                {
                    returnMessage += "\nPlayer with name '" + playerName + "' is already connected!";
                }

                bRetVal = false;
            }

            return(bRetVal);
        }
        /// <summary>
        /// Determine whether or not player is participating in a game session
        /// </summary>
        /// <param name="player">Backgammon player to be checked</param>
        /// <returns>null NetworkBackgammonPlayer object if name not found</returns>
        public NetworkBackgammonPlayer GetPlayerByName(string playerName)
        {
            NetworkBackgammonPlayer retval = null;

            // Look through the list of game sessions and make sure the player is not already playing in another room
            foreach (NetworkBackgammonPlayer player in connectedPlayers)
            {
                if (player.PlayerName.CompareTo(playerName) == 0)
                {
                    retval = player;
                    break;
                }
            }

            return(retval);
        }
        /// <summary>
        /// Get the game session the the "player" is currently apart of
        /// </summary>
        /// <param name="player">Backgammon player to be checked</param>
        /// <returns>null if player is not part of a game session</returns>
        public NetworkBackgammonGameSession GetGameSession(NetworkBackgammonPlayer player)
        {
            NetworkBackgammonGameSession retval = null;

            // Look through the list of game sessions and make sure the player is not already playing in another room
            foreach (NetworkBackgammonGameSession session in gameSessions)
            {
                if (session.ContainsPlayer(player))
                {
                    retval = session;
                    break;
                }
            }

            return(retval);
        }
        /// <summary>
        /// Determine whether or not player is participating in a game session
        /// </summary>
        /// <param name="player">Backgammon player to be checked</param>
        /// <returns>"True" if backgammon player in question is in a game session, otherwise "false"</returns>
        public bool IsPlayerInGameSession(NetworkBackgammonPlayer player)
        {
            bool retval = false;

            // Look through the list of game sessions and make sure the player is not already playing in another room
            foreach (NetworkBackgammonGameSession session in gameSessions)
            {
                if (session.ContainsPlayer(player))
                {
                    retval = true;
                    break;
                }
            }

            return(retval);
        }
コード例 #13
0
        private void challengeToolStripMenuItemChallenge_Click(object sender, EventArgs e)
        {
            if (gameRoom != null &&
                player != null &&
                listBoxConnectedPlayers.SelectedItem != null)
            {
                NetworkBackgammonPlayer challengedPlayer = (NetworkBackgammonPlayer)listBoxConnectedPlayers.SelectedItem;

                if (gameRoom.Challenge(player.PlayerName, challengedPlayer.PlayerName))
                {
                    groupBoxGameControls.Enabled = true;
                }
                else
                {
                    listBoxLog.Items.Add("Challenge failed (selected opponent rejected or timeout waiting for challenge response)!");
                }
            }
        }
コード例 #14
0
        private void m_playButton_Click(object sender, EventArgs e)
        {
            int curIndex = m_gameRoomPlayersListBox.SelectedIndex;

            if (curIndex >= 0)
            {
                NetworkBackgammonPlayer challengingPlayer = NetworkBackgammonClient.Instance.Player;
                NetworkBackgammonPlayer challengedPlayer  = (NetworkBackgammonPlayer)m_gameRoomPlayersListBox.Items[curIndex];

                string tempChallengingPlayer = String.Copy(challengingPlayer.PlayerName);
                string tempChallengedlayer   = String.Copy(challengedPlayer.PlayerName);

                // Setup the wait dialog
                waitDlg = new NetworkBackgammonWaitDialog(new NetworkBackgammonWaitDialog.WaitButtonActionDelegate(OnChallengeCancelled));
                waitDlg.WaitDialogLabel.Text = "Waiting for response from " + challengedPlayer.PlayerName;

                bool challengeProceed = true;

                lock (gameChallengeMutex)
                {
                    // Only execute challenge if none is pending (i.e. if gameChallengeThreadExchangeData object exists)
                    if (gameChallengeThreadExchangeData == null)
                    {
                        // Store challenged player name for thread access
                        gameChallengeThreadExchangeData = new GameChallengeDataContainer(challengedPlayer.PlayerName);
                    }
                    else
                    {
                        challengeProceed = false;
                    }
                }

                if (challengeProceed)
                {
                    // Create the challenge thread
                    challengeThread = new Thread(new ThreadStart(ChallengeThread));
                    // Start the thread
                    challengeThread.Start();

                    // Start up the wait dialog
                    waitDlg.ShowDialog(this);
                }
            }
        }
コード例 #15
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="_player1">Network backgammon player 1 to be part of this game session</param>
        /// <param name="_player2">Network backgammon player 2 to be part of this game session</param>
        public NetworkBackgammonGameSession(NetworkBackgammonPlayer _player1, NetworkBackgammonPlayer _player2)
        {
            defaultNotifier = new NetworkBackgammonNotifier(this);

            player1 = _player1;
            player2 = _player2;

            NetworkBackgammonDice dice1 = new NetworkBackgammonDice();
            NetworkBackgammonDice dice2 = new NetworkBackgammonDice();

            // Make sure the seeds used for the (pseudo) random generator instances are different
            // (otherwise, both dice will always roll the same values)
            while (dice1.Seed == dice2.Seed)
            {
                Thread.Sleep(1);
                dice2 = new NetworkBackgammonDice();
            }

            dice = new NetworkBackgammonDice[] { dice1, dice2 };
        }
コード例 #16
0
        /// <summary>
        /// Stops the game session state machine (thread)
        /// </summary>
        public void Stop()
        {
            if (threadStateMachine != null)
            {
                bStateMachineKeepRunning = false;

                // Wake-up state machine to allow for proper shutdown
                // (without forcing an abort)
                semStateMachine.Release();

                if (!threadStateMachine.Join(10000))
                {
                    threadStateMachine.Abort();
                }

                threadStateMachine = null;
            }

            eventQueue.Clear();

            // Terminate game for players
            Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.Terminated));
            if (player1 != null)
            {
                // Game Session stops listening for events from Player 1
                player1.RemoveListener(this);
                // Player 1 stops listening for events from Game Session
                RemoveListener(player1);
            }

            if (player2 != null)
            {
                // Game Session stops listening for events form Player 2
                player2.RemoveListener(this);
                // Player 2 stops listening for events from Game Session
                RemoveListener(player2);
            }

            player1 = null;
            player2 = null;
        }
        /// <summary>
        /// Exit the game room by player
        /// </summary>
        /// <param name="_player">Backgammon player who wants to leave the game room</param>
        public void Leave(NetworkBackgammonPlayer _player)
        {
            if (connectedPlayers.Contains(_player))
            {
                // The disconnected player should no longer be listening...
                RemoveListener(_player);
                // Stop listening to this player
                _player.RemoveListener(this);

                // Check if player is associated with a game room and remove if necessary
                NetworkBackgammonGameSession _playerGameSession = GetGameSession(_player);

                if (_playerGameSession != null)
                {
                    // Disconnect the player from the game session
                    _player.RemoveListener(_playerGameSession);
                    // Disconnect the game session from the player
                    _playerGameSession.RemoveListener(_player);

                    // Get the opposing player
                    NetworkBackgammonPlayer opposingPlayer = _playerGameSession.GetOpponent(_player);

                    if (opposingPlayer != null)
                    {
                        // Disconnect the player from the game session
                        opposingPlayer.RemoveListener(_playerGameSession);
                        // Disconnect the game session from the player
                        _playerGameSession.RemoveListener(opposingPlayer);
                    }

                    // Halt the game sesssion
                    _playerGameSession.Stop();
                }

                // Remove player from connected player list
                connectedPlayers.Remove(_player);

                // Broadcast the player disconnected event to all registered listeners
                Broadcast(new NetworkBackgammonGameRoomEvent(NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerDisconnected));
            }
        }
コード例 #18
0
        public void OnEventNotification(INetworkBackgammonNotifier sender, INetworkBackgammonEvent e)
        {
            if (e is GameSessionCheckerUpdatedEvent)
            {
                GameSessionCheckerUpdatedEvent updateEvent = (GameSessionCheckerUpdatedEvent)e;

                NetworkBackgammonPlayer curPlayer = updateEvent.GetPlayerByName(Title);

                if (curPlayer != null)
                {
                    // Update the pip count
                    if (InvokeRequired)
                    {
                        BeginInvoke(new OnUpdatePipCountDelegate(OnUpdatePipCount), curPlayer.PipCount);
                    }
                    else
                    {
                        OnUpdatePipCount(curPlayer.PipCount);
                    }
                }
            }
        }
コード例 #19
0
        public bool OnDisconnect(ref string returnMessage)
        {
            bool bRetVal = false;

            if (player != null)
            {
                if (gameRoom != null)
                {
                    gameRoom.Leave(player);

                    gameRoom.RemoveListener(this);
                    player.RemoveListener(this);

                    player = null;

                    bRetVal = true;
                }
                else
                {
                    if (returnMessage != null)
                    {
                        returnMessage += "\nNo game room available to disconnect from!";
                    }
                }
            }
            else
            {
                if (returnMessage != null)
                {
                    returnMessage += "\nPlayer is not connected!";
                }

                bRetVal = false;
            }

            return(bRetVal);
        }
コード例 #20
0
        public void OnEventNotification(INetworkBackgammonNotifier sender, INetworkBackgammonEvent e)
        {
            if (InvokeRequired)
            {
                Invoke(new NotifyDelegate(OnEventNotification), new object[] { sender, e });
            }
            else
            {
                buttonAction.Enabled = false;
                buttonAction.Text    = "[No Action]";

                #region Sender: Game Room

                if (sender is NetworkBackgammonRemoteGameRoom)
                {
                    try
                    {
                        if (e is NetworkBackgammonGameRoomEvent)
                        {
                            NetworkBackgammonGameRoomEvent gameRoomEvent = (NetworkBackgammonGameRoomEvent)e;

                            switch (gameRoomEvent.EventType)
                            {
                            case NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerConnected:
                                UpdateConnectedPlayersList();
                                break;

                            case NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerDisconnected:
                                UpdateConnectedPlayersList();
                                break;
                            }
                        }
                        else if (e is NetworkBackgammonChallengeEvent)
                        {
                            NetworkBackgammonChallengeEvent challengeEvent = (NetworkBackgammonChallengeEvent)e;

                            string challengingPlayer = challengeEvent.ChallengingPlayer;
                            string challengedPlayer  = challengeEvent.ChallengedPlayer;

                            if (challengingPlayer.CompareTo(player.PlayerName) != 0 &&
                                challengedPlayer.CompareTo(player.PlayerName) == 0)
                            {
                                bool challengeResponse = MessageBox.Show(
                                    "Accept game challenge from " + challengeEvent.ChallengingPlayer + "?",
                                    "Game Challenge",
                                    MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Question,
                                    MessageBoxDefaultButton.Button1) == DialogResult.Yes;

                                player.RespondToChallenge(challengeResponse, challengeEvent.ChallengingPlayer);

                                groupBoxGameControls.Enabled = challengeResponse;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        listBoxLog.Items.Add(ex.Message);
                    }
                }

                #endregion

                #region Sender: Game Session

                else if (sender is NetworkBackgammonGameSession)
                {
                    // Filter out broadcasts from our own player
                    if (sender != player)
                    {
                        try
                        {
                            NetworkBackgammonGameSession gameSession = (NetworkBackgammonGameSession)sender;

                            if (e is NetworkBackgammonGameSessionEvent)
                            {
                                // Generate warning if last event has been overwritten
                                // (Currently every event received is supposed to be responded too by means of an
                                //  action (e.g. move, dice roll acknowledge, etc), which resets the last event type to invalid)
                                if (lastGameSessionEventType != null)
                                {
                                    listBoxLog.Items.Add("Warning: Overwriting last event (" + lastGameSessionEventType.ToString() + ") with new event " + e.GetType().ToString() + " (i.e. last event hasn't been responded to by means of an action)");
                                }

                                // Latch the event type
                                lastGameSessionEventType = e.GetType();
                            }

                            #region Actions for initial dice roll

                            if (e is GameSessionInitialDiceRollEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionInitialDiceRollEvent gameSessionInitialDiceRollEvent = (GameSessionInitialDiceRollEvent)e;

                                // if (player.InitialDice != null)
                                if (gameSessionInitialDiceRollEvent.GetDiceForPlayer(player.PlayerName) != null)
                                {
                                    listBoxLog.Items.Add("Initial dice rolled: " + gameSessionInitialDiceRollEvent.GetDiceForPlayer(player.PlayerName).CurrentValue);

                                    buttonAction.Enabled = true;

                                    buttonAction.Text = "Confirm initial dice roll";
                                }
                                else
                                {
                                    listBoxLog.Items.Add("Warning: Event received is " + e.GetType().ToString() + " but dice values are missing");
                                }
                            }

                            #endregion

                            #region Actions for checker update

                            else if (e is GameSessionCheckerUpdatedEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionCheckerUpdatedEvent gameSessionCheckerUpdateEvent = (GameSessionCheckerUpdatedEvent)e;

                                player = gameSessionCheckerUpdateEvent.GetPlayerByName(player.PlayerName);

                                string strDice = "";

                                foreach (NetworkBackgammonDice d in gameSessionCheckerUpdateEvent.DiceRolled)
                                {
                                    strDice += " " + d.CurrentValue;
                                }

                                listBoxLog.Items.Add("Dice: " + strDice);

                                foreach (NetworkBackgammonChecker checker in player.Checkers)
                                {
                                    listBoxCheckers.Items.Add(checker);
                                }
                            }

                            #endregion

                            #region Actions for move expected

                            else if (e is GameSessionMoveExpectedEvent)
                            {
                                GameSessionMoveExpectedEvent gameSessionMoveExpectedEvent = (GameSessionMoveExpectedEvent)e;

                                if (player.PlayerName == gameSessionMoveExpectedEvent.ActivePlayer)
                                {
                                    listBoxLog.Items.Add("I'm the active player, expected to make the next move ...");

                                    groupBoxGameControls.BackColor = Color.DarkGreen;

                                    buttonAction.Enabled = true;

                                    buttonAction.Text = "Make Move";
                                }
                                else
                                {
                                    groupBoxGameControls.BackColor = Color.DarkRed;
                                }
                            }

                            #endregion

                            #region Actions for no (valid) move

                            else if (e is GameSessionNoPossibleMovesEvent)
                            {
                                GameSessionNoPossibleMovesEvent gameSessionNoPossibleMovesEvent = (GameSessionNoPossibleMovesEvent)e;

                                if (player.PlayerName == gameSessionNoPossibleMovesEvent.PlayerName)
                                {
                                    listBoxLog.Items.Add("I'm the active player, but have no (valid) moves ...");

                                    groupBoxGameControls.BackColor = Color.DarkGreen;

                                    buttonAction.Enabled = true;

                                    buttonAction.Text = "Confirm";
                                }
                                else
                                {
                                    groupBoxGameControls.BackColor = Color.DarkRed;
                                }
                            }

                            #endregion

                            #region Actions for player resignation

                            else if (e is GameSessionPlayerResignationEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionPlayerResignationEvent gameSessionPlayerResignationEvent = (GameSessionPlayerResignationEvent)e;

                                listBoxLog.Items.Add("Player " + gameSessionPlayerResignationEvent.ResigningPlayer + " has resigned from current game");

                                listBoxCheckers.Items.Clear();

                                groupBoxGameControls.BackColor = SystemColors.Control;

                                groupBoxGameControls.Enabled = false;
                            }

                            #endregion

                            #region Actions for player won game

                            else if (e is GameSessionPlayerWonEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionPlayerWonEvent gameSessionPlayerWonEvent = (GameSessionPlayerWonEvent)e;

                                if (gameSessionPlayerWonEvent.WinningPlayer == player.PlayerName)
                                {
                                    listBoxLog.Items.Add("Yeah!!! I won the game!!!");
                                }
                                else
                                {
                                    listBoxLog.Items.Add("Player " + gameSessionPlayerWonEvent.WinningPlayer + " won the game");
                                }

                                listBoxCheckers.Items.Clear();

                                groupBoxGameControls.BackColor = SystemColors.Control;

                                groupBoxGameControls.Enabled = false;
                            }

                            #endregion

                            else if (e is NetworkBackgammonGameSessionEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                NetworkBackgammonGameSessionEvent gameSessionEvent = (NetworkBackgammonGameSessionEvent)e;

                                switch (gameSessionEvent.EventType)
                                {
                                case NetworkBackgammonGameSessionEvent.GameSessionEventType.GameFinished:
                                {
                                    listBoxLog.Items.Add("Game finished");
                                }
                                break;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            listBoxLog.Items.Add(ex.Message);
                        }
                    }
                }

                #endregion
            }
        }
コード例 #21
0
        /// <summary>
        /// Calculates possible moves for the checkers of the active player.
        /// </summary>
        /// <param name="player1">Player 1</param>
        /// <param name="player2">Player 2</param>
        /// <param name="dice">Dice</param>
        /// <returns>Success (true) if at least one move of the active players checkers is possible, otherwise false.</returns>
        /// <remarks>
        /// Updates the active players list of possible moves.
        /// </remarks>
        public static bool CalculatePossibleMoves(ref NetworkBackgammonPlayer player1, ref NetworkBackgammonPlayer player2, NetworkBackgammonDice[] _dice)
        {
            // Abbreviations:
            //
            // AP: Active Player (e.g. checkerHistogramAP -> histogram of checkers of active player)
            // WP: Waiting Player (e.g. checkerWP -> checkers of the waiting player)
            // kvp: key-value-pair

            // Check whether only one player is active
            if (player1.Active == true && player2.Active == true)
            {
                throw new NetworkBackgammonGameEngineException("Both backgammon players cannot be active (it can only by one player's turn)!");
            }

            // Determine the active player
            NetworkBackgammonPlayer activePlayer  = player1.Active ? player1 : player2;
            NetworkBackgammonPlayer waitingPlayer = player1.Active ? player2 : player1;

            // Check whether dice values are passed in and if the array has no more than 2 elements and more than 0 elements
            // and if dice values are valid
            if (_dice == null)
            {
                throw new NetworkBackgammonGameEngineException("Dice values missing (reference to array is null)!");
            }
            else
            {
                if (_dice.Count() == 0)
                {
                    throw new NetworkBackgammonGameEngineException("Dice value array has 0 elements! Need at least on element!");
                }
                else
                {
                    if (_dice.Count() > 2)
                    {
                        throw new NetworkBackgammonGameEngineException("Too many dice values (passed in " + _dice.Count() + ", expected 1..2)");
                    }
                    else
                    {
                        foreach (NetworkBackgammonDice diceValue in _dice)
                        {
                            if (diceValue.CurrentValue < NetworkBackgammonDice.DiceValue.MIN ||
                                diceValue.CurrentValue > NetworkBackgammonDice.DiceValue.MAX)
                            {
                                throw new NetworkBackgammonGameEngineException("At least one dice has an invalid value (" + diceValue.CurrentValue + ")");
                            }
                        }
                    }
                }
            }

            // Check whether dice values are the same (tie) -> Use just one dice for all sub-sequent processing steps if it's a tie
            NetworkBackgammonDice[] diceToUse = _dice;
            if (_dice.Count() > 1)
            {
                if (_dice[0].CurrentValue == _dice[1].CurrentValue)
                {
                    diceToUse = new NetworkBackgammonDice[] { _dice[0] };
                }
            }

            bool bMovesCalulationDone       = false;
            bool bAllCheckersHomeOrOffBoard = true;
            bool bActivePlayerHasMoves      = false;

            #region Preparation

            // Delete possible moves for both, active ...
            foreach (NetworkBackgammonChecker checkerAP in activePlayer.Checkers)
            {
                checkerAP.PossibleMoves.Clear();
            }

            // ... and waiting player (just to be sure)
            foreach (NetworkBackgammonChecker checkerWP in waitingPlayer.Checkers)
            {
                checkerWP.PossibleMoves.Clear();
            }

            // Check whether all checkers of active player are home or off the board
            // This is necessary to determine whether active player is able to bear off
            // checkers (off the board)
            foreach (NetworkBackgammonChecker checkerAP in activePlayer.Checkers)
            {
                if (!((checkerAP.CurrentPosition.CurrentPosition >= NetworkBackgammonPosition.GameBoardPosition.HOME_START &&
                       checkerAP.CurrentPosition.CurrentPosition <= NetworkBackgammonPosition.GameBoardPosition.HOME_END) ||
                      checkerAP.CurrentPosition.CurrentPosition == NetworkBackgammonPosition.GameBoardPosition.OFFBOARD))
                {
                    bAllCheckersHomeOrOffBoard = false;
                    break;
                }
            }

            Dictionary <NetworkBackgammonPosition.GameBoardPosition, UInt32> checkerHistogramAP = new Dictionary <NetworkBackgammonPosition.GameBoardPosition, uint>();
            Dictionary <NetworkBackgammonPosition.GameBoardPosition, UInt32> checkerHistogramWP = new Dictionary <NetworkBackgammonPosition.GameBoardPosition, uint>();

            // Add checker position histogram containers for all positions checkers are sitting on (for active and waiting player)
            foreach (NetworkBackgammonPosition.GameBoardPosition positionValue in Enum.GetValues(typeof(NetworkBackgammonPosition.GameBoardPosition)))
            {
                if (!checkerHistogramAP.ContainsKey(positionValue))
                {
                    checkerHistogramAP.Add(positionValue, 0);
                }
                if (!checkerHistogramWP.ContainsKey(positionValue))
                {
                    checkerHistogramWP.Add(positionValue, 0);
                }
            }

            // Create checker position histograms
            foreach (NetworkBackgammonChecker checkerAP in activePlayer.Checkers)
            {
                checkerHistogramAP[checkerAP.CurrentPosition.CurrentPosition] += 1;
            }

            foreach (NetworkBackgammonChecker checkerWP in waitingPlayer.Checkers)
            {
                if (checkerWP.CurrentPosition.GetOppositePosition().CurrentPosition != NetworkBackgammonPosition.GameBoardPosition.INVALID)
                {
                    checkerHistogramWP[checkerWP.CurrentPosition.GetOppositePosition().CurrentPosition] += 1;
                }
                else
                {
                    checkerHistogramWP[checkerWP.CurrentPosition.CurrentPosition] += 1;
                }
            }

            Dictionary <NetworkBackgammonChecker, KeyValuePair <NetworkBackgammonDice, NetworkBackgammonPosition>[]> potentialPositionHistogram = new Dictionary <NetworkBackgammonChecker, KeyValuePair <NetworkBackgammonDice, NetworkBackgammonPosition>[]>();

            // Create potential positions for every checker
            foreach (NetworkBackgammonChecker checkerAP in activePlayer.Checkers)
            {
                if (!potentialPositionHistogram.ContainsKey(checkerAP))
                {
                    // List of potential positions associated associated with a certain dice value
                    List <KeyValuePair <NetworkBackgammonDice, NetworkBackgammonPosition> > potPosList = new List <KeyValuePair <NetworkBackgammonDice, NetworkBackgammonPosition> >();

                    foreach (NetworkBackgammonDice dice in diceToUse)
                    {
                        // Moving a checker off the board (bear off) is only allowed if all checkers of active player are in the home position
                        // (or off the board already)
                        if ((bAllCheckersHomeOrOffBoard) ||
                            (checkerAP.CurrentPosition + dice).CurrentPosition < NetworkBackgammonPosition.GameBoardPosition.OFFBOARD)
                        {
                            potPosList.Add(new KeyValuePair <NetworkBackgammonDice, NetworkBackgammonPosition>(dice, checkerAP.CurrentPosition + dice));
                        }
                    }

                    potentialPositionHistogram.Add(
                        checkerAP,
                        potPosList.ToArray());
                }
            }

            #endregion

            // First pass: Check whether any checkers are on the bar
            // as they'll have to be moved before anything else
            foreach (NetworkBackgammonChecker checkerAP in activePlayer.Checkers)
            {
                // Found a checker that's sitting on the bar
                if (checkerAP.CurrentPosition.CurrentPosition == NetworkBackgammonPosition.GameBoardPosition.BAR)
                {
                    bMovesCalulationDone = true;

                    foreach (NetworkBackgammonDice dice in diceToUse)
                    {
                        // Now, see whether opponents checker position allow us to move
                        if (checkerHistogramWP[(checkerAP.CurrentPosition + dice).CurrentPosition] <= 1)
                        {
                            checkerAP.PossibleMoves.Add(dice);

                            bActivePlayerHasMoves = true;
                        }
                    }
                }
            }

            if (!bMovesCalulationDone)
            {
                // Second pass: Check whether potential moves are valid
                foreach (KeyValuePair <NetworkBackgammonChecker, KeyValuePair <NetworkBackgammonDice, NetworkBackgammonPosition>[]> kvp in potentialPositionHistogram)
                {
                    foreach (KeyValuePair <NetworkBackgammonDice, NetworkBackgammonPosition> kvpDicePos in kvp.Value)
                    {
                        // Check whether waiting player occupies the potential position for active players checker
                        // (i.e. waiting player has more than 1 checker on the potential position)
                        // or potential position is off board (which is allways possible)
                        if (checkerHistogramWP[kvpDicePos.Value.CurrentPosition] <= 1 ||
                            kvpDicePos.Value.CurrentPosition == NetworkBackgammonPosition.GameBoardPosition.OFFBOARD)
                        {
                            kvp.Key.PossibleMoves.Add(kvpDicePos.Key);

                            bActivePlayerHasMoves = true;
                        }
                    }
                }
            }

            return(bActivePlayerHasMoves);
        }
        /// <summary>
        /// Challenge an opponent to a game
        /// </summary>
        /// <param name="_challengingPlayer">Challenging backgammon player</param>
        /// <param name="_challengedPlayer">Challenged backgammon player</param>
        /// <returns></returns>
        public bool Challenge(string _challengingPlayerName, string _challengedPlayerName)
        {
            bool retval = false;

            NetworkBackgammonPlayer _challengingPlayer = GetPlayerByName(_challengingPlayerName);
            NetworkBackgammonPlayer _challengedPlayer  = GetPlayerByName(_challengedPlayerName);

            // Check if the players are in the available player game room list
            //if (connectedPlayers.Contains(_challengingPlayer) && connectedPlayers.Contains(_challengedPlayer))
            if (_challengingPlayer != null && _challengedPlayer != null)
            {
                // Check if players are currently free to participate in a game session
                if (!IsPlayerInGameSession(_challengingPlayer) && !IsPlayerInGameSession(_challengedPlayer))
                {
                    Semaphore challengeSemaphore = new Semaphore(0, 1);

                    // Add game challenge data container instance to be used for the (asynchronous) challenge procedure
                    challengeSyncList.Add(_challengedPlayer, new NetworkBackgammonChallengeDataContainer(challengeSemaphore));

                    // Broadcast the player challenge event
                    Broadcast(new NetworkBackgammonChallengeEvent(_challengingPlayerName, _challengedPlayerName));

                    // Wait for response from challenged player (or timeout)
                    if (challengeSemaphore.WaitOne(challengeRequestTimeoutMs))
                    {
                        retval = challengeSyncList[_challengedPlayer].ChallengeAccepted;

                        // Create and start game session if challenge has been accepted by challenged player
                        if (retval)
                        {
                            // Create game session monitor if it doesn't exist yet
                            StartGameSessionMonitor();

                            // Create game session instance
                            NetworkBackgammonGameSession gameSession = new NetworkBackgammonGameSession(_challengingPlayer, _challengedPlayer);

                            // Append to list of game sessions...
                            gameSessions.Add(gameSession);
                            // Start the game...
                            gameSession.Start();

                            // Broadcast the game active event to all registered listeners
                            Broadcast(new NetworkBackgammonGameRoomEvent(NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerPlaying));
                        }

                        challengeSyncList.Remove(_challengedPlayer);

                        // Give the challenging player the challenge response
                        Broadcast(new NetworkBackgammonChallengeResponseEvent(retval, _challengedPlayerName, _challengingPlayerName));
                    }
                    else
                    {
                        challengeSyncList.Remove(_challengedPlayer);

                        retval = false;
                    }
                }
            }

            return(retval);
        }
        public void OnEventNotification(INetworkBackgammonNotifier sender, INetworkBackgammonEvent e)
        {
            if (sender is NetworkBackgammonPlayer)
            {
                NetworkBackgammonPlayer player = (NetworkBackgammonPlayer)sender;

                if (e is NetworkBackgammonChallengeResponseEvent)
                {
                    NetworkBackgammonChallengeResponseEvent challengeResponseEvent = (NetworkBackgammonChallengeResponseEvent)e;

                    if (challengeSyncList.Keys.Contains(player))
                    {
                        if (challengeSyncList[player] != null)
                        {
                            challengeSyncList[player].ChallengeAccepted = challengeResponseEvent.ChallengeAccepted;

                            try
                            {
                                challengeSyncList[player].ChallengeSemaphore.Release();
                            }
                            catch (SemaphoreFullException ex)
                            {
                                // TODO: If this exception occurs calling Release too many times...
                            }
                        }
                    }
                }
                else if (e is NetworkBackgammonChatEvent)
                {
                    // Pass the message through to the listeners
                    Broadcast((NetworkBackgammonChatEvent)e);
                }
            }
            else if (sender is NetworkBackgammonGameSession)
            {
                NetworkBackgammonGameSession gameSession = (NetworkBackgammonGameSession)sender;

                if (e is NetworkBackgammonGameSessionEvent)
                {
                    NetworkBackgammonGameSessionEvent gameSessionEvent = (NetworkBackgammonGameSessionEvent)e;

                    if (gameSessionEvent.EventType == NetworkBackgammonGameSessionEvent.GameSessionEventType.GameFinished)
                    {
                        bool newQueueItemAdd = true;

                        NetworkBackgammonEventQueueElement newQueueItem = new NetworkBackgammonEventQueueElement(e, sender);

                        lock (newQueueItem)
                        {
                            /*
                             * if (gameSessionsEventQueue.Count > 0)
                             * {
                             *  NetworkBackgammonEventQueueElement lastQueueItem = gameSessionsEventQueue.Last();
                             *  // Avoid adding the same event (from the same sender) twice
                             *  // Reason: Game Room listens to events from all players, i.e. also
                             *  // both players that are in one Game Session. Thus, all events broadcasted
                             *  // by the Game Session arrive here (at the Game Room) twice
                             *  if (gameSessionsEventQueue.Last().Notifier == sender &&
                             *      gameSessionsEventQueue.Last().Event == e)
                             *  {
                             *      newQueueItemAdd = false;
                             *  }
                             * }
                             */

                            if (newQueueItemAdd)
                            {
                                gameSessionsEventQueue.Enqueue(new NetworkBackgammonEventQueueElement(e, sender));

                                gameSessionsSemaphore.Release();
                            }
                        }
                    }
                }
            }
        }
コード例 #24
0
        /// <summary>
        /// Game session state machine (worker thread)
        /// </summary>
        private void Run()
        {
            GameSessionState currentState = GameSessionState.InitialDiceRoll;

            NetworkBackgammonEventQueueElement eventQueueElement = null;

            // Number of moves left for the active player
            UInt32 activePlayerMovesLeft   = 0;
            bool   activePlayerMoveDoubles = false;

            while (bStateMachineKeepRunning)
            {
                // Wait for another event
                semStateMachine.WaitOne();

                // HACK: Add function here to deal with the big switch statement
                if (!bStateMachineKeepRunning)
                {
                    break;
                }

                // Read the event element queue to get information on the next event to be processed
                if (eventQueue.Count > 0)
                {
                    eventQueueElement = eventQueue.Dequeue();
                }

                #region State Machine Pre-Processing

                // Handle special events that interfere with the regular game play (e.g. player resignation)
                if (eventQueueElement != null)
                {
                    if (eventQueueElement.Event is GameSessionPlayerResignationEvent)
                    {
                        currentState = GameSessionState.PlayerResigned;
                    }
                }

                #endregion

                #region State Machine Main Processing

                switch (currentState)
                {
                    #region State: Initial Dice Roll

                case GameSessionState.InitialDiceRoll:
                {
                    // Initialize both players checkers to their intial configuration
                    // (start positions)
                    player1.InitCheckers();
                    player2.InitCheckers();

                    // Use random number generator to figure out which player starts
                    RollDice();

                    player1.Active = false;
                    player2.Active = false;

                    player1.InitialDice = dice[0];
                    player2.InitialDice = dice[1];

                    Broadcast(new GameSessionInitialDiceRollEvent(
                                  player1.PlayerName, player1.InitialDice,
                                  player2.PlayerName, player2.InitialDice));

                    currentState = GameSessionState.InitialDiceRollAcknowledgeExpected;
                }
                break;

                    #endregion

                    #region State: Initial Dice Roll Acknowledge Expected

                case GameSessionState.InitialDiceRollAcknowledgeExpected:
                {
                    if (eventQueueElement != null)
                    {
                        try
                        {
                            if (eventQueueElement.Event is GameSessionInitialDiceRollAcknowledgeEvent)
                            {
                                GameSessionInitialDiceRollAcknowledgeEvent gameSessionEvent = (GameSessionInitialDiceRollAcknowledgeEvent)eventQueueElement.Event;

                                NetworkBackgammonPlayer sendingPlayer = (NetworkBackgammonPlayer)eventQueueElement.Notifier;

                                // Latch (flag) acknowledge of initial dice roll from respective player
                                sendingPlayer.InitialDice.FlagUsed = true;

                                // Check whether both players have acknowledged initial dice roll
                                if (player1.InitialDice.FlagUsed && player2.InitialDice.FlagUsed)
                                {
                                    // If dice rolled are a tie, roll again
                                    if (dice[0].CurrentValue == dice[1].CurrentValue)
                                    {
                                        RollDice();

                                        player1.InitialDice = dice[0];
                                        player2.InitialDice = dice[1];

                                        Broadcast(new GameSessionInitialDiceRollEvent(
                                                      player1.PlayerName, player1.InitialDice,
                                                      player2.PlayerName, player2.InitialDice));
                                    }
                                    else
                                    {
                                        // Determine active player (the one who won the initial dice roll
                                        if (dice[0].CurrentValueUInt32 > dice[1].CurrentValueUInt32)
                                        {
                                            player1.Active = true;
                                        }
                                        else
                                        {
                                            player2.Active = true;
                                        }

                                        // Calculate number of moves left for active player (based on dice values)
                                        activePlayerMoveDoubles = dice[0].CurrentValue == dice[1].CurrentValue;
                                        activePlayerMovesLeft   = (UInt32)(activePlayerMoveDoubles ? 4 : 2);

                                        // Calculate possible moves for active player (and figure out whether active player
                                        // actually has possible moves)
                                        bool activePlayerHasPossibleMoves =
                                            NetworkBackgammonGameEngine.CalculatePossibleMoves(
                                                ref player1,
                                                ref player2,
                                                activePlayerMoveDoubles ?
                                                new NetworkBackgammonDice[] { dice[0] } :
                                                dice);

                                        // Send initial checkers with positions (and possible valid moves
                                        // for the active player) to both players
                                        Broadcast(new GameSessionCheckerUpdatedEvent(player1, player2, dice[0], dice[1]));

                                        if (activePlayerHasPossibleMoves)
                                        {
                                            // Inform players about who's expected to make the next move
                                            Broadcast(new GameSessionMoveExpectedEvent(player1.Active ? player1.PlayerName : player2.PlayerName));

                                            // Set next iteration's state
                                            currentState = GameSessionState.MoveExpected;
                                        }
                                        else
                                        {
                                            // Inform both players that currently active player has no moves left
                                            // which needs to be acknowledged by the active player
                                            Broadcast(new GameSessionNoPossibleMovesEvent(player1.Active ? player1.PlayerName : player2.PlayerName));

                                            currentState = GameSessionState.NoPossibleMovesAcknowledgeExpected;
                                        }
                                    }
                                }
                            }
                        }
                        catch (Exception)
                        {
                            Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.Error));
                        }
                    }
                }
                break;

                    #endregion

                    #region State: Move Expected

                case GameSessionState.MoveExpected:
                {
                    if (eventQueueElement != null)
                    {
                        try
                        {
                            NetworkBackgammonPlayer      sendingPlayer     = (NetworkBackgammonPlayer)eventQueueElement.Notifier;
                            GameSessionMoveSelectedEvent moveSelectedEvent = (GameSessionMoveSelectedEvent)eventQueueElement.Event;

                            // Check whether the active player attempted to move
                            if (sendingPlayer.Active)
                            {
                                // Perform the selected move of the active player (and check whether the active player won the game
                                if (!NetworkBackgammonGameEngine.ExecuteMove(ref player1, ref player2, moveSelectedEvent.CheckerSelected, moveSelectedEvent.MoveSelected))
                                {
                                    // Figure out the next active player (could be the current
                                    // active player since up to 4 moves are allowed per turn)
                                    if (--activePlayerMovesLeft <= 0)
                                    {
                                        player1.Active = !player1.Active;
                                        player2.Active = !player2.Active;

                                        // Roll dice for active player
                                        RollDice();

                                        // Calculate number of moves left for active player (based on dice values)
                                        activePlayerMoveDoubles = dice[0].CurrentValue == dice[1].CurrentValue;
                                        activePlayerMovesLeft   = (UInt32)(activePlayerMoveDoubles ? 4 : 2);
                                    }

                                    // Calculate possible moves for active player (and figure out whether active player
                                    // actually has possible moves)
                                    bool activePlayerHasPossibleMoves = NetworkBackgammonGameEngine.CalculatePossibleMoves(
                                        ref player1,
                                        ref player2,
                                        activePlayerMoveDoubles ?
                                        new NetworkBackgammonDice[] { dice[0] } :
                                        activePlayerMovesLeft == 2 ?
                                        dice :
                                        new NetworkBackgammonDice[] { dice[0] == moveSelectedEvent.MoveSelected ? dice[1] : dice[0] });

                                    // Send updated checkers with positions (and possible valid moves
                                    // for the active player) to both players
                                    Broadcast(new GameSessionCheckerUpdatedEvent(player1, player2, dice[0], dice[1]));

                                    if (activePlayerHasPossibleMoves)
                                    {
                                        // Inform players about who's expected to make the next move
                                        Broadcast(new GameSessionMoveExpectedEvent(player1.Active ? player1.PlayerName : player2.PlayerName));
                                    }
                                    else
                                    {
                                        // Inform both players that currently active player has no moves left
                                        // which needs to be acknowledged by the active player
                                        Broadcast(new GameSessionNoPossibleMovesEvent(player1.Active ? player1.PlayerName : player2.PlayerName));

                                        currentState = GameSessionState.NoPossibleMovesAcknowledgeExpected;
                                    }
                                }
                                else
                                {
                                    // Inform both players that the game has been won by the active player
                                    Broadcast(new GameSessionPlayerWonEvent(sendingPlayer.PlayerName));

                                    currentState = GameSessionState.GameFinished;
                                }
                            }
                            else
                            {
                                Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.Error));
                            }
                        }
                        catch (Exception)
                        {
                            Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.Error));
                        }
                    }
                }
                break;

                    #endregion

                    #region State: No Possible Moves Acknowledge Expected

                case GameSessionState.NoPossibleMovesAcknowledgeExpected:
                {
                    if (eventQueueElement != null)
                    {
                        try
                        {
                            GameSessionNoPossibleMovesAcknowledgeEvent gameSessionNoPossibleMovesAcknowledgeEvent = (GameSessionNoPossibleMovesAcknowledgeEvent)eventQueueElement.Event;

                            // Make sure that the active player acknowledges (and not the waiting player)
                            if (gameSessionNoPossibleMovesAcknowledgeEvent.PlayerName == (player1.Active ? player1.PlayerName : player2.PlayerName))
                            {
                                player1.Active = !player1.Active;
                                player2.Active = !player2.Active;

                                // Roll dice for (new) active player
                                RollDice();

                                // Calculate number of moves left for active player (based on dice values)
                                activePlayerMoveDoubles = dice[0].CurrentValue == dice[1].CurrentValue;
                                activePlayerMovesLeft   = (UInt32)(activePlayerMoveDoubles ? 4 : 2);

                                bool activePlayerHasPossibleMoves = NetworkBackgammonGameEngine.CalculatePossibleMoves(
                                    ref player1,
                                    ref player2,
                                    activePlayerMoveDoubles ?
                                    new NetworkBackgammonDice[] { dice[0] } :
                                    activePlayerMovesLeft == 2 ?
                                    dice :
                                    new NetworkBackgammonDice[] { dice[0], dice[1] });

                                // Send updated checkers with positions (and possible valid moves
                                // for the active player) to both players
                                Broadcast(new GameSessionCheckerUpdatedEvent(player1, player2, dice[0], dice[1]));

                                if (activePlayerHasPossibleMoves)
                                {
                                    // Inform players about who's expected to make the next move
                                    Broadcast(new GameSessionMoveExpectedEvent(player1.Active ? player1.PlayerName : player2.PlayerName));

                                    currentState = GameSessionState.MoveExpected;
                                }
                                else
                                {
                                    // Inform both players that currently active player has no moves left
                                    // which needs to be acknowledged by the active player
                                    Broadcast(new GameSessionNoPossibleMovesEvent(player1.Active ? player1.PlayerName : player2.PlayerName));
                                }
                            }
                            else
                            {
                                Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.Error));
                            }
                        }
                        catch (Exception)
                        {
                            Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.Error));
                        }
                    }
                }
                break;

                    #endregion

                    #region State: Player Resigned

                case GameSessionState.PlayerResigned:
                {
                    if (eventQueueElement != null)
                    {
                        try
                        {
                            NetworkBackgammonPlayer resignedPlayer = (NetworkBackgammonPlayer)eventQueueElement.Notifier;

                            Broadcast(new GameSessionPlayerResignationEvent(resignedPlayer.PlayerName));

                            currentState = GameSessionState.GameFinished;
                        }
                        catch (Exception ex)
                        {
                            Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.Error));
                        }
                    }
                }
                break;

                    #endregion

                default:
                    break;
                }

                #endregion

                #region State Machine Post-Processing

                if (currentState == GameSessionState.GameFinished)
                {
                    Broadcast(new NetworkBackgammonGameSessionEvent(NetworkBackgammonGameSessionEvent.GameSessionEventType.GameFinished));

                    bStateMachineKeepRunning = false;
                }

                #endregion

                eventQueueElement = null;
            }
        }
コード例 #25
0
 /// <summary>
 /// Determines whether a backgammon player is part of this game session
 /// </summary>
 /// <param name="player">Backgammon player to be checked</param>
 /// <returns>"True" is backgammon player is part of this game session, otherwise "false"</returns>
 public bool ContainsPlayer(NetworkBackgammonPlayer player)
 {
     return((player == player1) || (player == player2));
 }