コード例 #1
0
ファイル: MiniMaxStrategy.cs プロジェクト: mathjeff/SCGSim
        public GameEffect ChooseBestAction(GameChoice choice, Game game)
        {
            game = game.Clone();
            // Inform the game and its descendents that it is a hypothetical game, so all players use the strategy of the player doing the imagining
            Readable_GamePlayer chooser = game.Get_ReadableSnapshot(choice.ControllerID);

            game.Strategy = game.GetStrategy(chooser);
            IEnumerable <GameEffect> effects = choice.Options;
            // create the base game
            Analyzed_GameState rootState = new Analyzed_GameState(game, null, null, this.GameEvaluator.EstimateWinProbabilities(game));

            rootState.ChoosingPlayerID = choice.ControllerID;
            // Put the first set of choices onto the starting gameState
            this.PutGameOptions(rootState, choice);
            // loop until we run out of time
            while (rootState.NumDescendents < this.NumTimeSteps)
            {
                // Find the current best path and explore it for one more time unit
                this.ProcessOnce(rootState);
                double winProbability = rootState.WinProbabilities[choice.ControllerID];
                if (winProbability == 0 || winProbability == 1)
                {
                    break;
                }
            }
            if (this.ShouldPrint)
            {
                Console.WriteLine("Plan for " + chooser.ToString());
                rootState.printBestPath();
            }
            return(rootState.FavoriteChild.SourceEffect);
        }
コード例 #2
0
        public override string ToString(Game game)
        {
            Readable_GamePlayer player         = this.playerProvider.GetValue(this.Cause, game, (Writable_GamePlayer)null);
            Resource            bonusResources = this.resourcesToGain_provider.GetValue(this.Cause, game, (Resource)null);

            return(player.ToString() + " gains " + bonusResources.ToString());
        }
コード例 #3
0
ファイル: WritableCard.cs プロジェクト: mathjeff/SCGSim
        public virtual bool IsPlayable(Game game)
        {
            // check that we have enough resources to play this card
            Readable_GamePlayer controller = game.Get_ReadableSnapshot(this.ControllerID);

            return(controller.Get_CurrentResources().Minus(this.cost).IsValid);
        }
コード例 #4
0
        public double EstimateWinProbability(Game game, ID <Readable_GamePlayer> playerId)
        {
            Readable_GamePlayer player = game.Get_ReadableSnapshot(playerId);

            // first check for obvious things like whether one player has already lost
            if (game.GetWinner() != null)
            {
                if (game.GetWinner() == player)
                {
                    return(1);
                }
                else
                {
                    return(0);
                }
            }
            if (game.GetLosers().Count == game.NumPlayers)
            {
                return(0);
                //return 1.0 / game.NumPlayers;
            }
            // Now compute a heuristic based on how much stuff each player has
            double totalScore   = 0;
            double playerScore  = 0;
            double activePlayer = 1;

            foreach (Readable_GamePlayer candidate in game.Players)
            {
                // Exchange rates:
                // n power and n toughness is worth n mana
                // losing 25% of your life is worth 2 mana
                // 1 crystal per turn is worth 2 mana now.
                // n cards in hand is worth n mana (the cards often generate n mana worth of value (plus the mana spent to play them) even though they often cost 2*n to draw them)
                // Being the active player is worth 0.5 cards and 0.5 mana/turn, but the active player has received 1 additional card and 1 additional mana, so these must each be subtracted instead
                // This results in this score (equivalent amount of mana this turn):
                // mana+manaPerTurn*2++((power+toughness)/2)+(log(life)/log(4/3))+(activePlayer?)*-1.5+handSize

                /*
                 * double score = candidate.Get_CurrentResources().ToNumber() * activePlayer / 2 + candidate.Get_ResourcesPerTurn().ToNumber() - activePlayer * 2 +
                 *  (candidate.Get_Total_MonsterDamage(game) + candidate.Get_Total_MonsterHealth(game)) / 2 + Math.Log(candidate.GetHealth()) / Math.Log(4.0 / 3.0);
                 */
                double score = candidate.Get_CurrentResources().ToNumber() * activePlayer + candidate.Get_ResourcesPerTurn().ToNumber() * 2
                               + (candidate.Get_Total_MonsterDamage(game) + candidate.Get_Total_MonsterHealth(game)) / 2 + Math.Log(candidate.GetHealth()) / Math.Log(4.0 / 3.0) + activePlayer * -1.5
                               + candidate.Get_ReadableHand().Count;

                if (score < 1) // can't have 0 or less probability of winning unless you've actually lost already
                {
                    score = 1;
                }

                totalScore += score;
                if (candidate == player)
                {
                    playerScore = score;
                }
                activePlayer *= 0;
            }
            return(playerScore / totalScore);
        }
コード例 #5
0
ファイル: Game.cs プロジェクト: mathjeff/SCGSim
        public void AddPlayer(Readable_GamePlayer player)
        {
            WriteControlled_Item <Readable_GamePlayer, Writable_GamePlayer> playerPair = new WriteControlled_Item <Readable_GamePlayer, Writable_GamePlayer>(new PlayerConverter());

            playerPair.PutReadonly(player);
            this.players.PutReadonly(player);
            this.TurnOrder.AddLast(player.GetID((Readable_GamePlayer)null));
        }
コード例 #6
0
ファイル: DrawEffect.cs プロジェクト: mathjeff/SCGSim
        public override string ToString(Game game)
        {
            int    numCards            = this.numCards_provider.GetValue(this, game, default(int));
            string cardSource          = this.cardProvider.ToString();
            Readable_GamePlayer player = this.playerProvider.GetValue(this, game, (Writable_GamePlayer)null);

            return("Draw " + numCards + " from " + cardSource + " for " + player);
        }
コード例 #7
0
ファイル: Game.cs プロジェクト: mathjeff/SCGSim
 public GameStrategy GetStrategy(Readable_GamePlayer player)
 {
     if (this.Strategy != null)
     {
         // This is a hypothetical game, so all players use the same strategy as the player doing the imagining
         return(this.Strategy);
     }
     // This is a real game, so each player can use their own strategy
     return(player.Strategy);
 }
コード例 #8
0
        public bool IsPlayable(Readable_MonsterCard card, Game game)
        {
            Readable_GamePlayer controller = game.Get_ReadableSnapshot(card.Get_ControllerID());
            IEnumerable <ID <Readable_MonsterCard> > cardsInPlay = controller.Get_MonsterIDsInPlay();

            if (cardsInPlay.Count() < 7)
            {
                return(true);
            }
            return(false);
        }
コード例 #9
0
ファイル: Game.cs プロジェクト: mathjeff/SCGSim
        public GameChoice Get_NextChoice()
        {
            if (this.pendingEffects.Count > 0)
            {
                // a previous effect still requires a player to make a choice, so that must be done before moving on to normal options (like playing more cards, attacking, or ending the turn)
                GameChoice choice = this.pendingEffects.First();
                this.pendingEffects.RemoveFirst();
                return(choice);
            }
            // There aren't any effects still requiring user input, so now the active player can choose on of the usual choices (playing a card, attacking, ending the turn or whatever)
            Readable_GamePlayer activePlayer = this.ActivePlayer;

            return(new GameChoice(this.Referee.Get_AvailableGameActions(this, activePlayer), activePlayer.GetID((Readable_GamePlayer)null)));
        }
コード例 #10
0
ファイル: Game.cs プロジェクト: mathjeff/SCGSim
        // returns all monsters in play
        public IList <Readable_MonsterCard> Get_MonstersInPlay()
        {
            List <Readable_MonsterCard> targets = new List <Readable_MonsterCard>();

            foreach (ID <Readable_GamePlayer> playerId in this.players.GetKeys())
            {
                Readable_GamePlayer player = this.players.GetReadable(playerId);
                foreach (ID <Readable_MonsterCard> monsterId in player.Get_MonsterIDsInPlay())
                {
                    Readable_MonsterCard monster = this.Get_ReadableSnapshot(monsterId);
                    targets.Add(monster);
                }
            }
            return(targets);
        }
コード例 #11
0
ファイル: Game.cs プロジェクト: mathjeff/SCGSim
        // returns all valid LifeTargets in play (monsters and players)
        public IList <Readable_LifeTarget> Get_LifeTargets()
        {
            List <Readable_LifeTarget> targets = new List <Readable_LifeTarget>();

            foreach (ID <Readable_GamePlayer> playerId in this.players.GetKeys())
            {
                Readable_GamePlayer player = this.players.GetReadable(playerId);
                targets.Add(player);
            }
            foreach (Readable_MonsterCard monster in this.Get_MonstersInPlay())
            {
                targets.Add(monster);
            }
            return(targets);
        }
コード例 #12
0
 public void CopyFrom(Readable_GamePlayer original)
 {
     // the hand should be small enough that we can just clone it for the moment
     this.hand.PutReadonly(original.Get_ReadableHand());
     this.Deck            = original.GetDeck().Clone();
     this.Health          = original.GetHealth();
     this.MaxHealth       = original.GetMaxHealth();
     this.NumDrawsSkipped = original.Get_NumDrawsSkipped();
     this.sourcePlayer    = original.SourcePlayer;
     this.ID = original.GetID((Readable_GamePlayer)null).ToInt();
     this.MonsterIDsInPlay = new WriteControlled_Item <IReadOnlyList <ID <Readable_MonsterCard> >, List <ID <Readable_MonsterCard> > >(new ListConverter <ID <Readable_MonsterCard> >());
     this.MonsterIDsInPlay.PutReadonly(original.Get_MonsterIDsInPlay());
     this.CurrentResources = original.Get_CurrentResources();
     this.ResourcesPerTurn = original.Get_ResourcesPerTurn();
 }
