AI Development Questions
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
Re: AI Development Questions
by Sloth » 07 Apr 2014, 16:02
Concerning r25363:
- Code: Select all
// will the creature attack (only relevant for sorcery speed)?
if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
&& game.getPhaseHandler().isPlayerTurn(ai)
&& ComputerUtilCard.doesCreatureAttackAI(ai, c)) {
return true;
}
- Code: Select all
//creature is attacking and would be destroyed itself
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& combat.isAttacking(c) && combat.isBlocked(c) ) {
List<Card> blockers = combat.getBlockers(c);
if (!blockers.isEmpty() && ComputerUtilCombat.blockerWouldBeDestroyed(ai, blockers.get(0), combat)) {
List<Card> threats = combat.getBlockers(c);
ComputerUtilCard.sortByEvaluateCreature(threats);
return (true && (ProtectAi.toProtectFrom(threats.get(0), sa) != null));
}
}
- Code: Select all
//make unblockable
if (ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1) {
AiAttackController aiAtk = new AiAttackController(ai, c);
String s = aiAtk.toProtectAttacker(sa);
if (s==null) {
return false;
} else {
Combat combat = ai.getGame().getCombat();
int dmg = ComputerUtilCombat.damageIfUnblocked(c, ai.getOpponent(), combat);
float ratio = 1.0f * dmg / ai.getOpponent().getLife();
Random r = MyRandom.getRandom();
return r.nextFloat() < ratio;
}
}
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: AI Development Questions
by excessum » 08 Apr 2014, 00:28
One of my long-term goals is to write a better AI system but it is probably going to be way off in the future. The current AI is entirely bottom-up which evaluates the state and possible actions at each priority step. I was considering to start with a simple top-down "plan" where the AI (or deck builder) decides its strategy based on the given deck (suicide aggro, burn spam, draw-go, etc.) and prioritises states and actions that agree with this.
For r25363:
Is there a simpler way to check for colors present rather than the clunky "switch" and chained "if" statesments that I am using? I was tempted to write a method for that in game.Card but I think there might be something that does that already somewhere.
Finally, extending the "grant unblockable" logic to ProtectAll is going to be challenging because voiding a subset of the blockers is usually enough. The problem would be to calculate which subset to avoid (most members or dangerous?) and the expected damage that can be done.
For r25363:
I forgot to remove this after I added the "grant unblockable" code since it does not affect the original patch I posted earlier.Sloth wrote:This part should probably be removed. This will cause a lot of spells to be wasted.
I copied this from the original code and yes, I should change it to attackerWouldBeDestroyed.Sloth wrote:The logic here looks messed up. ComputerUtilCombat.blockerWouldBeDestroyed(ai, blockers.get(0), combat) should be ComputerUtilCombat.attackerWouldBeDestroyed(ai, c, combat), no?
Missed out a getPossibleBlockers() within toProtectAttacker() which will now need the attacking Card as an argument.Sloth wrote:There should be a check here whether the opponent has any possible blockers, otherwise the AI will waste a spell on an unblockable creature.
Is there a simpler way to check for colors present rather than the clunky "switch" and chained "if" statesments that I am using? I was tempted to write a method for that in game.Card but I think there might be something that does that already somewhere.
Finally, extending the "grant unblockable" logic to ProtectAll is going to be challenging because voiding a subset of the blockers is usually enough. The problem would be to calculate which subset to avoid (most members or dangerous?) and the expected damage that can be done.
Re: AI Development Questions
by Sloth » 08 Apr 2014, 07:46
I would start very conservatively here. The AI should use "grant unblockable" mode very rarely, because the AI has no idea of tempo.excessum wrote:Finally, extending the "grant unblockable" logic to ProtectAll is going to be challenging because voiding a subset of the blockers is usually enough. The problem would be to calculate which subset to avoid (most members or dangerous?) and the expected damage that can be done.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: AI Development Questions
by excessum » 08 Apr 2014, 12:36
Hopefully my latest commit fixed the issues described earlier.
After further thinking, it seems to be impractical to mess with ProtectAllAI since its main use is as a finisher with the mass unblockable buff and the algorithm to calculate the potential value of casting it (ie. expected damage through blockers) is going to be a mess. My forays into the mana abilities is also a disaster since the tapping of mana sources that can also attack is heavily dependent on hand/board knowledge which the AI cannot evaluate properly anyway.
I have cleared my to-do list and I'm open to suggestions (simple ones I hope). Are there any plans to fix the issue with the Leave the Battlefield triggers (Blood Artist, Xathrid Necromancer, etc.)?
After further thinking, it seems to be impractical to mess with ProtectAllAI since its main use is as a finisher with the mass unblockable buff and the algorithm to calculate the potential value of casting it (ie. expected damage through blockers) is going to be a mess. My forays into the mana abilities is also a disaster since the tapping of mana sources that can also attack is heavily dependent on hand/board knowledge which the AI cannot evaluate properly anyway.
I have cleared my to-do list and I'm open to suggestions (simple ones I hope). Are there any plans to fix the issue with the Leave the Battlefield triggers (Blood Artist, Xathrid Necromancer, etc.)?
Re: AI Development Questions
by swordshine » 10 Apr 2014, 01:15
The leave-the-battlefield triggers are quite difficult to fix, probably need to refractor the related code and introduce more accurate timestamps.excessum wrote:I have cleared my to-do list and I'm open to suggestions (simple ones I hope). Are there any plans to fix the issue with the Leave the Battlefield triggers (Blood Artist, Xathrid Necromancer, etc.)?
- swordshine
- Posts: 682
- Joined: 11 Jul 2010, 02:37
- Has thanked: 116 times
- Been thanked: 87 times
Re: AI Development Questions
by excessum » 11 Apr 2014, 00:44
I spent some time looking at the trigger/stack/ChangeZoneEffect code and I can confidently say that I have absolutely no idea what is going on.swordshine wrote:The leave-the-battlefield triggers are quite difficult to fix, probably need to refractor the related code and introduce more accurate timestamps.
Moving on, I am thinking of developing a less bottom-up approach in the AI's choice of spells to play. This is most evident in Limited where the lack of quality removal and the larger number of "pump" spells played means that they are more likely to turn the game. The AI happily spends Excoriate or Divine Verdict on random filler creatures even if it can or already has a better creature in play, and tends to waste buffs like Mortal's Ardor or Mortal's Resolve for the measly +1 against an empty board instead of saving it for a blow-out in combat.
My proposal is to create a new class for the AI player that keeps track of its instants and evaluates the boardstate to judge if it is worthwhile to cast the spell now. The first issue I can think of is how to create or design such a class since all of the code I have fiddled with so far (AiAttackController, PlayerControllerAi, CombatUtil, etc ) are either static methods or instantiated as local variables with a limited scope.
Re: AI Development Questions
by excessum » 16 Apr 2014, 13:52
The attached patch is a WIP that will hopefully consolidate the various targeted removal spells with a common API to prevent the AI from wasting them at the first available target. Currently I am only looking at ChangeZoneAI (bounce and exile) where the code for bouncing to save friendlies is largely unused because the AI almost never have bounce spells in hand unless the opponent presents no targets (like Burn or heavy Control decks).
The general plan is to decrease the AI's use of removal frivolously so that it has them available for better targets like mid/late bombs, enchanted/equipped battlecruisers and stuff that the opponent is pumping. Using removal as an interrupt to pumps/enchants is not coded AFAIK and I need the AI to actually have removal in hand before attempting to code it lest it ends up like the above-mentioned bounce code.
The general plan is to decrease the AI's use of removal frivolously so that it has them available for better targets like mid/late bombs, enchanted/equipped battlecruisers and stuff that the opponent is pumping. Using removal as an interrupt to pumps/enchants is not coded AFAIK and I need the AI to actually have removal in hand before attempting to code it lest it ends up like the above-mentioned bounce code.
- Attachments
-
- useRemoval.txt
- (3.24 KiB) Downloaded 181 times
Re: AI Development Questions
by Sloth » 16 Apr 2014, 15:32
That's a good idea excessum. The numbers have to be tested, but it should definitely be an improvement.excessum wrote:The attached patch is a WIP that will hopefully consolidate the various targeted removal spells with a common API to prevent the AI from wasting them at the first available target. Currently I am only looking at ChangeZoneAI (bounce and exile) where the code for bouncing to save friendlies is largely unused because the AI almost never have bounce spells in hand unless the opponent presents no targets (like Burn or heavy Control decks).
The general plan is to decrease the AI's use of removal frivolously so that it has them available for better targets like mid/late bombs, enchanted/equipped battlecruisers and stuff that the opponent is pumping. Using removal as an interrupt to pumps/enchants is not coded AFAIK and I need the AI to actually have removal in hand before attempting to code it lest it ends up like the above-mentioned bounce code.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: AI Development Questions
by excessum » 17 Apr 2014, 13:31
The complete version of the patch is attached. The missing pieces are all documented in to-does and involve tedious checks for triggers and abilities. An example of the new system is as follows:
- Code: Select all
Excoriate vs Tormented Hero
valueTempo = 0.5 * 1 (cost of target) / 4 (cost of removal) * 2 (isSorcery) = 0.25
threat = 2 (power of target) / 16 (AI's life after 2 attacks) = 0.125
chance = max( valueTempo, threat ) = 0.25
- Attachments
-
- useRemoval2.txt
- (9.31 KiB) Downloaded 155 times
Re: AI Development Questions
by friarsol » 17 Apr 2014, 14:23
Is there any way we can merge the section "//evaluate threat of targeted card" with ComputerUtilCard.evaluateCreature() that already exists?
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: AI Development Questions
by excessum » 17 Apr 2014, 15:05
The logic for evaluateCreature() is more suitable as a comparator between creatures or as a raw "value" of a single creature. My code is more similar to "aiLifeToDamageRatio" in AiAttackController which evaluates the board/life state against the target creature.friarsol wrote:Is there any way we can merge the section "//evaluate threat of targeted card" with ComputerUtilCard.evaluateCreature() that already exists?
As I figure out more ways to change/improve the AI logic, I suppose I will eventually get around to writing proper method(s) for such code (it is already present in the "make unblockable" block in ProtectAI). I was thinking of implementing a much more complicated version to estimate the expected damage for groups of attacking and blocking creatures for ProtectAllAi but I shelved it because it was too messy.
Re: AI Development Questions
by excessum » 18 Apr 2014, 05:29
Here is a more fleshed-out version of the patch.
- Attachments
-
- useRemoval3.txt
- (9.88 KiB) Downloaded 155 times
Re: AI Development Questions
by Sloth » 20 Apr 2014, 08:40
in r25527 you removed a check that prevents curses from being used when the stack is not empty. I think this check was made to prevent the AI from wasting 2 removal spells on one target. So maybe the AI can check whether there's one of its own spells somewhere on the stack already.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: AI Development Questions
by excessum » 20 Apr 2014, 11:54
I did provide an explanation and a TODO for a better solution so I thought that was adequate. The other removal APIs (ChangeZoneAI/DestroyAI/PumpAI) all suffer from the same issue and do not have similar checks which is why I suggested placing the check together with useRemovalNow().Sloth wrote:in r25527 you removed a check that prevents curses from being used when the stack is not empty. I think this check was made to prevent the AI from wasting 2 removal spells on one target. So maybe the AI can check whether there's one of its own spells somewhere on the stack already.
AFAIK, the original check is only effective if something goes on the stack that does NOT invalidate the original removal (ie. cast Think Twice or cast something on something else). I would say that this situation is rare but not impossible so removing the check now would not cause any serious negative impact. Any other scenario like Mending Touch, Giant Growth, Gods Willing (since it was originally in DamageDealAI) will make a second burn spell valid since the removal as interrupt scenario I added will come in.
For the solution to this issue, a reverse analogue to predictThreatenedObject() like say predictSavedObject(SpellAbility interrupt) will be required since predicting if something does NOT affect the original target is harder.
Re: AI Development Questions
by Sloth » 20 Apr 2014, 13:49
The most likely scenario is when a random trigger goes on the stack when the removal spell is cast (like Throne of Bone). I'm not sure this is enough to require some kind of check. I have to think a bit more about it.excessum wrote:AFAIK, the original check is only effective if something goes on the stack that does NOT invalidate the original removal (ie. cast Think Twice or cast something on something else). I would say that this situation is rare but not impossible ...
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
45 posts
• Page 2 of 3 • 1, 2, 3
Who is online
Users browsing this forum: No registered users and 114 guests