public static void CalculateValues(TyState playerState, TyState opponentState, Controller player, Controller opponent, PlayerTask task, Spell spell)
        {
            if (_spellDictionary == null)
            {
                Init();
            }

            //give reward/punishment if spells cost less/more than usual:
            float diff = (float)spell.Card.Cost - (float)spell.Cost;

            playerState.BiasValue += diff * 1.25f;

            var key = spell.Card.Name;

            if (_spellDictionary.ContainsKey(key))
            {
                var action = _spellDictionary[key];
                action(playerState, opponentState, player, opponent, task, spell);
            }

            else if (TyConst.LOG_UNKNOWN_SECRETS)
            {
                TyDebug.LogInfo("Unknown spell: " + task.FullPrint());
            }
        }
        //Lightning Storm: Deal 2-3 damage to all enemy minions. Overload: (2)
        private static void LightningStorm(TyState playerState, TyState opponentState, Controller player, Controller opponent, PlayerTask task, Spell spell)
        {
            //give punishment when having less than this enemies:
            const int NUM_ENEMY_TARGETS = 3;

            playerState.BiasValue += (opponentState.NumMinionsOnBoard - NUM_ENEMY_TARGETS) * 1.25f;
        }
        private static void SpellDamageReward(TyState playerState, TyState opponentState, Controller player, Controller opponent, PlayerTask task, Spell spell, int damage, float reward)
        {
            var targetMinion = task.Target as Minion;

            if (spell.IsAffectedBySpellpower)
            {
                damage += player.CurrentSpellPower;
            }

            if (targetMinion.HasDivineShield && damage > 1)
            {
                //punishment for wasting damage for divine shield
                playerState.BiasValue -= 5.0f;
                return;
            }

            var targetHealth = targetMinion.Health;

            int diff = targetHealth - damage;

            float finalReward = diff * reward;

            //if the spell kills a minion on point, give additional bonus:
            if (diff == 0)
            {
                finalReward += reward;
            }

            playerState.BiasValue += finalReward;
        }
        public float GetStateValue(TyState playerState, TyState enemyState, Controller player, Controller opponent, PlayerTask task)
        {
            TyDebug.Assert(IsMyPlayer(player));
            TyDebug.Assert(!IsMyPlayer(opponent));

            if (EstimateSecretsAndSpells)
            {
                TySecretUtil.CalculateValues(playerState, enemyState, player, opponent);
                TySecretUtil.EstimateValues(enemyState, opponent);

                var spell = task.TryGetSpell();

                if (spell != null && !spell.IsSecret)
                {
                    TySpellUtil.CalculateValues(playerState, enemyState, player, opponent, task, spell);
                }
            }

            if (HasLost(enemyState))
            {
                return(Single.PositiveInfinity);
            }

            else if (HasLost(playerState))
            {
                return(Single.NegativeInfinity);
            }

            return(GetStateValueFor(playerState, enemyState) - GetStateValueFor(enemyState, playerState));
        }
Beispiel #5
0
        private static void CorrectHeroAttack(TyState lastPlayerState, TyState lastEnemyState, POGame.POGame lastState, PlayerTask playerTask, ref bool corrected)
        {
            var target        = playerTask.Target;
            var attackingHero = lastState.CurrentPlayer.Hero;

            lastPlayerState.WeaponDurability--;

            //hero attacks a minion:
            if (target is Minion)
            {
                var targetMinion = target as Minion;

                MinionTookDamage(targetMinion, lastEnemyState, lastPlayerState, attackingHero.TotalAttackDamage, false, playerTask);

                //"revenge" damage from the minion to the hero:
                ComputeDamageToHero(lastPlayerState, attackingHero, targetMinion.AttackDamage);
                corrected = true;
            }

            //hero attacks a hero:
            else if (target is Hero)
            {
                var targetHero = target as Hero;

                //compute damage to the targetHero:
                ComputeDamageToHero(lastEnemyState, targetHero, attackingHero.TotalAttackDamage);
                corrected = true;
            }
        }
