Added support for AI vs AI matches

This commit is contained in:
Maxmtg
2013-05-21 08:26:27 +00:00
parent 364667855d
commit 7c5eae6e42
9 changed files with 80 additions and 43 deletions

View File

@@ -840,9 +840,11 @@ public class GameAction {
}
// ai's cannot finish their game without human yet - so terminate a game if human has left.
/*
if (reason == null && !Iterables.any(game.getPlayers(), Predicates.and(Player.Predicates.NOT_LOST, Player.Predicates.isType(PlayerType.HUMAN)))) {
reason = GameEndReason.AllHumansLost;
}
*/
return reason;
}

View File

@@ -95,6 +95,8 @@ public final class GameOutcome implements Iterable<Entry<LobbyPlayer, PlayerStat
*/
public boolean isWinner(final LobbyPlayer who) {
PlayerStatistics stats = playerRating.get(who);
if ( stats == null )
return false;
return stats.getOutcome().hasWon();
}

View File

@@ -171,8 +171,6 @@ public class MatchController {
localHuman = p;
break;
}
if (null == localHuman)
throw new IllegalStateException("Cannot start a game without a human yet!");
FControl.SINGLETON_INSTANCE.setPlayer(localHuman);

View File

@@ -465,6 +465,9 @@ public class AiAttackController {
}
}
final boolean LOG_AI_ATTACKS = false;
/**
* <p>
* Getter for the field <code>attackers</code>.
@@ -522,6 +525,7 @@ public class AiAttackController {
return combat;
}
if (bAssault) {
if ( LOG_AI_ATTACKS )
System.out.println("Assault");
CardLists.sortByPowerDesc(attackersLeft);
for (Card attacker : attackersLeft) {
@@ -556,6 +560,7 @@ public class AiAttackController {
}
if (exalted) {
CardLists.sortByPowerDesc(this.attackers);
if ( LOG_AI_ATTACKS )
System.out.println("Exalted");
this.aiAggression = 6;
for (Card attacker : this.attackers) {
@@ -752,12 +757,15 @@ public class AiAttackController {
} else {
this.aiAggression = 0;
} // stay at home to block
if ( LOG_AI_ATTACKS )
System.out.println(String.valueOf(this.aiAggression) + " = ai aggression");
// ****************
// Evaluation the end
// ****************
if ( LOG_AI_ATTACKS )
System.out.println("Normal attack");
attackersLeft = this.notNeededAsBlockers(ai, attackersLeft);
@@ -859,6 +867,7 @@ public class AiAttackController {
boolean canBeBlocked = false;
int numberOfPossibleBlockers = 0;
if (!this.isEffectiveAttacker(ai, attacker, combat)) {
return false;
}
@@ -921,8 +930,8 @@ public class AiAttackController {
// if the creature cannot block and can kill all opponents they might as
// well attack, they do nothing staying back
if (canKillAll && isWorthLessThanAllKillers && !CombatUtil.canBlock(attacker)) {
System.out.println(attacker.getName()
+ " = attacking because they can't block, expecting to kill or damage player");
if ( LOG_AI_ATTACKS )
System.out.println(attacker.getName() + " = attacking because they can't block, expecting to kill or damage player");
return true;
}
@@ -938,15 +947,18 @@ public class AiAttackController {
switch (this.aiAggression) {
case 6: // Exalted: expecting to at least kill a creature of equal value or not be blocked
if ((canKillAll && isWorthLessThanAllKillers) || !canBeBlocked) {
if ( LOG_AI_ATTACKS )
System.out.println(attacker.getName() + " = attacking expecting to kill creature, or is unblockable");
return true;
}
break;
case 5: // all out attacking
if ( LOG_AI_ATTACKS )
System.out.println(attacker.getName() + " = all out attacking");
return true;
case 4: // expecting to at least trade with something
if (canKillAll || (canKillAllDangerous && !canBeKilledByOne) || !canBeBlocked) {
if ( LOG_AI_ATTACKS )
System.out.println(attacker.getName() + " = attacking expecting to at least trade with something");
return true;
}
@@ -956,20 +968,22 @@ public class AiAttackController {
if ((canKillAll && isWorthLessThanAllKillers)
|| ((canKillAllDangerous || hasAttackEffect || hasCombatEffect) && !canBeKilledByOne)
|| !canBeBlocked) {
System.out.println(attacker.getName()
+ " = attacking expecting to kill creature or cause damage, or is unblockable");
if ( LOG_AI_ATTACKS )
System.out.println(attacker.getName() + " = attacking expecting to kill creature or cause damage, or is unblockable");
return true;
}
break;
case 2: // attack expecting to attract a group block or destroying a
// single blocker and surviving
if (((canKillAll || hasAttackEffect || hasCombatEffect) && !canBeKilledByOne) || !canBeBlocked) {
if ( LOG_AI_ATTACKS )
System.out.println(attacker.getName() + " = attacking expecting to survive or attract group block");
return true;
}
break;
case 1: // unblockable creatures only
if (!canBeBlocked || (numberOfPossibleBlockers == 1 && canKillAll && !canBeKilledByOne)) {
if ( LOG_AI_ATTACKS )
System.out.println(attacker.getName() + " = attacking expecting not to be blocked");
return true;
}

View File

@@ -13,6 +13,7 @@ import forge.game.GameType;
import forge.game.MatchController;
import forge.game.MatchStartHelper;
import forge.game.PlayerStartConditions;
import forge.game.player.LobbyPlayer;
import forge.gui.SOverlayUtils;
import forge.gui.framework.ICDoc;
import forge.properties.ForgePreferences;
@@ -96,14 +97,14 @@ public enum CSubmenuConstructed implements ICDoc {
* @param gameType
*/
private void startGame(final GameType gameType) {
PlayerStartConditions humanPsc = VSubmenuConstructed.SINGLETON_INSTANCE.getDcHuman().getDeck();
PlayerStartConditions humanPsc = view.getDcHuman().getDeck();
String humanDeckErrorMessage = gameType.getDecksFormat().getDeckConformanceProblem(humanPsc.getOriginalDeck());
if (null != humanDeckErrorMessage) {
JOptionPane.showMessageDialog(null, "Your deck " + humanDeckErrorMessage, "Invalid deck", JOptionPane.ERROR_MESSAGE);
return;
}
PlayerStartConditions aiDeck = VSubmenuConstructed.SINGLETON_INSTANCE.getDcAi().getDeck();
PlayerStartConditions aiDeck = view.getDcAi().getDeck();
String aiDeckErrorMessage = gameType.getDecksFormat().getDeckConformanceProblem(aiDeck.getOriginalDeck());
if (null != aiDeckErrorMessage) {
JOptionPane.showMessageDialog(null, "AI deck " + aiDeckErrorMessage, "Invalid deck", JOptionPane.ERROR_MESSAGE);
@@ -115,7 +116,8 @@ public enum CSubmenuConstructed implements ICDoc {
final MatchStartHelper starter = new MatchStartHelper();
Lobby lobby = Singletons.getControl().getLobby();
starter.addPlayer(lobby.getGuiPlayer(), humanPsc);
LobbyPlayer firstPlayer = view.getCbSpectate().isSelected() ? lobby.getAiPlayer() : lobby.getGuiPlayer();
starter.addPlayer(firstPlayer, humanPsc);
starter.addPlayer(lobby.getAiPlayer(), aiDeck);
final MatchController mc = new MatchController(gameType, starter.getPlayerMap());

View File

@@ -35,13 +35,14 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
/** */
private final LblHeader lblTitle = new LblHeader("Sanctioned Format: Constructed");
private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 2"));
private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 3"));
private final StartButton btnStart = new StartButton();
private final JCheckBox cbSingletons = new FCheckBox("Singleton Mode");
private final JCheckBox cbArtifacts = new FCheckBox("Remove Artifacts");
private final JCheckBox cbRemoveSmall = new FCheckBox("Remove Small Creatures");
private final JCheckBox cbAiVsAi = new FCheckBox("Spectate AI vs AI match");
private final FDeckChooser dcHuman = new FDeckChooser("Select your deck:", PlayerType.HUMAN);
private final FDeckChooser dcAi = new FDeckChooser("Select AI deck:", PlayerType.COMPUTER);
@@ -51,12 +52,15 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
lblTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
final String strCheckboxConstraints = "h 30px!, gap 0 20px 0 0";
final String strCheckboxConstraints = "pushy, gap 0 20px 0 0";
final String strCheckboxConstraintsTop = "pushy, gap 0 20px 20px 0";
pnlStart.setOpaque(false);
pnlStart.add(cbSingletons, strCheckboxConstraints);
pnlStart.add(btnStart, "span 1 3, growx, pushx, align center");
pnlStart.add(cbSingletons, strCheckboxConstraintsTop);
pnlStart.add(cbAiVsAi, strCheckboxConstraintsTop);
pnlStart.add(btnStart, "span 1 2, growx, pushx, align center");
pnlStart.add(cbArtifacts, strCheckboxConstraints);
pnlStart.add(cbRemoveSmall, strCheckboxConstraints);
}
/* (non-Javadoc)
@@ -106,7 +110,7 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
dcHuman.populate();
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(dcAi, "w 44%!, gap 0 0 20px 20px, growy, pushy");
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(dcHuman, "w 44%!, gap 4% 4% 20px 20px, growy, pushy");
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(pnlStart, "span 2, gap 0 0 3.5%! 3.5%!, ax center");
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(pnlStart, "span 2, gap 0 0 2.5%! 3.5%!, ax center");
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().revalidate();
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().repaintSelf();
@@ -134,6 +138,11 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
return cbRemoveSmall;
}
/** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbSpectate() {
return cbAiVsAi;
}
//========== Overridden from IVDoc
/* (non-Javadoc)

View File

@@ -18,11 +18,15 @@
package forge.gui.match;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import com.google.common.collect.Lists;
import forge.Card;
import forge.FThreads;
import forge.GameEntity;
@@ -87,28 +91,34 @@ public enum CMatchUI {
final List<VField> fields = new ArrayList<VField>();
final List<VCommand> commands = new ArrayList<VCommand>();
VField humanField = new VField(EDocID.valueOf("FIELD_0"), localPlayer, localPlayer);
VCommand humanCommand = new VCommand(EDocID.COMMAND_0, localPlayer);
fields.add(0, humanField);
commands.add(0, humanCommand);
setAvatar(humanField, new ImageIcon(FSkin.getAvatars().get(Integer.parseInt(indices[0]))));
humanField.getLayoutControl().initialize();
humanCommand.getLayoutControl().initialize();
List<Player> sortedPlayers = Lists.newArrayList(players);
int i = 1;
for (Player p : players) {
if (p.equals(localPlayer)) {
continue;
int ixLocal = -1;
for(int i = 0; i < players.size(); i++) {
if( sortedPlayers.get(i) == localPlayer ) {
ixLocal = i;
break;
}
}
if( ixLocal > 0 ) {
Player p0 = sortedPlayers.remove(ixLocal);
sortedPlayers.add(0, p0);
}
int i = 0;
for (Player p : sortedPlayers) {
// A field must be initialized after it's instantiated, to update player info.
// No player, no init.
VField f = new VField(EDocID.valueOf("FIELD_" + i), p, localPlayer);
setAvatar(f, getPlayerAvatar(p, Integer.parseInt(indices[1])));
f.getLayoutControl().initialize();
fields.add(f);
VCommand c = new VCommand(EDocID.valueOf("COMMAND_" + i), p);
c.getLayoutControl().initialize();
fields.add(f);
commands.add(c);
//setAvatar(f, new ImageIcon(FSkin.getAvatars().get()));
setAvatar(f, getPlayerAvatar(p, Integer.parseInt(indices[i > 2 ? 1 : 0])));
f.getLayoutControl().initialize();
c.getLayoutControl().initialize();
i++;
}

View File

@@ -78,6 +78,7 @@ public class CHand implements ICDoc {
if (initializedAlready) { return; }
initializedAlready = true;
if ( player != null)
player.getZone(ZoneType.Hand).addObserver(o1);
view.getHandArea().addMouseListener(madCardClick);

View File

@@ -58,8 +58,7 @@ public class VHand implements IVDoc<CHand> {
if (player0 == null) {
tab.setText("NO PLAYER Hand");
}
else {
} else {
tab.setText(player0.getName() + " Hand");
}