It is currently 26 Apr 2024, 00:50
   
Text Size

AI Development Questions

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Re: AI Development Questions

Postby 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;
                }
This part should probably be removed. This will cause a lot of spells to be wasted.

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));
                        }
                       
                    }
The logic here looks messed up. ComputerUtilCombat.blockerWouldBeDestroyed(ai, blockers.get(0), combat) should be ComputerUtilCombat.attackerWouldBeDestroyed(ai, c, combat), no?

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;
                    }
                }
There should be a check here whether the opponent has any possible blockers, otherwise the AI will waste a spell on an unblockable creature.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Development Questions

Postby 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:
Sloth wrote:This part should probably be removed. This will cause a lot of spells to be wasted.
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:The logic here looks messed up. ComputerUtilCombat.blockerWouldBeDestroyed(ai, blockers.get(0), combat) should be ComputerUtilCombat.attackerWouldBeDestroyed(ai, c, combat), no?
I copied this from the original code and yes, I should change it to attackerWouldBeDestroyed.

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.
Missed out a getPossibleBlockers() within toProtectAttacker() which will now need the attacking Card as an argument.

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.
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby Sloth » 08 Apr 2014, 07:46

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.
I would start very conservatively here. The AI should use "grant unblockable" mode very rarely, because the AI has no idea of tempo.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Development Questions

Postby 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.)?
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby swordshine » 10 Apr 2014, 01:15

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.)?
The leave-the-battlefield triggers are quite difficult to fix, probably need to refractor the related code and introduce more accurate timestamps.
swordshine
 
Posts: 682
Joined: 11 Jul 2010, 02:37
Has thanked: 116 times
Been thanked: 87 times

Re: AI Development Questions

Postby excessum » 11 Apr 2014, 00:44

swordshine wrote:The leave-the-battlefield triggers are quite difficult to fix, probably need to refractor the related code and introduce more accurate timestamps.
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.

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.
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby 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.
Attachments
useRemoval.txt
(3.24 KiB) Downloaded 181 times
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby Sloth » 16 Apr 2014, 15:32

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.
That's a good idea excessum. The numbers have to be tested, but it should definitely be an improvement.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Development Questions

Postby 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
Assuming the AI does not have a higher priority spell to cast, it will have two 25% chances to cast Excoriate each turn. It is not very likely to cast it at each window but these chances add up very quickly so the situations of it holding a hand of removal is quite minimal. The sheer number of windows for instants to be cast make even tiny chances add up quickly over time so I rather error with having low chances.
Attachments
useRemoval2.txt
(9.31 KiB) Downloaded 155 times
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby 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

Postby excessum » 17 Apr 2014, 15:05

friarsol wrote:Is there any way we can merge the section "//evaluate threat of targeted card" with ComputerUtilCard.evaluateCreature() that already exists?
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.

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.
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby 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
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby 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.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Development Questions

Postby excessum » 20 Apr 2014, 11:54

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.
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().

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.
excessum
 
Posts: 177
Joined: 21 Oct 2013, 02:30
Has thanked: 0 time
Been thanked: 19 times

Re: AI Development Questions

Postby Sloth » 20 Apr 2014, 13:49

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 ...
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.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

PreviousNext

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 114 guests

cron

Who is online

In total there are 114 users online :: 0 registered, 0 hidden and 114 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 114 guests

Login Form