Beispiel #6
0
        private static bool CorrectForSummonAndEquip(Card card, TyState ownerState, TyState opponentState)
        {
            var  text    = card.Text;
            bool success = true;

            if (text.Contains("Equip"))
            {
                int dmg        = 0;
                int durability = 0;
                if (FindNumberValues(text, ref dmg, ref durability))
                {
                    EquipWeapon(ownerState, dmg, durability);
                    success = true;
                }
            }

            if (text.Contains("Summon"))
            {
                int dmg    = 0;
                int health = 0;
                if (FindNumberValues(text, ref dmg, ref health))
                {
                    ownerState.MinionValues += TyMinionUtil.ComputeMinionValue(health, dmg, 1);
                    //just assume that the minion has some sort of (unknown) ability:
                    //Testing.TyDebug.LogInfo("Summoned " + dmg + "/" + health);
                    ownerState.MinionValues += 3;
                    success = true;
                }
            }

            return(success);
        }
        //Gain 1 Mana Crystal this turn only.
        private static void TheCoin(TyState playerState, TyState opponentState, Controller player, Controller opponent, PlayerTask task, Spell spell)
        {
            var curMana = player.GetAvailableMana();
            var newMana = curMana + 1;

            bool enablesNewCards = false;

            for (int i = 0; i < player.HandZone.Count; i++)
            {
                IPlayable card = player.HandZone[i];

                //if the card can only be played after using the coin, then it is not bad:
                if (card.Cost > curMana && card.Cost <= newMana)
                {
                    enablesNewCards = true;
                    break;
                }
            }

            //if the coin does not enable to play new cards, give punishment.
            if (!enablesNewCards)
            {
                playerState.BiasValue -= 100.0f;
            }
        }
        public static void CalculateValues(TyState playerState, TyState opponentState, Controller player, Controller opponent)
        {
            if (_secretDictionary == null)
            {
                Init();
            }

            for (int i = 0; i < player.SecretZone.Count; i++)
            {
                var secret = player.SecretZone[i];
                var key    = secret.Card.Name;

                if (_secretDictionary.ContainsKey(key))
                {
                    var action = _secretDictionary[key];
                    action(playerState, opponentState, player, opponent, secret);
                }

                else
                {
                    if (TyConst.LOG_UNKNOWN_SECRETS)
                    {
                        TyDebug.LogWarning("Unknown secret: " + secret.Card.FullPrint());
                    }

                    playerState.BiasValue += secret.Card.Cost * SECRET_VALUE_FACTOR;
                }
            }
        }
        /// <summary> Gives points for having cards in the hand. </summary>
        private float GetHandValues(TyState state)
        {
            int firstThree = Math.Min(state.NumHandCards, 3);
            int remaining  = Math.Abs(state.NumHandCards - firstThree);

            //3 times the points for the first three cards, 2 for all remaining cards:
            return(3 * firstThree + 2 * remaining);
        }
        //After your opponent plays a minion, add two copies of it to_your hand.
        private static void FrozenClone(TyState playerState, TyState opponentState, Controller player, Controller opponent, Spell secret)
        {
            var mana   = opponent.GetAvailableMana();
            var minion = TyMinionUtil.EstimatedValueFromMana(mana);

            //dont multiply by 2, because player still has to play the minions:
            playerState.BiasValue += minion * 1.75f + TyStateUtility.LateReward(mana, 4, 4.0f);
        }
Beispiel #11
0
        private static void ComputeDamageToHero(TyState targetHeroState, Hero targetHero, int damageToHero)
        {
            int armor         = targetHero.Armor;
            int dmgAfterArmor = Math.Max(0, damageToHero - armor);

            targetHeroState.HeroArmor  = Math.Max(0, armor - damageToHero);
            targetHeroState.HeroHealth = Math.Max(0, targetHero.Health - dmgAfterArmor);
        }
        //After your opponent plays a minion, summon a copy of it.
        private static void MirrorEntity(TyState playerState, TyState opponentState, Controller player, Controller opponent, Spell secret)
        {
            var mana   = opponent.GetAvailableMana();
            var minion = TyMinionUtil.EstimatedValueFromMana(mana);

            playerState.BiasValue    += TyStateUtility.LateReward(mana, 4, 5.0f);
            playerState.MinionValues += minion;
        }
        private bool HasLost(TyState player)
        {
            if (player.HeroHealth <= 0)
            {
                return(true);
            }

            return(false);
        }
Beispiel #14
0
 private static void CorrectHeroPower(TyState lastPlayerState, TyState lastEnemyState, POGame.POGame lastState, PlayerTask task, ref bool corrected)
 {
     //Dagger mastery from rogue: equip 1/2 daggers
     if (lastState.CurrentPlayer.HeroClass == CardClass.ROGUE)
     {
         EquipWeapon(lastPlayerState, 1, 2);
         corrected = true;
     }
 }
        //When an enemy casts a spell on a minion, summon a 1/3 as the new target.
        private static void Spellbender(TyState playerState, TyState opponentState, Controller player, Controller opponent, Spell secret)
        {
            var myMana = player.GetAvailableMana();
            var possibleAverageMinion = TyMinionUtil.EstimatedValueFromMana(myMana);
            var myAverageMinion       = playerState.GetAverageMinionValue();

            //dont play if my minions are weaker than a "good" minion at that point in game, also punish when played early:
            playerState.BiasValue += (myAverageMinion - possibleAverageMinion) + TyStateUtility.LateReward(myMana, 4, 2.0f);
        }
        //Maelstrom Portal: Deal 1 damage to all enemy minions. Summon a random 1-Cost minion.
        private static void MaelstromPortal(TyState playerState, TyState opponentState, Controller player, Controller opponent, PlayerTask task, Spell spell)
        {
            const int NUM_TARGET_MINIONS = 3;

            //negative if below NUM_TARGET_MINIONS, neutral at NUM_TARGET_MINIONS, then positive:
            int diff = opponentState.NumMinionsOnBoard - NUM_TARGET_MINIONS;

            playerState.BiasValue += diff * 1.25f;
        }
        /// <summary> Gives points for clearing the minion zone of the given opponent. </summary>
        private float GetEmptyFieldValue(TyState state)
        {
            //its better to clear the board in later stages of the game (more enemies might appear each round):
            if (state.NumMinionsOnBoard == 0)
            {
                return(2.0f + Math.Min((float)state.TurnNumber, 10.0f));
            }

            return(0.0f);
        }
        private float GetStateValueFor(TyState player, TyState enemy)
        {
            float emptyFieldValue = Weights.GetWeight(TyStateWeights.WeightType.EmptyField) * GetEmptyFieldValue(enemy);
            float healthValue     = Weights.GetWeight(TyStateWeights.WeightType.HealthFactor) * GetHeroHealthArmorValue(player);
            float deckValue       = Weights.GetWeight(TyStateWeights.WeightType.DeckFactor) * GetDeckValue(player);
            float handValue       = Weights.GetWeight(TyStateWeights.WeightType.HandFactor) * GetHandValues(player);
            float minionValue     = Weights.GetWeight(TyStateWeights.WeightType.MinionFactor) * GetMinionValues(player);
            float biasValues      = Weights.GetWeight(TyStateWeights.WeightType.BiasFactor) * GetBiasValue(player);

            return(emptyFieldValue + deckValue + healthValue + handValue + minionValue + biasValues);
        }
 //Lightning Bolt: Deal 3 damage. Overload: (1)
 private static void LightningBolt(TyState playerState, TyState opponentState, Controller player, Controller opponent, PlayerTask task, Spell spell)
 {
     if (task.HasTarget)
     {
         //reward if the spell does NOT overkill an enemy:
         if (task.Target is Minion)
         {
             SpellDamageReward(playerState, opponentState, player, opponent, task, spell, 3, 1.25f);
         }
     }
 }
        //After your opponent plays a minion, deal $6 damage to it and any excess to their hero
        private static void ExplosiveRunes(TyState playerState, TyState opponentState, Controller player, Controller opponent, Spell secret)
        {
            //doesnt matter if played early or late (early: deals damage to hero, later will most likely kill a minion)

            //multiply with a factor because either it kills a minion (higher value than just the damage dealt)
            //or/and it deals damage to the hero (also worth more than just reducing the hp)
            const float FACTOR      = 2.0f;
            const int   BASE_DAMAGE = 6;

            opponentState.BiasValue -= ((BASE_DAMAGE + player.CurrentSpellPower) * FACTOR);
        }
        //When a minion attacks your hero, destroy it.
        private static void Vaporize(TyState playerState, TyState opponentState, Controller player, Controller opponent, Spell secret)
        {
            var opponentMana = opponent.GetAvailableMana();

            //punish playing early:
            playerState.BiasValue += TyStateUtility.LateReward(opponentMana, 5, 5.0f);

            //estimate destroying an enemy minion:
            float avgMinionValue = TyMinionUtil.EstimatedValueFromMana(opponentMana);

            opponentState.MinionValues -= avgMinionValue;
        }
Beispiel #22
0
        public static TyState FromSimulatedGame(POGame.POGame newState, Controller me, PlayerTask task)
        {
            TyState s = new TyState
            {
                HeroHealth = me.Hero.Health,
                HeroArmor  = me.Hero.Armor,

                TurnNumber = newState.Turn,

                NumDeckCards      = me.DeckZone.Count,
                NumHandCards      = me.HandZone.Count,
                NumMinionsOnBoard = me.BoardZone.Count,

                Fatigue      = me.Hero.Fatigue,
                MinionValues = TyMinionUtil.ComputeMinionValues(me)
            };

            if (me.Hero.Weapon != null)
            {
                s.WeaponDurability = me.Hero.Weapon.Durability;
                s.WeaponDamage     = me.Hero.Weapon.AttackDamage;
            }

            //this case is met, if the player uses a card that temporarily boosts attack:
            if (me.Hero.TotalAttackDamage > s.WeaponDamage)
            {
                s.WeaponDamage = me.Hero.TotalAttackDamage;

                //assume that the player can at least attack once:
                if (s.WeaponDurability == 0)
                {
                    s.WeaponDurability = 1;
                }
            }

            //aka, can't attack:
            if (me.Hero.IsFrozen)
            {
                s.WeaponDamage = 0;
            }

            var minion = task.TryGetMinion();

            if (minion != null)
            {
                //give reward/punishment of minions cost less/more than usual:
                float diff = (float)minion.Card.Cost - (float)minion.Cost;
                s.BiasValue += diff * 1.5f;
            }

            return(s);
        }
        //After your opponent plays a minion, transform it into a 1/1 Sheep.
        private static void PotionOfPolymorph(TyState playerState, TyState opponentState, Controller player, Controller opponent, Spell secret)
        {
            int opponentMana = opponent.GetAvailableMana();

            //punish playing early:
            playerState.BiasValue += TyStateUtility.LateReward(opponentMana, 5, 5.0f);

            //value is the difference between an average minion and the sheep:
            float sheepValue         = TyMinionUtil.ComputeMinionValue(1, 1, 1);
            float averageMinionValue = TyMinionUtil.EstimatedValueFromMana(opponentMana);
            float polymorphedValue   = (sheepValue - averageMinionValue);

            opponentState.MinionValues += polymorphedValue;
        }
Beispiel #24
0
        private static void RemoveMinion(Minion minion, TyState ownerState, TyState opponentState, PlayerTask task)
        {
            //remove the minion value from the overall minion values and remove it from the board
            ownerState.MinionValues -= TyMinionUtil.ComputeMinionValue(minion);
            ownerState.NumMinionsOnBoard--;

            if (minion.HasDeathrattle)
            {
                if (!CorrectForSummonAndEquip(minion.Card, ownerState, opponentState) && TyConst.LOG_UNKNOWN_CORRECTIONS)
                {
                    TyDebug.LogError("Unknown deathrattle from " + minion.Card.FullPrint());
                    TyDebug.LogWarning("After task " + task.FullPrint());
                }
            }
        }
        /// <summary> Estimates how good the given child state is. </summary>
        public static float GetStateValue(POGame.POGame parent, POGame.POGame child, PlayerTask task, TyStateAnalyzer analyzer)
        {
            float valueFactor = 1.0f;

            TyState myState    = null;
            TyState enemyState = null;

            Controller player   = null;
            Controller opponent = null;

            //it's a buggy state, mostly related to equipping/using weapons on heroes etc.
            //in this case use the old state and estimate the new state manually:
            if (child == null)
            {
                player   = parent.CurrentPlayer;
                opponent = parent.CurrentOpponent;

                myState    = TyState.FromSimulatedGame(parent, player, task);
                enemyState = TyState.FromSimulatedGame(parent, opponent, null);

                //if the correction failes, assume the task is x% better/worse:
                if (!TyState.CorrectBuggySimulation(myState, enemyState, parent, task))
                {
                    valueFactor = 1.25f;
                }
            }

            else
            {
                player   = child.CurrentPlayer;
                opponent = child.CurrentOpponent;

                //happens sometimes even with/without TURN_END, idk
                if (!analyzer.IsMyPlayer(player))
                {
                    player   = child.CurrentOpponent;
                    opponent = child.CurrentPlayer;
                }

                myState    = TyState.FromSimulatedGame(child, player, task);
                enemyState = TyState.FromSimulatedGame(child, opponent, null);
            }

            TyDebug.Assert(analyzer.IsMyPlayer(player));
            TyDebug.Assert(!analyzer.IsMyPlayer(opponent));
            return(analyzer.GetStateValue(myState, enemyState, player, opponent, task) * valueFactor);
        }
        //When your hero takes fatal damage, prevent it and become Immune this turn.
        private static void IceBlock(TyState playerState, TyState opponentState, Controller player, Controller opponent, Spell secret)
        {
            //give punishment when at full hp, give reward if hp lessens

            const int MAX_HEALTH    = 30;
            const int MIN_HEALTH    = 1;
            float     healthPercent = 1.0f - TyUtility.InverseLerp(playerState.HeroHealth, MIN_HEALTH, MAX_HEALTH);

            //punishment when at full hp:
            const float MIN_VALUE = -30.0f;
            //reward when at 1 hp:
            const float MAX_VALUE = 45.0f;

            float value = TyUtility.Lerp(MIN_VALUE, MAX_VALUE, healthPercent);

            playerState.BiasValue += value;
        }
