It is currently 31 Oct 2025, 11:16
   
Text Size

AI Work/Combat Prediction

Post MTG Forge Related Programming Questions Here

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

AI Work/Combat Prediction

Postby friarsol » 04 Feb 2011, 05:50

As part of my AI improvement work I'm now allowing the AI to activate spells/abilities during other phases. The very early work has quietly slipped into the SVN and you can now see the AI activating Tims (Prodigal Sorcerer) at the End of the Human's turn instead of during their main phase, at least when pinging players is concerned.

The new added responsiveness is pretty cool so far. I've already caught myself about to attack when the AI decides to Shatter an artifact during my main phase that I was going to use in combat.

The next thing I wanted to do was rewrite the Regeneration AI, since right now it "guesses" to regenerate things, and it would be much better to be responsive.

This is mostly for Sloth since I know he's worked the most in combat recently, but if anyone else happens to know feel free to chime in. So does anyone know if there is some type of combat destruction function right now?

Ideally, I would pass in a combatant. It would take creatures attacking/blocking it, plus a few other keywords into consideration (deathtouch, wither/infect, etc) and return true or false based on whether or not it would be destroyed. If it gets its toughness reduced to 0, that would actually return false, since that isn't destruction. But if it gets hit by deathtouch or lethal damage, then it would return true.

For blockers it might be a bit trickier because of Issue 77 (http://code.google.com/p/cardforge/issues/detail?id=77). Since we're really supposed to know the order damage is dealt to blockers, if we knew that information deciding if something would be destroyed would be much easier. Since we don't, we'd have to assume the creature we're checking is the first. Anyway, I'm rambling. If anyone has any suggestions or requests while I'm tweaking AIs feel free to add it here.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: AI Work/Combat Prediction

Postby Sloth » 04 Feb 2011, 11:52

I will try write you a function like this Sol. Most of it is done already. It just needs some structure changes.

EDIT: The function is finished. It's the boolean function combatantWouldBeDestroyed(Card combatant, Combat combat) in CombatUtil. To get the actual combat, use AllZone.Combat.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Work/Combat Prediction

Postby friarsol » 04 Feb 2011, 14:39

Sloth wrote:I will try write you a function like this Sol. Most of it is done already. It just needs some structure changes.

EDIT: The function is finished. It's the boolean function combatantWouldBeDestroyed(Card combatant, Combat combat) in CombatUtil. To get the actual combat, use AllZone.Combat.
Awesome. I'll check it out so i can finish up Regeneration.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: AI Work/Combat Prediction

Postby jeffwadsworth » 09 Feb 2011, 02:19

I was minding my own business and laying down a typical beatdown when the AI casted a First Volley on my Arc Runner during my main 1 phase! I cursed Sol under my breath.
jeffwadsworth
Super Tester Elite
 
Posts: 1172
Joined: 20 Oct 2010, 04:47
Location: USA
Has thanked: 287 times
Been thanked: 70 times

Re: AI Work/Combat Prediction

Postby friarsol » 09 Feb 2011, 02:48

::cackles::
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: AI Work/Combat Prediction

Postby Chris H. » 09 Feb 2011, 03:35

jeffwadsworth wrote:I was minding my own business and laying down a typical beatdown when the AI casted a First Volley on my Arc Runner during my main 1 phase! I cursed Sol under my breath.
`
In my play testing over the last couple of days I have seen several eye openers like this ... awesome. A sign of things to come. :D
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Re: AI Work/Combat Prediction

Postby Sloth » 09 Feb 2011, 06:23

I really appreciate your work to improve the AI, Sol. The AI is really what forge is about.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Work/Combat Prediction

Postby friarsol » 09 Feb 2011, 15:01

Sloth wrote:I really appreciate your work to improve the AI, Sol. The AI is really what forge is about.
I agree. And it's coming along bit by bit. Some of these changes that I'm making affect other parts of the AI which will probably need to be upgraded to handle the new abilities.

Example: If the AI has a blocker with regeneration that can be afforded, it should block the creature it would absorb the most damage from (considering trample) but not block a wither or infect creature (that would kill it). We probably would need to keep track of the available mana versus the "planned to be used" mana. So this would work properly.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Good Job

Postby mtgrares » 09 Feb 2011, 19:23

Great work friarsol. I will definitely enjoy playing against a smarter Forge.

Truthfully I tried to improve Forge's AI but it is just so hard to pin down to specifics. Also my lack of familiarity with the code didn't help since many things have been changed.
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: AI Work/Combat Prediction

Postby Masher8 » 25 Feb 2011, 20:34

Seeing as I've made some modifications to the attacking AI this seems as good a place to put this query as any.

When a creature has a blocking trigger that pumps it (for example Royal Trooper) the function CombatUtil.canDestroyBlocker doesn't take this into account. I guess the same may go for the attacking pump triggers. I've spent quite a bit of time reading the code to try to figure out how to add this but I can't see how this could be achieved.
Masher8
 
Posts: 18
Joined: 05 Feb 2011, 13:57
Has thanked: 0 time
Been thanked: 0 time

Re: AI Work/Combat Prediction

Postby Sloth » 26 Feb 2011, 15:42

Masher8 wrote:Seeing as I've made some modifications to the attacking AI this seems as good a place to put this query as any.

When a creature has a blocking trigger that pumps it (for example Royal Trooper) the function CombatUtil.canDestroyBlocker doesn't take this into account. I guess the same may go for the attacking pump triggers. I've spent quite a bit of time reading the code to try to figure out how to add this but I can't see how this could be achieved.
I guess this won't be easy, but I will give it try.

Some propositions for the attack class:

1. aiAggression is a nice idea. It would be easier to understand your code though, if a high number would indicate a high aggression. It seems to be mixed at the moment (5 is highest and 4 is lowest).

2.You don't need the canCauseDamage variable. Creatures that won't deal damage get filtered out here(at the very top of the class):
Code: Select all
attackers = attackers.filter(new CardListFilter()
      {
        public boolean addCard(Card c)
        {
          return (0 < getAttack(c) || c.getName().equals("Guiltfeeder")) && ! valuable.contains(c.getName());
        }
      });
You should update this filter though (your getNetCombatDamage is much better than getAttack).

3.If I'm reading it correctly, there should be no ! before isWorthLessThanAllKillers here:
Code: Select all
        // if the creature cannot block and can kill all opponents they might as well attack, they do nothing staying back
        if(canKillAllDangerous && !CombatUtil.canBlock(attacker) && !isWorthLessThanAllKillers){
            System.out.println(attacker.getName() + " = attacking because they can't block, expecting to kill or damage player");
            return true;
        }
4. The inner if clause here still doesn't make sense to me. Can you explain what you want to do with it?
Code: Select all
                // see if this attacking creature can destroy this defender, if not record that it can't kill everything
             if(!CombatUtil.canDestroyBlocker(defender, attacker)){
                    // make exception for walls, they are usually extra tough but not dangerous unless they have
                    // high power, so check for walls that can kill but ignore others
                    if(!(defender.isWall() && defender.getNetCombatDamage() <= 0)){
                       canKillAllDangerous = false; // there is a dangerous creature that can survive an attack from this creature
                    }
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Work/Combat Prediction

Postby Hellfish » 26 Feb 2011, 16:14

You may be able to use the AI trigger hooks Sol has been hard at work adding, at least to determine wether or not the AI would want the trigger to occur. Beyond that I'm not sure there is any other recourse than a full-on Min-Max solution.
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
User avatar
Hellfish
Programmer
 
Posts: 1297
Joined: 07 Jun 2009, 10:41
Location: South of the Pumphouse
Has thanked: 110 times
Been thanked: 169 times

Re: AI Work/Combat Prediction

Postby Masher8 » 27 Feb 2011, 14:58

Sloth wrote:I guess this won't be easy, but I will give it try.
Yes, having looked at it it seems far from simple, but it is leading to some suicidal attacks and stupid behaviour which is a bit of a shame. I think it'll have to be detected eventually, I don't normally construct decks with this kind of creature but they pop up in sealed and quest.
Sloth wrote:Some propositions for the attack class:

1. aiAggression is a nice idea. It would be easier to understand your code though, if a high number would indicate a high aggression. It seems to be mixed at the moment (5 is highest and 4 is lowest).
Yes, really the idea was to equip the AI with a few different attacking approaches and then look at the context to try to see which is the most suitable, then apply it. It doesn't always work but in the absence of a minimax type approach this kind of hard coding of a set of heuristics seemed the best bet.

Level 4 has ended up being retrofitted from it's original purpose to quite a conservative approach, but at the time I just wanted to get something out that improved things having promised to produce something. I intend to get a lot of it tidied up and modularised into functions so it can potentially be more generally useful as well as tidier.
Sloth wrote:2.You don't need the canCauseDamage variable. Creatures that won't deal damage get filtered out here(at the very top of the class):
Code: Select all
attackers = attackers.filter(new CardListFilter()
      {
        public boolean addCard(Card c)
        {
          return (0 < getAttack(c) || c.getName().equals("Guiltfeeder")) && ! valuable.contains(c.getName());
        }
      });
You should update this filter though (your getNetCombatDamage is much better than getAttack).
getNetCombatDamage is something I found while trying to solve problems I was having with Doran Siege Tower.

The canCauseDamage variable was added after a 0/1 bird of paradise was repeatedly attacking in one my test scenarios, so I guess the earlier filtering isn't working as expected in this context or I'm accessing a different collection or something. I'll certainly have another look at this.
Sloth wrote:3.If I'm reading it correctly, there should be no ! before isWorthLessThanAllKillers here:
Code: Select all
        // if the creature cannot block and can kill all opponents they might as well attack, they do nothing staying back
        if(canKillAllDangerous && !CombatUtil.canBlock(attacker) && !isWorthLessThanAllKillers){
            System.out.println(attacker.getName() + " = attacking because they can't block, expecting to kill or damage player");
            return true;
        }
I think you're right, this has "late night code revision" written all over it! #-o

I'll test it and commit the change if testing checks out.
Sloth wrote:4. The inner if clause here still doesn't make sense to me. Can you explain what you want to do with it?
Code: Select all
                // see if this attacking creature can destroy this defender, if not record that it can't kill everything
             if(!CombatUtil.canDestroyBlocker(defender, attacker)){
                    // make exception for walls, they are usually extra tough but not dangerous unless they have
                    // high power, so check for walls that can kill but ignore others
                    if(!(defender.isWall() && defender.getNetCombatDamage() <= 0)){
                       canKillAllDangerous = false; // there is a dangerous creature that can survive an attack from this creature
                    }
The wall exception is a result of lots of testing and development being done against decks with no walls, then seeing it's appalling performance against a deck with walls. This is because the general consideration is to compare how much damage each player can potentially cause in their turn which means walls are filtered out of the reckoning at an early stage.

If you ignore the wall exception for a moment, this code block records if the attacking creature can kill the defending creature, and if it can't to note it can't kill all the defending creatures. The result of this in a lot of combat scenarios is that creatures won't attack if there doesn't seem to be any point. However if the human has for example a Wall of Ice (and importantly because the whole 'should attack' function assesses one creature at a time) this could lead to a number of creatures hanging back when they're in no real danger and would benefit from attacking as a group as the wall can only block one. This exception checks to see if the defender being examined is a wall with the potential to cause damage (i.e. power more than 0) and is therefore to be counted as "dangerous" or not. It comes down to: if the defender being considered is a wall and it can't cause damage don't include it in calculations to see whether this creature is wasting it's time attacking against high toughness defenders.

It's really just a band aid until I come up with something better. The main goal, to eliminate a stupid AI behaviour in obviously attacking circumstances, is achieved but not ideally or with enough subtlety to guarantee an optimal AI choice in a wide range of circumstances. It still leads to a stupid behaviour, where they attack repeatedly if there are more than enough 0 power walls to block them all, but at least it stops Shield Spheres hanging around forever. Definitely something I plan to revisit.
Masher8
 
Posts: 18
Joined: 05 Feb 2011, 13:57
Has thanked: 0 time
Been thanked: 0 time

Re: AI Work/Combat Prediction

Postby Sloth » 27 Feb 2011, 16:16

Thanks for clearing things up Masher. I'm working on the P/T bonus predictions. They will be integrated into canDestroyBlocker and canDestroyAttacker.
I hope you don't mind me discussing your code openly.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: AI Work/Combat Prediction

Postby Masher8 » 27 Feb 2011, 18:19

Sloth wrote:Thanks for clearing things up Masher. I'm working on the P/T bonus predictions. They will be integrated into canDestroyBlocker and canDestroyAttacker.
I hope you don't mind me discussing your code openly.
Those would be very useful additions I think if they can be made to work.

The discussion is fine by me, code review by another pair of eyes is one of the best ways to improve quality, and on an open source effort getting explanations of difficult sections out there so people know what they're maintaining is important. I'm well aware I'm not cemented as a permanent fixture on the coding team. :)
Masher8
 
Posts: 18
Joined: 05 Feb 2011, 13:57
Has thanked: 0 time
Been thanked: 0 time

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 24 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 24 users online :: 0 registered, 0 hidden and 24 guests (based on users active over the past 10 minutes)
Most users ever online was 9298 on 10 Oct 2025, 12:54

Users browsing this forum: No registered users and 24 guests

Login Form