예제 #1
0
 public ClueCreator(IBoardContext boardContext, PlayerContext playerContext, IPlayCardStrategy playCardStrategy, IDiscardStrategy discardStrategy)
 {
     _boardContext     = boardContext ?? throw new ArgumentNullException(nameof(boardContext));
     _playerContext    = playerContext ?? throw new ArgumentNullException(nameof(playerContext));
     _playCardStrategy = playCardStrategy ?? throw new ArgumentNullException(nameof(playCardStrategy));
     _discardStrategy  = discardStrategy ?? throw new ArgumentNullException(nameof(discardStrategy));
 }
예제 #2
0
        public PlayerAction Predict(IPlayCardStrategy playCardStrategy, IDiscardStrategy discardStrategy)
        {
            if (playCardStrategy == null)
            {
                throw new ArgumentNullException(nameof(playCardStrategy));
            }
            if (discardStrategy == null)
            {
                throw new ArgumentNullException(nameof(discardStrategy));
            }

            IEstimator playCardEstimator = new PlayCardEstimator(playCardStrategy);
            var        cardsToPlay       = playCardEstimator.GetPossibleCards(_boardContext, _playerContext).ToList();


            if (cardsToPlay.Any())
            {
                var expectedCards     = _boardContext.GetExpectedCards();
                var possibleBlowCards = cardsToPlay.Except(expectedCards);
                if (!possibleBlowCards.Any())
                {
                    // карта/карты, которыми собирается сыграть игрок, к взрыву не приводят.
                    if (cardsToPlay.Any(c => c.Rank == Rank.Five))
                    {
                        return(new PlayCardWithRankFiveAction {
                            Cards = cardsToPlay
                        });
                    }
                    else
                    {
                        return(new PlayCardAction {
                            Cards = cardsToPlay.ToList()
                        });
                    }
                }
                else
                {
                    // одна из карт, которыми скорее всего сыграют, приведёт к взрыву.
                    return(new BlowCardAction()
                    {
                        Cards = possibleBlowCards.ToList()
                    });
                }
            }

            // раз игрок сыграть не может, то будет сбрасывать...

            IEstimator discardEstimator = new DiscardEstimator(discardStrategy);
            var        cardsToDiscard   = discardEstimator.GetPossibleCards(_boardContext, _playerContext);

            var uniqueCardsToDiscard = cardsToDiscard.Intersect(_boardContext.GetUniqueCards()).ToList();

            if (uniqueCardsToDiscard.Any())
            {
                return new DiscardUniqueCardAction()
                       {
                           Cards = uniqueCardsToDiscard
                       }
            }
            ;

            var cardsWhateverToPlay = cardsToDiscard.Intersect(_boardContext.GetWhateverToPlayCards()).ToList();

            if (cardsWhateverToPlay.Any())
            {
                return new DiscardCardWhateverToPlayAction()
                       {
                           Cards = cardsWhateverToPlay
                       }
            }
            ;

            return(new DiscardNoNeedCard {
                Cards = cardsToDiscard
            });
        }
    }
}
예제 #3
0
 public PlayCardEstimator(IPlayCardStrategy strategy)
 {
     _strategy = strategy;
 }
예제 #4
0
        public ClueAndAction Find()
        {
            var expectedCards = _boardContext.GetExpectedCards();

            var expectedThatCanPlay =
                _playerContext.Hand
                .Where(cih => expectedCards.Contains(cih.Card))
                .ToList();

            var cardsToPlay =
                expectedThatCanPlay.Where(cih => cih.Card.Rank == Rank.Five)
                .Concat(
                    expectedThatCanPlay
                    .Where(cih => cih.Card.Rank != Rank.Five)
                    .OrderBy(cih => cih.Card.Rank)
                    )
                .ToList();


            List <ClueAndAction> possibleClues = new List <ClueAndAction>();

            if (cardsToPlay.Any())
            {
                var clues =
                    cardsToPlay
                    .Select(card => ClueDetailInfo.CreateClues(card, _playerContext))
                    .Aggregate((acc, list) => acc.Concat(list).ToList())
                    .Distinct();

                foreach (var clue in clues)
                {
                    var playerContext = _playerContext.Clone();
                    playerContext.PossibleClue = clue;

                    PlayerActionPredictor predictor    = new PlayerActionPredictor(_boardContext, playerContext);
                    IPlayCardStrategy     playStrategy =
                        PlayStrategyFabric.Create(playerContext.Player.GameProvider, playerContext);

                    IDiscardStrategy discardStrategy =
                        DiscardStrategyFabric.Create(playerContext.Player.GameProvider, playerContext);

                    var action = predictor.Predict(playStrategy, discardStrategy);

                    if ((action.Outcome & OutcomeFlags.Play) > 0)
                    {
                        possibleClues.Add(new ClueAndAction {
                            Action = action, Clue = clue
                        });
                    }
                }
            }

            if (possibleClues.Count <= 1)
            {
                return(possibleClues.FirstOrDefault());
            }

            // раз возможных подсказок больше одной, то выберем ту, которая затрагивает большее число карт
            // из тех, которыми можно сыграть
            int           max           = 0;
            ClueAndAction clueAndAction = null;

            foreach (var clue in possibleClues)
            {
                int cardsAffected = CardsToClue(clue.Clue);
                if (cardsAffected > max)
                {
                    max           = cardsAffected;
                    clueAndAction = clue;
                }
            }

            return(clueAndAction);
        }
