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)); }
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)); }