private void PlayerDiscardsDownToHandLimit(IPlayer <IPandemicTurn> player, int playerId)
        {
            var playerState = _state.PlayerStates[playerId];

            while (playerState.PlayerHand.Count > PlayerHandLimit)
            {
                var discardCardsTurn = new PandemicTurn(_validator)
                {
                    CurrentPlayerId = playerId, State = _state, TurnType = PandemicTurnType.DiscardCards
                };
                player.GetTurn(discardCardsTurn);
                var stateDeltas = _stateEditor.ApplyTurn(_state, discardCardsTurn);
                BroadCastStateDeltas(stateDeltas);
            }
        }
        private void AllowPlayersToPlayEventCards()
        {
            if (_state.IsGameOver)
            {
                return;
            }

            foreach (var player in Players)
            {
                var playerState = _state.PlayerStates[player.Id];
                if (playerState.PlayerHand.Any(c => c.PlayerCardType == PlayerCardType.Event))
                {
                    var playEventsTurn = new PandemicTurn(_validator)
                    {
                        CurrentPlayerId = player.Id, State = _state, TurnType = PandemicTurnType.PlayEventCards
                    };

                    player.GetTurn(playEventsTurn);
                    var stateDeltas = _stateEditor.ApplyTurn(_state, playEventsTurn);
                    BroadCastStateDeltas(stateDeltas);
                }
            }
        }
        public IGameState Play()
        {
            BroadcastGameStart();
            Setup(Players);

            while (!_state.IsGameOver)
            {
                foreach (var player in Players)
                {
                    if (_state.IsGameOver)
                    {
                        break;
                    }

                    AllowPlayersToPlayEventCards();
                    for (var actionNumber = 1; actionNumber <= 4; actionNumber++)
                    {
                        var turn = new PandemicTurn(_validator)
                        {
                            CurrentPlayerId = player.Id, State = _state, TurnType = PandemicTurnType.TakeActions
                        };
                        player.GetTurn(turn);
                        var stateDeltas = _stateEditor.ApplyTurn(_state, turn);
                        BroadCastStateDeltas(stateDeltas);
                    }

                    // draw 2 new player cards
                    var newPlayerCards = _state.PlayerDeck.Draw(2);
                    foreach (var newPlayerCard in newPlayerCards)
                    {
                        if (State.IsGameOver)
                        {
                            break;
                        }

                        if (newPlayerCard.PlayerCardType == PlayerCardType.Epidemic)
                        {
                            var stateDeltas = _stateEditor.Epidemic(_state);
                            BroadCastStateDeltas(stateDeltas);
                            _state.PlayerDiscardPile.AddCard(newPlayerCard);
                        }
                        else
                        {
                            _state.PlayerStates[player.Id].PlayerHand.Add(newPlayerCard);
                            var stateDeltas = new List <IDelta>()
                            {
                                new CardIsDrawnOrDiscardedDelta
                                {
                                    PlayerId           = player.Id,
                                    PandemicPlayerCard = newPlayerCard,
                                    DrawnOrDiscarded   = DrawnOrDiscarded.Drawn
                                }
                            };
                            BroadCastStateDeltas(stateDeltas);
                        }
                    }

                    if (!State.IsGameOver)
                    {
                        AllowPlayersToPlayEventCards();
                        PlayerDiscardsDownToHandLimit(player, player.Id);
                        var stateDeltas = _stateEditor.InfectCities(_state);
                        BroadCastStateDeltas(stateDeltas);
                    }
                }
            }

            BroadcastGameEnd();

            return(_state);
        }