コード例 #13
0
ファイル: LifeEffect.cs プロジェクト: mathjeff/SCGSim
        public override string ToString(Game game)
        {
            int amountToGain = this.amountToGain_provider.GetValue(this, game, default(int));
            Readable_GamePlayer controller = this.chooserProvider.GetValue(this, game, (Readable_GamePlayer)null);
            string result = controller.ToString();

            if (amountToGain > 0)
            {
                result += " heals a target for " + amountToGain;
            }
            else
            {
                result += " damages a target for " + (amountToGain * -1);
            }
            return(result);
        }
コード例 #14
0
ファイル: Game.cs プロジェクト: mathjeff/SCGSim
 }                                    // in charge of which type of game (Hearthstone, Magic, Hearts, or whatever) is being played
 public List <GameEffect> Get_AvailableGameActions(Readable_GamePlayer player)
 {
     return(this.Referee.Get_AvailableGameActions(this, player));
 }
コード例 #15
0
        public List <GameEffect> Get_AvailableGameActions(Game game, Readable_GamePlayer player)
        {
            // This function only gets called when there are no effects in progress (like choosing the target of a triggered effect).
            List <GameEffect> options = new List <GameEffect>();

            // So, a player has these types of options: 1. Play a card. 2. Attack with a monster. 3. Activate their special ability. 4. End their turn
            // Let the player play any card
            foreach (ID <ReadableCard> cardId in player.Get_ReadableHand())
            {
                ReadableCard card = game.Get_ReadableSnapshot(cardId);
                if (card.IsPlayable(game))
                {
                    options.Add(new PlayCard_Effect(card.GetID((ReadableCard)null)));
                }
            }
            // Let the player attack with any monster
            IEnumerable <ID <Readable_MonsterCard> > availableAttacker_IDs = player.Get_MonsterIDsInPlay();

            // first figure out which monsters can be attacked (if any monsters have Taunt, they are the only ones that may be attacked)
            foreach (ID <Readable_GamePlayer> playerId in game.TurnOrder)
            {
                // make sure this is a different player
                if (!playerId.Equals(player.GetID((Readable_GamePlayer)null)))
                {
                    LinkedList <ID <Readable_LifeTarget> > requiredTarget_IDs = new LinkedList <ID <Readable_LifeTarget> >();
                    LinkedList <ID <Readable_LifeTarget> > allTarget_Ids      = new LinkedList <ID <Readable_LifeTarget> >();
                    Readable_GamePlayer controller = game.Get_ReadableSnapshot(playerId);
                    foreach (ID <Readable_MonsterCard> monsterId in controller.Get_MonsterIDsInPlay())
                    {
                        Readable_MonsterCard     monster     = game.Get_ReadableSnapshot(monsterId);
                        ID <Readable_LifeTarget> convertedID = monster.GetID((Readable_LifeTarget)null);
                        allTarget_Ids.AddLast(convertedID);
                        if (monster.Get_MustBeAttacked())
                        {
                            requiredTarget_IDs.AddLast(convertedID);
                        }
                    }
                    if (requiredTarget_IDs.Count != 0)
                    {
                        // There is a monster with taunt, so the only valid targets are the monsters with taunt
                        allTarget_Ids = requiredTarget_IDs;
                    }
                    else
                    {
                        // There are no monsters with taunt, so the valid targets are all monsters and the opponent too
                        allTarget_Ids.AddLast(controller.GetID((Readable_LifeTarget)null));
                    }
                    // Now allow each monster to attack each available target
                    foreach (ID <Readable_MonsterCard> attackerId in availableAttacker_IDs)
                    {
                        if (game.Get_ReadableSnapshot(attackerId).Get_CanAttack())
                        {
                            foreach (ID <Readable_LifeTarget> targetId in allTarget_Ids)
                            {
                                options.Add(new AttackEffect(attackerId.AsType((Readable_LifeTarget)null), targetId));
                            }
                        }
                    }
                }
            }

            // Let the player end their turn
            options.Add(new EndTurn_Effect(player.GetID((Readable_GamePlayer)null)));
            return(options);
        }
コード例 #16
0
 public ID <Readable_GamePlayer> GetID(Readable_GamePlayer outputType)
 {
     return(new ID <Readable_GamePlayer>(this.ID));
 }