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)); }
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 }); } } }
public PlayCardEstimator(IPlayCardStrategy strategy) { _strategy = strategy; }
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)); }