/**
*
*/
package cz.cuni.mff.abacs.burglar;
import cz.cuni.mff.abacs.burglar.logics.DataMap;
import cz.cuni.mff.abacs.burglar.logics.ExecutingMap;
import cz.cuni.mff.abacs.burglar.logics.planning.instructions.Instruction;
import cz.cuni.mff.abacs.burglar.logics.storage.XMLLoader;
import cz.cuni.mff.abacs.burglar.logics.storage.XMLSaver;
import cz.cuni.mff.abacs.burglar.visual.VisualBurglar;
import cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningListener;
import cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningThread;
import cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningThread.Type;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.List;
/**
* Runnable class for the level creation.
*
*
* @author abacs
*
*/
public class LevelGenerator implements PlanningListener {
// constants:
/** String representation of the input map parameter. */
private static final String STR_MAP = "-m";
/** String representation of the output level parameter. */
private static final String STR_LEVEL = "-l";
/** String representation of the number of traps parameter. */
private static final String STR_TRAPS = "-t";
/** String representation of the resource path parameter. */
private static final String STR_RESOURCES = "-resources";
/** The string printed to the user if the input parameters are invalid. */
private static final String STR_USAGE =
"level generator usage: \n" +
"\t-generator\tlevel generator\n" +
"\t[" + STR_MAP + " %s]\tinput xml file\n" +
"\t[" + STR_LEVEL + " %d]\toutput xml file\n" +
"\t[" + STR_TRAPS + " %d]\trequired number of traprooms\n" +
"\t[" + STR_RESOURCES + " %s]\tlocation of the resources directory (default is \"./resources/\")" +
"If there is no input file defined, the program uses standard input.\n" +
"If there is no output file defined, the program uses standard output." +
"If there is no defined number of required traps, the program" +
" looks for it in a map definition, if finds none, it creates no traps.";
// -------------------------------------------------------------------------
// variables:
/** The level representation. */
private ExecutingMap _map;
/** The thread building the user challenges. */
private PlanningThread _planningThread = null;
// -------------------------------------------------------------------------
// constructors:
protected LevelGenerator() { }
// -------------------------------------------------------------------------
// implementation:
/**
* Loads a map file.
*
* @param mapName path to the XML file
*/
protected void load(String mapName) {
this._map = XMLLoader.load(mapName);
}
/**
* Loads map from a stream.
*
* @param inputStream XML stream
*/
protected void load(InputStream inputStream) {
this._map = XMLLoader.load(inputStream);
}
/**
* Writes the level or map to a file with the selected name.
*
* @param levelName path to the output file
*/
protected void save(String levelName) {
XMLSaver.save(_map, levelName);
}
/**
* Writes the level or map to an out stream.
*
* @param outputStream
*/
protected void save(OutputStream outputStream) {
XMLSaver.save(_map, outputStream);
}
/**
* Starts the planning thread to generate the required number of traps.
*/
protected void startPlanning() {
// start placing guards on the map:
this._planningThread =
new PlanningThread(
this._map,
Type.SELECTING_TRAP_ROOMS,
this
);
this._planningThread.start();
}
/**
* Sets the required number of traps.
*
* @param number trap number
*/
protected void setRequiredNumberOfTraps(int number) {
this._map.setRequiredTrapRoomCount(number);
}
// -------------------------------------------------------------------------
// callbacks:
@Override
public void planningFinished(
List<Instruction> resultedInstructions,
PlanningThread thread
) {
// empty, not required
}
@Override
public void planningFinished(
List<Instruction> resultedInstructions,
List<Integer> avoidedTrapRooms,
PlanningThread thread
) {
// empty, not required
}
@Override
public void planningFinished(PlanningThread thread) {
// empty, not required
}
@Override
public void selectingTrapRoomsFinished(
List<Integer> trapRooms,
PlanningThread thread
) {
DataMap map = (DataMap)this._map;
List<List<Integer>> components = map.breakToComponents(trapRooms);
for(List<Integer> component : components){
if(component.size() > 1){
((ExecutingMap)map).addGuardPatrol(component);
}else{
map.addCameraToRoom(component.get(0));
}
}
// invalidates the planning thread pointer to show that
// the planning has finished
this._planningThread = null;
}
// -------------------------------------------------------------------------
/**
* Main function of the object.
*
* @param hasInputFile if true, we are using file input, otherwise stream.
* @param hasOutputFile if true, we are using file output, otherwise stream.
* @param hasRequiredNumber do we know how many traps to create.
* @param inputFile input file name, if exists
* @param outputFile output file name, if exists
* @param trapRoomNumber number of required traps
*/
public static void execute(
boolean hasInputFile,
boolean hasOutputFile,
boolean hasRequiredNumber,
String inputFile,
String outputFile,
int trapRoomNumber
) {
LevelGenerator generator = new LevelGenerator();
if(hasInputFile){
generator.load(inputFile);
}else{
generator.load(System.in);
}
if(hasRequiredNumber)
generator.setRequiredNumberOfTraps(trapRoomNumber);
generator.startPlanning();
while(generator._planningThread != null){
// TODO more sophisticated waiting
}
if(hasOutputFile){
generator.save(outputFile);
}else{
generator.save(System.out);
}
}
// -------------------------------------------------------------------------
/**
* The implicit inputs and outputs are standard input/output.
*
* arguments:
* "-m %s": input map name
* "-l %s": output level name
* "-t %d": required number of trap rooms
*/
public static void main(String[] args) {
boolean hasInputFile = false;
boolean hasOutputFile = false;
boolean hasRequiredNumber = false;
String inputFile = "";
String outputFile = "";
int trapRoomNumber = 0;
for(int index = 0; index < args.length; index++){
String value = args[index];
//
if(value.equals(STR_MAP)){
if(index + 1 < args.length){
hasInputFile = true;
inputFile = args[index + 1];
index++;
}else{
System.err.println(STR_USAGE);
System.exit(-1);
}
}
//
if(value.equals(STR_LEVEL)){
if(index + 1 < args.length){
hasOutputFile = true;
outputFile = args[index + 1];
index++;
}else{
System.err.println(STR_USAGE);
System.exit(-1);
}
}
//
if(value.equals(STR_TRAPS)){
if(index + 1 < args.length){
try{
trapRoomNumber = Integer.valueOf(args[index + 1]);
hasRequiredNumber = true;
}catch(Exception e){
System.err.println(STR_USAGE);
System.exit(-1);
}
index++;
}else{
System.err.println(STR_USAGE);
System.exit(-1);
}
}
//
if(value.equals(STR_RESOURCES)){
if(index + 1 < args.length){
VisualBurglar.changeResourcesPath(args[index + 1]);
index++;
}else{
System.err.println(STR_USAGE);
System.exit(-1);
}
}
}
// execute:
LevelGenerator.execute(
hasInputFile,
hasOutputFile,
hasRequiredNumber,
inputFile,
outputFile,
trapRoomNumber
);
System.exit(0);
}
}