Skip to content
13 changes: 13 additions & 0 deletions src/main/java/dk/sdu/mmmi/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import dk.sdu.mmmi.modulemon.Collision.CollisionProcessing;
import dk.sdu.mmmi.modulemon.CustomBattleView.CustomBattleView;
import dk.sdu.mmmi.modulemon.Game;
import dk.sdu.mmmi.modulemon.HeadlessBattleView.HeadlessBattleView;
import dk.sdu.mmmi.modulemon.Interaction.InteractProcessing;
import dk.sdu.mmmi.modulemon.MCTSBattleAI.MCTSBattleAIFactory;
import dk.sdu.mmmi.modulemon.Map.MapView;
Expand Down Expand Up @@ -33,6 +34,8 @@ public static void main(String[] args) throws IOException, URISyntaxException {

var battleAI = new dk.sdu.mmmi.modulemon.BattleAI.BattleAIFactory();
battleAI.setSettingsService(settings);
var nonAlphaBetaBattleAI = new dk.sdu.mmmi.modulemon.BattleAI.NoABBattleAIFactory();
nonAlphaBetaBattleAI.setSettingsService(settings);
var mctsBattleAI = new MCTSBattleAIFactory();
mctsBattleAI.setSettingsService(settings);
var simpleBattleAI = new dk.sdu.mmmi.modulemon.SimpleAI.BattleAIFactory(); // Uncomment for Simple AI
Expand All @@ -54,6 +57,15 @@ public static void main(String[] args) throws IOException, URISyntaxException {
customBattle.addBattleAI(battleAI);
customBattle.addBattleAI(mctsBattleAI);
customBattle.addBattleAI(simpleBattleAI);
customBattle.addBattleAI(nonAlphaBetaBattleAI);

var headlessBattle = new HeadlessBattleView();
headlessBattle.setSettings(settings);
headlessBattle.addBattleAI(battleAI);
headlessBattle.addBattleAI(mctsBattleAI);
headlessBattle.addBattleAI(simpleBattleAI);
headlessBattle.addBattleAI(nonAlphaBetaBattleAI);
headlessBattle.setMonsterRegistry(monsterRegistry);


// Map stuff
Expand Down Expand Up @@ -91,6 +103,7 @@ public static void main(String[] args) throws IOException, URISyntaxException {
game.setSettingsService(settings);
game.addGameViewServiceList(battle);
game.addGameViewServiceList(customBattle);
game.addGameViewServiceList(headlessBattle);
game.addGameViewServiceList(map);
}
}
13 changes: 13 additions & 0 deletions src/main/java/dk/sdu/mmmi/modulemon/BattleAI/BattleAI.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ public class BattleAI implements IBattleAI {
private int defaultTimeLimitms = 1000;
private IGameSettings settings = null;

public BattleAI(IBattleSimulation battleSimulation, IBattleParticipant participant, IGameSettings settings, boolean useAlphaBeta){
var enableKnowlegdeStates = (Boolean) settings.getSetting(SettingsRegistry.getInstance().getAIKnowlegdeStateEnabled());
System.out.println(String.format("Minimax AI using knowledge states: %b", enableKnowlegdeStates));
knowledgeState = new KnowledgeState(!enableKnowlegdeStates);
this.participantToControl = participant;
this.opposingParticipant = participantToControl == battleSimulation.getState().getPlayer()
? battleSimulation.getState().getEnemy()
: battleSimulation.getState().getPlayer();
this.battleSimulation = battleSimulation;
defaultUseAlphaBetaPruning = useAlphaBeta;
defaultTimeLimitms = (Integer) settings.getSetting(SettingsRegistry.getInstance().getAIProcessingTimeSetting());
}



public BattleAI(IBattleSimulation battleSimulation, IBattleParticipant participantToControl, IGameSettings settings) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dk.sdu.mmmi.modulemon.BattleAI;

import dk.sdu.mmmi.modulemon.CommonBattle.IBattleParticipant;
import dk.sdu.mmmi.modulemon.CommonBattleSimulation.IBattleAI;
import dk.sdu.mmmi.modulemon.CommonBattleSimulation.IBattleAIFactory;
import dk.sdu.mmmi.modulemon.CommonBattleSimulation.IBattleSimulation;
import dk.sdu.mmmi.modulemon.common.SettingsRegistry;
import dk.sdu.mmmi.modulemon.common.services.IGameSettings;

public class NoABBattleAIFactory implements IBattleAIFactory {
private IGameSettings settings = null;

public NoABBattleAIFactory() {

}

@Override
public IBattleAI getBattleAI(IBattleSimulation battleSimulation, IBattleParticipant participantToControl) {
return new BattleAI(battleSimulation, participantToControl, this.settings, false);
}

public void setSettingsService(IGameSettings settings) {
System.out.println("Settings injected into AIFactory");
this.settings = settings;
if (settings.getSetting(SettingsRegistry.getInstance().getAIProcessingTimeSetting())==null) {
settings.setSetting(SettingsRegistry.getInstance().getAIProcessingTimeSetting(), 1000);
}
if (settings.getSetting(SettingsRegistry.getInstance().getAIAlphaBetaSetting())==null) {
settings.setSetting(SettingsRegistry.getInstance().getAIAlphaBetaSetting(), true);
}
}

public void removeSettingsService(IGameSettings settings) {
this.settings = null;
}

@Override
public String toString() {
return "Minimax -AB";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ public class BattleResult implements IBattleResult {
private IBattleParticipant player;
private IBattleParticipant enemy;
private int turnCount;
private IBattleParticipant starter;

public BattleResult(IBattleParticipant winner, IBattleParticipant player, IBattleParticipant enemy, int turnCount) {
public BattleResult(IBattleParticipant winner, IBattleParticipant player, IBattleParticipant enemy, IBattleParticipant starter, int turnCount) {
this.winner = winner;
this.player = player;
this.enemy = enemy;
this.starter = starter;
this.turnCount = turnCount;
}

Expand All @@ -31,8 +33,14 @@ public IBattleParticipant getEnemy() {
return enemy;
}

@Override
public IBattleParticipant getStarter() {
return starter;
}

@Override
public int getTurns() {
return turnCount;
}

}
12 changes: 11 additions & 1 deletion src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,17 @@ public void forceBattleEnd() {

public void handleBattleEnd(VictoryBattleEvent victoryBattleEvent) {
if (_battleCallback != null) {
_battleCallback.onBattleEnd(new BattleResult(victoryBattleEvent.getWinner(), _battleSimulation.getState().getPlayer(), _battleSimulation.getState().getEnemy(), _numTurns));
var starter = _battleSimulation.playerStarted()
? _battleSimulation.getState().getPlayer()
: _battleSimulation.getState().getEnemy();
var result = new BattleResult(
victoryBattleEvent.getWinner(),
_battleSimulation.getState().getPlayer(),
_battleSimulation.getState().getEnemy(),
starter,
_numTurns
);
_battleCallback.onBattleEnd(result);
} else {
gameViewManager.setDefaultView();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@
import dk.sdu.mmmi.modulemon.CommonMonster.IMonsterMove;

import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BattleSimulation implements IBattleSimulation {

private BattleState battleState;

private IBattleEvent nextEvent;
private Runnable onNextEvent;

private IBattleAI opponentAI;
private IBattleAIFactory opponentAIFactory;
private IBattleAI playerAI;
private IBattleAIFactory playerAIFactory;
private IBattleMonsterProcessor monsterProcessor;

private ExecutorService AIExecutor = Executors.newFixedThreadPool(1);
private boolean playerStarted;

@Override
public void StartBattle(IBattleParticipant player, IBattleParticipant enemy) {
Expand Down Expand Up @@ -51,8 +49,15 @@ public void StartBattle(IBattleParticipant player, IBattleParticipant enemy) {
}

// Assign first turn
IMonster firstMonster = monsterProcessor.whichMonsterStarts(player.getActiveMonster(), enemy.getActiveMonster());
IMonster firstMonster;
if(this.playerAIFactory != null && player.getActiveMonster().getName().equals(enemy.getActiveMonster().getName())){
Random rand = new Random();
firstMonster = rand.nextFloat() > 0.5 ? player.getActiveMonster() : enemy.getActiveMonster();
} else {
firstMonster = monsterProcessor.whichMonsterStarts(player.getActiveMonster(), enemy.getActiveMonster());
}
IBattleParticipant firstToTakeTurn = firstMonster == player.getActiveMonster() ? player : enemy;
this.playerStarted = firstMonster == player.getActiveMonster();

this.battleState = new BattleState(player, enemy);
this.battleState.setActiveParticipant(firstToTakeTurn);
Expand Down Expand Up @@ -337,6 +342,11 @@ public IBattleAIFactory getPlayerAIFactory() {
return playerAIFactory;
}

@Override
public boolean playerStarted() {
return this.playerStarted;
}

@Override
public boolean isPlayerControlledByAI() {
return this.playerAIFactory != null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public interface IBattleResult {
IBattleParticipant getWinner();
IBattleParticipant getPlayer();
IBattleParticipant getEnemy();
IBattleParticipant getStarter();
int getTurns();

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ public interface IBattleSimulation {
IBattleAIFactory getOpponentAIFactory();
void setPlayerAIFactory(IBattleAIFactory BattleAIFactory);
IBattleAIFactory getPlayerAIFactory();
boolean playerStarted();
}
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ private int getGridAdjustedCursor(int cursorPosition) {
}

private IBattleAIFactory getSelectedAI(Integer index) {
if (index == null) {
if (index == null || battleAIFactoryList.size() == 0) {
return null;
}
return this.battleAIFactoryList.get(index % battleAIFactoryList.size());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package dk.sdu.mmmi.modulemon.HeadlessBattleView;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import dk.sdu.mmmi.modulemon.Game;
import dk.sdu.mmmi.modulemon.common.data.GameData;
import dk.sdu.mmmi.modulemon.common.drawing.TextUtils;
import dk.sdu.mmmi.modulemon.common.services.IGameSettings;

public class HeadlessBattleScene {
private SpriteBatch spriteBatch;
public static final Color SelectColor = Color.valueOf("2a75bb");
private Color startColor = Color.WHITE;
private Color amountColor = Color.WHITE;
private String[] teams = {"Team A", "Team B"};
private String teamAAIText = "";
private String teamBAIText = "";
private int teamIndex = -1;
private int AIIndex = -1;
private int battleAmount = -1;
private boolean choosing = false;

public HeadlessBattleScene(IGameSettings settings) {
spriteBatch = new SpriteBatch();
}

private static TextUtils text = TextUtils.getInstance();

public void draw(GameData gameData) {
var screenWidth = gameData.getDisplayWidth();
var screenHeight = gameData.getDisplayHeight();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.setProjectionMatrix(Game.cam.combined);
spriteBatch.begin();

text.setCoordinateMode(TextUtils.CoordinateMode.CENTER);
final int textTopMargin = 60;
text.drawTitleFont(spriteBatch, "Simulate Battles", Color.valueOf("ffcb05"), gameData.getDisplayWidth() / 2f, gameData.getDisplayHeight() - textTopMargin);
text.setCoordinateMode(TextUtils.CoordinateMode.TOP_LEFT); // Reset
spriteBatch.end();

spriteBatch.begin();
text.setCoordinateMode(TextUtils.CoordinateMode.BOTTOM_RIGHT);
int textGap = 75;
int leftOffset = 150;
int topOffset = 50;

for (var i = 0; i < teams.length; i++) {
var teamTextColor = teamIndex == i ? SelectColor : Color.WHITE;
var AITextColor = AIIndex == i ? SelectColor : Color.WHITE;
var yPos = ((screenHeight / 2f) + topOffset) - i * textGap;
var AIText = i == 0 ? teamAAIText : teamBAIText;
text.setCoordinateMode(TextUtils.CoordinateMode.BOTTOM_RIGHT);
text.drawBigBoldRoboto(spriteBatch, teams[i], teamTextColor, screenWidth / 2f, yPos);
text.setCoordinateMode(TextUtils.CoordinateMode.CENTER);
var textHeight = 15;
text.drawNormalBoldRoboto(spriteBatch, AIText, AITextColor, screenWidth / 2f + leftOffset, yPos + textHeight);
if (choosing && AIIndex == i) {
var arrowSpacingFromEdge = 20;
var textLength = 220;
var horizontalOffset = 260;
text.drawNormalRoboto(spriteBatch, "<", Color.WHITE, screenWidth / 2f + horizontalOffset + arrowSpacingFromEdge - textLength, yPos + textHeight);
text.drawNormalRoboto(spriteBatch, ">", Color.WHITE, screenWidth / 2f + horizontalOffset - arrowSpacingFromEdge, yPos + textHeight);
}
}
text.setCoordinateMode(TextUtils.CoordinateMode.BOTTOM_RIGHT);
var amountHeight = (screenHeight / 2f) - 100;
text.drawNormalBoldRoboto(spriteBatch, "Battle amount:", choosing ? Color.WHITE : amountColor, screenWidth / 2f, amountHeight);
text.setCoordinateMode(TextUtils.CoordinateMode.CENTER);
var textHeight = 7.5f;
if (choosing && AIIndex == -1) {
var arrowSpacingFromEdge = 20;
var textLength = 125;
var horizontalOffset = 212.5f;
text.drawNormalRoboto(spriteBatch, "<", Color.WHITE, screenWidth / 2f + horizontalOffset + arrowSpacingFromEdge - textLength, amountHeight + textHeight);
text.drawNormalRoboto(spriteBatch, ">", Color.WHITE, screenWidth / 2f + horizontalOffset - arrowSpacingFromEdge, amountHeight + textHeight);
}
text.drawNormalBoldRoboto(spriteBatch, String.valueOf(battleAmount), choosing ? amountColor : Color.WHITE, screenWidth / 2f + leftOffset, amountHeight + textHeight);
text.setCoordinateMode(TextUtils.CoordinateMode.CENTER);
text.drawBigBoldRoboto(spriteBatch, "Start", startColor, screenWidth / 2f, (screenHeight / 2f) - 200);
text.setCoordinateMode(TextUtils.CoordinateMode.TOP_LEFT);
spriteBatch.end();

}

public void setStartColor(Color startColor) {
this.startColor = startColor;
}

public void setTeamIndex(int teamIndex) {
this.teamIndex = teamIndex;
}

public void setAIIndex(int AIIndex) {
this.AIIndex = AIIndex;
}

public void setAmountColor(Color amountColor) {
this.amountColor = amountColor;
}

public void setTeamAAIText(String teamAAIText) {
this.teamAAIText = teamAAIText;
}

public void setTeamBAIText(String teamBAIText) {
this.teamBAIText = teamBAIText;
}

public void setChoosing(boolean choosing) {
this.choosing = choosing;
}

public void setBattleAmount(int battleAmount) {
this.battleAmount = battleAmount;
}
}
Loading