mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 03:38: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;
|
return attack;
|
||||||
}//sumAttack()
|
}//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)
|
public static int sumFirstStrikeAttack(CardList c)
|
||||||
{
|
{
|
||||||
int attack = 0;
|
int attack = 0;
|
||||||
|
|||||||
@@ -138,8 +138,10 @@ import java.util.*;
|
|||||||
for(int i = 0; i < stop; i++)
|
for(int i = 0; i < stop; i++)
|
||||||
totalAttack += getAttack(humanList.get(i));
|
totalAttack += getAttack(humanList.get(i));
|
||||||
|
|
||||||
//-3 so the computer will try to stay at 3 life
|
//originally -3 so the computer will try to stay at 3 life
|
||||||
return (AllZone.Computer_Life.getLife() - 3) <= totalAttack;
|
//+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()
|
private boolean doAssault()
|
||||||
|
|||||||
@@ -75,6 +75,16 @@ public class ComputerUtil_Block2
|
|||||||
return list;
|
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
|
//finds a blocker that destroys the attacker, the blocker is not destroyed
|
||||||
//returns null if no blocker is found
|
//returns null if no blocker is found
|
||||||
Card safeSingleBlock(Card attacker)
|
Card safeSingleBlock(Card attacker)
|
||||||
@@ -125,28 +135,60 @@ public class ComputerUtil_Block2
|
|||||||
//returns an array of size 0 if not multiple blocking
|
//returns an array of size 0 if not multiple blocking
|
||||||
Card[] multipleBlock(Card attacker)
|
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();
|
int defense = getDefense(attacker) - attacker.getDamage();
|
||||||
//if attacker cannot be destroyed
|
//if attacker cannot be destroyed
|
||||||
if(defense > CardListUtil.sumAttack(c))
|
if(defense > CardListUtil.sumAttack(c))
|
||||||
return new Card[] {};
|
return new Card[] {};
|
||||||
|
|
||||||
CardList block = new CardList();
|
CardList block = new CardList();
|
||||||
c.shuffle();
|
c.shuffle();
|
||||||
|
|
||||||
while(defense > CardListUtil.sumAttack(block))
|
while(defense > CardListUtil.sumAttack(block))
|
||||||
block.add(c.remove(0));
|
block.add(c.remove(0));
|
||||||
|
|
||||||
Card check[] = block.toArray();
|
Card check[] = block.toArray();
|
||||||
|
|
||||||
//no single blockers, that should be handled somewhere else
|
//no single blockers, that should be handled somewhere else
|
||||||
if(check.length == 1)
|
if(check.length == 1)
|
||||||
return new Card[] {};
|
return new Card[] {};
|
||||||
|
|
||||||
return check;
|
return check;
|
||||||
}//multipleBlock()
|
}//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
|
//finds a blocker, both the attacker lives and blockers dies
|
||||||
//returns null if no blocker is found
|
//returns null if no blocker is found
|
||||||
@@ -219,6 +261,7 @@ public class ComputerUtil_Block2
|
|||||||
{
|
{
|
||||||
|
|
||||||
boolean doubleStrike = attackers.get(i).hasDoubleStrike();
|
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
|
//the computer blocks 50% of the time or if the computer would lose the game
|
||||||
shouldBlock = random.nextBoolean() || blockersLife <= sumUnblockedAttackers(combat);
|
shouldBlock = random.nextBoolean() || blockersLife <= sumUnblockedAttackers(combat);
|
||||||
@@ -234,68 +277,87 @@ public class ComputerUtil_Block2
|
|||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
int randomInt = random.nextInt(100);
|
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)
|
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
|
}//for attackers
|
||||||
|
|
||||||
return combat;
|
return combat;
|
||||||
|
|||||||
Reference in New Issue
Block a user