From c58a1495ac61fe4965ae168fae9f40a2ba6a02f4 Mon Sep 17 00:00:00 2001 From: excessum Date: Mon, 25 Jul 2016 14:00:46 +0000 Subject: [PATCH] - Re-factored CharmAi further --- .../main/java/forge/ai/ability/CharmAi.java | 196 +++++++++--------- 1 file changed, 101 insertions(+), 95 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java index f037ce165a8..e278568916c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java @@ -28,13 +28,24 @@ public class CharmAi extends SpellAbilityAi { // Reset the chosen list otherwise it will be locked in forever by earlier calls sa.setChosenList(null); List choices = CharmEffect.makePossibleOptions(sa); - List chosenList = min > 1 ? chooseMultipleOptionsAi(choices, ai, min) - : chooseOptionsAi(choices, sa, ai, timingRight, num, min, sa.hasParam("CanRepeatModes"), false); + List chosenList; + + if (!ai.equals(sa.getActivatingPlayer())) { + // This branch is for "An Opponent chooses" Charm spells from Alliances + // Current just choose the first available spell, which seem generally less disastrous for the AI. + //return choices.subList(0, 1); + chosenList = choices.subList(1, choices.size()); + } else if ("Triskaidekaphobia".equals(sa.getHostCard().getName())) { + chosenList = chooseTriskaidekaphobia(choices, ai); + } else { + chosenList = min > 1 ? chooseMultipleOptionsAi(choices, ai, min) + : chooseOptionsAi(choices, ai, timingRight, num, min, sa.hasParam("CanRepeatModes"), false); + } if (chosenList.isEmpty()) { if (timingRight) { // Set minimum choices for triggers where chooseMultipleOptionsAi() returns null - chosenList = chooseOptionsAi(choices, sa, ai, true, num, min, sa.hasParam("CanRepeatModes"), false); + chosenList = chooseOptionsAi(choices, ai, true, num, min, sa.hasParam("CanRepeatModes"), false); } else { return false; } @@ -45,99 +56,9 @@ public class CharmAi extends SpellAbilityAi { return r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); } - private List chooseOptionsAi(List choices, SpellAbility sa, final Player ai, - boolean playNow, int num, int min, boolean allowRepeat, boolean opponentChoser) { + private List chooseOptionsAi(List choices, final Player ai, boolean playNow, int num, + int min, boolean allowRepeat, boolean opponentChoser) { List chosenList = new ArrayList(); - - if (opponentChoser) { - // This branch is for "An Opponent chooses" Charm spells from Alliances - // Current just choose the first available spell, which seem generally less disastrous for the AI. - //return choices.subList(0, 1); - return choices.subList(1, choices.size()); - } else if ("Triskaidekaphobia".equals(sa.getHostCard().getName())) { - AbilitySub gain = choices.get(0); - AbilitySub lose = choices.get(1); - FCollection opponents = ai.getOpponents(); - - boolean oppTainted = false; - boolean allyTainted = ai.isCardInPlay("Tainted Remedy"); - final int aiLife = ai.getLife(); - - //Check if Opponent controls Tainted Remedy - for (Player p : opponents) { - if (p.isCardInPlay("Tainted Remedy")) { - oppTainted = true; - break; - } - } - // if ai or ally of ai does control Tainted Remedy, prefer gain life instead of lose - if (!allyTainted) { - for (Player p : ai.getAllies()) { - if (p.isCardInPlay("Tainted Remedy")) { - allyTainted = true; - break; - } - } - } - - if (!ai.canLoseLife() || ai.cantLose()) { - // ai cant lose life, or cant lose the game, don't think about others - chosenList.add(allyTainted ? gain : lose); - } else if (oppTainted || ai.getGame().isCardInPlay("Rain of Gore")) { - // Rain of Gore does negate lifegain, so don't benefit the others - // same for if a oppoent does control Tainted Remedy - // but if ai cant gain life, the effects are negated - chosenList.add(ai.canGainLife() ? lose : gain); - } else if (ai.getGame().isCardInPlay("Sulfuric Vortex")) { - // no life gain, but extra life loss. - if (aiLife >= 17) - chosenList.add(lose); - // try to prevent to get to 13 with extra lose - else if (aiLife < 13 || ((aiLife - 13) % 2) == 1) { - chosenList.add(gain); - } else { - chosenList.add(lose); - } - } else if (ai.canGainLife() && aiLife <= 5) { - // critical Life try to gain more - chosenList.add(gain); - } else if(!ai.canGainLife() && aiLife == 14 ) { - // ai cant gain life, but try to avoid falling to 13 - // but if a oppoent does control Tainted Remedy its irrelevant - chosenList.add(oppTainted ? lose : gain); - } else if (allyTainted) { - // Tainted Remedy negation logic, try gain instead of lose - // because negation does turn it into lose for opponents - boolean oppCritical = false; - // an oppoent is Critical = 14, and can't gain life, try to lose life instead - // but only if ai doesn't kill itself with that. - if (aiLife != 14) { - for (Player p : opponents) { - if (p.getLife() == 14 && !p.canGainLife() && p.canLoseLife()) { - oppCritical = true; - break; - } - } - } - chosenList.add(aiLife == 12 || oppCritical ? lose : gain); - } else { - // normal logic, try to gain life if its critical - boolean oppCritical = false; - // an oppoent is Critical = 12, and can gain life, try to gain life instead - // but only if ai doesn't kill itself with that. - if (aiLife != 12) { - for (Player p : opponents) { - if (p.getLife() == 12 && p.canGainLife()) { - oppCritical = true; - break; - } - } - } - chosenList.add(aiLife == 14 || aiLife <= 10 || oppCritical ? gain : lose); - } - return chosenList; - } - // Make choice(s) AiController aic = ((PlayerControllerAi) ai.getController()).getAi(); for (int i = 0; i < num; i++) { @@ -180,6 +101,91 @@ public class CharmAi extends SpellAbilityAi { return chosenList; } + private List chooseTriskaidekaphobia(List choices, final Player ai) { + List chosenList = new ArrayList(); + AbilitySub gain = choices.get(0); + AbilitySub lose = choices.get(1); + FCollection opponents = ai.getOpponents(); + + boolean oppTainted = false; + boolean allyTainted = ai.isCardInPlay("Tainted Remedy"); + final int aiLife = ai.getLife(); + + //Check if Opponent controls Tainted Remedy + for (Player p : opponents) { + if (p.isCardInPlay("Tainted Remedy")) { + oppTainted = true; + break; + } + } + // if ai or ally of ai does control Tainted Remedy, prefer gain life instead of lose + if (!allyTainted) { + for (Player p : ai.getAllies()) { + if (p.isCardInPlay("Tainted Remedy")) { + allyTainted = true; + break; + } + } + } + + if (!ai.canLoseLife() || ai.cantLose()) { + // ai cant lose life, or cant lose the game, don't think about others + chosenList.add(allyTainted ? gain : lose); + } else if (oppTainted || ai.getGame().isCardInPlay("Rain of Gore")) { + // Rain of Gore does negate lifegain, so don't benefit the others + // same for if a oppoent does control Tainted Remedy + // but if ai cant gain life, the effects are negated + chosenList.add(ai.canGainLife() ? lose : gain); + } else if (ai.getGame().isCardInPlay("Sulfuric Vortex")) { + // no life gain, but extra life loss. + if (aiLife >= 17) + chosenList.add(lose); + // try to prevent to get to 13 with extra lose + else if (aiLife < 13 || ((aiLife - 13) % 2) == 1) { + chosenList.add(gain); + } else { + chosenList.add(lose); + } + } else if (ai.canGainLife() && aiLife <= 5) { + // critical Life try to gain more + chosenList.add(gain); + } else if(!ai.canGainLife() && aiLife == 14 ) { + // ai cant gain life, but try to avoid falling to 13 + // but if a oppoent does control Tainted Remedy its irrelevant + chosenList.add(oppTainted ? lose : gain); + } else if (allyTainted) { + // Tainted Remedy negation logic, try gain instead of lose + // because negation does turn it into lose for opponents + boolean oppCritical = false; + // an oppoent is Critical = 14, and can't gain life, try to lose life instead + // but only if ai doesn't kill itself with that. + if (aiLife != 14) { + for (Player p : opponents) { + if (p.getLife() == 14 && !p.canGainLife() && p.canLoseLife()) { + oppCritical = true; + break; + } + } + } + chosenList.add(aiLife == 12 || oppCritical ? lose : gain); + } else { + // normal logic, try to gain life if its critical + boolean oppCritical = false; + // an oppoent is Critical = 12, and can gain life, try to gain life instead + // but only if ai doesn't kill itself with that. + if (aiLife != 12) { + for (Player p : opponents) { + if (p.getLife() == 12 && p.canGainLife()) { + oppCritical = true; + break; + } + } + } + chosenList.add(aiLife == 14 || aiLife <= 10 || oppCritical ? gain : lose); + } + return chosenList; + } + // Choice selection for charms that require multiple choices (eg. Cryptic Command, DTK commands) private List chooseMultipleOptionsAi(List choices, final Player ai, int min) { AbilitySub goodChoice = null;