package com.hearthsim.player.playercontroller; import com.hearthsim.card.Card; import com.hearthsim.card.minion.Hero; import com.hearthsim.card.minion.Minion; import com.hearthsim.card.spellcard.SpellDamage; import com.hearthsim.card.weapon.WeaponCard; import com.hearthsim.model.BoardModel; import com.hearthsim.model.PlayerSide; import com.hearthsim.util.DeepCopyable; import com.hearthsim.util.IdentityLinkedList; import java.util.HashMap; public class WeightedScorer implements BoardScorer, DeepCopyable<WeightedScorer> { private double myAttackWeight; // weight for the attack score private double myHealthWeight; private double enemyAttackWeight; // weight for the attack score private double enemyHealthWeight; private double myHeroHealthWeight; private double enemyHeroHealthWeight; private double tauntWeight; private double manaWeight; private double myNumMinionsWeight; private double enemyNumMinionsWeight; private double spellDamageAddWeight; private double spellDamageMultiplierWeight; private double myDivineShieldWeight; private double enemyDivineShieldWeight; private double myWeaponWeight; private double enemyWeaponWeight; private double myChargeWeight; private HashMap<Class<? extends Minion>, Double> minionOnBoardExtraScore; private HashMap<Class<? extends Card>, Double> cardInHandExtraScore; public WeightedScorer() { // TODO Auto-generated constructor stub } @Override public double boardScore(BoardModel board) { Iterable<Minion> myBoardMinions; Iterable<Minion> opBoardMinions; IdentityLinkedList<Card> myHandCards; myBoardMinions = board.getCurrentPlayer().getMinions(); opBoardMinions = board.getWaitingPlayer().getMinions(); myHandCards = board.getCurrentPlayer().getHand(); // my board score double boardScore = 0.0; for (final Minion minion : myBoardMinions) { boardScore += this.minionOnBoardScore(minion, PlayerSide.CURRENT_PLAYER, board); } // opponent board score for (final Minion minion : opBoardMinions) { boardScore -= this.minionOnBoardScore(minion, PlayerSide.WAITING_PLAYER, board); } // weapons double weaponScore = 0.0; weaponScore += this.weaponScore(board.getCurrentPlayer().getHero()); weaponScore -= this.weaponScore(board.getWaitingPlayer().getHero()); // my cards. The more cards that I have, the better double handScore = 0.0; for (final Card card : myHandCards) { handScore += this.cardInHandScore(card, board); } // the more we beat on the opponent hero, the better double heroScore = 0; heroScore += heroHealthScore_p0(board.getCurrentPlayer().getHero().getHealth(), board.getCurrentPlayer().getHero() .getArmor()); heroScore += heroHealthScore_p1(board.getWaitingPlayer().getHero().getHealth(), board.getWaitingPlayer().getHero() .getArmor()); // the more minions you have, the better. The less minions the enemy has, the better double minionScore = 0.0; minionScore += myNumMinionsWeight * (board.getCurrentPlayer().getNumMinions()); minionScore -= enemyNumMinionsWeight * (board.getWaitingPlayer().getNumMinions()); return boardScore + handScore + heroScore + minionScore + weaponScore; } /** * Returns the card score for a particular card assuming that it is in the hand * * @param card * @return */ @Override public double cardInHandScore(Card card, BoardModel board) { double theScore = 0.001; // need non-zero so the AI values TheCoin and Innervate if (card instanceof SpellDamage) { theScore += ((SpellDamage)card).getAttack() * spellDamageMultiplierWeight + spellDamageAddWeight; } else if (card instanceof Minion) { // Charge modeling. Charge's value primarily comes from the fact that it can be used immediately upon placing it. // After the card is placed, it's really just like any other minion, except maybe for small value in bouncing it. // So, the additional score for charge minions should really only apply when it is still in the hand. Minion minion = (Minion)card; theScore += card.getBaseManaCost() * manaWeight + (minion.getCharge() ? myChargeWeight : 0.0); } else theScore += card.getBaseManaCost() * manaWeight; if (cardInHandExtraScore != null) { Double val = cardInHandExtraScore.get(card.getClass()); if (val != null) theScore += val; } return theScore; } @Override public double minionOnBoardScore(Minion minion, PlayerSide side, BoardModel board) { double score = 0.0001; score += minion.getAttack() * (side == PlayerSide.CURRENT_PLAYER ? myAttackWeight : enemyAttackWeight); score += minion.getTotalHealth() * (side == PlayerSide.CURRENT_PLAYER ? myHealthWeight : enemyHealthWeight); score += (minion.getTaunt() ? 1.0 : 0.0) * tauntWeight; if (minion.getDivineShield()) score += (minion.getAttack() + minion.getTotalHealth()) * (side == PlayerSide.CURRENT_PLAYER ? myDivineShieldWeight : enemyDivineShieldWeight); if (minionOnBoardExtraScore != null) { Double val = minionOnBoardExtraScore.get(minion.getClass()); if (val != null) score += val; } return score; } @Override public double heroHealthScore_p0(double heroHealth, double heroArmor) { double toRet = myHeroHealthWeight * (heroHealth + heroArmor); if (heroHealth <= 0) { // dead enemy hero is a very good thing toRet -= 100000000.0; } return toRet; } @Override public double heroHealthScore_p1(double heroHealth, double heroArmor) { double toRet = -enemyHeroHealthWeight * (heroHealth + heroArmor); if (heroHealth <= 0) { // dead enemy hero is a very good thing toRet += 100000.0; } return toRet; } protected double weaponScore(Hero hero) { WeaponCard weapon = hero.getWeapon(); if (weapon == null) { return 0; } return hero.getAttack() * hero.getWeapon().getWeaponCharge() * myWeaponWeight; } public double getMyChargeWeight() { return myChargeWeight; } public void setMyChargeWeight(double myChargeWeight) { this.myChargeWeight = myChargeWeight; } public double getMyAttackWeight() { return myAttackWeight; } public void setMyAttackWeight(double myAttackWeight) { this.myAttackWeight = myAttackWeight; } public double getMyHealthWeight() { return myHealthWeight; } public void setMyHealthWeight(double myHealthWeight) { this.myHealthWeight = myHealthWeight; } public double getEnemyAttackWeight() { return enemyAttackWeight; } public void setEnemyAttackWeight(double enemyAttackWeight) { this.enemyAttackWeight = enemyAttackWeight; } public double getEnemyHealthWeight() { return enemyHealthWeight; } public void setEnemyHealthWeight(double enemyHealthWeight) { this.enemyHealthWeight = enemyHealthWeight; } public double getMyHeroHealthWeight() { return myHeroHealthWeight; } public void setMyHeroHealthWeight(double myHeroHealthWeight) { this.myHeroHealthWeight = myHeroHealthWeight; } public double getEnemyHeroHealthWeight() { return enemyHeroHealthWeight; } public void setEnemyHeroHealthWeight(double enemyHeroHealthWeight) { this.enemyHeroHealthWeight = enemyHeroHealthWeight; } public double getTauntWeight() { return tauntWeight; } public void setTauntWeight(double tauntWeight) { this.tauntWeight = tauntWeight; } public double getManaWeight() { return manaWeight; } public void setManaWeight(double manaWeight) { this.manaWeight = manaWeight; } public double getMyNumMinionsWeight() { return myNumMinionsWeight; } public void setMyNumMinionsWeight(double myNumMinionsWeight) { this.myNumMinionsWeight = myNumMinionsWeight; } public double getEnemyNumMinionsWeight() { return enemyNumMinionsWeight; } public void setEnemyNumMinionsWeight(double enemyNumMinionsWeight) { this.enemyNumMinionsWeight = enemyNumMinionsWeight; } public double getSpellDamageAddWeight() { return spellDamageAddWeight; } public void setSpellDamageAddWeight(double spellDamageAddWeight) { this.spellDamageAddWeight = spellDamageAddWeight; } public double getSpellDamageMultiplierWeight() { return spellDamageMultiplierWeight; } public void setSpellDamageMultiplierWeight(double spellDamageMultiplierWeight) { this.spellDamageMultiplierWeight = spellDamageMultiplierWeight; } public double getMyDivineShieldWeight() { return myDivineShieldWeight; } public void setMyDivineShieldWeight(double myDivineShieldWeight) { this.myDivineShieldWeight = myDivineShieldWeight; } public double getEnemyDivineShieldWeight() { return enemyDivineShieldWeight; } public void setEnemyDivineShieldWeight(double enemyDivineShieldWeight) { this.enemyDivineShieldWeight = enemyDivineShieldWeight; } public double getMyWeaponWeight() { return myWeaponWeight; } public void setMyWeaponWeight(double myWeaponWeight) { this.myWeaponWeight = myWeaponWeight; } public double getEnemyWeaponWeight() { return enemyWeaponWeight; } public void setEnemyWeaponWeight(double enemyWeaponWeight) { this.enemyWeaponWeight = enemyWeaponWeight; } public void putMinionOnBoardExtraScore(Class<? extends Minion> clazz, double value) { if (minionOnBoardExtraScore == null) minionOnBoardExtraScore = new HashMap<>(); minionOnBoardExtraScore.put(clazz, value); } public void putCardInHandExtraScore(Class<? extends Card> class1, double value) { if (cardInHandExtraScore == null) cardInHandExtraScore = new HashMap<>(); cardInHandExtraScore.put(class1, value); } @Override public WeightedScorer deepCopy() { WeightedScorer copied = new WeightedScorer(); copied.myAttackWeight = myAttackWeight; // weight for the attack score copied.myHealthWeight = myHealthWeight; copied.enemyAttackWeight = enemyAttackWeight; // weight for the attack score copied.enemyHealthWeight = enemyHealthWeight; copied.myHeroHealthWeight = myHeroHealthWeight; copied.enemyHeroHealthWeight = enemyHeroHealthWeight; copied.tauntWeight = tauntWeight; copied.manaWeight = manaWeight; copied.myNumMinionsWeight = myNumMinionsWeight; copied.enemyNumMinionsWeight = enemyNumMinionsWeight; copied.spellDamageAddWeight = spellDamageAddWeight; copied.spellDamageMultiplierWeight = spellDamageMultiplierWeight; copied.myDivineShieldWeight = myDivineShieldWeight; copied.enemyDivineShieldWeight = enemyDivineShieldWeight; copied.myWeaponWeight = myWeaponWeight; copied.enemyWeaponWeight = enemyWeaponWeight; copied.myChargeWeight = myChargeWeight; return copied; } }