mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
AI: improved stability:
- fixed game errors with source related filters (related to #13713); - fixed game freeze in hand's cards selection (related to #13290); - fixed game freeze in target amount selection with X=0 (related to #13290);
This commit is contained in:
parent
e8342e1f11
commit
6ad2cdaa78
5 changed files with 38 additions and 55 deletions
|
|
@ -692,7 +692,7 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
|| target.getOriginalTarget() instanceof TargetCardInHand) {
|
||||
isAddedSomething = false;
|
||||
if (outcome.isGood()) {
|
||||
// good
|
||||
// good - choose max possible
|
||||
Cards cards = new CardsImpl(possibleTargets);
|
||||
List<Card> cardsInHand = new ArrayList<>(cards.getCards(game));
|
||||
while (!target.isChosen(game)
|
||||
|
|
@ -703,36 +703,42 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.contains(card.getId())) {
|
||||
target.addTarget(card.getId(), source, game);
|
||||
isAddedSomething = true;
|
||||
cardsInHand.remove(card);
|
||||
if (target.isChoiceCompleted(game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cardsInHand.remove(card);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// bad
|
||||
// bad - choose the lowest possible
|
||||
findPlayables(game);
|
||||
for (Card card : unplayable.values()) {
|
||||
if (target.isChosen(game)) {
|
||||
return isAddedSomething;
|
||||
}
|
||||
if (possibleTargets.contains(card.getId())
|
||||
&& target.canTarget(abilityControllerId, card.getId(), source, game)
|
||||
&& !target.contains(card.getId())) {
|
||||
target.addTarget(card.getId(), source, game);
|
||||
isAddedSomething = true;
|
||||
if (target.isChoiceCompleted(game)) {
|
||||
return true;
|
||||
if (target.isChosen(game)) {
|
||||
return isAddedSomething;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hand.isEmpty()) {
|
||||
for (Card card : hand.getCards(game)) {
|
||||
if (target.isChosen(game)) {
|
||||
return isAddedSomething;
|
||||
}
|
||||
if (possibleTargets.contains(card.getId())
|
||||
&& target.canTarget(abilityControllerId, card.getId(), source, game)
|
||||
&& !target.contains(card.getId())) {
|
||||
target.addTarget(card.getId(), source, game);
|
||||
isAddedSomething = true;
|
||||
if (target.isChoiceCompleted(game)) {
|
||||
return true;
|
||||
if (target.isChosen(game)) {
|
||||
return isAddedSomething;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -854,39 +860,6 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) {
|
||||
List<Permanent> targets;
|
||||
TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget());
|
||||
if (outcome.isGood()) {
|
||||
targets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
|
||||
} else {
|
||||
targets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
|
||||
}
|
||||
|
||||
if (targets.isEmpty()) {
|
||||
if (outcome.isGood()) {
|
||||
if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) {
|
||||
return tryAddTarget(target, getId(), source, game);
|
||||
}
|
||||
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) {
|
||||
return tryAddTarget(target, randomOpponentId, source, game);
|
||||
}
|
||||
}
|
||||
|
||||
if (targets.isEmpty() && target.isRequired(source)) {
|
||||
targets = game.getBattlefield().getActivePermanents(((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), playerId, game);
|
||||
}
|
||||
for (Permanent permanent : targets) {
|
||||
List<UUID> alreadyTargeted = target.getTargets();
|
||||
if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) {
|
||||
if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) {
|
||||
return tryAddTarget(target, permanent.getId(), source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target.getOriginalTarget() instanceof TargetPlayerOrPlaneswalker
|
||||
|| target.getOriginalTarget() instanceof TargetOpponentOrPlaneswalker) {
|
||||
List<Permanent> targets;
|
||||
TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget());
|
||||
|
||||
// TODO: in multiplayer game there many opponents - if random opponents don't have targets then AI must use next opponent, but it skips
|
||||
// (e.g. you randomOpponentId must be replaced by List<UUID> randomOpponents)
|
||||
|
|
@ -1239,6 +1212,7 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
throw new IllegalStateException("Target wasn't handled in computer's chooseTarget method: " + target.getClass().getCanonicalName());
|
||||
} //end of chooseTarget method
|
||||
|
||||
@Deprecated // TODO: replace by source only version
|
||||
protected Card selectCard(UUID abilityControllerId, List<Card> cards, Outcome outcome, Target target, Game game) {
|
||||
return selectCardInner(abilityControllerId, cards, outcome, target, null, game);
|
||||
}
|
||||
|
|
@ -1279,6 +1253,10 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString());
|
||||
}
|
||||
|
||||
if (target.getAmountRemaining() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UUID sourceId = source != null ? source.getSourceId() : null;
|
||||
|
||||
// sometimes a target selection can be made from a player that does not control the ability
|
||||
|
|
@ -2576,6 +2554,7 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
tournament.submitDeck(playerId, deck);
|
||||
}
|
||||
|
||||
@Deprecated // TODO: replace by source only version
|
||||
public Card selectBestCard(List<Card> cards, List<ColoredManaSymbol> chosenColors) {
|
||||
return selectBestCardInner(cards, chosenColors, null, null, null);
|
||||
}
|
||||
|
|
@ -2623,14 +2602,6 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
return bestCard;
|
||||
}
|
||||
|
||||
public Card selectWorstCard(List<Card> cards, List<ColoredManaSymbol> chosenColors) {
|
||||
return selectWorstCardInner(cards, chosenColors, null, null, null);
|
||||
}
|
||||
|
||||
public Card selectWorstCardTarget(List<Card> cards, List<ColoredManaSymbol> chosenColors, Target target, Ability targetingSource, Game game) {
|
||||
return selectWorstCardInner(cards, chosenColors, target, targetingSource, game);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetingSource null on non-target choice like choose and source on targeting choice like chooseTarget
|
||||
*/
|
||||
|
|
@ -3097,6 +3068,7 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
return before != after;
|
||||
}
|
||||
|
||||
@Deprecated // TODO: replace by source only version
|
||||
private boolean selectPlayer(Outcome outcome, Target target, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) {
|
||||
return selectPlayerInner(outcome, target, null, abilityControllerId, randomOpponentId, game, required);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,6 +288,10 @@ public final class SimulatedPlayerMCTS extends MCTSPlayer {
|
|||
|
||||
@Override
|
||||
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) {
|
||||
if (target.getAmountRemaining() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<UUID> possibleTargets = target.possibleTargets(playerId, source, game);
|
||||
if (possibleTargets.isEmpty()) {
|
||||
return !target.isRequired(source);
|
||||
|
|
|
|||
|
|
@ -1042,6 +1042,10 @@ public class HumanPlayer extends PlayerImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (target.getAmountRemaining() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2328,7 +2328,7 @@ public class TestPlayer implements Player {
|
|||
continue;
|
||||
}
|
||||
if (hasObjectTargetNameOrAlias(permanent, targetName)) {
|
||||
if (target.isNotTarget() || target.canTarget(abilityControllerId, permanent.getId(), source, game)) {
|
||||
if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) {
|
||||
if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) {
|
||||
target.add(permanent.getId(), game);
|
||||
isAddedSomething = true;
|
||||
|
|
@ -2336,7 +2336,7 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
}
|
||||
} else if ((permanent.getName() + '-' + permanent.getExpansionSetCode()).equals(targetName)) { // TODO: remove search by exp code?
|
||||
if (target.isNotTarget() || target.canTarget(abilityControllerId, permanent.getId(), source, game)) {
|
||||
if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) {
|
||||
if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) {
|
||||
target.add(permanent.getId(), game);
|
||||
isAddedSomething = true;
|
||||
|
|
@ -2371,7 +2371,7 @@ public class TestPlayer implements Player {
|
|||
isAddedSomething = false;
|
||||
for (Player player : game.getPlayers().values()) {
|
||||
if (player.getName().equals(choiceRecord)) {
|
||||
if (target.canTarget(abilityControllerId, player.getId(), null, game) && !target.contains(player.getId())) {
|
||||
if (target.canTarget(abilityControllerId, player.getId(), source, game) && !target.contains(player.getId())) {
|
||||
target.add(player.getId(), game);
|
||||
isAddedSomething = true;
|
||||
}
|
||||
|
|
@ -2538,7 +2538,8 @@ public class TestPlayer implements Player {
|
|||
String playerName = targetDefinition.substring(targetDefinition.indexOf("targetPlayer=") + 13);
|
||||
for (Player player : game.getPlayers().values()) {
|
||||
if (player.getName().equals(playerName)
|
||||
&& target.canTarget(abilityControllerId, player.getId(), source, game)) {
|
||||
&& target.canTarget(abilityControllerId, player.getId(), source, game)
|
||||
&& !target.contains(player.getId())) {
|
||||
target.addTarget(player.getId(), source, game);
|
||||
targets.remove(targetDefinition);
|
||||
return true;
|
||||
|
|
@ -2887,7 +2888,7 @@ public class TestPlayer implements Player {
|
|||
|
||||
@Override
|
||||
public boolean chooseUse(Outcome outcome, String message, String secondMessage, String trueText, String falseText, Ability source, Game game) {
|
||||
if (message.equals("Scry 1?")) {
|
||||
if (message != null && message.equals("Scry 1?")) {
|
||||
return false;
|
||||
}
|
||||
assertAliasSupportInChoices(false);
|
||||
|
|
@ -4326,7 +4327,9 @@ public class TestPlayer implements Player {
|
|||
// chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount)
|
||||
// if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx)
|
||||
|
||||
Assert.assertNotEquals("chooseTargetAmount needs non zero amount remaining", 0, target.getAmountRemaining());
|
||||
if (target.getAmountRemaining() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assertAliasSupportInTargets(true);
|
||||
if (!targets.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ class OublietteTarget extends TargetSacrifice {
|
|||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game));
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game));
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue