mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 11:32:00 -08:00
- AI will now block and attack a little more sanely. The sim methods are not working right now, so they were commented out.
This commit is contained in:
parent
fec750ef01
commit
1d7e9e55be
1 changed files with 323 additions and 273 deletions
|
|
@ -25,7 +25,6 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import mage.Constants.Outcome;
|
||||
|
|
@ -68,6 +67,7 @@ import mage.target.TargetCard;
|
|||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import mage.player.ai.utils.RateCard;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -77,7 +77,6 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
|
||||
private static final transient org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ComputerPlayer6.class);
|
||||
private static final ExecutorService pool = Executors.newFixedThreadPool(1);
|
||||
|
||||
protected int maxDepth;
|
||||
protected int maxNodes;
|
||||
protected int maxThink;
|
||||
|
|
@ -87,11 +86,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
protected Combat combat;
|
||||
protected int currentScore;
|
||||
protected SimulationNode2 root;
|
||||
|
||||
private static final String FILE_WITH_INSTRUCTIONS = "config/ai.please.cast.this.txt";
|
||||
private List<String> suggested = new ArrayList<String>();
|
||||
protected Set<String> actionCache;
|
||||
|
||||
private static final List<TreeOptimizer> optimizers = new ArrayList<TreeOptimizer>();
|
||||
|
||||
static {
|
||||
|
|
@ -113,8 +110,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
super(player);
|
||||
this.maxDepth = player.maxDepth;
|
||||
this.currentScore = player.currentScore;
|
||||
if (player.combat != null)
|
||||
if (player.combat != null) {
|
||||
this.combat = player.combat.copy();
|
||||
}
|
||||
this.actions.addAll(player.actions);
|
||||
this.targets.addAll(player.targets);
|
||||
this.choices.addAll(player.choices);
|
||||
|
|
@ -213,9 +211,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
|
||||
protected void act(Game game) {
|
||||
if (actions == null || actions.size() == 0)
|
||||
if (actions == null || actions.size() == 0) {
|
||||
pass();
|
||||
else {
|
||||
} else {
|
||||
boolean usedStack = false;
|
||||
while (actions.peek() != null) {
|
||||
Ability ability = actions.poll();
|
||||
|
|
@ -232,8 +230,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
}
|
||||
this.activateAbility((ActivatedAbility) ability, game);
|
||||
if (ability.isUsesStack())
|
||||
if (ability.isUsesStack()) {
|
||||
usedStack = true;
|
||||
}
|
||||
if (!suggested.isEmpty() && !(ability instanceof PassAbility)) {
|
||||
Iterator<String> it = suggested.iterator();
|
||||
while (it.hasNext()) {
|
||||
|
|
@ -247,10 +246,11 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
}
|
||||
}
|
||||
if (usedStack)
|
||||
if (usedStack) {
|
||||
pass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void calculateActions(Game game) {
|
||||
if (!getNextAction(game)) {
|
||||
|
|
@ -309,8 +309,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
actions = new LinkedList<Ability>(root.abilities);
|
||||
combat = root.combat;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -345,8 +344,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
logger.debug("lose - break");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (val > alpha) {
|
||||
alpha = val;
|
||||
bestChild = child;
|
||||
|
|
@ -363,13 +361,13 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
}
|
||||
node.children.clear();
|
||||
if (bestChild != null)
|
||||
if (bestChild != null) {
|
||||
node.children.add(bestChild);
|
||||
}
|
||||
if (!currentPlayerId.equals(playerId)) {
|
||||
//logger.info("returning minimax beta: " + beta);
|
||||
return beta;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//logger.info("returning minimax alpha: " + alpha);
|
||||
return alpha;
|
||||
}
|
||||
|
|
@ -416,8 +414,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
protected Integer addActionsTimed() {
|
||||
FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() throws Exception
|
||||
{
|
||||
public Integer call() throws Exception {
|
||||
return addActions(root, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
}
|
||||
});
|
||||
|
|
@ -458,19 +455,16 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
UUID currentPlayerId = node.getGame().getPlayerList().get();
|
||||
//logger.info("reached - " + val + ", playerId=" + playerId + ", node.pid="+currentPlayerId);
|
||||
return val;
|
||||
}
|
||||
else if (node.getChildren().size() > 0) {
|
||||
} else if (node.getChildren().size() > 0) {
|
||||
logger.debug("simulating -- somthing added children:" + node.getChildren().size());
|
||||
val = minimaxAB(node, depth - 1, alpha, beta);
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logger.debug("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + (node.getPlayerId().equals(playerId) ? "yes" : "no"));
|
||||
if (allPassed(game)) {
|
||||
if (!game.getStack().isEmpty()) {
|
||||
resolve(node, depth, game);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
game.getPlayers().resetPassed();
|
||||
playNext(game, game.getActivePlayerId(), node);
|
||||
}
|
||||
|
|
@ -482,8 +476,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
//declared attackers or blockers or triggered abilities
|
||||
logger.debug("simulating -- attack/block/trigger added children:" + node.getChildren().size());
|
||||
val = minimaxAB(node, depth - 1, alpha, beta);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val = simulatePriority(node, game, depth, alpha, beta);
|
||||
}
|
||||
}
|
||||
|
|
@ -515,8 +508,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
Game sim = game.copy();
|
||||
if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) {
|
||||
sim.applyEffects();
|
||||
if (checkForRepeatedAction(sim, node, action, currentPlayer.getId()))
|
||||
if (checkForRepeatedAction(sim, node, action, currentPlayer.getId())) {
|
||||
continue;
|
||||
}
|
||||
if (!sim.isGameOver() && action.isUsesStack()) {
|
||||
// only pass if the last action uses the stack
|
||||
sim.getPlayer(currentPlayer.getId()).pass();
|
||||
|
|
@ -543,8 +537,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
logger.debug("lose - break");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (val > alpha) {
|
||||
alpha = val;
|
||||
bestNode = newNode;
|
||||
|
|
@ -594,8 +587,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}*/
|
||||
//logger.info("returning priority beta: " + beta);
|
||||
return beta;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/*if (alpha == Integer.MIN_VALUE) {
|
||||
int val = GameStateEvaluator2.evaluate(playerId, game);
|
||||
logger.info("returning priority beta: " + val);
|
||||
|
|
@ -645,16 +637,18 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
|
||||
protected boolean allPassed(Game game) {
|
||||
for (Player player : game.getPlayers().values()) {
|
||||
if (!player.isPassed() && !player.hasLost() && !player.hasLeft())
|
||||
if (!player.isPassed() && !player.hasLost() && !player.hasLeft()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean choose(Outcome outcome, Choice choice, Game game) {
|
||||
if (choices.isEmpty())
|
||||
if (choices.isEmpty()) {
|
||||
return super.choose(outcome, choice, game);
|
||||
}
|
||||
if (!choice.isChosen()) {
|
||||
for (String achoice : choices) {
|
||||
choice.setChoice(achoice);
|
||||
|
|
@ -670,8 +664,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
|
||||
@Override
|
||||
public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) {
|
||||
if (targets.isEmpty())
|
||||
if (targets.isEmpty()) {
|
||||
return super.chooseTarget(outcome, cards, target, source, game);
|
||||
}
|
||||
if (!target.doneChosing()) {
|
||||
for (UUID targetId : targets) {
|
||||
target.addTarget(targetId, source, game);
|
||||
|
|
@ -687,8 +682,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
|
||||
@Override
|
||||
public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) {
|
||||
if (targets.isEmpty())
|
||||
if (targets.isEmpty()) {
|
||||
return super.choose(outcome, cards, target, game);
|
||||
}
|
||||
if (!target.doneChosing()) {
|
||||
for (UUID targetId : targets) {
|
||||
target.add(targetId, game);
|
||||
|
|
@ -721,8 +717,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
boolean skip = false;
|
||||
while (true) {
|
||||
Phase currentPhase = game.getPhase();
|
||||
if (!skip)
|
||||
if (!skip) {
|
||||
currentPhase.getStep().endStep(game, activePlayerId);
|
||||
}
|
||||
game.applyEffects();
|
||||
switch (currentPhase.getStep().getType()) {
|
||||
case UNTAP:
|
||||
|
|
@ -781,10 +778,10 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
} else {
|
||||
game.getStep().beginStep(game, activePlayerId);
|
||||
}
|
||||
if (game.getStep().getHasPriority())
|
||||
if (game.getStep().getHasPriority()) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -898,10 +895,11 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
|
||||
/**
|
||||
* Choose attackers based on static information.
|
||||
* That means that AI won't look to the future as it was before, but just choose attackers based on current state
|
||||
* of the game. This is worse, but at least it is easier to implement and won't lead to the case when AI doesn't
|
||||
* do anything - neither attack nor block.
|
||||
* Choose attackers based on static information. That means that AI won't
|
||||
* look to the future as it was before, but just choose attackers based on
|
||||
* current state of the game. This is worse, but at least it is easier to
|
||||
* implement and won't lead to the case when AI doesn't do anything -
|
||||
* neither attack nor block.
|
||||
*
|
||||
* @param game
|
||||
* @param activePlayerId
|
||||
|
|
@ -919,8 +917,22 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
return;
|
||||
}
|
||||
|
||||
for (Permanent attacker : attackersList) {
|
||||
System.out.println("Number of potential attackers " + attackersList.size());
|
||||
System.out.println("Potential attacker is " + attacker.getName());
|
||||
}
|
||||
|
||||
if (attackersList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Permanent> possibleBlockers = defender.getAvailableBlockers(game);
|
||||
|
||||
for (Permanent blocker : possibleBlockers) {
|
||||
System.out.println("Number of blockers " + possibleBlockers.size());
|
||||
System.out.println("Blocker is " + blocker.getName());
|
||||
}
|
||||
|
||||
List<Permanent> killers = CombatUtil.canKillOpponent(game, attackersList, possibleBlockers, defender);
|
||||
if (!killers.isEmpty()) {
|
||||
for (Permanent attacker : killers) {
|
||||
|
|
@ -929,14 +941,14 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
return;
|
||||
}
|
||||
|
||||
CombatUtil.handleExalted();
|
||||
//CombatUtil.handleExalted();
|
||||
|
||||
//TODO: refactor -- extract to method
|
||||
List<Permanent> counterAttackList = new ArrayList<Permanent>();
|
||||
int counterAttackDamage = 0;
|
||||
int defenderForces = 0;
|
||||
int defenderForcesForBlock = 0;
|
||||
|
||||
//List<Permanent> counterAttackList = new ArrayList<Permanent>();
|
||||
//int counterAttackDamage = 0;
|
||||
//int defenderForces = 0;
|
||||
//int defenderForcesForBlock = 0;
|
||||
/*
|
||||
FilterCreatureForCombat filter = new FilterCreatureForCombat();
|
||||
for (Permanent possibleAttacker : game.getBattlefield().getAllActivePermanents(filter, defender.getId(), game)) {
|
||||
//TODO: it can be improved with next turn emulation
|
||||
|
|
@ -1062,15 +1074,43 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
finalAttackers.add(attacker);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
System.out.println("AI final attackers size: " + attackersList.size());
|
||||
// The AI will now attack more sanely. Simple, but good enough for now.
|
||||
// The sim minmax does not work at the moment.
|
||||
|
||||
for (Permanent attacker : finalAttackers) {
|
||||
boolean safeToAttack;
|
||||
CombatEvaluator eval = new CombatEvaluator();
|
||||
|
||||
for (Permanent attacker : attackersList) {
|
||||
safeToAttack = true;
|
||||
int attackerValue = eval.evaluate(attacker, game);
|
||||
for (Permanent blocker : possibleBlockers) {
|
||||
int blockerValue = eval.evaluate(blocker, game);
|
||||
if (attacker.getPower().getValue() <= blocker.getToughness().getValue()
|
||||
&& attacker.getToughness().getValue() <= blocker.getPower().getValue()) {
|
||||
safeToAttack = false;
|
||||
}
|
||||
|
||||
if (attacker.getToughness().getValue() == blocker.getPower().getValue()
|
||||
&& attacker.getPower().getValue() == blocker.getToughness().getValue()) {
|
||||
if (attackerValue < blockerValue
|
||||
|| blocker.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId())
|
||||
|| blocker.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId())) {
|
||||
safeToAttack = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())) {
|
||||
safeToAttack = true;
|
||||
}
|
||||
if (safeToAttack) {
|
||||
attackingPlayer.declareAttacker(attacker.getId(), defenderId, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
private boolean shouldAttack(Game game, UUID attackingPlayerId, UUID defenderId, Permanent attacker, List<Permanent> blockers, int aggressionRate) {
|
||||
boolean canBeKilledByOne = false;
|
||||
boolean canKillAll = true;
|
||||
|
|
@ -1080,17 +1120,22 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
boolean canBeBlocked = false;
|
||||
int numberOfPossibleBlockers = 0;
|
||||
|
||||
int life = game.getPlayer(defenderId).getLife();
|
||||
int poison = game.getPlayer(defenderId).getCounters().getCount(CounterType.POISON);
|
||||
//int life = game.getPlayer(defenderId).getLife();
|
||||
//int poison = game.getPlayer(defenderId).getCounters().getCount(CounterType.POISON);
|
||||
|
||||
if (!isEffectiveAttacker(game, attackingPlayerId, defenderId, attacker, life, poison)) {
|
||||
System.out.println("Ahh, this is why it is not attacking");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Permanent defender : blockers) {
|
||||
System.out.println("The blocker is " + defender.getName());
|
||||
if (defender.canBlock(attacker.getId(), game)) {
|
||||
System.out.println("The blocker can block the attacker" + defender.getName() + attacker.getName());
|
||||
numberOfPossibleBlockers += 1;
|
||||
System.out.println("The number of possible blockers is " + numberOfPossibleBlockers);
|
||||
SurviveInfo info = CombatUtil.willItSurvive(game, attackingPlayerId, defenderId, attacker, defender);
|
||||
System.out.println("Did the attacker die? " + info.isAttackerDied());
|
||||
if (info.isAttackerDied()) {
|
||||
boolean canBeReallyKilled = true;
|
||||
for (Ability ability : attacker.getAbilities()) {
|
||||
|
|
@ -1129,6 +1174,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
canBeBlocked = true;
|
||||
}
|
||||
|
||||
// This is how I know this does quite work. Something is wrong with the sim part.
|
||||
System.out.println("canKillAll, canKillAllDangerous, canbeKilledByOne, canBeBlocked " + canKillAll + canKillAllDangerous + canBeKilledByOne + canBeBlocked);
|
||||
|
||||
switch (aggressionRate) {
|
||||
case 4:
|
||||
if (canKillAll || (canKillAllDangerous && !canBeKilledByOne) || !canBeBlocked) {
|
||||
|
|
@ -1185,7 +1233,6 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
private int getAggressionRate(double oppScore, double ourScore, int outNumber, double score, boolean doAttack, double turnsUntilDeathByUnblockable, boolean doUnblockableAttack, int aggressionRate) {
|
||||
if (score > 0 && doAttack) {
|
||||
aggressionRate = 5;
|
||||
|
|
@ -1203,7 +1250,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
return aggressionRate;
|
||||
}
|
||||
|
||||
*/
|
||||
private void declareAttackers(Game game, UUID activePlayerId, SimulationNode2 node) {
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE, null, null, activePlayerId));
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, activePlayerId, activePlayerId))) {
|
||||
|
|
@ -1246,7 +1293,8 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
@Override
|
||||
public void selectBlockers(Game game, UUID defendingPlayerId) {
|
||||
logger.debug("selectBlockers");
|
||||
if (combat != null && combat.getGroups().size() > 0) {
|
||||
declareBlockers(game, playerId);
|
||||
/*if (combat != null && combat.getGroups().size() > 0) {
|
||||
List<CombatGroup> groups = game.getCombat().getGroups();
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (i < combat.getGroups().size()) {
|
||||
|
|
@ -1257,6 +1305,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1279,8 +1328,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
|||
}
|
||||
|
||||
private boolean checkForRepeatedAction(Game sim, SimulationNode2 node, Ability action, UUID playerId) {
|
||||
if (action instanceof PassAbility)
|
||||
if (action instanceof PassAbility) {
|
||||
return false;
|
||||
}
|
||||
int newVal = GameStateEvaluator2.evaluate(playerId, sim);
|
||||
SimulationNode2 test = node.getParent();
|
||||
while (test != null) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue