Example #1
0
        public ClueAndAction CreateClueToAvoid(IBoardContext boardContext, IPlayerContext playerContext)
        {
            // 1. Поищем подсказки, после которых игрок точно сходит
            var clueToPlayFinder = new ClueToPlayFinder(boardContext, playerContext);
            var actionToPlay     = clueToPlayFinder.Find();

            if (actionToPlay != null)
            {
                return(actionToPlay);
            }

            var variants = new List <ClueAndAction>();

            var clues =
                playerContext.Hand
                .Where(cih => Cards.Contains(cih.Card))
                .Select(cih => ClueDetailInfo.CreateClues(cih, playerContext))
                .Aggregate((acc, c) => acc.Concat(c).ToList())
                .Distinct();

            foreach (var clue in clues)
            {
                // применим подсказку и посмотрим, будет ли всё хорошо
                playerContext.PossibleClue = clue;

                // контекст должен чуток измениться...
                var playCardStrategy = PlayStrategyFabric.Create(playerContext.Player.GameProvider, playerContext);
                var discardStrategy  =
                    DiscardStrategyFabric.Create(playerContext.Player.GameProvider, playerContext);

                var playerPredictor = new PlayerActionPredictor(boardContext, playerContext);
                var newAction       = playerPredictor.Predict(playCardStrategy, discardStrategy);


                if (IsNewActionCorrect(newAction))
                {
                    variants.Add(new ClueAndAction {
                        Clue = clue, Action = newAction
                    });
                }
            }

            return(ChooseClue(playerContext, variants));
        }
Example #2
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);
        }
        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));
        }