172 lines
6.0 KiB
Java
172 lines
6.0 KiB
Java
package magic.ai;
|
|
|
|
import java.util.Set;
|
|
|
|
import magic.model.MagicAbility;
|
|
import magic.model.MagicCard;
|
|
import magic.model.MagicCardDefinition;
|
|
import magic.model.MagicColor;
|
|
import magic.model.MagicGame;
|
|
import magic.model.MagicPermanent;
|
|
import magic.model.MagicPowerToughness;
|
|
import magic.model.choice.MagicCombatCreature;
|
|
|
|
public class ArtificialScoringSystem {
|
|
|
|
public static final int WIN_GAME_SCORE=100000000;
|
|
public static final int LOSE_GAME_SCORE=-WIN_GAME_SCORE;
|
|
public static final int ITEM_ON_STACK_SCORE=-1;
|
|
public static final int UNEQUIP_SCORE=-100;
|
|
public static final int UNNECESSARY_EQUIP_SCORE=-1000;
|
|
|
|
private static final int[] LIFE_SCORES={
|
|
0,1000,2000,3000,4000,
|
|
4500,5000,5500,6000,6500,
|
|
7000,7400,7800,8200,8600,
|
|
9000,9200,9400,9600,9800,
|
|
10000
|
|
};
|
|
|
|
private static final int[] POISON_SCORES={
|
|
5000,4700,4400,4100,3800,
|
|
3400,3000,2500,2000,1000,
|
|
0
|
|
};
|
|
|
|
private static final int MAX_LIFE=LIFE_SCORES.length-1;
|
|
|
|
private static final int MAX_POISON=10;
|
|
|
|
private static final int LIFE_ABOVE_MULTIPLIER=100;
|
|
|
|
private static final int UNKNOWN_CARD_SCORE=300;
|
|
|
|
private static final int PERMANENT_SCORE=300;
|
|
|
|
public static int getTurnScore(final MagicGame game) {
|
|
return Math.max(0,10-(game.getTurn()-1)>>1);
|
|
}
|
|
|
|
public static int getLoseGameScore(final MagicGame game) {
|
|
// Lose score is lowered in function of the turn and phase when it occurs. Encourages AI to win as fast as possible.
|
|
return LOSE_GAME_SCORE+game.getTurn()*2500+game.getPhase().getType().ordinal()*200;
|
|
}
|
|
|
|
public static int getCardDefinitionScore(final MagicCardDefinition cardDefinition) {
|
|
return getCardDefinitionScore(cardDefinition, 1);
|
|
}
|
|
|
|
// score for a card that gets put into play without paying the mana cost
|
|
public static int getFreeCardDefinitionScore(final MagicCardDefinition cardDefinition) {
|
|
return getCardDefinitionScore(cardDefinition, 0);
|
|
}
|
|
|
|
private static int getCardDefinitionScore(final MagicCardDefinition cardDefinition, final int costFactor) {
|
|
if (cardDefinition.isLand()) {
|
|
int score=(int)(cardDefinition.getValue()*50);
|
|
for (final MagicColor color : MagicColor.values()) {
|
|
score+=cardDefinition.getManaSource(color)*50;
|
|
}
|
|
return score;
|
|
}
|
|
final int score=(int)(cardDefinition.getValue()*100) - costFactor * cardDefinition.getConvertedCost() * 20;
|
|
if (cardDefinition.isCreature()) {
|
|
return score+(cardDefinition.getCardPower()+cardDefinition.getCardToughness())*10;
|
|
} else if (!cardDefinition.isToken()) {
|
|
return score+cardDefinition.getRemoval()*50+cardDefinition.getRarity()*30;
|
|
} else {
|
|
return score;
|
|
}
|
|
}
|
|
|
|
public static int getCardScore(final MagicCard card) {
|
|
return card.isKnown()?card.getCardDefinition().getScore():UNKNOWN_CARD_SCORE;
|
|
}
|
|
|
|
public static int getFreeCardScore(final MagicCard card) {
|
|
return card.isKnown()?card.getCardDefinition().getFreeScore():UNKNOWN_CARD_SCORE;
|
|
}
|
|
|
|
public static int getFixedPermanentScore(final MagicPermanent permanent) {
|
|
int score = permanent.getCardScore();
|
|
if (permanent.isCreature()) {
|
|
score+=permanent.getActivations().size()*50;
|
|
score+=permanent.getManaActivations().size()*80;
|
|
} else {
|
|
score+=PERMANENT_SCORE;
|
|
if (permanent.isEquipment()) {
|
|
score+=100;
|
|
}
|
|
}
|
|
return score;
|
|
}
|
|
|
|
public static int getVariablePermanentScore(final MagicPermanent permanent) {
|
|
int score = permanent.getCountersScore()*30;
|
|
if (!permanent.canTap()) {
|
|
score+=getTappedScore(permanent);
|
|
}
|
|
if (permanent.isCreature()) {
|
|
// used to consider pt and abilities without EOT effects, now includes EOT effects
|
|
final MagicPowerToughness pt=permanent.getPowerToughness();
|
|
final Set<MagicAbility> abilityFlags=permanent.getAbilityFlags();
|
|
score+=pt.power()*300+pt.getPositiveToughness()*200+MagicAbility.getScore(abilityFlags)*(pt.getPositivePower()+1)/2;
|
|
score+=permanent.getEquipmentPermanents().size()*50+permanent.getAuraPermanents().size()*100;
|
|
}
|
|
return score;
|
|
}
|
|
|
|
public static int getTappedScore(final MagicPermanent permanent) {
|
|
return permanent.isCreature()?-10:-5;
|
|
}
|
|
|
|
public static int getLifeScore(final int life) {
|
|
if (life>MAX_LIFE) {
|
|
return LIFE_SCORES[MAX_LIFE]+(life-MAX_LIFE)*LIFE_ABOVE_MULTIPLIER;
|
|
} else if (life>=0) {
|
|
return LIFE_SCORES[life];
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public static int getPoisonScore(final int poison) {
|
|
if (poison>MAX_POISON) {
|
|
return POISON_SCORES[MAX_POISON];
|
|
}
|
|
return POISON_SCORES[poison];
|
|
}
|
|
|
|
public static int getManaScore(final int amount) {
|
|
return -amount;
|
|
}
|
|
|
|
public static int getAttackerScore(final MagicCombatCreature attacker) {
|
|
int score=attacker.power*5+attacker.lethalDamage*2-attacker.candidateBlockers.length;
|
|
for (final MagicCombatCreature blocker : attacker.candidateBlockers) {
|
|
score-=blocker.power;
|
|
}
|
|
// Dedicated attacker.
|
|
if (attacker.hasAbility(MagicAbility.AttacksEachTurnIfAble) ||
|
|
attacker.hasAbility(MagicAbility.CannotBlock)) {
|
|
score+=10;
|
|
}
|
|
// Abilities for attacking.
|
|
if (attacker.hasAbility(MagicAbility.Trample) ||
|
|
attacker.hasAbility(MagicAbility.Vigilance)) {
|
|
score+=8;
|
|
}
|
|
// Dangerous to block.
|
|
if (!attacker.normalDamage ||
|
|
attacker.hasAbility(MagicAbility.FirstStrike) ||
|
|
attacker.hasAbility(MagicAbility.Indestructible)) {
|
|
score+=7;
|
|
}
|
|
return score;
|
|
}
|
|
|
|
public static int getMillScore(final int amount) {
|
|
return -amount;
|
|
}
|
|
}
|