package game;
import game.controllers.GhostController;
import game.controllers.Human;
import game.controllers.PacManController;
import game.core.G;
import game.core.GameView;
import game.core.Replay;
import game.core._G_;
import game.core._RG_;
import game.entries.ghosts.MyGhosts;
/*
* This class may be used to execute the game in timed or un-timed modes, with or without
* visuals. Competitors should implement their controllers in game.entries.ghosts and
* game.entries.pacman respectively. The skeleton classes are already provided. The package
* structure should not be changed (although you may create sub-packages in these packages).
*/
@SuppressWarnings("unused")
public class Exec
{
//Several options are listed - simply remove comments to use the option you want
public static void main(String[] args)
{
Exec exec=new Exec();
//this can be used for numerical testing (non-visual, no delays)
// exec.runExperiment(new RandomPacMan(),new AttractRepelGhosts(true),100);
//run game without time limits (un-comment if required)
// exec.runGame(new RandomPacMan(),new RandomGhosts(),true,G.DELAY);
//run game with time limits (un-comment if required)
// exec.runGameTimed(new Human(),new AttractRepelGhosts(true),true);
//run game with time limits. Here NearestPillPacManVS is chosen to illustrate how to use graphics for debugging/information purposes
exec.runGameTimed(new Human(), new MyGhosts(true), true);
//this allows you to record a game and replay it later. This could be very useful when
//running many games in non-visual mode - one can then pick out those that appear irregular
//and replay them in visual mode to see what is happening.
// exec.runGameTimedAndRecorded(new Human(),new AttractRepelGhosts(false),true,"human-v-Legacy2.txt");
// exec.replayGame("human-v-Legacy2.txt");
}
protected int pacDir;
protected int[] ghostDirs;
protected _G_ game;
protected PacMan pacMan;
protected Ghosts ghosts;
protected boolean pacmanPlayed,ghostsPlayed;
/*
* For running multiple games without visuals. This is useful to get a good idea of how well a controller plays
* against a chosen opponent: the random nature of the game means that performance can vary from game to game.
* Running many games and looking at the average score (and standard deviation/error) helps to get a better
* idea of how well the controller is likely to do in the competition.
*/
public void runExperiment(PacManController pacManController,GhostController ghostController,int trials)
{
double avgScore=0;
game=new _G_();
for(int i=0;i<trials;i++)
{
game.newGame();
while(!game.gameOver())
{
long due=System.currentTimeMillis()+G.DELAY;
game.advanceGame(pacManController.getAction(game.copy(),due),ghostController.getActions(game.copy(),due));
}
avgScore+=game.getScore();
System.out.println(game.getScore());
}
System.out.println(avgScore/trials);
}
/*
* Run game without time limit. Very good for testing as game progresses as soon as the controllers
* return their action(s). Can be played with and without visual display of game states. The delay
* is purely for visual purposes (as otherwise the game could be too fast if controllers compute quickly.
* For testing, this can be set to 0 for fasted game play.
*/
public void runGame(PacManController pacManController,GhostController ghostController,boolean visual,int delay)
{
game=new _G_();
game.newGame();
GameView gv=null;
if(visual)
gv=new GameView(game).showGame();
while(!game.gameOver())
{
long due=System.currentTimeMillis()+G.DELAY;
game.advanceGame(pacManController.getAction(game.copy(),due),ghostController.getActions(game.copy(),due));
try{Thread.sleep(delay);}catch(Exception e){}
if(visual)
gv.repaint();
}
}
/*
* Run game with time limit. This is how it will be done in the competition.
* Can be played with and without visual display of game states.
*/
public void runGameTimed(PacManController pacManController,GhostController ghostController,boolean visual)
{
game=new _G_();
game.newGame();
pacMan=new PacMan(pacManController);
ghosts=new Ghosts(ghostController);
GameView gv=null;
if(visual)
{
gv=new GameView(game).showGame();
if(pacManController instanceof Human)
gv.getFrame().addKeyListener((Human)pacManController);
}
while(!game.gameOver())
{
pacMan.alert();
ghosts.alert();
try
{
Thread.sleep(G.DELAY);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
game.advanceGame(pacDir,ghostDirs);
if(visual)
gv.repaint();
}
pacMan.kill();
ghosts.kill();
}
/*
* Runs a game and records all directions taken by all controllers - the data may then be used to replay any game saved using
* replayGame(-).
*/
public void runGameTimedAndRecorded(PacManController pacManController,GhostController ghostController,boolean visual,String fileName)
{
StringBuilder history=new StringBuilder();
int lastLevel=0;
boolean firstWrite=false; //this makes sure the content of any existing files is overwritten
game=new _G_();
game.newGame();
pacMan=new PacMan(pacManController);
ghosts=new Ghosts(ghostController);
GameView gv=null;
if(visual)
{
gv=new GameView(game).showGame();
if(pacManController instanceof Human)
gv.getFrame().addKeyListener((Human)pacManController);
}
while(!game.gameOver())
{
pacMan.alert();
ghosts.alert();
try
{
Thread.sleep(G.DELAY);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
int[] actionsTaken=game.advanceGame(pacDir,ghostDirs);
if(visual)
gv.repaint();
history=addActionsToString(history,actionsTaken,game.getCurLevel()==lastLevel);
//saves actions after every level
if(game.getCurLevel()!=lastLevel)
{
Replay.saveActions(history.toString(),fileName,firstWrite);
lastLevel=game.getCurLevel();
firstWrite=true;
history=new StringBuilder();
}
}
//save the final actions
Replay.saveActions(history.toString(),fileName,firstWrite);
pacMan.kill();
ghosts.kill();
}
/*
* This is used to replay a recorded game. The controllers are given by the class Replay which may
* also be used to load the actions from file.
*/
public void replayGame(String fileName)
{
_RG_ game=new _RG_();
game.newGame();
Replay replay=new Replay(fileName);
PacManController pacManController=replay.getPacMan();
GhostController ghostController=replay.getGhosts();
GameView gv=new GameView(game).showGame();
while(!game.gameOver())
{
game.advanceGame(pacManController.getAction(game.copy(),0),ghostController.getActions(game.copy(),0));
gv.repaint();
try{Thread.sleep(G.DELAY);}catch(Exception e){}
}
}
private StringBuilder addActionsToString(StringBuilder history,int[] actionsTaken,boolean newLine)
{
history.append((game.getTotalTime()-1)+"\t"+actionsTaken[0]+"\t");
for (int i=0;i<G.NUM_GHOSTS;i++)
history.append(actionsTaken[i+1]+"\t");
if(newLine)
history.append("\n");
return history;
}
//sets the latest direction to take for each game step (if controller replies in time)
public void setGhostDirs(int[] ghostDirs)
{
this.ghostDirs=ghostDirs;
this.ghostsPlayed=true;
}
//sets the latest direction to take for each game step (if controller replies in time)
public void setPacDir(int pacDir)
{
this.pacDir=pacDir;
this.pacmanPlayed=true;
}
/*
* Wraps the controller in a thread for the timed execution. This class then updates the
* directions for Exec to parse to the game.
*/
public class PacMan extends Thread
{
private PacManController pacMan;
private boolean alive;
public PacMan(PacManController pacMan)
{
this.pacMan=pacMan;
alive=true;
start();
}
public synchronized void kill()
{
alive=false;
notify();
}
public synchronized void alert()
{
notify();
}
public synchronized void run()
{
while(alive)
{
try
{
synchronized(this)
{
wait();
}
setPacDir(pacMan.getAction(game.copy(),System.currentTimeMillis()+G.DELAY));
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
/*
* Wraps the controller in a thread for the timed execution. This class then updates the
* directions for Exec to parse to the game.
*/
public class Ghosts extends Thread
{
private GhostController ghosts;
private boolean alive;
public Ghosts(GhostController ghosts)
{
this.ghosts=ghosts;
alive=true;
start();
}
public synchronized void kill()
{
alive=false;
notify();
}
public synchronized void alert()
{
notify();
}
public synchronized void run()
{
while(alive)
{
try
{
synchronized(this)
{
wait();
}
setGhostDirs(ghosts.getActions(game.copy(),System.currentTimeMillis()+G.DELAY));
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}