package rts;
import gui.PhysicalGameStatePanel;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.JFrame;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import rts.units.UnitDefinitionManager;
import ai.AI;
/**
* \package rts
* \brief The RTS game engine
*/
/**
* \brief Used to set up and run games between agents.
* @author Jeff Bernard
*
*/
public class Game {
public static final int FOLLOW_ALL_TEAMS = -1;
public GameState gs; /**< the current game state */
public PhysicalGameState pgs; /**< the current physical game state */
private ArrayList<AI> agents; /**< the ai agents playing the game */
private int turn_length; /**< how long (msec) a cycle should last */
private int max_game_cycles; /**< maximum number of cycles a game should be */
public int cycle;
static private UnitDefinitionManager unit_definitions; /**< the unit definitions for each player */
private String level_xml;
private String game_xml;
/**
* Loads the physical game state from XML
* @param xml XML map file
* @param gameXML game definition XML file
* @param turn_time turn time limit in milliseconds
* @param cycles max number of game cycles
*/
public Game(String xml, String gameXML, int turn_time, int cycles) {
level_xml = xml;
game_xml = gameXML;
agents = new ArrayList<AI>();
resetGame();
turn_length = turn_time;
max_game_cycles = cycles;
}
/**
* Clones the game state so you can run simulations
* @param state the state you are cloning
* @param start_player id of the player who should start first
* @param turn_time milliseconds per turn
* @param cycles max number of cycles to run
*/
public Game(GameState state, int start_player, int turn_time, int cycles) {
turn_length = turn_time;
max_game_cycles = cycles;
agents = new ArrayList<AI>();
pgs = new PhysicalGameState(start_player, state, unit_definitions);
gs = new GameState(pgs);
}
/**
* Adds an AI to control a player
* @param agent
*/
public void addAgent(AI agent) {
agents.add(agent);
}
/**
* Gets an agent
* @param i index of the agent
* @return null or the agent
*/
public AI getAgent(int i) {
if (i < 0 || i >= agents.size()) {
return null;
}
return agents.get(i);
}
/**
* Resets the game (keeping the same players and game)
*/
public void resetGame() {
try {
unit_definitions = new UnitDefinitionManager(new SAXBuilder().build(game_xml).getRootElement());
pgs = new PhysicalGameState(new SAXBuilder().build(level_xml).getRootElement(), unit_definitions);
} catch (JDOMException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
gs = new GameState(pgs);
ArrayList<AI> ais = new ArrayList<AI>();
for (int i = 0; i < agents.size(); i++) {
try {
ais.add(agents.get(i).getClass().newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
agents = ais;
}
/**
* Resets the players
*/
public void resetPlayers() {
agents.clear();
}
/**
* Players the game (no visualization)
* @param fog whether or not to play the game with fog of war
* @return the winner(s) (empty on draw)
*/
public ArrayList<Integer> play(boolean fog) {
if (agents.size() != pgs.numberOfPlayers()) {
System.out.println("Not the right number of players. Expected "+pgs.numberOfPlayers()+" but got "+agents.size()+" players");
return new ArrayList<Integer>();
}
pgs.fog = fog;
boolean gameover = false;
cycle = 0;
do {
for (int i = 0; i < agents.size(); i++) {
// update GS here
pgs.setCurrentPlayer(i);
gs.update();
// ...
pgs.setTimeLimit(System.currentTimeMillis()+turn_length);
agents.get(i).getAction(gs, turn_length);
}
// simulate:
gameover = pgs.cycle();
cycle++;
}while(!gameover && cycle < max_game_cycles);
int winner = pgs.winner();
if (winner == -1) {
winner = pgs.winnerByScore();
}
if (winner != -1) {
return pgs.teams.get(winner);
}
return new ArrayList<Integer>();
}
/**
* Plays the game, displaying a visualization
* @param frame_height
* @param fog whether or not the play the game with fog of war
* @param show_fog whether or not to render fog in the visualization
* @param team the team to follow
* @return the winners (empty on draw)
*/
public ArrayList<Integer> playVisual(int frame_height, boolean fog, boolean show_fog, int team) {
if (agents.size() != pgs.numberOfPlayers()) {
System.out.println("Not the right number of players. Expected "+pgs.numberOfPlayers()+" but got "+agents.size()+" players");
return new ArrayList<Integer>();
}
pgs.fog = fog;
JFrame window = PhysicalGameStatePanel.newVisualizer(this, frame_height, show_fog, team);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
boolean gameover = false;
cycle = 0;
long cycle_end = System.currentTimeMillis()+turn_length;
do{
if (System.currentTimeMillis() >= cycle_end) {
for (int i = 0; i < agents.size(); i++) {
// update GS here
pgs.setCurrentPlayer(i);
gs.update();
// ...
pgs.setTimeLimit(System.currentTimeMillis()+turn_length);
agents.get(i).getAction(gs, turn_length);
}
// simulate:
gameover = pgs.cycle();
window.repaint();
cycle_end += turn_length;
cycle++;
} else {
try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}while(!gameover && cycle < max_game_cycles);
int winner = pgs.winner();
if (winner == -1) {
winner = pgs.winnerByScore();
}
if (winner != -1) {
return pgs.teams.get(winner);
}
return new ArrayList<Integer>();
}
}