Beispiel #27
0
        private static void EquipWeapon(TyState lastPlayerState, int attackDamage, int durability)
        {
            int newSum = attackDamage + durability;
            int oldSum = lastPlayerState.WeaponDamage + lastPlayerState.WeaponDurability;

            //equipping a worse weapon:
            if (newSum > 0 && newSum <= oldSum)
            {
                //assign negative values to indicate for a bad move (kinda hacky to do it that way):
                lastPlayerState.WeaponDamage     = -Math.Abs(lastPlayerState.WeaponDamage);
                lastPlayerState.WeaponDurability = -Math.Abs(lastPlayerState.WeaponDurability);
            }

            //equip either 0/0 (destroy) or a better weapon:
            else
            {
                lastPlayerState.WeaponDamage     = attackDamage;
                lastPlayerState.WeaponDurability = durability;
            }
        }
Beispiel #28
0
        public static bool CorrectBuggySimulation(TyState lastPlayerState, TyState lastEnemyState, POGame.POGame lastState, PlayerTask task)
        {
            var taskType = task.PlayerTaskType;

            //Testing.TyDebug.LogError(task.FullPrint());

            bool corrected = false;

            if (taskType == PlayerTaskType.END_TURN)
            {
                CorrectTurnEnd(lastPlayerState, lastEnemyState, lastState, task, ref corrected);
            }

            else if (taskType == PlayerTaskType.HERO_ATTACK)
            {
                CorrectHeroAttack(lastPlayerState, lastEnemyState, lastState, task, ref corrected);
            }

            else if (taskType == PlayerTaskType.PLAY_CARD)
            {
                CorrectPlayCard(lastPlayerState, lastEnemyState, lastState, task, ref corrected);
            }

            else if (taskType == PlayerTaskType.MINION_ATTACK)
            {
                CorrectMinionAttack(lastPlayerState, lastEnemyState, lastState, task, ref corrected);
            }

            else if (taskType == PlayerTaskType.HERO_POWER)
            {
                CorrectHeroPower(lastPlayerState, lastEnemyState, lastState, task, ref corrected);
            }

            if (TyConst.LOG_UNKNOWN_CORRECTIONS && !corrected)
            {
                TyDebug.LogError("Unknown buggy PlayerTask: " + task.FullPrint());
            }

            return(corrected);
        }
Beispiel #29
0
        private static void CorrectMinionAttack(TyState lastPlayerState, TyState lastEnemyState, POGame.POGame lastState, PlayerTask task, ref bool corrected)
        {
            if (task.HasSource)
            {
                if (task.Source is Minion)
                {
                    var minionSource = task.Source as Minion;

                    if (task.HasTarget)
                    {
                        if (task.Target is Minion)
                        {
                            var targetMinion = (task.Target as Minion);

                            MinionTookDamage(targetMinion, lastEnemyState, lastPlayerState, minionSource.AttackDamage, minionSource.Poisonous, task);
                            MinionTookDamage(minionSource, lastPlayerState, lastEnemyState, targetMinion.AttackDamage, targetMinion.Poisonous, task);
                            corrected = true;
                        }
                    }
                }
            }
        }
Beispiel #30
0
        private static void MinionTookDamage(Minion targetMinion, TyState ownerState, TyState opponentState, int totalAttackDamage, bool poison, PlayerTask task)
        {
            //didn't take damage:
            if (targetMinion.HasDivineShield)
            {
                ownerState.MinionValues -= TyMinionUtil.DIVINE_SHIELD_VALUE;
            }

            else
            {
                int damage = totalAttackDamage;

                if (poison || damage >= targetMinion.Health)
                {
                    RemoveMinion(targetMinion, ownerState, opponentState, task);
                }
                else
                {
                    ownerState.MinionValues -= damage;
                }
            }
        }