예제 #5
0
        public IClueSituationStrategy FindClueCandidate(IReadOnlyList <Player> players)
        {
            // player1 -> player2 -> player3 -> player4
            // подсказку даёт player1.
            // Пока не будет сброса или не будет сыграна 5, то
            //      прогнозируем ход следующего игрока.
            //      игрок сбрасывает некритичную карту --> выход из цикла [если была подсказка в уме, то дать её]
            //      игрок ходит пятёркой --> выход из цикла [если была в уме подсказка, то дать её]
            //
            //      игрок ходит не пятёркой, карта ложится в фейерверк --> оценить действия следующего игрока
            //      игрок ходит не пятёркой, что приводит к взрыву     --> дать подсказку, оценить действия следующего игрока
            //
            //      игрок сбрасывает критичную карту, нет подсказки --> безвыходная ситуация. Надо сбрасывать самому
            //      игрок сбрасывает критичную карту, есть подсказка --> дать подсказку, оценить действия следующего игрока

            LogUniqueCards();

            var boardContext = _boardContext;
            //IBoardContext boardContext = BoardContext.Create(_board.FireworkPile, _board.DiscardPile, _pilesAnalyzer, new Card[0]);

            State state = new NoCluesState(boardContext);

            foreach (var playerToClue in players)
            {
                IEnumerable <Card> otherPlayerCards = GetPlayersCards(playerToClue);

                var playerHand = playerToClue.ShowCards(_clueGiver);

                boardContext = boardContext.ChangeContext(otherPlayerCards);
                IPlayerContext playerContext = new PlayerContext(playerToClue, playerHand);

                // надо оценить, что будет делать другой игрок.
                IPlayCardStrategy playCardStrategy = PlayStrategyFabric.Create(_gameProvider, playerContext);
                IDiscardStrategy  discardStrategy  = DiscardStrategyFabric.Create(_gameProvider, playerContext);

                var playerActionPredictor = new PlayerActionPredictor(boardContext, playerContext);

                var action = playerActionPredictor.Predict(playCardStrategy, discardStrategy);
                action.Log(_clueGiver.Name, playerToClue.Name);

                state.BoardContext = boardContext;
                state        = state.Handle(action, playerContext);
                boardContext = state.BoardContext;

                if (state.IsFinalState)
                {
                    break;
                }
            }


            Logger.Log.Info("");

            if (state.Solution != null)
            {
                return(state.Solution);
            }
            if (state.OptionalSolution != null)
            {
                // TODO проверить, что подсказка ещё актуальна.
                // Пример: после подсказки игрок А сходит жёлтой двойкой.
                // Но мы знаем, что по-любому игрок Б сходит жёлтой двойкой.


                return(state.OptionalSolution);
            }

            // выскочили из цикла, но не придумали подсказку...
            // Значит, можно расслабиться...

            var playersCircle = players;

            if (state.IgnoreUntil != null)
            {
                playersCircle =
                    players.SkipWhile(p => p != state.IgnoreUntil)
                    .Skip(1)
                    .Concat(players.TakeWhile(p => p != state.IgnoreUntil))
                    .ToList()
                    .AsReadOnly();
            }
            // костыль на случай конца игры
            // осталось по ходу у двух игроков: А и Б.
            // А попытался подсказать Б. Не вышло.
            // Без костыля playersCircle будет пустым.
            if (!playersCircle.Any())
            {
                playersCircle = players;
            }

            return
                (new NoCriticalSituation(_clueGiver, playersCircle, boardContext));
        }