mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Made a number of AI combat improvements:
- Computer should take into account creatures with trample now, when blocking. - Computer will not care about human attackers the next turn quite as much, hopefully this will prevent the AI from stopping to attack altogether if it's low on life.
This commit is contained in:
@@ -271,6 +271,19 @@ public class CardListUtil
|
||||
return attack;
|
||||
}//sumAttack()
|
||||
|
||||
public static int sumDefense(CardList c)
|
||||
{
|
||||
int defense = 0;
|
||||
|
||||
for(int i = 0; i < c.size(); i++){
|
||||
//if(c.get(i).isCreature() && c.get(i).hasSecondStrike()) {
|
||||
if(c.get(i).isCreature() )
|
||||
defense += c.get(i).getNetDefense();
|
||||
}
|
||||
//System.out.println("Total attack: " +attack);
|
||||
return defense;
|
||||
}//sumAttack()
|
||||
|
||||
public static int sumFirstStrikeAttack(CardList c)
|
||||
{
|
||||
int attack = 0;
|
||||
|
||||
@@ -138,8 +138,10 @@ import java.util.*;
|
||||
for(int i = 0; i < stop; i++)
|
||||
totalAttack += getAttack(humanList.get(i));
|
||||
|
||||
//-3 so the computer will try to stay at 3 life
|
||||
return (AllZone.Computer_Life.getLife() - 3) <= totalAttack;
|
||||
//originally -3 so the computer will try to stay at 3 life
|
||||
//+1 now to prevent the AI from not attacking when it's got low life
|
||||
//(seems to happen too often)
|
||||
return (AllZone.Computer_Life.getLife() + 1) <= totalAttack;
|
||||
}
|
||||
|
||||
private boolean doAssault()
|
||||
|
||||
@@ -75,6 +75,16 @@ public class ComputerUtil_Block2
|
||||
return list;
|
||||
}
|
||||
|
||||
private CardList getPossibleBlockersWithFirstStrike(Card attacker)
|
||||
{
|
||||
CardList list = new CardList();
|
||||
for(int i = 0; i < possibleBlockers.size(); i++)
|
||||
if(CombatUtil.canBlock(attacker, possibleBlockers.get(i)) && (attacker.hasFirstStrike() || attacker.hasDoubleStrike()))
|
||||
list.add(possibleBlockers.get(i));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
//finds a blocker that destroys the attacker, the blocker is not destroyed
|
||||
//returns null if no blocker is found
|
||||
Card safeSingleBlock(Card attacker)
|
||||
@@ -125,28 +135,60 @@ public class ComputerUtil_Block2
|
||||
//returns an array of size 0 if not multiple blocking
|
||||
Card[] multipleBlock(Card attacker)
|
||||
{
|
||||
CardList c = getPossibleBlockers(attacker);
|
||||
CardList c;
|
||||
if (attacker.hasDoubleStrike() || attacker.hasFirstStrike())
|
||||
c = getPossibleBlockersWithFirstStrike(attacker);
|
||||
else
|
||||
c = getPossibleBlockers(attacker);
|
||||
|
||||
int defense = getDefense(attacker) - attacker.getDamage();
|
||||
//if attacker cannot be destroyed
|
||||
if(defense > CardListUtil.sumAttack(c))
|
||||
return new Card[] {};
|
||||
return new Card[] {};
|
||||
|
||||
CardList block = new CardList();
|
||||
c.shuffle();
|
||||
|
||||
while(defense > CardListUtil.sumAttack(block))
|
||||
block.add(c.remove(0));
|
||||
block.add(c.remove(0));
|
||||
|
||||
Card check[] = block.toArray();
|
||||
|
||||
//no single blockers, that should be handled somewhere else
|
||||
if(check.length == 1)
|
||||
return new Card[] {};
|
||||
return new Card[] {};
|
||||
|
||||
return check;
|
||||
}//multipleBlock()
|
||||
|
||||
Card[] multipleTrampleBlock(Card attacker)
|
||||
{
|
||||
CardList c;
|
||||
if (attacker.hasDoubleStrike() || attacker.hasFirstStrike())
|
||||
c = getPossibleBlockersWithFirstStrike(attacker);
|
||||
else
|
||||
c = getPossibleBlockers(attacker);
|
||||
|
||||
int attack = getAttack(attacker);
|
||||
//if computer can't save himself:
|
||||
if(attack > (CardListUtil.sumDefense(c) + AllZone.GameAction.getPlayerLife(Constant.Player.Computer).getLife() ))
|
||||
return new Card[] {};
|
||||
|
||||
CardList block = new CardList();
|
||||
c.shuffle();
|
||||
|
||||
while(attack >= (CardListUtil.sumDefense(block) + AllZone.GameAction.getPlayerLife(Constant.Player.Computer).getLife() )
|
||||
&& c.size() != 0)
|
||||
block.add(c.remove(0));
|
||||
|
||||
Card check[] = block.toArray();
|
||||
|
||||
//no single blockers, that should be handled somewhere else
|
||||
if(check.length == 1)
|
||||
return new Card[] {};
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
//finds a blocker, both the attacker lives and blockers dies
|
||||
//returns null if no blocker is found
|
||||
@@ -219,6 +261,7 @@ public class ComputerUtil_Block2
|
||||
{
|
||||
|
||||
boolean doubleStrike = attackers.get(i).hasDoubleStrike();
|
||||
boolean trample = attackers.get(i).getKeyword().contains("Trample");
|
||||
|
||||
//the computer blocks 50% of the time or if the computer would lose the game
|
||||
shouldBlock = random.nextBoolean() || blockersLife <= sumUnblockedAttackers(combat);
|
||||
@@ -234,68 +277,87 @@ public class ComputerUtil_Block2
|
||||
Random random = new Random();
|
||||
int randomInt = random.nextInt(100);
|
||||
|
||||
if (randomInt >= 10)
|
||||
boolean multiTrample = false;
|
||||
//multiblocks for trample
|
||||
if (trample && AllZone.Computer_Life.getLife() <= getAttack(attackers.get(i)) )
|
||||
{
|
||||
c = safeSingleBlock(attackers.get(i));
|
||||
Card[] m = multipleTrampleBlock(attackers.get(i));
|
||||
for(int inner = 0; inner < m.length; inner++)
|
||||
{
|
||||
if(m.length != 1)
|
||||
{
|
||||
possibleBlockers.remove(m[inner]);
|
||||
combat.addBlocker(attackers.get(i), m[inner]);
|
||||
multiTrample = true;
|
||||
}
|
||||
}//for
|
||||
}
|
||||
|
||||
if (!multiTrample)
|
||||
{
|
||||
if (randomInt >= 10)
|
||||
{
|
||||
c = safeSingleBlock(attackers.get(i));
|
||||
if(c != null)
|
||||
testing("safe");
|
||||
}
|
||||
if(c == null && randomInt >= 15)
|
||||
{
|
||||
//shield block - attacker lives, blocker lives
|
||||
c = shieldSingleBlock(attackers.get(i));
|
||||
if(c != null)
|
||||
testing("shield");
|
||||
}
|
||||
|
||||
if(c == null && shouldBlock)
|
||||
{
|
||||
//trade block - attacker dies, blocker dies
|
||||
c = tradeSingleBlock(attackers.get(i));
|
||||
|
||||
if(c != null)
|
||||
testing("trading");
|
||||
}
|
||||
|
||||
|
||||
if(c == null && shouldBlock)
|
||||
{
|
||||
//chump block - attacker lives, blocker dies
|
||||
c = chumpSingleBlock(attackers.get(i));
|
||||
if(c != null)
|
||||
testing("chumping");
|
||||
}
|
||||
|
||||
if(c == null && doubleStrike && AllZone.Computer_Life.getLife() <= (getAttack(attackers.get(i))*2))
|
||||
{
|
||||
c = forceBlock(attackers.get(i));
|
||||
if (c != null)
|
||||
testing("forcing");
|
||||
}
|
||||
|
||||
if(c != null)
|
||||
testing("safe");
|
||||
{
|
||||
|
||||
//if (!c.getKeyword().contains("This card can block any number of creatures."))
|
||||
possibleBlockers.remove(c);
|
||||
combat.addBlocker(attackers.get(i), c);
|
||||
}
|
||||
|
||||
//multiple blockers
|
||||
if(c == null && shouldBlock)
|
||||
{
|
||||
Card[] m = multipleBlock(attackers.get(i));
|
||||
for(int inner = 0; inner < m.length; inner++)
|
||||
{
|
||||
//to prevent a single flyer from blocking a single non-flyer
|
||||
//tradeSingleBlock() checks for a flyer blocking a non-flyer also
|
||||
if(m.length != 1)
|
||||
{
|
||||
possibleBlockers.remove(m[inner]);
|
||||
combat.addBlocker(attackers.get(i), m[inner]);
|
||||
}
|
||||
}//for
|
||||
}//if
|
||||
}
|
||||
if(c == null && randomInt >= 15)
|
||||
{
|
||||
//shield block - attacker lives, blocker lives
|
||||
c = shieldSingleBlock(attackers.get(i));
|
||||
if(c != null)
|
||||
testing("shield");
|
||||
}
|
||||
|
||||
if(c == null && shouldBlock)
|
||||
{
|
||||
//trade block - attacker dies, blocker dies
|
||||
c = tradeSingleBlock(attackers.get(i));
|
||||
|
||||
if(c != null)
|
||||
testing("trading");
|
||||
}
|
||||
|
||||
|
||||
if(c == null && shouldBlock)
|
||||
{
|
||||
//chump block - attacker lives, blocker dies
|
||||
c = chumpSingleBlock(attackers.get(i));
|
||||
if(c != null)
|
||||
testing("chumping");
|
||||
}
|
||||
|
||||
if(c == null && doubleStrike && AllZone.Computer_Life.getLife() <= (getAttack(attackers.get(i))*2))
|
||||
{
|
||||
c = forceBlock(attackers.get(i));
|
||||
if (c != null)
|
||||
testing("forcing");
|
||||
}
|
||||
|
||||
if(c != null)
|
||||
{
|
||||
|
||||
//if (!c.getKeyword().contains("This card can block any number of creatures."))
|
||||
possibleBlockers.remove(c);
|
||||
combat.addBlocker(attackers.get(i), c);
|
||||
}
|
||||
|
||||
//multiple blockers
|
||||
if(c == null && shouldBlock)
|
||||
{
|
||||
Card[] m = multipleBlock(attackers.get(i));
|
||||
for(int inner = 0; inner < m.length; inner++)
|
||||
{
|
||||
//to prevent a single flyer from blocking a single non-flyer
|
||||
//tradeSingleBlock() checks for a flyer blocking a non-flyer also
|
||||
if(m.length != 1)
|
||||
{
|
||||
possibleBlockers.remove(m[inner]);
|
||||
combat.addBlocker(attackers.get(i), m[inner]);
|
||||
}
|
||||
}//for
|
||||
}//if
|
||||
}//for attackers
|
||||
|
||||
return combat;
|
||||
|
||||
Reference in New Issue
Block a user