From ab10b57f0f5acc57eef5d8345e2c866caf50f6c8 Mon Sep 17 00:00:00 2001 From: diegopliebana <4TiMebos> Date: Thu, 30 Mar 2017 12:01:17 +0100 Subject: [PATCH] .DS_Store out --- .gitignore | 1 + src/core/game/BasicGame.java | 450 +- src/core/game/ForwardModel.java | 2 +- src/core/game/Game.java | 4230 ++++++++--------- src/core/game/GameDescription.java | 816 ++-- src/core/game/SLDescription.java | 622 +-- src/core/logging/Logger.java | 56 +- src/core/logging/Message.java | 20 +- src/core/termination/SpriteCounter.java | 16 +- src/core/termination/SpriteCounterMore.java | 14 +- src/core/vgdl/Node.java | 4 +- src/core/vgdl/VGDLParser.java | 1126 ++--- src/ontology/effects/binary/Align.java | 8 +- .../effects/binary/BounceForward.java | 10 +- src/ontology/effects/binary/PullWithIt.java | 16 +- src/tools/LevelAnalyzer.java | 842 ++-- src/tracks/ruleGeneration/RuleGenMachine.java | 702 +-- .../ruleGeneration/TestRuleGeneration.java | 2 +- .../RuleGenerator.java | 966 ++-- .../randomRuleGenerator/RuleGenerator.java | 292 +- src/tracks/singlePlayer/Test.java | 6 +- 21 files changed, 5101 insertions(+), 5100 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..e43b0f9889 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/src/core/game/BasicGame.java b/src/core/game/BasicGame.java index ac6edf027d..cabbd378af 100644 --- a/src/core/game/BasicGame.java +++ b/src/core/game/BasicGame.java @@ -20,251 +20,251 @@ */ public class BasicGame extends Game { - /** - * Allows definition of sprite size from the VGDL description. If indicated, - * super.block_size is set to this variable. square_size should be divisible - * by all speeds in the game definition. - */ - public int square_size; - - /** - * List of sprites that should not be traversable for the pathfinder. This - * list can be specified with sprite string identifiers separated by commas. - */ - public String obs; - - // List of IDs of the sprites should not be traversable for the pathfinder. - private ArrayList obstacles; - - /** - * Default constructor for a basic game. - * - * @param content - * Contains parameters for the game. - */ - public BasicGame(GameContent content) { - super(); - - // Add here whatever mappings are common for all BasicGames. - charMapping.put('w', new ArrayList()); - charMapping.get('w').add("wall"); - - charMapping.put('A', new ArrayList()); - charMapping.get('A').add("avatar"); - - // Default values for frame rate and maximum number of sprites allowed. - square_size = -1; - MAX_SPRITES = 10000; - - // Parse the arguments. - this.parseParameters(content); - } - - /** - * Builds a level, receiving a file name. - * - * @param gamelvl - * file name containing the level. - */ - public void buildLevel(String gamelvl, int randomSeed) { - String[] lines = new IO().readFile(gamelvl); - - // Pathfinder - obstacles = new ArrayList<>(); - boolean doPathf = false; - - if (obs != null) { - doPathf = true; - int obsArray[] = VGDLRegistry.GetInstance().explode(obs); - for (Integer it : obsArray) - obstacles.add(it); + /** + * Allows definition of sprite size from the VGDL description. If indicated, + * super.block_size is set to this variable. square_size should be divisible + * by all speeds in the game definition. + */ + public int square_size; + + /** + * List of sprites that should not be traversable for the pathfinder. This + * list can be specified with sprite string identifiers separated by commas. + */ + public String obs; + + // List of IDs of the sprites should not be traversable for the pathfinder. + private ArrayList obstacles; + + /** + * Default constructor for a basic game. + * + * @param content + * Contains parameters for the game. + */ + public BasicGame(GameContent content) { + super(); + + // Add here whatever mappings are common for all BasicGames. + charMapping.put('w', new ArrayList()); + charMapping.get('w').add("wall"); + + charMapping.put('A', new ArrayList()); + charMapping.get('A').add("avatar"); + + // Default values for frame rate and maximum number of sprites allowed. + square_size = -1; + MAX_SPRITES = 10000; + + // Parse the arguments. + this.parseParameters(content); } - if (doPathf) - pathf = new PathFinder(obstacles); + /** + * Builds a level, receiving a file name. + * + * @param gamelvl + * file name containing the level. + */ + public void buildLevel(String gamelvl, int randomSeed) { + String[] lines = new IO().readFile(gamelvl); + + // Pathfinder + obstacles = new ArrayList<>(); + boolean doPathf = false; + + if (obs != null) { + doPathf = true; + int obsArray[] = VGDLRegistry.GetInstance().explode(obs); + for (Integer it : obsArray) + obstacles.add(it); + } - buildStringLevel(lines, randomSeed); + if (doPathf) + pathf = new PathFinder(obstacles); - if (doPathf) { - long t = System.currentTimeMillis(); + buildStringLevel(lines, randomSeed); - pathf.run(this.getObservation()); - System.out.println(System.currentTimeMillis() - t); - } - } - - @Override - /** - * Builds a level from this game, reading it from file. - * - * @param gamelvl - * filename of the level to load. - */ - public void buildStringLevel(String[] lines, int randomSeed) { - // Read the level description - String[] desc_lines = lines; - - // Dimensions of the level read from the file. - size.width = desc_lines[0].length(); - size.height = desc_lines.length; - - if (square_size != -1) { - block_size = square_size; - } else { - block_size = Math.max(2, (int) 800.0 / Math.max(size.width, size.height)); - } - screenSize = new Dimension(size.width * block_size, size.height * block_size); - - for (int i = 0; i < size.height; ++i) { - String line = desc_lines[i]; - if (line.length() < size.width) { - // This might happen. We just concat ' ' until size. - desc_lines[i] = completeLine(line, size.width - line.length(), " "); - } + if (doPathf) { + long t = System.currentTimeMillis(); + + pathf.run(this.getObservation()); + System.out.println(System.currentTimeMillis() - t); + } } - ArrayList avatars = new ArrayList(); - // All sprites are created and placed here: - for (int i = 0; i < size.height; ++i) { - String line = desc_lines[i]; - - // For each character - for (int j = 0; j < size.width; ++j) { - Character c = line.charAt(j); - - // If this character is defined in the array of mappings. - if (charMapping.containsKey(c)) { - for (String obj : charMapping.get(c)) { - int similarTiles = 0; - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { - if (Math.abs(x) != Math.abs(y) - && (j + x >= 0 && j + x < size.width && i + y >= 0 && i + y < size.height)) { - if (charMapping.containsKey(desc_lines[i + y].charAt(j + x))) { - ArrayList neighborTiles = charMapping - .get(desc_lines[i + y].charAt(j + x)); - if (neighborTiles.contains(obj)) { - similarTiles += Math.floor(Math.abs(x) * (x + 3) / 2) - + Math.abs(y) * (y + 3) * 2; + @Override + /** + * Builds a level from this game, reading it from file. + * + * @param gamelvl + * filename of the level to load. + */ + public void buildStringLevel(String[] lines, int randomSeed) { + // Read the level description + String[] desc_lines = lines; + + // Dimensions of the level read from the file. + size.width = desc_lines[0].length(); + size.height = desc_lines.length; + + if (square_size != -1) { + block_size = square_size; + } else { + block_size = Math.max(2, (int) 800.0 / Math.max(size.width, size.height)); + } + screenSize = new Dimension(size.width * block_size, size.height * block_size); + + for (int i = 0; i < size.height; ++i) { + String line = desc_lines[i]; + if (line.length() < size.width) { + // This might happen. We just concat ' ' until size. + desc_lines[i] = completeLine(line, size.width - line.length(), " "); + } + } + + ArrayList avatars = new ArrayList(); + // All sprites are created and placed here: + for (int i = 0; i < size.height; ++i) { + String line = desc_lines[i]; + + // For each character + for (int j = 0; j < size.width; ++j) { + Character c = line.charAt(j); + + // If this character is defined in the array of mappings. + if (charMapping.containsKey(c)) { + for (String obj : charMapping.get(c)) { + int similarTiles = 0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + if (Math.abs(x) != Math.abs(y) + && (j + x >= 0 && j + x < size.width && i + y >= 0 && i + y < size.height)) { + if (charMapping.containsKey(desc_lines[i + y].charAt(j + x))) { + ArrayList neighborTiles = charMapping + .get(desc_lines[i + y].charAt(j + x)); + if (neighborTiles.contains(obj)) { + similarTiles += Math.floor(Math.abs(x) * (x + 3) / 2) + + Math.abs(y) * (y + 3) * 2; + } + } + } + } + } + + // Get its position and add it to the game. + Vector2d position = new Vector2d(j * block_size, i * block_size); + VGDLSprite s = addSpriteIn(obj, position); + if(s == null){ + continue; + } + if (s.is_avatar) { + avatars.add(s); + } + if (s.autotiling) { + s.image = s.allImages.get(similarTiles); + } + if (s.randomtiling >= 0) { + Random random = new Random(randomSeed); + if (random.nextDouble() > s.randomtiling && s.allImages.size() > 0) { + s.image = s.allImages.get(random.nextInt(s.allImages.size())); + } + } } - } } - } + else if(c != ' '){ + Logger.getInstance().addMessage(new Message(Message.WARNING, "\"" + c + "\" isnot defined in the level mapping.")); + } } + } - // Get its position and add it to the game. - Vector2d position = new Vector2d(j * block_size, i * block_size); - VGDLSprite s = addSpriteIn(obj, position); - if(s == null){ - continue; - } - if (s.is_avatar) { - avatars.add(s); - } - if (s.autotiling) { - s.image = s.allImages.get(similarTiles); - } - if (s.randomtiling >= 0) { - Random random = new Random(randomSeed); - if (random.nextDouble() > s.randomtiling && s.allImages.size() > 0) { - s.image = s.allImages.get(random.nextInt(s.allImages.size())); - } + if (avatars.size() > no_players) { + Logger.getInstance().addMessage(new Message(Message.WARNING, + "No more than " + no_players + " avatar(s) allowed (Others are destroyed).")); + for(int i=0; i(); + + // Generate the initial state observation. + this.createAvatars(-1); + this.initForwardModel(); } - if (avatars.size() > no_players) { - Logger.getInstance().addMessage(new Message(Message.WARNING, - "No more than " + no_players + " avatar(s) allowed (Others are destroyed).")); - for(int i=0; i(); - - // Generate the initial state observation. - this.createAvatars(-1); - this.initForwardModel(); - } - - /** - * Reads the parameters of a game type. - * - * @param content - * list of parameter-value pairs. - */ - protected void parseParameters(GameContent content) { - super.parseParameters(content); - - VGDLFactory factory = VGDLFactory.GetInstance(); - Class refClass = VGDLFactory.registeredGames.get(content.referenceClass); - // System.out.println("refClass" + refClass.toString()); - if (!this.getClass().equals(refClass)) { - System.out.println("Error: Game subclass instance not the same as content.referenceClass" + " " - + this.getClass() + " " + refClass); - return; + /** + * Adds one sprites in the position indicated. + * + * @param key + * sprite type to add. + * @param position + * position where the sprite will be placed + */ + public VGDLSprite addSpriteIn(String key, Vector2d position) { + int itype = VGDLRegistry.GetInstance().getRegisteredSpriteValue(key); + return addSprite(itype, position); + } + + /** + * Adds all sprites that 'c' represents in the position indicated. + * + * @param keys + * List of sprite types to add. + * @param position + * position where all these sprites will be placed. + */ + public void addSpritesIn(ArrayList keys, Vector2d position) { + // We might have more than one sprite in the same position. + for (String objectType : keys) { + addSpriteIn(objectType, position); + } } - factory.parseParameters(content, this); - } - - @Override - public boolean isGameOver() { - return false; - } - - /** - * Adds one sprites in the position indicated. - * - * @param key - * sprite type to add. - * @param position - * position where the sprite will be placed - */ - public VGDLSprite addSpriteIn(String key, Vector2d position) { - int itype = VGDLRegistry.GetInstance().getRegisteredSpriteValue(key); - return addSprite(itype, position); - } - - /** - * Adds all sprites that 'c' represents in the position indicated. - * - * @param keys - * List of sprite types to add. - * @param position - * position where all these sprites will be placed. - */ - public void addSpritesIn(ArrayList keys, Vector2d position) { - // We might have more than one sprite in the same position. - for (String objectType : keys) { - addSpriteIn(objectType, position); + /** + * Takes a line and concats filler as many times as specified. + * + * @param base + * initial string. + * @param occurrences + * how many times filler is appended + * @param filler + * string to append occurrences times to base. + * @return the resultant string. + */ + private String completeLine(String base, int occurrences, String filler) { + for (int i = 0; i < occurrences; ++i) + base = base.concat(filler); + return base; } - } - - /** - * Takes a line and concats filler as many times as specified. - * - * @param base - * initial string. - * @param occurrences - * how many times filler is appended - * @param filler - * string to append occurrences times to base. - * @return the resultant string. - */ - private String completeLine(String base, int occurrences, String filler) { - for (int i = 0; i < occurrences; ++i) - base = base.concat(filler); - return base; - } } diff --git a/src/core/game/ForwardModel.java b/src/core/game/ForwardModel.java index 8b815244c8..69a7862a3e 100644 --- a/src/core/game/ForwardModel.java +++ b/src/core/game/ForwardModel.java @@ -456,7 +456,7 @@ private void initNonVolatile(Game a_gameState) this.avatars = new MovingAvatar[no_players]; for (int i = 0; i < no_players; i++) { if(a_gameState.avatars[i] != null){ - avatars[i] = (MovingAvatar) a_gameState.avatars[i].copy(); + avatars[i] = (MovingAvatar) a_gameState.avatars[i].copy(); avatars[i].setKeyHandler(a_gameState.avatars[i].getKeyHandler()); } } diff --git a/src/core/game/Game.java b/src/core/game/Game.java index 4dc6a70aa1..d573b8c9a5 100755 --- a/src/core/game/Game.java +++ b/src/core/game/Game.java @@ -39,2163 +39,2163 @@ */ public abstract class Game { - /** - * z-level of sprite types (in case of overlap) - */ - protected int[] spriteOrder; - - /** - * Singletons of the game. - */ - protected boolean[] singletons; - - /** - * Content objects for the different sprite types.. The index is the type of - * object Content encloses information about the class of the object and its - * parameters. - */ - protected Content[] classConst; - - /** - * Parameters for a Game Space. Unused in normal games. - */ - public HashMap parameters; - - /** - * List of template sprites, one for each object in the above "classConst" - * array. - */ - protected VGDLSprite[] templateSprites; - - /** - * Groups of sprites in the level. Each element of the array is a collection - * of sprites of a given type, which is also the index of the array. - */ - protected SpriteGroup[] spriteGroups; - - /** - * Relationships for collisions: double array of (list of) effects. - * Interaction between two sprites can trigger more than one effect. - * collisionEffects[] -> int id of the FIRST element taking part on the - * effects. collisionEffects[][] -> int id of the SECOND element taking part - * on the effects. - * - */ - protected ArrayList[][] collisionEffects; - - /** - * Pairs of all defined effects in the game. - */ - protected ArrayList> definedEffects; - - /** - * List of EOS effects - */ - protected ArrayList[] eosEffects; - - /** - * List of TIME effects - */ - protected TreeSet timeEffects; - - /** - * List of types that can trigger an EOS effect. - */ - protected ArrayList definedEOSEffects; - - /** - * Historic of events related to the avatar happened during the game. The - * entries are ordered asc. by game step. - */ - protected TreeSet historicEvents; - - /** - * For each entry, int identifier of sprite type, a list with all the itypes - * this sprite belongs to. - */ - protected ArrayList[] iSubTypes; - - /** - * For each entry, int identifier of sprite type, a list with all the itypes - * this sprite belongs to. - */ - protected ArrayList>[] shieldedEffects; - - /** - * Arraylist to hold collisions between objects in every frame - */ - protected Bucket[] bucketList; - - /** - * Mapping between characters in the level and the entities they represent. - */ - protected HashMap> charMapping; - - /** - * Termination set conditions to finish the game. - */ - protected ArrayList terminations; - - /** - * List of sprites killed in the game. - */ - public ArrayList kill_list; - - /** - * Limit number of each resource type - */ - protected int[] resources_limits; - - /** - * Color for each resource - */ - protected Color[] resources_colors; - - /** - * Screen size. - */ - protected Dimension screenSize; - - /** - * Dimensions of the game. - */ - protected Dimension size; - - /** - * Indicates if the game is stochastic. - */ - protected boolean is_stochastic; - - /** - * Number of sprites this game has. - */ - protected int num_sprites; - - /** - * Game tick - */ - protected int gameTick; - - /** - * Handling when the window is closed - */ - public static WindowInput wi = new WindowInput(); - - /** - * Size of the block in pixels. - */ - protected int block_size = 10; - - /** - * Quick reference to the gamer - */ - protected MovingAvatar[] avatars; - - /** - * Indicates if the game is ended. - */ - protected boolean isEnded; - - /** - * State observation for this game. - */ - protected ForwardModel fwdModel; - - /** - * Maximum number of sprites in a game. - */ - protected static int MAX_SPRITES; - - /** - * Random number generator for this game. It can only be received when the - * game is started. - */ - private Random random; - - /** - * Id of the sprite type "avatar". - */ - private int avatarId; - - /** - * Id of the sprite type "wall". - */ - private int wallId; - - /** - * Flag that can only be set to true externally. If true, the agent is - * disqualified. - */ - private boolean disqualified; - - /** - * Next ID to generate for sprites; - */ - protected int nextSpriteID; - - /** - * Key Handler for human play. The default is - * CompetitionParameters.KEY_INPUT - */ - public String key_handler; - - /** - * Pathfinder. - */ - protected PathFinder pathf; - - /** - * Avatars last actions. Array for all avatars in the game. Index in array - * corresponds to playerID. - */ - protected Types.ACTIONS[] avatarLastAction; - - public int no_players = 1; // default to single player - - public int no_counters = 0; // default no counters - public int[] counter; - - public static KeyHandler ki; - - /** - * Default constructor. - */ - public Game() { - // data structures to hold the game definition. - definedEffects = new ArrayList>(); - definedEOSEffects = new ArrayList(); - charMapping = new HashMap>(); - terminations = new ArrayList(); - historicEvents = new TreeSet(); - timeEffects = new TreeSet(); - - // Game attributes: - size = new Dimension(); - is_stochastic = false; - disqualified = false; - num_sprites = 0; - nextSpriteID = 0; - - loadDefaultConstr(); - } - - /** - * Loads the constructor information for default objects (walls, avatar). - */ - public void loadDefaultConstr() { - // If more elements are added here, initSprites() must be modified - // accordingly! - VGDLRegistry.GetInstance().registerSprite("wall"); - VGDLRegistry.GetInstance().registerSprite("avatar"); - } - - /** - * Initialisation after the game is parsed. - */ - public void initMulti() { - avatars = new MovingAvatar[no_players]; - avatarLastAction = new Types.ACTIONS[no_players]; - for (int i = 0; i < no_players; i++) - avatarLastAction[i] = Types.ACTIONS.ACTION_NIL; - - counter = new int[no_counters]; - } - - /** - * Modify the sprite order for the renderer of the GVG-AI - * @param spOrder the request order - */ - public void changeSpriteOrder(ArrayList spOrder){ - spriteOrder = new int[spOrder.size()]; - // We need here the default 2 sprites: - avatarId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("avatar"); - wallId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("wall"); - - // 1. "avatar" ALWAYS at the end of the array. - for (int i = 0; i < no_players; i++) { - spriteOrder[spriteOrder.length - 1 - i] = avatarId; - } - // 2. Other sprite types are sorted using spOrder - int i = 0; - for (Integer intId : spOrder) { - if (intId != avatarId) { - spriteOrder[i++] = intId; - } - } - } - - /** - * Initializes the sprite structures that hold the game. - * - * @param spOrder - * order of sprite types to be drawn on the screen. - * @param sings - * sprites that are marked as singletons. - * @param constructors - * map of sprite constructor's information. - */ - public void initSprites(ArrayList spOrder, ArrayList sings, - HashMap constructors) { - ArrayList resources = new ArrayList(); - - // We need here the default 2 sprites: - avatarId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("avatar"); - wallId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("wall"); - - // Initialize the sprite render order. - this.changeSpriteOrder(spOrder); - - // Singletons - singletons = new boolean[VGDLRegistry.GetInstance().numSpriteTypes()]; - for (Integer intId : sings) { - singletons[intId] = true; - } - - // Constructors, as many as number of sprite types, so they are accessed - // by its id: - classConst = new Content[VGDLRegistry.GetInstance().numSpriteTypes()]; - templateSprites = new VGDLSprite[classConst.length]; - - // By default, we have 2 constructors: - Content wallConst = new SpriteContent("wall", "Immovable"); - wallConst.parameters.put("color", "DARKGRAY"); - ((SpriteContent) wallConst).itypes.add(wallId); - classConst[wallId] = wallConst; - - Content avatarConst = new SpriteContent("avatar", "MovingAvatar"); - ((SpriteContent) avatarConst).itypes.add(avatarId); - classConst[avatarId] = avatarConst; - - // Now, the other constructors. - Set> entries = constructors.entrySet(); - for (Map.Entry entry : entries) { - classConst[entry.getKey()] = entry.getValue(); - - // Special case: we create a dummy Resource sprite of each resource - // type. - String refClass = entry.getValue().referenceClass; - if (refClass != null && refClass.equals("Resource")) { - VGDLSprite resourceTest = VGDLFactory.GetInstance().createSprite(this, entry.getValue(), - new Vector2d(0, 0), new Dimension(1, 1)); - resources.add((Resource) resourceTest); - } - } - - // Structures to hold game sprites, as many as number of sprite types, - // so they are accessed by its id: - spriteGroups = new SpriteGroup[classConst.length]; - shieldedEffects = new ArrayList[classConst.length]; - collisionEffects = new ArrayList[classConst.length][classConst.length]; - eosEffects = new ArrayList[classConst.length]; - iSubTypes = new ArrayList[classConst.length]; - bucketList = new Bucket[classConst.length]; - resources_limits = new int[classConst.length]; - resources_colors = new Color[classConst.length]; - - // For each sprite type... - for (int j = 0; j < spriteGroups.length; ++j) { - // Create the space for the sprites and effects of this type. - spriteGroups[j] = new SpriteGroup(j); - shieldedEffects[j] = new ArrayList<>(); - eosEffects[j] = new ArrayList(); - timeEffects = new TreeSet(); - bucketList[j] = new Bucket(); - - // Declare the extended types list of this sprite type. - iSubTypes[j] = (ArrayList) ((SpriteContent) classConst[j]).subtypes.clone(); - - for (int k = 0; k < spriteGroups.length; ++k) { - // Create the array list of collision effects for each pair of - // sprite types. - collisionEffects[j][k] = new ArrayList(); - } - - } - - // Add walls and avatars to the subtypes list. - if (!iSubTypes[wallId].contains(wallId)) - iSubTypes[wallId].add(wallId); - - if (!iSubTypes[avatarId].contains(avatarId)) - iSubTypes[avatarId].add(avatarId); - - // Resources: use the list of resources created before to store limit - // and color of each resource. - for (int i = 0; i < resources.size(); ++i) { - Resource r = resources.get(i); - resources_limits[r.resource_type] = r.limit; - resources_colors[r.resource_type] = r.color; - } - } - - /** - * Check if the current itype has no children nodes - * - * @param itype - * sprite index - * @return true if its lead node, false otherwise - */ - private boolean isLeafNode(int itype) { - SpriteContent sc = (SpriteContent) classConst[itype]; - - return sc.subtypes.size() <= 1 || sc.subtypes.get(sc.subtypes.size() - 1) == itype; - } - - /** - * Get all parent sprites for a certain sprite - * - * @param itype - * id for the current node - * @return a list of all parent nodes' ids - */ - private ArrayList parentNodes(int itype) { - SpriteContent sc = (SpriteContent) classConst[itype]; - - ArrayList parents = new ArrayList(); - parents.addAll(sc.itypes); - parents.remove(parents.size() - 1); - - return parents; - } - - /** - * Expand a non leaf node using its children - * - * @param itype - * sprite index - * @return a list of all leaf children under the hierarchy of itype sprite - */ - private ArrayList expandNonLeafNode(int itype) { - ArrayList result = new ArrayList(); - boolean[] visited = new boolean[classConst.length]; - ArrayList queue = new ArrayList(); - queue.add(itype); - - while (!queue.isEmpty()) { - int current = queue.remove(0); - if (visited[current]) { - continue; - } - - if (isLeafNode(current)) { - result.add(VGDLRegistry.GetInstance().getRegisteredSpriteKey(current)); - } else { - SpriteContent sc = (SpriteContent) classConst[current]; - queue.addAll(sc.subtypes); - } - visited[current] = true; - } - - return result; - } - - /** - * Method used to access the number of players in a game. - * - * @return number of players. - */ - public int getNoPlayers() { - return no_players; - } - - public int getNoCounters() { - return no_counters; - } - - public int getValueCounter(int idx) { - return counter[idx]; - } - - /** - * return sprite type of certain sprite - * - * @param sp - * sprite object - * @return sprite type (avatar, resource, portal, npc, static, moving) - */ - private int getSpriteCategory(VGDLSprite sp) { - if (sp.is_avatar) - return Types.TYPE_AVATAR; - - // Is it a resource? - if (sp.is_resource) - return Types.TYPE_RESOURCE; - - // Is it a portal? - if (sp.portal) - return Types.TYPE_PORTAL; - - // Is it npc? - if (sp.is_npc) - return Types.TYPE_NPC; - - // Is it immovable? - if (sp.is_static) - return Types.TYPE_STATIC; - - // is it created by the avatar? - if (sp.is_from_avatar) - return Types.TYPE_FROMAVATAR; - - return Types.TYPE_MOVABLE; - } - - /** - * Convert a sprite content object to Sprite Data object - * - * @param sc - * sprite content object for a certain sprite - * @return sprite data object for the current sprite content - */ - private SpriteData initializeSpriteData(SpriteContent sc) { - SpriteData data = new SpriteData(sc.parameters); - data.name = sc.identifier; - data.type = sc.referenceClass; - - VGDLSprite sprite = VGDLFactory.GetInstance().createSprite(this, sc, new Vector2d(), new Dimension(1, 1)); - switch (getSpriteCategory(sprite)) { - case Types.TYPE_NPC: - data.isNPC = true; - break; - case Types.TYPE_AVATAR: - data.isAvatar = true; - break; - case Types.TYPE_PORTAL: - data.isPortal = true; - break; - case Types.TYPE_RESOURCE: - data.isResource = true; - break; - case Types.TYPE_STATIC: - data.isStatic = true; - break; - } - - ArrayList dependentSprites = sprite.getDependentSprites(); - for (String s : dependentSprites) { - ArrayList expandedSprites = expandNonLeafNode( - VGDLRegistry.GetInstance().getRegisteredSpriteValue(s)); - data.sprites.addAll(expandedSprites); - } - - return data; - } - - /** - * Get an array of sprite data objects for all leaf sprite nodes. - * - * @return Array of sprite data - */ - public ArrayList getSpriteData() { - ArrayList result = new ArrayList(); - - for (int i = 0; i < classConst.length; i++) { - SpriteContent sc = (SpriteContent) classConst[i]; - if (isLeafNode(i)) { - result.add(initializeSpriteData(sc)); - } - } - - return result; - } - - /** - * Construct and return a temporary avatar sprite - * - * @return a temproary avatar sprite - */ - public VGDLSprite getTempAvatar(SpriteData sprite) { - avatarId = VGDLRegistry.GetInstance().getRegisteredSpriteValue(sprite.name); - if (((SpriteContent) classConst[avatarId]).referenceClass != null) { - VGDLSprite result = VGDLFactory.GetInstance().createSprite(this, (SpriteContent) classConst[avatarId], - new Vector2d(), new Dimension(1, 1)); - if (result != null) { + /** + * z-level of sprite types (in case of overlap) + */ + protected int[] spriteOrder; + + /** + * Singletons of the game. + */ + protected boolean[] singletons; + + /** + * Content objects for the different sprite types.. The index is the type of + * object Content encloses information about the class of the object and its + * parameters. + */ + protected Content[] classConst; + + /** + * Parameters for a Game Space. Unused in normal games. + */ + public HashMap parameters; + + /** + * List of template sprites, one for each object in the above "classConst" + * array. + */ + protected VGDLSprite[] templateSprites; + + /** + * Groups of sprites in the level. Each element of the array is a collection + * of sprites of a given type, which is also the index of the array. + */ + protected SpriteGroup[] spriteGroups; + + /** + * Relationships for collisions: double array of (list of) effects. + * Interaction between two sprites can trigger more than one effect. + * collisionEffects[] -> int id of the FIRST element taking part on the + * effects. collisionEffects[][] -> int id of the SECOND element taking part + * on the effects. + * + */ + protected ArrayList[][] collisionEffects; + + /** + * Pairs of all defined effects in the game. + */ + protected ArrayList> definedEffects; + + /** + * List of EOS effects + */ + protected ArrayList[] eosEffects; + + /** + * List of TIME effects + */ + protected TreeSet timeEffects; + + /** + * List of types that can trigger an EOS effect. + */ + protected ArrayList definedEOSEffects; + + /** + * Historic of events related to the avatar happened during the game. The + * entries are ordered asc. by game step. + */ + protected TreeSet historicEvents; + + /** + * For each entry, int identifier of sprite type, a list with all the itypes + * this sprite belongs to. + */ + protected ArrayList[] iSubTypes; + + /** + * For each entry, int identifier of sprite type, a list with all the itypes + * this sprite belongs to. + */ + protected ArrayList>[] shieldedEffects; + + /** + * Arraylist to hold collisions between objects in every frame + */ + protected Bucket[] bucketList; + + /** + * Mapping between characters in the level and the entities they represent. + */ + protected HashMap> charMapping; + + /** + * Termination set conditions to finish the game. + */ + protected ArrayList terminations; + + /** + * List of sprites killed in the game. + */ + public ArrayList kill_list; + + /** + * Limit number of each resource type + */ + protected int[] resources_limits; + + /** + * Color for each resource + */ + protected Color[] resources_colors; + + /** + * Screen size. + */ + protected Dimension screenSize; + + /** + * Dimensions of the game. + */ + protected Dimension size; + + /** + * Indicates if the game is stochastic. + */ + protected boolean is_stochastic; + + /** + * Number of sprites this game has. + */ + protected int num_sprites; + + /** + * Game tick + */ + protected int gameTick; + + /** + * Handling when the window is closed + */ + public static WindowInput wi = new WindowInput(); + + /** + * Size of the block in pixels. + */ + protected int block_size = 10; + + /** + * Quick reference to the gamer + */ + protected MovingAvatar[] avatars; + + /** + * Indicates if the game is ended. + */ + protected boolean isEnded; + + /** + * State observation for this game. + */ + protected ForwardModel fwdModel; + + /** + * Maximum number of sprites in a game. + */ + protected static int MAX_SPRITES; + + /** + * Random number generator for this game. It can only be received when the + * game is started. + */ + private Random random; + + /** + * Id of the sprite type "avatar". + */ + private int avatarId; + + /** + * Id of the sprite type "wall". + */ + private int wallId; + + /** + * Flag that can only be set to true externally. If true, the agent is + * disqualified. + */ + private boolean disqualified; + + /** + * Next ID to generate for sprites; + */ + protected int nextSpriteID; + + /** + * Key Handler for human play. The default is + * CompetitionParameters.KEY_INPUT + */ + public String key_handler; + + /** + * Pathfinder. + */ + protected PathFinder pathf; + + /** + * Avatars last actions. Array for all avatars in the game. Index in array + * corresponds to playerID. + */ + protected Types.ACTIONS[] avatarLastAction; + + public int no_players = 1; // default to single player + + public int no_counters = 0; // default no counters + public int[] counter; + + public static KeyHandler ki; + + /** + * Default constructor. + */ + public Game() { + // data structures to hold the game definition. + definedEffects = new ArrayList>(); + definedEOSEffects = new ArrayList(); + charMapping = new HashMap>(); + terminations = new ArrayList(); + historicEvents = new TreeSet(); + timeEffects = new TreeSet(); + + // Game attributes: + size = new Dimension(); + is_stochastic = false; + disqualified = false; + num_sprites = 0; + nextSpriteID = 0; + + loadDefaultConstr(); + } + + /** + * Loads the constructor information for default objects (walls, avatar). + */ + public void loadDefaultConstr() { + // If more elements are added here, initSprites() must be modified + // accordingly! + VGDLRegistry.GetInstance().registerSprite("wall"); + VGDLRegistry.GetInstance().registerSprite("avatar"); + } + + /** + * Initialisation after the game is parsed. + */ + public void initMulti() { + avatars = new MovingAvatar[no_players]; + avatarLastAction = new Types.ACTIONS[no_players]; + for (int i = 0; i < no_players; i++) + avatarLastAction[i] = Types.ACTIONS.ACTION_NIL; + + counter = new int[no_counters]; + } + + /** + * Modify the sprite order for the renderer of the GVG-AI + * @param spOrder the request order + */ + public void changeSpriteOrder(ArrayList spOrder){ + spriteOrder = new int[spOrder.size()]; + // We need here the default 2 sprites: + avatarId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("avatar"); + wallId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("wall"); + + // 1. "avatar" ALWAYS at the end of the array. + for (int i = 0; i < no_players; i++) { + spriteOrder[spriteOrder.length - 1 - i] = avatarId; + } + // 2. Other sprite types are sorted using spOrder + int i = 0; + for (Integer intId : spOrder) { + if (intId != avatarId) { + spriteOrder[i++] = intId; + } + } + } + + /** + * Initializes the sprite structures that hold the game. + * + * @param spOrder + * order of sprite types to be drawn on the screen. + * @param sings + * sprites that are marked as singletons. + * @param constructors + * map of sprite constructor's information. + */ + public void initSprites(ArrayList spOrder, ArrayList sings, + HashMap constructors) { + ArrayList resources = new ArrayList(); + + // We need here the default 2 sprites: + avatarId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("avatar"); + wallId = VGDLRegistry.GetInstance().getRegisteredSpriteValue("wall"); + + // Initialize the sprite render order. + this.changeSpriteOrder(spOrder); + + // Singletons + singletons = new boolean[VGDLRegistry.GetInstance().numSpriteTypes()]; + for (Integer intId : sings) { + singletons[intId] = true; + } + + // Constructors, as many as number of sprite types, so they are accessed + // by its id: + classConst = new Content[VGDLRegistry.GetInstance().numSpriteTypes()]; + templateSprites = new VGDLSprite[classConst.length]; + + // By default, we have 2 constructors: + Content wallConst = new SpriteContent("wall", "Immovable"); + wallConst.parameters.put("color", "DARKGRAY"); + ((SpriteContent) wallConst).itypes.add(wallId); + classConst[wallId] = wallConst; + + Content avatarConst = new SpriteContent("avatar", "MovingAvatar"); + ((SpriteContent) avatarConst).itypes.add(avatarId); + classConst[avatarId] = avatarConst; + + // Now, the other constructors. + Set> entries = constructors.entrySet(); + for (Map.Entry entry : entries) { + classConst[entry.getKey()] = entry.getValue(); + + // Special case: we create a dummy Resource sprite of each resource + // type. + String refClass = entry.getValue().referenceClass; + if (refClass != null && refClass.equals("Resource")) { + VGDLSprite resourceTest = VGDLFactory.GetInstance().createSprite(this, entry.getValue(), + new Vector2d(0, 0), new Dimension(1, 1)); + resources.add((Resource) resourceTest); + } + } + + // Structures to hold game sprites, as many as number of sprite types, + // so they are accessed by its id: + spriteGroups = new SpriteGroup[classConst.length]; + shieldedEffects = new ArrayList[classConst.length]; + collisionEffects = new ArrayList[classConst.length][classConst.length]; + eosEffects = new ArrayList[classConst.length]; + iSubTypes = new ArrayList[classConst.length]; + bucketList = new Bucket[classConst.length]; + resources_limits = new int[classConst.length]; + resources_colors = new Color[classConst.length]; + + // For each sprite type... + for (int j = 0; j < spriteGroups.length; ++j) { + // Create the space for the sprites and effects of this type. + spriteGroups[j] = new SpriteGroup(j); + shieldedEffects[j] = new ArrayList<>(); + eosEffects[j] = new ArrayList(); + timeEffects = new TreeSet(); + bucketList[j] = new Bucket(); + + // Declare the extended types list of this sprite type. + iSubTypes[j] = (ArrayList) ((SpriteContent) classConst[j]).subtypes.clone(); + + for (int k = 0; k < spriteGroups.length; ++k) { + // Create the array list of collision effects for each pair of + // sprite types. + collisionEffects[j][k] = new ArrayList(); + } + + } + + // Add walls and avatars to the subtypes list. + if (!iSubTypes[wallId].contains(wallId)) + iSubTypes[wallId].add(wallId); + + if (!iSubTypes[avatarId].contains(avatarId)) + iSubTypes[avatarId].add(avatarId); + + // Resources: use the list of resources created before to store limit + // and color of each resource. + for (int i = 0; i < resources.size(); ++i) { + Resource r = resources.get(i); + resources_limits[r.resource_type] = r.limit; + resources_colors[r.resource_type] = r.color; + } + } + + /** + * Check if the current itype has no children nodes + * + * @param itype + * sprite index + * @return true if its lead node, false otherwise + */ + private boolean isLeafNode(int itype) { + SpriteContent sc = (SpriteContent) classConst[itype]; + + return sc.subtypes.size() <= 1 || sc.subtypes.get(sc.subtypes.size() - 1) == itype; + } + + /** + * Get all parent sprites for a certain sprite + * + * @param itype + * id for the current node + * @return a list of all parent nodes' ids + */ + private ArrayList parentNodes(int itype) { + SpriteContent sc = (SpriteContent) classConst[itype]; + + ArrayList parents = new ArrayList(); + parents.addAll(sc.itypes); + parents.remove(parents.size() - 1); + + return parents; + } + + /** + * Expand a non leaf node using its children + * + * @param itype + * sprite index + * @return a list of all leaf children under the hierarchy of itype sprite + */ + private ArrayList expandNonLeafNode(int itype) { + ArrayList result = new ArrayList(); + boolean[] visited = new boolean[classConst.length]; + ArrayList queue = new ArrayList(); + queue.add(itype); + + while (!queue.isEmpty()) { + int current = queue.remove(0); + if (visited[current]) { + continue; + } + + if (isLeafNode(current)) { + result.add(VGDLRegistry.GetInstance().getRegisteredSpriteKey(current)); + } else { + SpriteContent sc = (SpriteContent) classConst[current]; + queue.addAll(sc.subtypes); + } + visited[current] = true; + } + return result; - } - } - - return null; - } - - /** - * Return an array of termination data objects. These objects represents the - * termination conditions for the game - * - * @return array of Termination Data objects - */ - public ArrayList getTerminationData() { - ArrayList result = new ArrayList(); - - TerminationData td; - for (Termination tr : terminations) { - td = new TerminationData(); - int lastDot = tr.getClass().getName().lastIndexOf('.'); - td.type = tr.getClass().getName().substring(lastDot + 1); - td.limit = tr.limit; - td.win = tr.win; - - ArrayList sprites = tr.getTerminationSprites(); - for (String s : sprites) { - int itype = VGDLRegistry.GetInstance().getRegisteredSpriteValue(s); - if (isLeafNode(itype)) { - td.sprites.add(s); - } else { - td.sprites.addAll(expandNonLeafNode(itype)); + } + + /** + * Method used to access the number of players in a game. + * + * @return number of players. + */ + public int getNoPlayers() { + return no_players; + } + + public int getNoCounters() { + return no_counters; + } + + public int getValueCounter(int idx) { + return counter[idx]; + } + + /** + * return sprite type of certain sprite + * + * @param sp + * sprite object + * @return sprite type (avatar, resource, portal, npc, static, moving) + */ + private int getSpriteCategory(VGDLSprite sp) { + if (sp.is_avatar) + return Types.TYPE_AVATAR; + + // Is it a resource? + if (sp.is_resource) + return Types.TYPE_RESOURCE; + + // Is it a portal? + if (sp.portal) + return Types.TYPE_PORTAL; + + // Is it npc? + if (sp.is_npc) + return Types.TYPE_NPC; + + // Is it immovable? + if (sp.is_static) + return Types.TYPE_STATIC; + + // is it created by the avatar? + if (sp.is_from_avatar) + return Types.TYPE_FROMAVATAR; + + return Types.TYPE_MOVABLE; + } + + /** + * Convert a sprite content object to Sprite Data object + * + * @param sc + * sprite content object for a certain sprite + * @return sprite data object for the current sprite content + */ + private SpriteData initializeSpriteData(SpriteContent sc) { + SpriteData data = new SpriteData(sc.parameters); + data.name = sc.identifier; + data.type = sc.referenceClass; + + VGDLSprite sprite = VGDLFactory.GetInstance().createSprite(this, sc, new Vector2d(), new Dimension(1, 1)); + switch (getSpriteCategory(sprite)) { + case Types.TYPE_NPC: + data.isNPC = true; + break; + case Types.TYPE_AVATAR: + data.isAvatar = true; + break; + case Types.TYPE_PORTAL: + data.isPortal = true; + break; + case Types.TYPE_RESOURCE: + data.isResource = true; + break; + case Types.TYPE_STATIC: + data.isStatic = true; + break; + } + + ArrayList dependentSprites = sprite.getDependentSprites(); + for (String s : dependentSprites) { + ArrayList expandedSprites = expandNonLeafNode( + VGDLRegistry.GetInstance().getRegisteredSpriteValue(s)); + data.sprites.addAll(expandedSprites); } - } - result.add(td); + return data; } - return result; - } + /** + * Get an array of sprite data objects for all leaf sprite nodes. + * + * @return Array of sprite data + */ + public ArrayList getSpriteData() { + ArrayList result = new ArrayList(); - /** - * Get a list of interaction data objects between two sprite types. These - * objects represents the effect happened to the first sprite type. - * - * @param itype1 - * The first sprite type object - * @param itype2 - * The second sprite type object - * @return array of interaction data objects. - */ - public ArrayList getInteractionData(int itype1, int itype2) { - ArrayList results = new ArrayList(); + for (int i = 0; i < classConst.length; i++) { + SpriteContent sc = (SpriteContent) classConst[i]; + if (isLeafNode(i)) { + result.add(initializeSpriteData(sc)); + } + } - ArrayList parent1 = new ArrayList(); - ArrayList parent2 = new ArrayList(); + return result; + } - if (itype1 != -1) { - parent1.addAll(parentNodes(itype1)); - parent1.add(itype1); + /** + * Construct and return a temporary avatar sprite + * + * @return a temproary avatar sprite + */ + public VGDLSprite getTempAvatar(SpriteData sprite) { + avatarId = VGDLRegistry.GetInstance().getRegisteredSpriteValue(sprite.name); + if (((SpriteContent) classConst[avatarId]).referenceClass != null) { + VGDLSprite result = VGDLFactory.GetInstance().createSprite(this, (SpriteContent) classConst[avatarId], + new Vector2d(), new Dimension(1, 1)); + if (result != null) { + return result; + } + } + + return null; + } + + /** + * Return an array of termination data objects. These objects represents the + * termination conditions for the game + * + * @return array of Termination Data objects + */ + public ArrayList getTerminationData() { + ArrayList result = new ArrayList(); + + TerminationData td; + for (Termination tr : terminations) { + td = new TerminationData(); + int lastDot = tr.getClass().getName().lastIndexOf('.'); + td.type = tr.getClass().getName().substring(lastDot + 1); + td.limit = tr.limit; + td.win = tr.win; + + ArrayList sprites = tr.getTerminationSprites(); + for (String s : sprites) { + int itype = VGDLRegistry.GetInstance().getRegisteredSpriteValue(s); + if (isLeafNode(itype)) { + td.sprites.add(s); + } else { + td.sprites.addAll(expandNonLeafNode(itype)); + } + } + + result.add(td); + } + + return result; } - if (itype2 != -1) { - parent2.addAll(parentNodes(itype2)); - parent2.add(itype2); + /** + * Get a list of interaction data objects between two sprite types. These + * objects represents the effect happened to the first sprite type. + * + * @param itype1 + * The first sprite type object + * @param itype2 + * The second sprite type object + * @return array of interaction data objects. + */ + public ArrayList getInteractionData(int itype1, int itype2) { + ArrayList results = new ArrayList(); + + ArrayList parent1 = new ArrayList(); + ArrayList parent2 = new ArrayList(); + + if (itype1 != -1) { + parent1.addAll(parentNodes(itype1)); + parent1.add(itype1); + } + + if (itype2 != -1) { + parent2.addAll(parentNodes(itype2)); + parent2.add(itype2); + } + + ArrayList effects = new ArrayList(); + if (parent1.size() > 0 && parent2.size() > 0) { + for (int p1 : parent1) { + for (int p2 : parent2) { + effects.addAll(getCollisionEffects(p1, p2)); + } + } + } else if (parent1.size() > 0) { + for (int p1 : parent1) { + effects.addAll(getEosEffects(p1)); + + } + } else if (parent2.size() > 0) { + for (int p2 : parent2) { + effects.addAll(getEosEffects(p2)); + } + } + + InteractionData temp; + for (Effect e : effects) { + temp = new InteractionData(); + temp.type = e.getClass().getName(); + temp.type = temp.type.substring(temp.type.lastIndexOf('.') + 1); + temp.scoreChange = e.scoreChange; + temp.sprites.addAll(e.getEffectSprites()); + + results.add(temp); + } + + return results; } - ArrayList effects = new ArrayList(); - if (parent1.size() > 0 && parent2.size() > 0) { - for (int p1 : parent1) { - for (int p2 : parent2) { - effects.addAll(getCollisionEffects(p1, p2)); + /** + * Sets the game back to the state prior to load a level. + */ + public void reset() { + num_sprites = 0; + + for (int i = 0; i < no_players; i++) { + avatars[i] = null; + } + for (int i = 0; i < no_counters; i++) { + counter[i] = 0; + } + isEnded = false; + gameTick = -1; + disqualified = false; + avatarLastAction = new Types.ACTIONS[no_players]; + for (int i = 0; i < no_players; i++) + avatarLastAction[i] = Types.ACTIONS.ACTION_NIL; + + // For each sprite type... + for (int i = 0; i < spriteGroups.length; ++i) { + // Create the space for the sprites and effects of this type. + spriteGroups[i].clear(); } - } - } else if (parent1.size() > 0) { - for (int p1 : parent1) { - effects.addAll(getEosEffects(p1)); - } - } else if (parent2.size() > 0) { - for (int p2 : parent2) { - effects.addAll(getEosEffects(p2)); - } + if (kill_list != null) { + kill_list.clear(); + } + for (int j = 0; j < spriteGroups.length; ++j) { + bucketList[j].clear(); + } + + for (int i = 0; i < templateSprites.length; ++i) { + templateSprites[i] = null; + } + + historicEvents.clear(); + + resetShieldEffects(); + } + + /** + * Starts the forward model for the game. + */ + public void initForwardModel() { + fwdModel = new ForwardModel(this); + fwdModel.update(this); + } + + /** + * Reads the parameters of a game type. + * + * @param content + * list of parameter-value pairs. + */ + protected void parseParameters(GameContent content) { + VGDLFactory factory = VGDLFactory.GetInstance(); + Class refClass = VGDLFactory.registeredGames.get(content.referenceClass); + // System.out.inn("refClass" + refClass.toString()); + if (!this.getClass().equals(refClass)) { + System.out.println("Error: Game subclass instance not the same as content.referenceClass" + " " + + this.getClass() + " " + refClass); + return; + } + + factory.parseParameters(content, this); + + // taking care of the key handler parameter: + + if (key_handler != null && key_handler.equalsIgnoreCase("Pulse")) + CompetitionParameters.KEY_HANDLER = CompetitionParameters.KEY_PULSE; + + ki = CompetitionParameters.KEY_HANDLER == CompetitionParameters.KEY_INPUT ? new KeyInput() + : new KeyPulse(no_players); } - InteractionData temp; - for (Effect e : effects) { - temp = new InteractionData(); - temp.type = e.getClass().getName(); - temp.type = temp.type.substring(temp.type.lastIndexOf('.') + 1); - temp.scoreChange = e.scoreChange; - temp.sprites.addAll(e.getEffectSprites()); + /** + * Adds a new sprite to the pool of sprites of the game. Increments the + * sprite counter and also modifies is_stochastic and the avatar + * accordingly. + * + * @param sprite + * the new sprite to add. + * @param itype + * main int type of this sprite (leaf of the hierarchy of types). + */ + protected void addSprite(VGDLSprite sprite, int itype) { + sprite.spriteID = nextSpriteID; + spriteGroups[itype].addSprite(nextSpriteID++, sprite); + num_sprites++; + + if (sprite.is_stochastic) + this.is_stochastic = true; - results.add(temp); + if (itype == wallId) { + sprite.loadImage("wall.png"); + } else if (itype == avatarId) { + sprite.loadImage("avatar.png"); + } } - return results; - } + /** + * Returns the number of sprites of the type given by parameter, and all its + * subtypes + * + * @param itype + * parent itype requested. + * @return the number of sprites of the type and subtypes. + */ + public int getNumSprites(int itype) { + int acum = 0; + for (Integer subtype : this.iSubTypes[itype]) { + acum += spriteGroups[subtype].numSprites(); + } + return acum; + } + + /** + * Returns an arraylist of subtypes of the given parent type. + * + * @param itype + * parent itype requested. + */ + public ArrayList getSubTypes(int itype) { + return this.iSubTypes[itype]; + } + + /** + * Returns the number of sprites disabled of the type given by parameter and + * all its subtypes + * + * @param itype + * parent itype requested. + * @return the number of disabled sprites of the type and subtypes. + */ + public int getNumDisabledSprites(int itype) { + int acum = 0; + for (Integer subtype : this.iSubTypes[itype]) { + acum += spriteGroups[subtype].numDisabledSprites(); + } + return acum; + } + + /** + * Runs a game, without graphics. + * + * @param players + * Players that play this game. + * @param randomSeed + * sampleRandom seed for the whole game. + * @return the score of the game played. + */ + public double[] runGame(Player[] players, int randomSeed) { + // Prepare some structures and references for this game. + prepareGame(players, randomSeed, -1); + + // Play until the game is ended + while (!isEnded) { + this.gameCycle(); // Execute a game cycle. + } - /** - * Sets the game back to the state prior to load a level. - */ - public void reset() { - num_sprites = 0; + // Update the forward model for the game state sent to the controller. + fwdModel.update(this); + + return handleResult(); + } + + /** + * Plays the game, graphics enabled. + * + * @param players + * Players that play this game. + * @param randomSeed + * sampleRandom seed for the whole game. + * @param isHuman + * indicates if a human is playing the game. + * @param humanID + * ID of the human player + * @return the score of the game played. + */ + + public double[] playGame(Player[] players, int randomSeed, boolean isHuman, int humanID) { + // Prepare some structures and references for this game. + prepareGame(players, randomSeed, humanID); + + // Create and initialize the panel for the graphics. + VGDLViewer view = new VGDLViewer(this, players[humanID]); + JEasyFrame frame; + frame = new JEasyFrame(view, "Java-VGDL"); + + frame.addKeyListener(ki); + frame.addWindowListener(wi); + wi.windowClosed = false; + + // Determine the delay for playing with a good fps. + double delay = CompetitionParameters.LONG_DELAY; + for (Player player : players) + if (player instanceof tracks.singlePlayer.tools.human.Agent) { + delay = 1000.0 / CompetitionParameters.DELAY; // in milliseconds + break; + } - for (int i = 0; i < no_players; i++) { - avatars[i] = null; - } - for (int i = 0; i < no_counters; i++) { - counter[i] = 0; - } - isEnded = false; - gameTick = -1; - disqualified = false; - avatarLastAction = new Types.ACTIONS[no_players]; - for (int i = 0; i < no_players; i++) - avatarLastAction[i] = Types.ACTIONS.ACTION_NIL; - - // For each sprite type... - for (int i = 0; i < spriteGroups.length; ++i) { - // Create the space for the sprites and effects of this type. - spriteGroups[i].clear(); - } - - if (kill_list != null) { - kill_list.clear(); - } - for (int j = 0; j < spriteGroups.length; ++j) { - bucketList[j].clear(); - } - - for (int i = 0; i < templateSprites.length; ++i) { - templateSprites[i] = null; - } - - historicEvents.clear(); - - resetShieldEffects(); - } - - /** - * Starts the forward model for the game. - */ - public void initForwardModel() { - fwdModel = new ForwardModel(this); - fwdModel.update(this); - } - - /** - * Reads the parameters of a game type. - * - * @param content - * list of parameter-value pairs. - */ - protected void parseParameters(GameContent content) { - VGDLFactory factory = VGDLFactory.GetInstance(); - Class refClass = VGDLFactory.registeredGames.get(content.referenceClass); - // System.out.inn("refClass" + refClass.toString()); - if (!this.getClass().equals(refClass)) { - System.out.println("Error: Game subclass instance not the same as content.referenceClass" + " " - + this.getClass() + " " + refClass); - return; - } - - factory.parseParameters(content, this); - - // taking care of the key handler parameter: - - if (key_handler != null && key_handler.equalsIgnoreCase("Pulse")) - CompetitionParameters.KEY_HANDLER = CompetitionParameters.KEY_PULSE; - - ki = CompetitionParameters.KEY_HANDLER == CompetitionParameters.KEY_INPUT ? new KeyInput() - : new KeyPulse(no_players); - } - - /** - * Adds a new sprite to the pool of sprites of the game. Increments the - * sprite counter and also modifies is_stochastic and the avatar - * accordingly. - * - * @param sprite - * the new sprite to add. - * @param itype - * main int type of this sprite (leaf of the hierarchy of types). - */ - protected void addSprite(VGDLSprite sprite, int itype) { - sprite.spriteID = nextSpriteID; - spriteGroups[itype].addSprite(nextSpriteID++, sprite); - num_sprites++; - - if (sprite.is_stochastic) - this.is_stochastic = true; - - if (itype == wallId) { - sprite.loadImage("wall.png"); - } else if (itype == avatarId) { - sprite.loadImage("avatar.png"); - } - } - - /** - * Returns the number of sprites of the type given by parameter, and all its - * subtypes - * - * @param itype - * parent itype requested. - * @return the number of sprites of the type and subtypes. - */ - public int getNumSprites(int itype) { - int acum = 0; - for (Integer subtype : this.iSubTypes[itype]) { - acum += spriteGroups[subtype].numSprites(); - } - return acum; - } - - /** - * Returns an arraylist of subtypes of the given parent type. - * - * @param itype - * parent itype requested. - */ - public ArrayList getSubTypes(int itype) { - return this.iSubTypes[itype]; - } - - /** - * Returns the number of sprites disabled of the type given by parameter and - * all its subtypes - * - * @param itype - * parent itype requested. - * @return the number of disabled sprites of the type and subtypes. - */ - public int getNumDisabledSprites(int itype) { - int acum = 0; - for (Integer subtype : this.iSubTypes[itype]) { - acum += spriteGroups[subtype].numDisabledSprites(); - } - return acum; - } - - /** - * Runs a game, without graphics. - * - * @param players - * Players that play this game. - * @param randomSeed - * sampleRandom seed for the whole game. - * @return the score of the game played. - */ - public double[] runGame(Player[] players, int randomSeed) { - // Prepare some structures and references for this game. - prepareGame(players, randomSeed, -1); - - // Play until the game is ended - while (!isEnded) { - this.gameCycle(); // Execute a game cycle. - } - - // Update the forward model for the game state sent to the controller. - fwdModel.update(this); - - return handleResult(); - } - - /** - * Plays the game, graphics enabled. - * - * @param players - * Players that play this game. - * @param randomSeed - * sampleRandom seed for the whole game. - * @param isHuman - * indicates if a human is playing the game. - * @param humanID - * ID of the human player - * @return the score of the game played. - */ - - public double[] playGame(Player[] players, int randomSeed, boolean isHuman, int humanID) { - // Prepare some structures and references for this game. - prepareGame(players, randomSeed, humanID); - - // Create and initialize the panel for the graphics. - VGDLViewer view = new VGDLViewer(this, players[humanID]); - JEasyFrame frame; - frame = new JEasyFrame(view, "Java-VGDL"); - - frame.addKeyListener(ki); - frame.addWindowListener(wi); - wi.windowClosed = false; - - // Determine the delay for playing with a good fps. - double delay = CompetitionParameters.LONG_DELAY; - for (Player player : players) - if (player instanceof tracks.singlePlayer.tools.human.Agent) { - delay = 1000.0 / CompetitionParameters.DELAY; // in milliseconds - break; - } - - boolean firstRun = true; - - // Play until the game is ended - while (!isEnded && !wi.windowClosed) { - // Determine the time to adjust framerate. - long then = System.currentTimeMillis(); - - this.gameCycle(); // Execute a game cycle. - - // Get the remaining time to keep fps. - long now = System.currentTimeMillis(); - int remaining = (int) Math.max(0, delay - (now - then)); - - // Wait until de next cycle. - waitStep(remaining); - - // Draw all sprites in the panel. - view.paint(this.spriteGroups); - - // Update the frame title to reflect current score and tick. - this.setTitle(frame); - - if (firstRun && isHuman) { - if (CompetitionParameters.dialogBoxOnStartAndEnd) { - JOptionPane.showMessageDialog(frame, "Click OK to start."); - } - - firstRun = false; - } - } - - if (isHuman && !wi.windowClosed && CompetitionParameters.killWindowOnEnd) { - if (CompetitionParameters.dialogBoxOnStartAndEnd) { - if (no_players == 1) { - String sb = "GAMEOVER: YOU LOSE."; - if (avatars[humanID] != null) { - sb = "GAMEOVER: YOU " - + ((avatars[humanID].getWinState() == Types.WINNER.PLAYER_WINS) ? "WIN." : "LOSE."); - } - JOptionPane.showMessageDialog(frame, sb); - } else { - String sb = ""; - for (int i = 0; i < no_players; i++) { - if (avatars[i] != null && avatars[i].getWinState() == Types.WINNER.PLAYER_WINS) { - sb += "Player " + i + "; "; + boolean firstRun = true; + + // Play until the game is ended + while (!isEnded && !wi.windowClosed) { + // Determine the time to adjust framerate. + long then = System.currentTimeMillis(); + + this.gameCycle(); // Execute a game cycle. + + // Get the remaining time to keep fps. + long now = System.currentTimeMillis(); + int remaining = (int) Math.max(0, delay - (now - then)); + + // Wait until de next cycle. + waitStep(remaining); + + // Draw all sprites in the panel. + view.paint(this.spriteGroups); + + // Update the frame title to reflect current score and tick. + this.setTitle(frame); + + if (firstRun && isHuman) { + if (CompetitionParameters.dialogBoxOnStartAndEnd) { + JOptionPane.showMessageDialog(frame, "Click OK to start."); + } + + firstRun = false; + } + } + + if (isHuman && !wi.windowClosed && CompetitionParameters.killWindowOnEnd) { + if (CompetitionParameters.dialogBoxOnStartAndEnd) { + if (no_players == 1) { + String sb = "GAMEOVER: YOU LOSE."; + if (avatars[humanID] != null) { + sb = "GAMEOVER: YOU " + + ((avatars[humanID].getWinState() == Types.WINNER.PLAYER_WINS) ? "WIN." : "LOSE."); + } + JOptionPane.showMessageDialog(frame, sb); + } else { + String sb = ""; + for (int i = 0; i < no_players; i++) { + if (avatars[i] != null && avatars[i].getWinState() == Types.WINNER.PLAYER_WINS) { + sb += "Player " + i + "; "; + } + } + if (sb.equals("")) + sb = "NONE"; + JOptionPane.showMessageDialog(frame, "GAMEOVER - WINNER: " + sb); + } } - } - if (sb.equals("")) - sb = "NONE"; - JOptionPane.showMessageDialog(frame, "GAMEOVER - WINNER: " + sb); - } - } - frame.dispose(); - } - - // Update the forward model for the game state sent to the controller. - fwdModel.update(this); - - return handleResult(); - } - - /** - * Sets the title of the game screen, depending on the game ending state. - * - * @param frame - * The frame whose title needs to be set. - */ - private void setTitle(JEasyFrame frame) { - String sb = ""; - sb += "Java-VGDL: "; - for (int i = 0; i < no_players; i++) { - if (avatars[i] != null) { - sb += "Player" + i + "-Score:" + avatars[i].getScore() + ". "; - } - } - sb += "Tick:" + this.getGameTick(); - - // sb += " --Counter:"; - // for (int i = 0; i < no_counters; i++) { - // sb += counter[i] + ", "; - // } - - if (!isEnded) - frame.setTitle(sb); - else { - for (int i = 0; i < no_players; i++) { - if (avatars[i] != null && avatars[i].getWinState() == Types.WINNER.PLAYER_WINS) - sb += " [Player " + i + " WINS!]"; + frame.dispose(); + } + + // Update the forward model for the game state sent to the controller. + fwdModel.update(this); + + return handleResult(); + } + + /** + * Sets the title of the game screen, depending on the game ending state. + * + * @param frame + * The frame whose title needs to be set. + */ + private void setTitle(JEasyFrame frame) { + String sb = ""; + sb += "Java-VGDL: "; + for (int i = 0; i < no_players; i++) { + if (avatars[i] != null) { + sb += "Player" + i + "-Score:" + avatars[i].getScore() + ". "; + } + } + sb += "Tick:" + this.getGameTick(); + + // sb += " --Counter:"; + // for (int i = 0; i < no_counters; i++) { + // sb += counter[i] + ", "; + // } + + if (!isEnded) + frame.setTitle(sb); + else { + for (int i = 0; i < no_players; i++) { + if (avatars[i] != null && avatars[i].getWinState() == Types.WINNER.PLAYER_WINS) + sb += " [Player " + i + " WINS!]"; + else + sb += " [Player " + i + " LOSES!]"; + } + } + + frame.setTitle(sb); + + } + + /** + * Initializes some variables for the game to be played, such as the game + * tick, sampleRandom number generator, forward model and assigns the player + * to the avatar. + * + * @param players + * Players that play this game. + * @param randomSeed + * sampleRandom seed for the whole game. + */ + private void prepareGame(Player[] players, int randomSeed, int humanID) { + // Start tick counter. + gameTick = -1; + + // Create the sampleRandom generator. + random = new Random(randomSeed); + + // Assigns the player to the avatar of the game. + createAvatars(humanID); + assignPlayer(players); + + // Initialize state observation (sets all non-volatile references). + initForwardModel(); + } + + /** + * This is a standard game cycle in J-VGDL. It advances the game tick, + * updates the forward model and rolls an action in all entities, handling + * collisions and end game situations. + */ + private void gameCycle() { + gameTick++; // next game tick. + + // Update our state observation (forward model) with the information of + // the current game state. + fwdModel.update(this); + // System.out.println(avatars[0].rect); + + // Execute a game cycle: + this.tick(); // update for all entities. + this.eventHandling(); // handle events such collisions. + this.clearAll(fwdModel); // clear all additional data, including dead + // sprites. + this.terminationHandling(); // check for game termination. + this.checkTimeOut(); // Check for end of game by time steps. + + // if(gameTick == 0 || isEnded) + // fwdModel.printObservationGrid(); //uncomment this to show the + // observation grid. + } + + /** + * Handles the result for the game, considering disqualifications. Prints + * the result (score, time and winner) and returns the score of the game. + * Default player ID used 0 for single player games. + * + * @return the result of the game. + */ + public double[] handleResult() { + // check all players disqualified and set scores + for (int i = 0; i < avatars.length; i++) { + if (avatars[i] != null) { + if (avatars[i].is_disqualified()) { + avatars[i].setWinState(Types.WINNER.PLAYER_DISQ); + avatars[i].setScore(Types.SCORE_DISQ); + } + // For sanity: winning a game always gives a positive score + else if (avatars[i].getWinState() == Types.WINNER.PLAYER_WINS) + if (avatars[i].getScore() <= 0) + avatars[i].setScore(1); + } + } + + // Prints the result: score, time and winner. + // printResult(); + + double[] scores = new double[no_players]; + for (int i = 0; i < no_players; i++) { + if (avatars[i] == null) { + scores[i] = Types.SCORE_DISQ; + } else { + scores[i] = avatars[i].getScore(); + } + } + + return scores; + } + + /** + * Checks if the game must finish because of number of cycles played. This + * is a value stored in CompetitionParameters.MAX_TIMESTEPS. If the game is + * due to end, the winner is determined and the flag isEnded is set to true. + */ + protected void checkTimeOut() { + if (gameTick >= CompetitionParameters.MAX_TIMESTEPS) { + isEnded = true; + for (int i = 0; i < no_players; i++) { + if (avatars[i].getWinState() != Types.WINNER.PLAYER_WINS) + avatars[i].setWinState(Types.WINNER.PLAYER_LOSES); + } + } + } + + /** + * Prints the result of the game, indicating the winner, the score and the + * number of game ticks played, in this order. + */ + public void printResult() { + String sb1 = ""; + String sb2 = ""; + for (int i = 0; i < no_players; i++) { + if (avatars[i] != null) { + sb1 += "Player" + i + ":" + avatars[i].getWinState().key() + ", "; + sb2 += "Player" + i + "-Score:" + avatars[i].getScore() + ", "; + } else { + sb1 += "Player" + i + ":-100, "; + sb2 += "Player" + i + "-Score:" + Types.SCORE_DISQ + ", "; + } + } + + System.out.println("Result (1->win; 0->lose): " + sb1 + sb2 + "timesteps:" + this.getGameTick()); + // System.out.println("Result (1->win; 0->lose):"+ winner.key() + ", + // Score:" + score + ", timesteps:" + this.getGameTick()); + } + + /** + * Returns the complete result of the game (victory, score, timestep). + * Indicated in triplets, one per player. + * + * @return [w0,s0,t0,w1,s1,t1,...] + */ + public double[] getFullResult() { + int result_dims = 3; + double[] allRes = new double[no_players * result_dims]; + for (int i = 0; i < no_players; i++) { + + allRes[i * result_dims] = avatars[i].getWinState().key(); + allRes[i * result_dims + 1] = avatars[i].getScore(); + allRes[i * result_dims + 2] = this.getGameTick(); + } + return allRes; + } + + /** + * Disqualifies the player in the game, and also sets the isEnded flag to + * true. + */ + // comment this method out to check if mistakes in method overloading + // anywhere + public void disqualify() { + disqualified = true; + isEnded = true; + } + + /** + * Overloaded method for multiplayer games. Same functionality as above. + * + * @param id + * - id of the player that was disqualified + */ + public void disqualify(int id) { + if (id == -1) + disqualified = true; else - sb += " [Player " + i + " LOSES!]"; - } - } - - frame.setTitle(sb); - - } - - /** - * Initializes some variables for the game to be played, such as the game - * tick, sampleRandom number generator, forward model and assigns the player - * to the avatar. - * - * @param players - * Players that play this game. - * @param randomSeed - * sampleRandom seed for the whole game. - */ - private void prepareGame(Player[] players, int randomSeed, int humanID) { - // Start tick counter. - gameTick = -1; - - // Create the sampleRandom generator. - random = new Random(randomSeed); - - // Assigns the player to the avatar of the game. - createAvatars(humanID); - assignPlayer(players); - - // Initialize state observation (sets all non-volatile references). - initForwardModel(); - } - - /** - * This is a standard game cycle in J-VGDL. It advances the game tick, - * updates the forward model and rolls an action in all entities, handling - * collisions and end game situations. - */ - private void gameCycle() { - gameTick++; // next game tick. - - // Update our state observation (forward model) with the information of - // the current game state. - fwdModel.update(this); - // System.out.println(avatars[0].rect); - - // Execute a game cycle: - this.tick(); // update for all entities. - this.eventHandling(); // handle events such collisions. - this.clearAll(fwdModel); // clear all additional data, including dead - // sprites. - this.terminationHandling(); // check for game termination. - this.checkTimeOut(); // Check for end of game by time steps. - - // if(gameTick == 0 || isEnded) - // fwdModel.printObservationGrid(); //uncomment this to show the - // observation grid. - } - - /** - * Handles the result for the game, considering disqualifications. Prints - * the result (score, time and winner) and returns the score of the game. - * Default player ID used 0 for single player games. - * - * @return the result of the game. - */ - public double[] handleResult() { - // check all players disqualified and set scores - for (int i = 0; i < avatars.length; i++) { - if (avatars[i] != null) { - if (avatars[i].is_disqualified()) { - avatars[i].setWinState(Types.WINNER.PLAYER_DISQ); - avatars[i].setScore(Types.SCORE_DISQ); - } - // For sanity: winning a game always gives a positive score - else if (avatars[i].getWinState() == Types.WINNER.PLAYER_WINS) - if (avatars[i].getScore() <= 0) - avatars[i].setScore(1); - } - } - - // Prints the result: score, time and winner. - // printResult(); - - double[] scores = new double[no_players]; - for (int i = 0; i < no_players; i++) { - if (avatars[i] == null) { - scores[i] = Types.SCORE_DISQ; - } else { - scores[i] = avatars[i].getScore(); - } - } - - return scores; - } - - /** - * Checks if the game must finish because of number of cycles played. This - * is a value stored in CompetitionParameters.MAX_TIMESTEPS. If the game is - * due to end, the winner is determined and the flag isEnded is set to true. - */ - protected void checkTimeOut() { - if (gameTick >= CompetitionParameters.MAX_TIMESTEPS) { - isEnded = true; - for (int i = 0; i < no_players; i++) { - if (avatars[i].getWinState() != Types.WINNER.PLAYER_WINS) - avatars[i].setWinState(Types.WINNER.PLAYER_LOSES); - } - } - } - - /** - * Prints the result of the game, indicating the winner, the score and the - * number of game ticks played, in this order. - */ - public void printResult() { - String sb1 = ""; - String sb2 = ""; - for (int i = 0; i < no_players; i++) { - if (avatars[i] != null) { - sb1 += "Player" + i + ":" + avatars[i].getWinState().key() + ", "; - sb2 += "Player" + i + "-Score:" + avatars[i].getScore() + ", "; - } else { - sb1 += "Player" + i + ":-100, "; - sb2 += "Player" + i + "-Score:" + Types.SCORE_DISQ + ", "; - } - } - - System.out.println("Result (1->win; 0->lose): " + sb1 + sb2 + "timesteps:" + this.getGameTick()); - // System.out.println("Result (1->win; 0->lose):"+ winner.key() + ", - // Score:" + score + ", timesteps:" + this.getGameTick()); - } - - /** - * Returns the complete result of the game (victory, score, timestep). - * Indicated in triplets, one per player. - * - * @return [w0,s0,t0,w1,s1,t1,...] - */ - public double[] getFullResult() { - int result_dims = 3; - double[] allRes = new double[no_players * result_dims]; - for (int i = 0; i < no_players; i++) { - - allRes[i * result_dims] = avatars[i].getWinState().key(); - allRes[i * result_dims + 1] = avatars[i].getScore(); - allRes[i * result_dims + 2] = this.getGameTick(); - } - return allRes; - } - - /** - * Disqualifies the player in the game, and also sets the isEnded flag to - * true. - */ - // comment this method out to check if mistakes in method overloading - // anywhere - public void disqualify() { - disqualified = true; - isEnded = true; - } - - /** - * Overloaded method for multiplayer games. Same functionality as above. - * - * @param id - * - id of the player that was disqualified - */ - public void disqualify(int id) { - if (id == -1) - disqualified = true; - else - avatars[id].disqualify(true); - isEnded = true; - } - - /** - * Method to create the array of avatars from the sprites. - */ - public void createAvatars(int humanID) { - - // Avatars will usually be the first elements, starting from the end. - - // Find avatar sprites - ArrayList avSprites = new ArrayList<>(); - int idx = spriteOrder.length; - int numAvatarSprites = 0; - while (true) { - idx--; - if (idx > 0) { - int spriteTypeId = spriteOrder[idx]; - int num = spriteGroups[spriteTypeId].numSprites(); - if (num > 0) { - // There should be just one sprite in the avatar's group in - // single player games. - // Could be more than one avatar in multiplayer games - for (int j = 0; j < num; j++) { - VGDLSprite thisSprite = spriteGroups[spriteTypeId].getSpriteByIdx(j); - if (thisSprite.is_avatar) { - avSprites.add((MovingAvatar) thisSprite); + avatars[id].disqualify(true); + isEnded = true; + } + + /** + * Method to create the array of avatars from the sprites. + */ + public void createAvatars(int humanID) { + + // Avatars will usually be the first elements, starting from the end. + + // Find avatar sprites + ArrayList avSprites = new ArrayList<>(); + int idx = spriteOrder.length; + int numAvatarSprites = 0; + while (true) { + idx--; + if (idx > 0) { + int spriteTypeId = spriteOrder[idx]; + int num = spriteGroups[spriteTypeId].numSprites(); + if (num > 0) { + // There should be just one sprite in the avatar's group in + // single player games. + // Could be more than one avatar in multiplayer games + for (int j = 0; j < num; j++) { + VGDLSprite thisSprite = spriteGroups[spriteTypeId].getSpriteByIdx(j); + if (thisSprite.is_avatar) { + avSprites.add((MovingAvatar) thisSprite); + } + } + } + } else { + numAvatarSprites = avSprites.size(); + // System.out.println("Done finding avatars: " + + // numAvatarSprites); + break; } - } - } - } else { - numAvatarSprites = avSprites.size(); - // System.out.println("Done finding avatars: " + - // numAvatarSprites); - break; - } - } - - Collections.reverse(avSprites); // read in reverse order - if (!avSprites.isEmpty()) { - for (int i = 0; i < no_players; i++) { - if (numAvatarSprites > i) { // check if there's enough avatars - // just in case - avatars[i] = avSprites.get(i); - avatars[i].setKeyHandler(ki); - avatars[i].setPlayerID(i); - } - } - } else { - Logger.getInstance().addMessage(new Message(Message.WARNING, "No avatars found.")); - } - } - - /** - * Looks for the avatar of the game in the existing sprites. If the player - * received as a parameter is not null, it is assigned to it. - * - * @param players - * the players that will play the game (only 1 in single player - * games). - */ - private void assignPlayer(Player[] players) { - // iterate through all avatars and assign their players - if (players.length == no_players) { - for (int i = 0; i < no_players; i++) { - if (players[i] != null && avatars[i] != null) { - avatars[i].player = players[i]; - avatars[i].setPlayerID(i); - // avatars[i].player.setPlayerID(i); - } else { - System.out.println("Null player."); - } - } - } else { - System.out.println("Not enough players."); - } - } - - /** - * Holds the game for the specified duration milliseconds - * - * @param duration - * time to wait. - */ - void waitStep(int duration) { - - try { - Thread.sleep(duration); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - /** - * Performs one tick for the game: calling update(this) in all sprites. It - * follows the opposite order of the drawing order (inverse spriteOrder[]). - * Avatar is always updated first. Doesn't update disabled sprites. - */ - protected void tick() { - // Now, do all of the avatars. - for (int i = 0; i < no_players; i++) { - if (avatars[i] != null && !avatars[i].is_disabled()) { - avatars[i].preMovement(); - avatars[i].update(this); - } else if (avatars[i] == null) { - System.out.println(gameTick + ": Something went wrong, no avatar, ID = " + i); - } - } - // random = new Random(this.gameTick * 100); //uncomment this for - // testing a new rnd generator after avatar's move - - int spriteOrderCount = spriteOrder.length; - for (int i = spriteOrderCount - 1; i >= 0; --i) { - int spriteTypeInt = spriteOrder[i]; - ArrayList spritesList = spriteGroups[spriteTypeInt].getSprites(); - if (spritesList != null) - for (VGDLSprite sp : spritesList) { - if (!(sp instanceof MovingAvatar) && !sp.is_disabled()) { - sp.preMovement(); - sp.update(this); - } - } - - } - } - - /** - * Handles collisions and triggers events. - */ - protected void eventHandling() { - // Array to indicate that the sprite type has no representative in - // collisions. - boolean noSprites[] = new boolean[spriteGroups.length]; - - // First, check the effects that are triggered in a timely manner. - while (timeEffects.size() > 0 && timeEffects.first().nextExecution <= gameTick) { - TimeEffect ef = timeEffects.pollFirst(); - if (ef.enabled) { - int intId = ef.itype; - boolean exec = false; - - // if intId==-1, we have no sprite - if (intId == -1) { - // With no sprite, the effect is independent from particular - // sprites. - ef.execute(null, null, this); - exec = true; - - // Affect score for all players: - if (ef.applyScore) { + } + + Collections.reverse(avSprites); // read in reverse order + if (!avSprites.isEmpty()) { for (int i = 0; i < no_players; i++) { - avatars[i].addScore(ef.getScoreChange(i)); + if (numAvatarSprites > i) { // check if there's enough avatars + // just in case + avatars[i] = avSprites.get(i); + avatars[i].setKeyHandler(ki); + avatars[i].setPlayerID(i); + } } - } + } else { + Logger.getInstance().addMessage(new Message(Message.WARNING, "No avatars found.")); + } + } + /** + * Looks for the avatar of the game in the existing sprites. If the player + * received as a parameter is not null, it is assigned to it. + * + * @param players + * the players that will play the game (only 1 in single player + * games). + */ + private void assignPlayer(Player[] players) { + // iterate through all avatars and assign their players + if (players.length == no_players) { + for (int i = 0; i < no_players; i++) { + if (players[i] != null && avatars[i] != null) { + avatars[i].player = players[i]; + avatars[i].setPlayerID(i); + // avatars[i].player.setPlayerID(i); + } else { + System.out.println("Null player."); + } + } } else { + System.out.println("Not enough players."); + } + } + + /** + * Holds the game for the specified duration milliseconds + * + * @param duration + * time to wait. + */ + void waitStep(int duration) { + + try { + Thread.sleep(duration); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } - ArrayList allTypes = iSubTypes[intId]; - for (Integer itype : allTypes) { - // Find all sprites of this subtype. - Collection sprites = this.getSprites(itype); - for (VGDLSprite sp : sprites) { - // Check that they are not dead (could happen in - // this same cycle). - if (!kill_list.contains(sp) && !sp.is_disabled()) { - executeEffect(ef, sp, null); - exec = true; - } + /** + * Performs one tick for the game: calling update(this) in all sprites. It + * follows the opposite order of the drawing order (inverse spriteOrder[]). + * Avatar is always updated first. Doesn't update disabled sprites. + */ + protected void tick() { + // Now, do all of the avatars. + for (int i = 0; i < no_players; i++) { + if (avatars[i] != null && !avatars[i].is_disabled()) { + avatars[i].preMovement(); + avatars[i].update(this); + } else if (avatars[i] == null) { + System.out.println(gameTick + ": Something went wrong, no avatar, ID = " + i); } - } - } - - // If the time effect is repetitive, need to reinsert in the - // list of effects - if (ef.repeating) { - if (!exec) - ef.planExecution(this); - this.addTimeEffect(ef); - } - } - - } - - // Secondly, we handle single sprite events (EOS). Take each sprite - // itype that has - // a EOS effect defined. - for (Integer intId : definedEOSEffects) { - // For each effect that this sprite has assigned. - for (Effect ef : eosEffects[intId]) { - // Take all the subtypes in the hierarchy of this sprite. - ArrayList allTypes = iSubTypes[intId]; - if (ef.enabled) - for (Integer itype : allTypes) { - // Add all sprites of this subtype to the list of - // sprites. - // These are sprites that could potentially collide with - // EOS - Collection sprites = this.getSprites(itype); - try{ - for (VGDLSprite sp : sprites) { - // Check if they are at the edge to trigger the - // effect. Also check that they - // are not dead (could happen in this same cycle). - if (isAtEdge(sp.rect) && !kill_list.contains(sp) && !sp.is_disabled()) { - executeEffect(ef, sp, null); - } - } + } + // random = new Random(this.gameTick * 100); //uncomment this for + // testing a new rnd generator after avatar's move + + int spriteOrderCount = spriteOrder.length; + for (int i = spriteOrderCount - 1; i >= 0; --i) { + int spriteTypeInt = spriteOrder[i]; + ArrayList spritesList = spriteGroups[spriteTypeInt].getSprites(); + if (spritesList != null) + for (VGDLSprite sp : spritesList) { + if (!(sp instanceof MovingAvatar) && !sp.is_disabled()) { + sp.preMovement(); + sp.update(this); + } + } + + } + } + + /** + * Handles collisions and triggers events. + */ + protected void eventHandling() { + // Array to indicate that the sprite type has no representative in + // collisions. + boolean noSprites[] = new boolean[spriteGroups.length]; + + // First, check the effects that are triggered in a timely manner. + while (timeEffects.size() > 0 && timeEffects.first().nextExecution <= gameTick) { + TimeEffect ef = timeEffects.pollFirst(); + if (ef.enabled) { + int intId = ef.itype; + boolean exec = false; + + // if intId==-1, we have no sprite + if (intId == -1) { + // With no sprite, the effect is independent from particular + // sprites. + ef.execute(null, null, this); + exec = true; + + // Affect score for all players: + if (ef.applyScore) { + for (int i = 0; i < no_players; i++) { + avatars[i].addScore(ef.getScoreChange(i)); + } + } + + } else { + + ArrayList allTypes = iSubTypes[intId]; + for (Integer itype : allTypes) { + // Find all sprites of this subtype. + Collection sprites = this.getSprites(itype); + for (VGDLSprite sp : sprites) { + // Check that they are not dead (could happen in + // this same cycle). + if (!kill_list.contains(sp) && !sp.is_disabled()) { + executeEffect(ef, sp, null); + exec = true; + } + } + } + } + + // If the time effect is repetitive, need to reinsert in the + // list of effects + if (ef.repeating) { + if (!exec) + ef.planExecution(this); + this.addTimeEffect(ef); + } } - catch(ConcurrentModificationException e){ - Logger.getInstance().addMessage(new Message(Message.WARNING, "you can't spawn sprites outside of the screen.")); + + } + + // Secondly, we handle single sprite events (EOS). Take each sprite + // itype that has + // a EOS effect defined. + for (Integer intId : definedEOSEffects) { + // For each effect that this sprite has assigned. + for (Effect ef : eosEffects[intId]) { + // Take all the subtypes in the hierarchy of this sprite. + ArrayList allTypes = iSubTypes[intId]; + if (ef.enabled) + for (Integer itype : allTypes) { + // Add all sprites of this subtype to the list of + // sprites. + // These are sprites that could potentially collide with + // EOS + Collection sprites = this.getSprites(itype); + try{ + for (VGDLSprite sp : sprites) { + // Check if they are at the edge to trigger the + // effect. Also check that they + // are not dead (could happen in this same cycle). + if (isAtEdge(sp.rect) && !kill_list.contains(sp) && !sp.is_disabled()) { + executeEffect(ef, sp, null); + } + } + } + catch(ConcurrentModificationException e){ + Logger.getInstance().addMessage(new Message(Message.WARNING, "you can't spawn sprites outside of the screen.")); + } + } + } + + } + + // Now, we handle events between pairs of sprites, for each pair of + // sprites that + // has a paired effect defined: + for (Pair p : definedEffects) { + // We iterate over the (potential) multiple effects that these + // two sprites could have defined between them. + for (Effect ef : collisionEffects[p.first][p.second]) { + if (ef.enabled) { + + if (shieldedEffects[p.first].size() > 0) { + if (shieldedEffects[p.first].contains(new Pair(p.second, ef.hashCode))) + continue; + } + + ArrayList firstx = new ArrayList(); + ArrayList secondx = new ArrayList(); + + ArrayList allTypes1 = iSubTypes[p.first]; + for (int i : allTypes1) { + firstx.addAll(getSprites(i)); + } + ArrayList allTypes2 = iSubTypes[p.second]; + for (int j : allTypes2) { + secondx.addAll(getSprites(j)); + } + + ArrayList new_secondx = new ArrayList(); + + for (VGDLSprite s1 : firstx) { + new_secondx = new ArrayList(); + + for (VGDLSprite s2 : secondx) { + if ((s1 != s2 && s1.rect.intersects(s2.rect))) { + new_secondx.add(s2); + } + } + + for (int a = 0; a < new_secondx.size(); a++) { + for (int b = 0; b < new_secondx.size(); b++) { + if (a < b) { + if (Math.sqrt(((s1.getPosition().x - new_secondx.get(a).getPosition().x) + * (s1.getPosition().x - new_secondx.get(a).getPosition().x)) + + + ((s1.getPosition().y - new_secondx.get(a).getPosition().y) + * (s1.getPosition().y - new_secondx.get(a).getPosition().y))) > Math + .sqrt(((s1.getPosition().x + - new_secondx.get(b).getPosition().x) + * (s1.getPosition().x + - new_secondx.get(b).getPosition().x)) + + + + ((s1.getPosition().y + - new_secondx.get(b).getPosition().y) + * (s1.getPosition().y - new_secondx.get(b) + .getPosition().y)))) { + new_secondx.add(a, new_secondx.get(b)); + new_secondx.remove(b + 1); + } + } + } + } + + for (int i = 0; i < new_secondx.size(); i++) { + if (!kill_list.contains(s1) && s1 != new_secondx.get(i) + && s1.rect.intersects(new_secondx.get(i).rect)) { + executeEffect(ef, s1, new_secondx.get(i)); + } + } + } + } + } + } + + } + + private void executeEffect(Effect ef, VGDLSprite s1, VGDLSprite s2) { + // There is a collision. Apply the effect. + ef.execute(s1, s2, this); + + // Affect score: + if (ef.applyScore) { + // apply scores for all avatars + for (int i = 0; i < no_players; i++) { + avatars[i].addScore(ef.getScoreChange(i)); + } + } + + // Add to events history. + if (s1 != null && s2 != null) + addEvent(s1, s2); + + if (ef.count) { + for (int i = 0; i < no_counters; i++) { + this.counter[i] += ef.getCounter(i); } - } - } - - } - - // Now, we handle events between pairs of sprites, for each pair of - // sprites that - // has a paired effect defined: - for (Pair p : definedEffects) { - // We iterate over the (potential) multiple effects that these - // two sprites could have defined between them. - for (Effect ef : collisionEffects[p.first][p.second]) { - if (ef.enabled) { - - if (shieldedEffects[p.first].size() > 0) { - if (shieldedEffects[p.first].contains(new Pair(p.second, ef.hashCode))) - continue; - } - - ArrayList firstx = new ArrayList(); - ArrayList secondx = new ArrayList(); - - ArrayList allTypes1 = iSubTypes[p.first]; - for (int i : allTypes1) { - firstx.addAll(getSprites(i)); - } - ArrayList allTypes2 = iSubTypes[p.second]; - for (int j : allTypes2) { - secondx.addAll(getSprites(j)); - } - - ArrayList new_secondx = new ArrayList(); - - for (VGDLSprite s1 : firstx) { - new_secondx = new ArrayList(); - - for (VGDLSprite s2 : secondx) { - if ((s1 != s2 && s1.rect.intersects(s2.rect))) { - new_secondx.add(s2); - } + } + + if (ef.countElse) { + for (int i = 0; i < no_counters; i++) { + this.counter[i] += ef.getCounterElse(i); } + } + } + + private void addEvent(VGDLSprite s1, VGDLSprite s2) { + if (s1.is_avatar) + historicEvents.add( + new Event(gameTick, false, s1.getType(), s2.getType(), s1.spriteID, s2.spriteID, s1.getPosition())); + + else if (s1.is_from_avatar) + historicEvents.add( + new Event(gameTick, true, s1.getType(), s2.getType(), s1.spriteID, s2.spriteID, s1.getPosition())); + + else if (s2.is_avatar) + historicEvents.add( + new Event(gameTick, false, s2.getType(), s1.getType(), s2.spriteID, s1.spriteID, s2.getPosition())); - for (int a = 0; a < new_secondx.size(); a++) { - for (int b = 0; b < new_secondx.size(); b++) { - if (a < b) { - if (Math.sqrt(((s1.getPosition().x - new_secondx.get(a).getPosition().x) - * (s1.getPosition().x - new_secondx.get(a).getPosition().x)) + - - ((s1.getPosition().y - new_secondx.get(a).getPosition().y) - * (s1.getPosition().y - new_secondx.get(a).getPosition().y))) > Math - .sqrt(((s1.getPosition().x - - new_secondx.get(b).getPosition().x) - * (s1.getPosition().x - - new_secondx.get(b).getPosition().x)) - + - - ((s1.getPosition().y - - new_secondx.get(b).getPosition().y) - * (s1.getPosition().y - new_secondx.get(b) - .getPosition().y)))) { - new_secondx.add(a, new_secondx.get(b)); - new_secondx.remove(b + 1); - } + else if (s2.is_from_avatar) + historicEvents.add( + new Event(gameTick, true, s2.getType(), s1.getType(), s2.spriteID, s1.spriteID, s2.getPosition())); + } + + /** + * Checks if a given rectangle is at the edge of the screen. + * + * @param rect + * the rectangle to check + * @return true if rect is at the edge of the screen. + */ + private boolean isAtEdge(Rectangle rect) { + Rectangle r = new Rectangle(screenSize); + if (!r.contains(rect)) { + return true; + } + return false; + } + + /** + * Handles termination conditions, for every termination defined in + * 'terminations' array. + */ + protected void terminationHandling() { + int numTerminations = terminations.size(); + for (int i = 0; !isEnded && i < numTerminations; ++i) { + Termination t = terminations.get(i); + if (t.isDone(this)) { + isEnded = true; + for (int j = 0; j < no_players; j++) { + if (avatars[j] != null) { + avatars[j].setWinState(t.win(j) ? Types.WINNER.PLAYER_WINS : Types.WINNER.PLAYER_LOSES); + } } - } } + } + } - for (int i = 0; i < new_secondx.size(); i++) { - if (!kill_list.contains(s1) && s1 != new_secondx.get(i) - && s1.rect.intersects(new_secondx.get(i).rect)) { - executeEffect(ef, s1, new_secondx.get(i)); - } + /** + * Deletes all the sprites killed in the previous step. Also, clears the + * array of collisions from the last step. + * + * @param fm + * Forward model where we are cleaning sprites. + */ + protected void clearAll(ForwardModel fm) { + for (VGDLSprite sprite : kill_list) { + int spriteType = sprite.getType(); + this.spriteGroups[spriteType].removeSprite(sprite); + if (fm != null) { + fm.removeSpriteObservation(sprite); } - } - } - } - } - - } - - private void executeEffect(Effect ef, VGDLSprite s1, VGDLSprite s2) { - // There is a collision. Apply the effect. - ef.execute(s1, s2, this); - - // Affect score: - if (ef.applyScore) { - // apply scores for all avatars - for (int i = 0; i < no_players; i++) { - avatars[i].addScore(ef.getScoreChange(i)); - } - } - - // Add to events history. - if (s1 != null && s2 != null) - addEvent(s1, s2); - - if (ef.count) { - for (int i = 0; i < no_counters; i++) { - this.counter[i] += ef.getCounter(i); - } - } - - if (ef.countElse) { - for (int i = 0; i < no_counters; i++) { - this.counter[i] += ef.getCounterElse(i); - } - } - } - - private void addEvent(VGDLSprite s1, VGDLSprite s2) { - if (s1.is_avatar) - historicEvents.add( - new Event(gameTick, false, s1.getType(), s2.getType(), s1.spriteID, s2.spriteID, s1.getPosition())); - - else if (s1.is_from_avatar) - historicEvents.add( - new Event(gameTick, true, s1.getType(), s2.getType(), s1.spriteID, s2.spriteID, s1.getPosition())); - - else if (s2.is_avatar) - historicEvents.add( - new Event(gameTick, false, s2.getType(), s1.getType(), s2.spriteID, s1.spriteID, s2.getPosition())); - - else if (s2.is_from_avatar) - historicEvents.add( - new Event(gameTick, true, s2.getType(), s1.getType(), s2.spriteID, s1.spriteID, s2.getPosition())); - } - - /** - * Checks if a given rectangle is at the edge of the screen. - * - * @param rect - * the rectangle to check - * @return true if rect is at the edge of the screen. - */ - private boolean isAtEdge(Rectangle rect) { - Rectangle r = new Rectangle(screenSize); - if (!r.contains(rect)) { - return true; - } - return false; - } - - /** - * Handles termination conditions, for every termination defined in - * 'terminations' array. - */ - protected void terminationHandling() { - int numTerminations = terminations.size(); - for (int i = 0; !isEnded && i < numTerminations; ++i) { - Termination t = terminations.get(i); - if (t.isDone(this)) { - isEnded = true; - for (int j = 0; j < no_players; j++) { - if (avatars[j] != null) { - avatars[j].setWinState(t.win(j) ? Types.WINNER.PLAYER_WINS : Types.WINNER.PLAYER_LOSES); - } - } - } - } - } - - /** - * Deletes all the sprites killed in the previous step. Also, clears the - * array of collisions from the last step. - * - * @param fm - * Forward model where we are cleaning sprites. - */ - protected void clearAll(ForwardModel fm) { - for (VGDLSprite sprite : kill_list) { - int spriteType = sprite.getType(); - this.spriteGroups[spriteType].removeSprite(sprite); - if (fm != null) { - fm.removeSpriteObservation(sprite); - } - - if (sprite.is_avatar) - // go through all avatars to see which avatar is dead - for (int i = 0; i < no_players; i++) - if (sprite == avatars[i]) - avatars[i] = null; - - num_sprites--; - - } - kill_list.clear(); - - for (int j = 0; j < spriteGroups.length; ++j) { - bucketList[j].clear(); - } - - resetShieldEffects(); - } - - /** - * Cleans the array of shielded effects. - */ - private void resetShieldEffects() { - for (int i = 0; i < shieldedEffects.length; ++i) - shieldedEffects[i].clear(); - } - - /** - * Adds a new Shield effect to the scene. - * - * @param type1 - * Recipient of the effect (sprite ID) - * @param type2 - * Second sprite ID - * @param functHash - * Hash of the effect name to shield. - */ - public void addShield(int type1, int type2, long functHash) { - Pair newShield = new Pair(type2, functHash); - shieldedEffects[type1].add(newShield); - } - - /** - * Adds a sprite given a content and position. - * - * @param itype - * integer that identifies the definition of the sprite to add - * @param position - * where the sprite has to be placed. - */ - public VGDLSprite addSprite(int itype, Vector2d position) { - return this.addSprite((SpriteContent) classConst[itype], position, itype, false); - } - - /** - * Adds a sprite given a content and position. - * - * @param itype - * integer that identifies the definition of the sprite to add - * @param position - * where the sprite has to be placed. - * @param force - * if true, ignores the singleton restrictions and creates it - * anyway. - */ - public VGDLSprite addSprite(int itype, Vector2d position, boolean force) { - return this.addSprite((SpriteContent) classConst[itype], position, itype, force); - } - - /** - * Adds a sprite given a content and position. It checks for possible - * singletons. - * - * @param content - * definition of the sprite to add - * @param position - * where the sprite has to be placed. - * @param itype - * integer identifier of this type of sprite. - * @param force - * If true, forces the creation ignoring singleton restrictions - */ - public VGDLSprite addSprite(SpriteContent content, Vector2d position, int itype, boolean force) { - if (num_sprites > MAX_SPRITES) { - Logger.getInstance().addMessage(new Message(Message.WARNING, "Sprite limit reached.")); - return null; - } - - // Check for singleton Sprites - boolean anyother = false; - if (!force) { - - for (Integer typeInt : content.itypes) { - // If this type is a singleton and we have one already - if (singletons[typeInt] && getNumSprites(typeInt) > 0) { - // that's it, no more creations of this type. - anyother = true; - break; - } - } - } - - // Only create the sprite if there is not any other sprite that blocks - // it. - if (!anyother) { - VGDLSprite newSprite; - - if (templateSprites[itype] == null) // don't have a template yet, so - // need to create one - { - newSprite = VGDLFactory.GetInstance().createSprite(this, content, position, - new Dimension(block_size, block_size)); - - // Assign its types and add it to the collection of sprites. - newSprite.itypes = (ArrayList) content.itypes.clone(); - - // save a copy as template object - templateSprites[itype] = newSprite.copy(); - } else // we already have a template, so simply copy that one - { - newSprite = templateSprites[itype].copy(); - - // make sure the copy is moved to the correct position - newSprite.setRect(position, new Dimension(block_size, block_size)); - - // Set last rect - newSprite.lastrect = new Rectangle(newSprite.rect); - } - - // add the sprite to the collection of sprites in the game - this.addSprite(newSprite, itype); - return newSprite; - } - - Logger.getInstance().addMessage(new Message(Message.WARNING, "You can't have multiple objects of singleton.")); - return null; - } - - public void _updateCollisionDict(VGDLSprite sprite) { - } - - /** - * Returns the game score. - */ - public double getScore() { - return getScore(0); - } - - /** - * Method overloaded for multi player games. Returns the game score of the - * specified player. - * - * @param playerID - * ID of the player. - */ - public double getScore(int playerID) { - return avatars[playerID].getScore(); - } - - /** - * Reverses the direction of a given sprite. - * - * @param sprite - * sprite to reverse. - */ - public void reverseDirection(VGDLSprite sprite) { - sprite.orientation = new Direction(-sprite.orientation.x(), -sprite.orientation.y()); - } - - /** - * Kills a given sprite, adding it to the list of sprites killed at this - * step. - * - * @param sprite - * the sprite to kill. - * @param transformed - * - indicates if the sprite was transformed (necessary to kill - * sprite even if avatar, instead of disabling it). - */ - public void killSprite(VGDLSprite sprite, boolean transformed) { - if (sprite instanceof MovingAvatar && !transformed) { // if avatar, just - // disable - sprite.setDisabled(true); - } else { - kill_list.add(sprite); - } - } - - /** - * Gets an iterator for the collection of sprites for a particular sprite - * type. - * - * @param spriteItype - * type of the sprite to retrieve. - * @return sprite collection of the specified type. - */ - public Iterator getSpriteGroup(int spriteItype) { - return spriteGroups[spriteItype].getSpriteIterator(); - } - - /** - * Gets an iterator for the collection of sprites for a particular sprite - * type, AND all subtypes. - * - * @param spriteItype - * type of the sprite to retrieve. - * @return sprite collection of the specified type and subtypes. - */ - public Iterator getSubSpritesGroup(int spriteItype) { - // Create a sprite group for all the sprites - SpriteGroup allSprites = new SpriteGroup(spriteItype); - // Get all the subtypes - ArrayList allTypes = iSubTypes[spriteItype]; - - // Add sprites of this type, and all subtypes. - allSprites.addAllSprites(this.getSprites(spriteItype)); - for (Integer itype : allTypes) { - allSprites.addAllSprites(this.getSprites(itype)); - } - - // Return the iterator. - return allSprites.getSpriteIterator(); - } - - /** - * Gets the collection of sprites for a particular sprite type. - * - * @param spriteItype - * type of the sprite to retrieve. - * @return sprite collection of the specified type. - */ - public ArrayList getSprites(int spriteItype) { - return spriteGroups[spriteItype].getSprites(); - } - - /** - * Gets the array of collisions defined for two types of sprites. - * - * @param spriteItype1 - * type of the first sprite. - * @param spriteItype2 - * type of the second sprite. - * @return the collection of the effects defined between the two sprite - * types. - */ - public ArrayList getCollisionEffects(int spriteItype1, int spriteItype2) { - return collisionEffects[spriteItype1][spriteItype2]; - } - - /** - * Returns all paired effects defined in the game. - * - * @return all paired effects defined in the game. - */ - public ArrayList> getDefinedEffects() { - return definedEffects; - } - - /** - * Returns the list of sprite type with at least one EOS effect defined. - * - * @return the list of sprite type with at least one EOS effect defined. - */ - public ArrayList getDefinedEosEffects() { - return definedEOSEffects; - } - - /** - * Returns all EOS effects defined in the game. - * - * @return all EOS effects defined in the game. - */ - public ArrayList getEosEffects(int obj1) { - return eosEffects[obj1]; - } - - /** - * Adds a time effect to the game. - */ - public void addTimeEffect(TimeEffect ef) { - timeEffects.add(ef); - } - - /** - * Returns the char mapping of this array, that relates characters in the - * level with sprite names that it references. - * - * @return the char mapping of this array. For each character, there is a - * list of N sprite names. - */ - public HashMap> getCharMapping() { - return charMapping; - } - - /** - * Set the char mapping that is used to parse loaded levels - * - * @param charMapping - * new character mapping - */ - public void setCharMapping(HashMap> charMapping) { - this.charMapping = charMapping; - } - - /** - * Gets the array of termination conditions for this game. - * - * @return the array of termination conditions. - */ - public ArrayList getTerminations() { - return terminations; - } - - /** - * Gets the maximum amount of resources of type resourceId that are allowed - * by entities in the game. - * - * @param resourceId - * the id of the resource to query for. - * @return maximum amount of resources of type resourceId. - */ - public int getResourceLimit(int resourceId) { - return resources_limits[resourceId]; - } - - /** - * Gets the color of the resource of type resourceId - * - * @param resourceId - * id of the resource to query for. - * @return Color assigned to this resource. - */ - public Color getResourceColor(int resourceId) { - return resources_colors[resourceId]; - } - - /** - * Gets the dimensions of the screen. - * - * @return the dimensions of the screen. - */ - public Dimension getScreenSize() { - return screenSize; - } - - /** - * Defines this game as stochastic (or not) depending on the parameter - * passed. - * - * @param stoch - * true if the game is stochastic. - */ - public void setStochastic(boolean stoch) { - is_stochastic = stoch; - } - - /** - * Returns the avatar of the game in single player games. - * - * @return the avatar of the game. - */ - public MovingAvatar getAvatar() { - return getAvatar(0); - } - - /** - * Overloaded method, returns the avatar of the player specified (for multi - * player games). - * - * @param playerID - * ID of the player desired. - * @return the corresponding avatar. - */ - public MovingAvatar getAvatar(int playerID) { - return avatars[playerID]; - } - - /** - * Returns an array of all avatars in the game. - * - * @return array of avatars. - */ - public MovingAvatar[] getAvatars() { - return avatars; - } - - /** - * Sets the avatar of the game. - * - * @param newAvatar - * the avatar of the game. - */ - public void setAvatar(MovingAvatar newAvatar) { - avatars[0] = newAvatar; - } - - /** - * Overloaded method, sets the avatar specified. - * - * @param newAvatar - * the avatar of the game. - * @param playerID - * the ID of the player desired. - */ - public void setAvatar(MovingAvatar newAvatar, int playerID) { - avatars[playerID] = newAvatar; - } - - /** - * Sets the last action executed by the avatar. It could be NIL in case of - * time overspent. - * - * @param action - * the action to set. - */ - public void setAvatarLastAction(Types.ACTIONS action) { - setAvatarLastAction(action, 0); - } - - /** - * Overloaded method for multi player games. Sets the last action executed - * by the avatar with the corresponding player ID. It could be NIL in case - * of time overspent. - * - * @param action - * the action to set. - * @param playerID - * the ID of the player. - */ - public void setAvatarLastAction(Types.ACTIONS action, int playerID) { - this.avatarLastAction[playerID] = action; - } - - /** - * Indicates if the game is over, or if it is still being played. - * - * @return true if the game is over, false if it is still being played. - */ - public abstract boolean isGameOver(); - - /** - * clear all the interactions and termination in the current game - */ - public void clearInteractionTerminationData() { - this.setStochastic(false); - this.terminations.clear(); - - this.definedEffects.clear(); - for (int i = 0; i < this.collisionEffects.length; i++) { - for (int j = 0; j < this.collisionEffects[i].length; j++) { - this.collisionEffects[i][j].clear(); - } - } - - this.definedEOSEffects.clear(); - for (int i = 0; i < this.eosEffects.length; i++) { - this.eosEffects[i].clear(); - } - - this.timeEffects.clear(); - } - - /** - * Retuns the observation of this state. - * - * @return the observation. - */ - public StateObservation getObservation() { - return new StateObservation(fwdModel.copy()); - } - - /** - * Retuns the observation of this state (for multiplayer). - * - * @return the observation. - */ - public StateObservationMulti getObservationMulti() { - return new StateObservationMulti(fwdModel.copy()); - } - - /** - * Returns the sampleRandom object - * - * @return the sampleRandom generator. - */ - public Random getRandomGenerator() { - return random; - } - - /** - * Returns the current game tick of this game. - * - * @return the current game tick of this game. - */ - public int getGameTick() { - return gameTick; - } - - /** - * Returns the winner of this game. A value from Types.WINNER. - * - * @return the winner of this game. - */ - public Types.WINNER getWinner() { - return getWinner(0); - } - - /** - * Overloaded method for multi player games. Returns the win state of the - * specified player. - * - * @param playerID - * ID of the player. - * @return the win state of the specified player. - */ - public Types.WINNER getWinner(int playerID) { - return avatars[playerID].getWinState(); - } - - /** - * Returns an array of type Types.WINNER containing the win state of all - * players in the game. Index in the array corresponds to playerID. - * - * @return array of Types.WINNER values. - */ - public Types.WINNER[] getMultiWinner() { - Types.WINNER[] winners = new Types.WINNER[no_players]; - for (int i = 0; i < no_players; i++) { - winners[i] = avatars[i].getWinState(); - } - return winners; - } - - /** - * Gets the order in which the sprites are drawn. - * - * @return the order of the sprites. - */ - public int[] getSpriteOrder() { - return spriteOrder; - } - - /** - * Returns the number of sprites - */ - public static int getMaxSprites() { - return MAX_SPRITES; - } - - /** - * Indicates how many pixels form a block in the game. - * - * @return how many pixels form a block in the game. - */ - public int getBlockSize() { - return block_size; - } - - public abstract void buildStringLevel(String[] levelString, int randomSeed); - - /** - * Builds a level, receiving a file name. - * - * @param gamelvl - * file name containing the level. - */ - public void buildLevel(String gamelvl, int randomSeed) { - } - - public ArrayList getPath(Vector2d start, Vector2d end) { - Vector2d pathStart = new Vector2d(start); - Vector2d pathEnd = new Vector2d(end); - - pathStart.mul(1.0 / (double) block_size); - pathEnd.mul(1.0 / (double) block_size); - - return pathf.getPath(pathStart, pathEnd); - } - - public HashMap getParameters() { - return parameters; - } - - public void setParameters(HashMap parameters) { - this.parameters = parameters; - } - - /** - * Class for helping collision detection. - */ - protected class Bucket { - ArrayList allSprites; - HashMap> spriteLists; - int totalNumSprites; - - public Bucket() { - allSprites = new ArrayList(); - spriteLists = new HashMap>(); - totalNumSprites = 0; - } - - public void clear() { - allSprites.clear(); - spriteLists.clear(); - totalNumSprites = 0; - } - - public void add(VGDLSprite sp) { - int bucket = sp.bucket; - ArrayList sprites = spriteLists.get(bucket); - if (sprites == null) { - sprites = new ArrayList(); - spriteLists.put(bucket, sprites); - } - sprites.add(sp); - allSprites.add(sp); - totalNumSprites++; - } - - public int size() { - return totalNumSprites; - } - - public int size(int bucket) { - ArrayList sprites = spriteLists.get(bucket); - if (sprites == null) - return 0; - return sprites.size(); + + if (sprite.is_avatar) + // go through all avatars to see which avatar is dead + for (int i = 0; i < no_players; i++) + if (sprite == avatars[i]) + avatars[i] = null; + + num_sprites--; + + } + kill_list.clear(); + + for (int j = 0; j < spriteGroups.length; ++j) { + bucketList[j].clear(); + } + + resetShieldEffects(); + } + + /** + * Cleans the array of shielded effects. + */ + private void resetShieldEffects() { + for (int i = 0; i < shieldedEffects.length; ++i) + shieldedEffects[i].clear(); + } + + /** + * Adds a new Shield effect to the scene. + * + * @param type1 + * Recipient of the effect (sprite ID) + * @param type2 + * Second sprite ID + * @param functHash + * Hash of the effect name to shield. + */ + public void addShield(int type1, int type2, long functHash) { + Pair newShield = new Pair(type2, functHash); + shieldedEffects[type1].add(newShield); + } + + /** + * Adds a sprite given a content and position. + * + * @param itype + * integer that identifies the definition of the sprite to add + * @param position + * where the sprite has to be placed. + */ + public VGDLSprite addSprite(int itype, Vector2d position) { + return this.addSprite((SpriteContent) classConst[itype], position, itype, false); + } + + /** + * Adds a sprite given a content and position. + * + * @param itype + * integer that identifies the definition of the sprite to add + * @param position + * where the sprite has to be placed. + * @param force + * if true, ignores the singleton restrictions and creates it + * anyway. + */ + public VGDLSprite addSprite(int itype, Vector2d position, boolean force) { + return this.addSprite((SpriteContent) classConst[itype], position, itype, force); + } + + /** + * Adds a sprite given a content and position. It checks for possible + * singletons. + * + * @param content + * definition of the sprite to add + * @param position + * where the sprite has to be placed. + * @param itype + * integer identifier of this type of sprite. + * @param force + * If true, forces the creation ignoring singleton restrictions + */ + public VGDLSprite addSprite(SpriteContent content, Vector2d position, int itype, boolean force) { + if (num_sprites > MAX_SPRITES) { + Logger.getInstance().addMessage(new Message(Message.WARNING, "Sprite limit reached.")); + return null; + } + + // Check for singleton Sprites + boolean anyother = false; + if (!force) { + + for (Integer typeInt : content.itypes) { + // If this type is a singleton and we have one already + if (singletons[typeInt] && getNumSprites(typeInt) > 0) { + // that's it, no more creations of this type. + anyother = true; + break; + } + } + } + + // Only create the sprite if there is not any other sprite that blocks + // it. + if (!anyother) { + VGDLSprite newSprite; + + if (templateSprites[itype] == null) // don't have a template yet, so + // need to create one + { + newSprite = VGDLFactory.GetInstance().createSprite(this, content, position, + new Dimension(block_size, block_size)); + + // Assign its types and add it to the collection of sprites. + newSprite.itypes = (ArrayList) content.itypes.clone(); + + // save a copy as template object + templateSprites[itype] = newSprite.copy(); + } else // we already have a template, so simply copy that one + { + newSprite = templateSprites[itype].copy(); + + // make sure the copy is moved to the correct position + newSprite.setRect(position, new Dimension(block_size, block_size)); + + // Set last rect + newSprite.lastrect = new Rectangle(newSprite.rect); + } + + // add the sprite to the collection of sprites in the game + this.addSprite(newSprite, itype); + return newSprite; + } + + Logger.getInstance().addMessage(new Message(Message.WARNING, "You can't have multiple objects of singleton.")); + return null; + } + + public void _updateCollisionDict(VGDLSprite sprite) { + } + + /** + * Returns the game score. + */ + public double getScore() { + return getScore(0); + } + + /** + * Method overloaded for multi player games. Returns the game score of the + * specified player. + * + * @param playerID + * ID of the player. + */ + public double getScore(int playerID) { + return avatars[playerID].getScore(); + } + + /** + * Reverses the direction of a given sprite. + * + * @param sprite + * sprite to reverse. + */ + public void reverseDirection(VGDLSprite sprite) { + sprite.orientation = new Direction(-sprite.orientation.x(), -sprite.orientation.y()); + } + + /** + * Kills a given sprite, adding it to the list of sprites killed at this + * step. + * + * @param sprite + * the sprite to kill. + * @param transformed + * - indicates if the sprite was transformed (necessary to kill + * sprite even if avatar, instead of disabling it). + */ + public void killSprite(VGDLSprite sprite, boolean transformed) { + if (sprite instanceof MovingAvatar && !transformed) { // if avatar, just + // disable + sprite.setDisabled(true); + } else { + kill_list.add(sprite); + } } - public ArrayList getAllSprites() { - return allSprites; + /** + * Gets an iterator for the collection of sprites for a particular sprite + * type. + * + * @param spriteItype + * type of the sprite to retrieve. + * @return sprite collection of the specified type. + */ + public Iterator getSpriteGroup(int spriteItype) { + return spriteGroups[spriteItype].getSpriteIterator(); + } + + /** + * Gets an iterator for the collection of sprites for a particular sprite + * type, AND all subtypes. + * + * @param spriteItype + * type of the sprite to retrieve. + * @return sprite collection of the specified type and subtypes. + */ + public Iterator getSubSpritesGroup(int spriteItype) { + // Create a sprite group for all the sprites + SpriteGroup allSprites = new SpriteGroup(spriteItype); + // Get all the subtypes + ArrayList allTypes = iSubTypes[spriteItype]; + + // Add sprites of this type, and all subtypes. + allSprites.addAllSprites(this.getSprites(spriteItype)); + for (Integer itype : allTypes) { + allSprites.addAllSprites(this.getSprites(itype)); + } + + // Return the iterator. + return allSprites.getSpriteIterator(); + } + + /** + * Gets the collection of sprites for a particular sprite type. + * + * @param spriteItype + * type of the sprite to retrieve. + * @return sprite collection of the specified type. + */ + public ArrayList getSprites(int spriteItype) { + return spriteGroups[spriteItype].getSprites(); + } + + /** + * Gets the array of collisions defined for two types of sprites. + * + * @param spriteItype1 + * type of the first sprite. + * @param spriteItype2 + * type of the second sprite. + * @return the collection of the effects defined between the two sprite + * types. + */ + public ArrayList getCollisionEffects(int spriteItype1, int spriteItype2) { + return collisionEffects[spriteItype1][spriteItype2]; + } + + /** + * Returns all paired effects defined in the game. + * + * @return all paired effects defined in the game. + */ + public ArrayList> getDefinedEffects() { + return definedEffects; + } + + /** + * Returns the list of sprite type with at least one EOS effect defined. + * + * @return the list of sprite type with at least one EOS effect defined. + */ + public ArrayList getDefinedEosEffects() { + return definedEOSEffects; + } + + /** + * Returns all EOS effects defined in the game. + * + * @return all EOS effects defined in the game. + */ + public ArrayList getEosEffects(int obj1) { + return eosEffects[obj1]; + } + + /** + * Adds a time effect to the game. + */ + public void addTimeEffect(TimeEffect ef) { + timeEffects.add(ef); + } + + /** + * Returns the char mapping of this array, that relates characters in the + * level with sprite names that it references. + * + * @return the char mapping of this array. For each character, there is a + * list of N sprite names. + */ + public HashMap> getCharMapping() { + return charMapping; + } + + /** + * Set the char mapping that is used to parse loaded levels + * + * @param charMapping + * new character mapping + */ + public void setCharMapping(HashMap> charMapping) { + this.charMapping = charMapping; + } + + /** + * Gets the array of termination conditions for this game. + * + * @return the array of termination conditions. + */ + public ArrayList getTerminations() { + return terminations; + } + + /** + * Gets the maximum amount of resources of type resourceId that are allowed + * by entities in the game. + * + * @param resourceId + * the id of the resource to query for. + * @return maximum amount of resources of type resourceId. + */ + public int getResourceLimit(int resourceId) { + return resources_limits[resourceId]; + } + + /** + * Gets the color of the resource of type resourceId + * + * @param resourceId + * id of the resource to query for. + * @return Color assigned to this resource. + */ + public Color getResourceColor(int resourceId) { + return resources_colors[resourceId]; + } + + /** + * Gets the dimensions of the screen. + * + * @return the dimensions of the screen. + */ + public Dimension getScreenSize() { + return screenSize; + } + + /** + * Defines this game as stochastic (or not) depending on the parameter + * passed. + * + * @param stoch + * true if the game is stochastic. + */ + public void setStochastic(boolean stoch) { + is_stochastic = stoch; + } + + /** + * Returns the avatar of the game in single player games. + * + * @return the avatar of the game. + */ + public MovingAvatar getAvatar() { + return getAvatar(0); + } + + /** + * Overloaded method, returns the avatar of the player specified (for multi + * player games). + * + * @param playerID + * ID of the player desired. + * @return the corresponding avatar. + */ + public MovingAvatar getAvatar(int playerID) { + return avatars[playerID]; + } + + /** + * Returns an array of all avatars in the game. + * + * @return array of avatars. + */ + public MovingAvatar[] getAvatars() { + return avatars; + } + + /** + * Sets the avatar of the game. + * + * @param newAvatar + * the avatar of the game. + */ + public void setAvatar(MovingAvatar newAvatar) { + avatars[0] = newAvatar; + } + + /** + * Overloaded method, sets the avatar specified. + * + * @param newAvatar + * the avatar of the game. + * @param playerID + * the ID of the player desired. + */ + public void setAvatar(MovingAvatar newAvatar, int playerID) { + avatars[playerID] = newAvatar; + } + + /** + * Sets the last action executed by the avatar. It could be NIL in case of + * time overspent. + * + * @param action + * the action to set. + */ + public void setAvatarLastAction(Types.ACTIONS action) { + setAvatarLastAction(action, 0); + } + + /** + * Overloaded method for multi player games. Sets the last action executed + * by the avatar with the corresponding player ID. It could be NIL in case + * of time overspent. + * + * @param action + * the action to set. + * @param playerID + * the ID of the player. + */ + public void setAvatarLastAction(Types.ACTIONS action, int playerID) { + this.avatarLastAction[playerID] = action; + } + + /** + * Indicates if the game is over, or if it is still being played. + * + * @return true if the game is over, false if it is still being played. + */ + public abstract boolean isGameOver(); + + /** + * clear all the interactions and termination in the current game + */ + public void clearInteractionTerminationData() { + this.setStochastic(false); + this.terminations.clear(); + + this.definedEffects.clear(); + for (int i = 0; i < this.collisionEffects.length; i++) { + for (int j = 0; j < this.collisionEffects[i].length; j++) { + this.collisionEffects[i][j].clear(); + } + } + + this.definedEOSEffects.clear(); + for (int i = 0; i < this.eosEffects.length; i++) { + this.eosEffects[i].clear(); + } + + this.timeEffects.clear(); + } + + /** + * Retuns the observation of this state. + * + * @return the observation. + */ + public StateObservation getObservation() { + return new StateObservation(fwdModel.copy()); + } + + /** + * Retuns the observation of this state (for multiplayer). + * + * @return the observation. + */ + public StateObservationMulti getObservationMulti() { + return new StateObservationMulti(fwdModel.copy()); + } + + /** + * Returns the sampleRandom object + * + * @return the sampleRandom generator. + */ + public Random getRandomGenerator() { + return random; + } + + /** + * Returns the current game tick of this game. + * + * @return the current game tick of this game. + */ + public int getGameTick() { + return gameTick; + } + + /** + * Returns the winner of this game. A value from Types.WINNER. + * + * @return the winner of this game. + */ + public Types.WINNER getWinner() { + return getWinner(0); + } + + /** + * Overloaded method for multi player games. Returns the win state of the + * specified player. + * + * @param playerID + * ID of the player. + * @return the win state of the specified player. + */ + public Types.WINNER getWinner(int playerID) { + return avatars[playerID].getWinState(); + } + + /** + * Returns an array of type Types.WINNER containing the win state of all + * players in the game. Index in the array corresponds to playerID. + * + * @return array of Types.WINNER values. + */ + public Types.WINNER[] getMultiWinner() { + Types.WINNER[] winners = new Types.WINNER[no_players]; + for (int i = 0; i < no_players; i++) { + winners[i] = avatars[i].getWinState(); + } + return winners; } - - public HashMap> getSpriteList() { - return spriteLists; + + /** + * Gets the order in which the sprites are drawn. + * + * @return the order of the sprites. + */ + public int[] getSpriteOrder() { + return spriteOrder; } - } + /** + * Returns the number of sprites + */ + public static int getMaxSprites() { + return MAX_SPRITES; + } + + /** + * Indicates how many pixels form a block in the game. + * + * @return how many pixels form a block in the game. + */ + public int getBlockSize() { + return block_size; + } + + public abstract void buildStringLevel(String[] levelString, int randomSeed); + + /** + * Builds a level, receiving a file name. + * + * @param gamelvl + * file name containing the level. + */ + public void buildLevel(String gamelvl, int randomSeed) { + } + + public ArrayList getPath(Vector2d start, Vector2d end) { + Vector2d pathStart = new Vector2d(start); + Vector2d pathEnd = new Vector2d(end); + + pathStart.mul(1.0 / (double) block_size); + pathEnd.mul(1.0 / (double) block_size); + + return pathf.getPath(pathStart, pathEnd); + } + + public HashMap getParameters() { + return parameters; + } + + public void setParameters(HashMap parameters) { + this.parameters = parameters; + } + + /** + * Class for helping collision detection. + */ + protected class Bucket { + ArrayList allSprites; + HashMap> spriteLists; + int totalNumSprites; + + public Bucket() { + allSprites = new ArrayList(); + spriteLists = new HashMap>(); + totalNumSprites = 0; + } + + public void clear() { + allSprites.clear(); + spriteLists.clear(); + totalNumSprites = 0; + } + + public void add(VGDLSprite sp) { + int bucket = sp.bucket; + ArrayList sprites = spriteLists.get(bucket); + if (sprites == null) { + sprites = new ArrayList(); + spriteLists.put(bucket, sprites); + } + sprites.add(sp); + allSprites.add(sp); + totalNumSprites++; + } + + public int size() { + return totalNumSprites; + } + + public int size(int bucket) { + ArrayList sprites = spriteLists.get(bucket); + if (sprites == null) + return 0; + return sprites.size(); + } + + public ArrayList getAllSprites() { + return allSprites; + } + + public HashMap> getSpriteList() { + return spriteLists; + } + + } } diff --git a/src/core/game/GameDescription.java b/src/core/game/GameDescription.java index 79ad4784fc..215eca749d 100644 --- a/src/core/game/GameDescription.java +++ b/src/core/game/GameDescription.java @@ -15,474 +15,474 @@ /** * This is an abstract class encapsulating all the data required for generating * and testing game levels. - * + * * @author Ahmed A Khalifa */ public class GameDescription { - /** - * object from the current loaded game. This object is used to initialize - * other fields and get interaction data. - */ - private Game currentGame; - - /** - * abstract data about main avatar - */ - private ArrayList avatar; - - /** - * list of all allowed actions by the avatar including the NIL action - */ - private ArrayList actionsNIL; - - /** - * list of all allowed actions by the avatar - */ - private ArrayList actions; - - /** - * list of sprite data for all npc labeled objects - */ - private ArrayList npcList; - - /** - * list of sprite data for all portal labeled objects - */ - private ArrayList portalList; - - /** - * list of sprite data for all resource labeled objects - */ - private ArrayList resourceList; - - /** - * list of sprite data for all static labeled objects - */ - private ArrayList staticList; - - /** - * list of sprite data that is not labeled any of the previous - */ - private ArrayList movingList; - - /** - * list of termination data objects that supplies game termination - * conditions - */ - private ArrayList terminationData; - - /** - * - */ - private HashMap> charMapping; - - /** - * Constructor to the Game Description. It initialize all the data using the - * passed game object. - * - * @param currentGame - * The current running game object. - */ - public GameDescription(Game currentGame) { - this.currentGame = currentGame; - this.avatar = new ArrayList(); - this.npcList = new ArrayList(); - this.portalList = new ArrayList(); - this.resourceList = new ArrayList(); - this.staticList = new ArrayList(); - this.movingList = new ArrayList(); - this.charMapping = currentGame.getCharMapping(); - - reset(currentGame); - } - - private boolean checkHaveInteraction(String stype) { - ArrayList allSprites = currentGame.getSpriteData(); - for (SpriteData sprite : allSprites) { - if (getInteraction(stype, sprite.name).size() > 0) { - return true; - } - if (getInteraction(sprite.name, stype).size() > 0) { - return true; - } + /** + * object from the current loaded game. This object is used to initialize + * other fields and get interaction data. + */ + private Game currentGame; + + /** + * abstract data about main avatar + */ + private ArrayList avatar; + + /** + * list of all allowed actions by the avatar including the NIL action + */ + private ArrayList actionsNIL; + + /** + * list of all allowed actions by the avatar + */ + private ArrayList actions; + + /** + * list of sprite data for all npc labeled objects + */ + private ArrayList npcList; + + /** + * list of sprite data for all portal labeled objects + */ + private ArrayList portalList; + + /** + * list of sprite data for all resource labeled objects + */ + private ArrayList resourceList; + + /** + * list of sprite data for all static labeled objects + */ + private ArrayList staticList; + + /** + * list of sprite data that is not labeled any of the previous + */ + private ArrayList movingList; + + /** + * list of termination data objects that supplies game termination + * conditions + */ + private ArrayList terminationData; + + /** + * + */ + private HashMap> charMapping; + + /** + * Constructor to the Game Description. It initialize all the data using the + * passed game object. + * + * @param currentGame + * The current running game object. + */ + public GameDescription(Game currentGame) { + this.currentGame = currentGame; + this.avatar = new ArrayList(); + this.npcList = new ArrayList(); + this.portalList = new ArrayList(); + this.resourceList = new ArrayList(); + this.staticList = new ArrayList(); + this.movingList = new ArrayList(); + this.charMapping = currentGame.getCharMapping(); + + reset(currentGame); } - return false; - } - - /** - * Reset the game description object and assign new game object - * - * @param currentGame - * new game object assigned - */ - public void reset(Game currentGame) { - this.currentGame = currentGame; - this.avatar.clear(); - this.npcList.clear(); - this.portalList.clear(); - this.resourceList.clear(); - this.staticList.clear(); - this.movingList.clear(); - this.charMapping = currentGame.getCharMapping(); - - ArrayList allSprites = this.currentGame.getSpriteData(); - for (SpriteData sd : allSprites) { - if (sd.isAvatar) { - if (checkHaveInteraction(sd.name)) { - avatar.add(sd); + private boolean checkHaveInteraction(String stype) { + ArrayList allSprites = currentGame.getSpriteData(); + for (SpriteData sprite : allSprites) { + if (getInteraction(stype, sprite.name).size() > 0) { + return true; + } + if (getInteraction(sprite.name, stype).size() > 0) { + return true; + } } - } else if (sd.isNPC) { - npcList.add(sd); - } else if (sd.isPortal) { - portalList.add(sd); - } else if (sd.isResource) { - resourceList.add(sd); - } else if (sd.isStatic) { - staticList.add(sd); - } else { - movingList.add(sd); - } - } - for (int i = 0; i < avatar.size(); i++) { - MovingAvatar temp = (MovingAvatar) currentGame.getTempAvatar(avatar.get(i)); - if (actions == null || actions.size() < temp.actions.size()) { - actionsNIL = temp.actionsNIL; - actions = temp.actions; - } + return false; } - terminationData = currentGame.getTerminationData(); - } - - /** - * Build the generated level to be tested using an agent using the original - * Level Mapping. - * - * @param level - * a string of characters that are supplied in the character - * mapping - * @return StateObservation object that can be used to simulate the game. - * return null when there is errors - */ - public StateObservation testLevel(String level) { - return testLevel(level, null); - } - - /** - * Build the generated level to be tested using an agent. You should call - * this version if you are using your own character mapping - * - * @param level - * a string of characters that are supplied in the character - * mapping - * @return StateObservation object that can be used to simulate the game. - * return null when there is errors - */ - public StateObservation testLevel(String level, HashMap> charMapping) { - Logger.getInstance().flushMessages(); - - if (charMapping != null) { - currentGame.setCharMapping(charMapping); - } - String[] lines = level.split("\n"); - currentGame.reset(); - currentGame.buildStringLevel(lines, new Random().nextInt()); - currentGame.setCharMapping(this.charMapping); - - if(Logger.getInstance().getMessageCount(1) > 0){ - return null; - } - return currentGame.getObservation(); - } - - /** - * get list of errors and warnings from the system - * - * @return a list of errors and warnings - * type 0: warnings - * type 1: errors - */ - public ArrayList getErrors(){ - return Logger.getInstance().getMessages(); - } - - /** - * Get player supported actions - * - * @param includeNIL - * boolean to identify if the NIL action should exists in the - * supported actions - * @return list of all player supported actions - */ - public ArrayList getAvailableActions(boolean includeNIL) { - if (includeNIL) { - return actionsNIL; + /** + * Reset the game description object and assign new game object + * + * @param currentGame + * new game object assigned + */ + public void reset(Game currentGame) { + this.currentGame = currentGame; + this.avatar.clear(); + this.npcList.clear(); + this.portalList.clear(); + this.resourceList.clear(); + this.staticList.clear(); + this.movingList.clear(); + this.charMapping = currentGame.getCharMapping(); + + ArrayList allSprites = this.currentGame.getSpriteData(); + for (SpriteData sd : allSprites) { + if (sd.isAvatar) { + if (checkHaveInteraction(sd.name)) { + avatar.add(sd); + } + } else if (sd.isNPC) { + npcList.add(sd); + } else if (sd.isPortal) { + portalList.add(sd); + } else if (sd.isResource) { + resourceList.add(sd); + } else if (sd.isStatic) { + staticList.add(sd); + } else { + movingList.add(sd); + } + } + + for (int i = 0; i < avatar.size(); i++) { + MovingAvatar temp = (MovingAvatar) currentGame.getTempAvatar(avatar.get(i)); + if (actions == null || actions.size() < temp.actions.size()) { + actionsNIL = temp.actionsNIL; + actions = temp.actions; + } + } + + terminationData = currentGame.getTerminationData(); } - return actions; - } - - /** - * Get avatar sprite data information - * - * @return avatar's sprite data - */ - public ArrayList getAvatar() { - return avatar; - } - - /** - * Get NPCs sprite data information - * - * @return array of sprite data - */ - public ArrayList getNPC() { - return npcList; - } - - /** - * Get Statics sprite data information - * - * @return array of sprite data - */ - public ArrayList getStatic() { - return staticList; - } - - /** - * Get Resources sprite data information - * - * @return array of sprite data - */ - public ArrayList getResource() { - return resourceList; - } - - /** - * Get Portals sprite data information - * - * @return array of sprite data - */ - public ArrayList getPortal() { - return portalList; - } - - /** - * Get all movable sprites - * - * @return arary of sprite data - */ - public ArrayList getMoving() { - return movingList; - } - - /** - * Get all defined game sprites - * - * @return an array of sprite data - */ - public ArrayList getAllSpriteData() { - ArrayList result = new ArrayList(); - result.addAll(avatar); - result.addAll(npcList); - result.addAll(resourceList); - result.addAll(staticList); - result.addAll(portalList); - result.addAll(movingList); - - return result; - } - - /** - * Get a list of all effects happening to the first sprite - * - * @param stype1 - * the sprite name of the first sprite in the collision - * @param stype2 - * the sprite name of the second sprite in the collision - * @return an array of all possible effects. If there is no effects, an - * empty array is returned - */ - public ArrayList getInteraction(String stype1, String stype2) { - int itype1 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(stype1); - int itype2 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(stype2); - - return currentGame.getInteractionData(itype1, itype2); - } - - /** - * Get a list of all termination conditions for the current game - * - * @return an array of termination data objects - */ - public ArrayList getTerminationConditions() { - return terminationData; - } - - /** - * Get default character mapping - * - * @return hashmap of level characters and their corresponding sprites - */ - public HashMap> getLevelMapping() { - return charMapping; - } - - /** - * Simple data class represents all game sprites - */ - public static class SpriteData implements Cloneable { - private HashMap parameters; - /** - * VGDL class type for the current sprite + * Build the generated level to be tested using an agent using the original + * Level Mapping. + * + * @param level + * a string of characters that are supplied in the character + * mapping + * @return StateObservation object that can be used to simulate the game. + * return null when there is errors */ - public String type; + public StateObservation testLevel(String level) { + return testLevel(level, null); + } /** - * Sprite name + * Build the generated level to be tested using an agent. You should call + * this version if you are using your own character mapping + * + * @param level + * a string of characters that are supplied in the character + * mapping + * @return StateObservation object that can be used to simulate the game. + * return null when there is errors */ - public String name; + public StateObservation testLevel(String level, HashMap> charMapping) { + Logger.getInstance().flushMessages(); + + if (charMapping != null) { + currentGame.setCharMapping(charMapping); + } + String[] lines = level.split("\n"); + currentGame.reset(); + currentGame.buildStringLevel(lines, new Random().nextInt()); + currentGame.setCharMapping(this.charMapping); + + if(Logger.getInstance().getMessageCount(1) > 0){ + return null; + } + return currentGame.getObservation(); + } /** - * List of all dependent sprite names + * get list of errors and warnings from the system + * + * @return a list of errors and warnings + * type 0: warnings + * type 1: errors */ - public ArrayList sprites; + public ArrayList getErrors(){ + return Logger.getInstance().getMessages(); + } - public boolean isSingleton; + /** + * Get player supported actions + * + * @param includeNIL + * boolean to identify if the NIL action should exists in the + * supported actions + * @return list of all player supported actions + */ + public ArrayList getAvailableActions(boolean includeNIL) { + if (includeNIL) { + return actionsNIL; + } - public boolean isAvatar; - public boolean isNPC; - public boolean isPortal; - public boolean isResource; - public boolean isStatic; + return actions; + } - public SpriteData(HashMap parameters) { - this.sprites = new ArrayList(); - this.parameters = parameters; + /** + * Get avatar sprite data information + * + * @return avatar's sprite data + */ + public ArrayList getAvatar() { + return avatar; } - @Override - public String toString() { - String reset = ""; - for(String key:parameters.keySet()){ - reset += " " + key + "=" + parameters.get(key); - } - return name + " > " + type + " " + reset; + /** + * Get NPCs sprite data information + * + * @return array of sprite data + */ + public ArrayList getNPC() { + return npcList; } - + /** - * Used in encode the names sprites - * @param oldName the current name for the sprite - * @param newName the new name for the sprite + * Get Statics sprite data information + * + * @return array of sprite data */ - public void changeSpriteName(String oldName, String newName){ - if(name.equalsIgnoreCase(oldName)){ - name = newName; - } - for(int i=0; i getStatic() { + return staticList; } - @Override - protected Object clone() throws CloneNotSupportedException { - SpriteData s = new SpriteData(this.parameters); - s.type = type; - s.name = name; - for (int i = 0; i < sprites.size(); i++) { - s.sprites.add(sprites.get(i)); - } - s.isSingleton = isSingleton; - s.isAvatar = isAvatar; - s.isNPC = isNPC; - s.isPortal = isPortal; - s.isResource = isResource; - s.isStatic = isStatic; - - return s; + /** + * Get Resources sprite data information + * + * @return array of sprite data + */ + public ArrayList getResource() { + return resourceList; } - } - /** - * Simple data class represents all game termination conditions - */ - public static class TerminationData { /** - * Termination Condition type + * Get Portals sprite data information + * + * @return array of sprite data */ - public String type; + public ArrayList getPortal() { + return portalList; + } /** - * Array of all dependent sprite names + * Get all movable sprites + * + * @return arary of sprite data */ - public ArrayList sprites; + public ArrayList getMoving() { + return movingList; + } /** - * Condition Limit + * Get all defined game sprites + * + * @return an array of sprite data */ - public int limit; + public ArrayList getAllSpriteData() { + ArrayList result = new ArrayList(); + result.addAll(avatar); + result.addAll(npcList); + result.addAll(resourceList); + result.addAll(staticList); + result.addAll(portalList); + result.addAll(movingList); + + return result; + } /** - * String containing booleans to differentiate between Winning or Losing - * Condition + * Get a list of all effects happening to the first sprite + * + * @param stype1 + * the sprite name of the first sprite in the collision + * @param stype2 + * the sprite name of the second sprite in the collision + * @return an array of all possible effects. If there is no effects, an + * empty array is returned */ - public String win; + public ArrayList getInteraction(String stype1, String stype2) { + int itype1 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(stype1); + int itype2 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(stype2); - public TerminationData() { - sprites = new ArrayList(); + return currentGame.getInteractionData(itype1, itype2); } /** - * Player ID for win state used is 0, default for single player games. - * - * @return + * Get a list of all termination conditions for the current game + * + * @return an array of termination data objects */ - @Override - public String toString() { - String[] winners = win.split(","); - String result = Boolean.parseBoolean(winners[0]) ? "Win" : "Lose"; - result += ":" + type + " " + sprites.toString(); - return result; + public ArrayList getTerminationConditions() { + return terminationData; } - } - /** - * Simple data class represents the interaction between game sprites - */ - public static class InteractionData { /** - * Interaction class type + * Get default character mapping + * + * @return hashmap of level characters and their corresponding sprites */ - public String type; + public HashMap> getLevelMapping() { + return charMapping; + } /** - * The amount of score this interaction changes + * Simple data class represents all game sprites */ - public String scoreChange; + public static class SpriteData implements Cloneable { + private HashMap parameters; + + /** + * VGDL class type for the current sprite + */ + public String type; + + /** + * Sprite name + */ + public String name; + + /** + * List of all dependent sprite names + */ + public ArrayList sprites; + + public boolean isSingleton; + + public boolean isAvatar; + public boolean isNPC; + public boolean isPortal; + public boolean isResource; + public boolean isStatic; + + public SpriteData(HashMap parameters) { + this.sprites = new ArrayList(); + this.parameters = parameters; + } + + @Override + public String toString() { + String reset = ""; + for(String key:parameters.keySet()){ + reset += " " + key + "=" + parameters.get(key); + } + return name + " > " + type + " " + reset; + } + + /** + * Used in encode the names sprites + * @param oldName the current name for the sprite + * @param newName the new name for the sprite + */ + public void changeSpriteName(String oldName, String newName){ + if(name.equalsIgnoreCase(oldName)){ + name = newName; + } + for(int i=0; i sprites; + public static class TerminationData { + /** + * Termination Condition type + */ + public String type; + + /** + * Array of all dependent sprite names + */ + public ArrayList sprites; + + /** + * Condition Limit + */ + public int limit; + + /** + * String containing booleans to differentiate between Winning or Losing + * Condition + */ + public String win; + + public TerminationData() { + sprites = new ArrayList(); + } - public InteractionData() { - sprites = new ArrayList(); + /** + * Player ID for win state used is 0, default for single player games. + * + * @return + */ + @Override + public String toString() { + String[] winners = win.split(","); + String result = Boolean.parseBoolean(winners[0]) ? "Win" : "Lose"; + result += ":" + type + " " + sprites.toString(); + return result; + } } - @Override - public String toString() { - return type + " (" + scoreChange + ") " + sprites.toString(); + /** + * Simple data class represents the interaction between game sprites + */ + public static class InteractionData { + /** + * Interaction class type + */ + public String type; + + /** + * The amount of score this interaction changes + */ + public String scoreChange; + + /** + * All the depending sprites on that + */ + public ArrayList sprites; + + public InteractionData() { + sprites = new ArrayList(); + } + + @Override + public String toString() { + return type + " (" + scoreChange + ") " + sprites.toString(); + } } - } } diff --git a/src/core/game/SLDescription.java b/src/core/game/SLDescription.java index 14c0c3e061..29b426a6bf 100644 --- a/src/core/game/SLDescription.java +++ b/src/core/game/SLDescription.java @@ -11,355 +11,355 @@ import core.logging.Message; public class SLDescription { - /** - * the keyword to encode the sprites in the game - */ - private String KEYWORD = "sprite"; - - /** - * the current game object - */ - private Game currentGame; - /** - * the current level - */ - private String[] level; - /** - * the current game sprites - */ - private SpriteData[] gameSprites; - /** - * the current encoded level - */ - private String[][] currentLevel; + /** + * the keyword to encode the sprites in the game + */ + private String KEYWORD = "sprite"; - /** - * the seed value to encode the names - */ - private int shift; + /** + * the current game object + */ + private Game currentGame; + /** + * the current level + */ + private String[] level; + /** + * the current game sprites + */ + private SpriteData[] gameSprites; + /** + * the current encoded level + */ + private String[][] currentLevel; - /** - * random object for random seeds - */ - private Random random; + /** + * the seed value to encode the names + */ + private int shift; - /** - * constructor for the SLDescription contains information about game sprites - * and the current level - * - * @param currentGame - * the current game - * @param level - * the current level - * @param shift - * random seed to encode the sprites - * @throws Exception - * if the level is empty - */ - public SLDescription(Game currentGame, String[] level, int shift) throws Exception { - this.currentGame = currentGame; - this.level = level; - this.gameSprites = null; - this.currentLevel = null; + /** + * random object for random seeds + */ + private Random random; - this.shift = shift; - this.random = new Random(this.shift); + /** + * constructor for the SLDescription contains information about game sprites + * and the current level + * + * @param currentGame + * the current game + * @param level + * the current level + * @param shift + * random seed to encode the sprites + * @throws Exception + * if the level is empty + */ + public SLDescription(Game currentGame, String[] level, int shift) throws Exception { + this.currentGame = currentGame; + this.level = level; + this.gameSprites = null; + this.currentLevel = null; - this.reset(currentGame, level); - } + this.shift = shift; + this.random = new Random(this.shift); - /** - * reset the current variables to a new current game and level - * - * @param currentGame - * the new game - * @param level - * the new level - * @throws Exception - * if the level is empty - */ - public void reset(Game currentGame, String[] level) throws Exception { - this.currentGame = currentGame; - this.level = level; - if (this.currentGame == null) { - return; + this.reset(currentGame, level); } + /** - * get all the game sprites in the game + * reset the current variables to a new current game and level + * + * @param currentGame + * the new game + * @param level + * the new level + * @throws Exception + * if the level is empty */ - ArrayList list = this.currentGame.getSpriteData(); - this.gameSprites = new SpriteData[list.size()]; - for (int i = 0; i < this.gameSprites.length; i++) { - this.gameSprites[i] = list.get(i); - } + public void reset(Game currentGame, String[] level) throws Exception { + this.currentGame = currentGame; + this.level = level; + if (this.currentGame == null) { + return; + } + /** + * get all the game sprites in the game + */ + ArrayList list = this.currentGame.getSpriteData(); + this.gameSprites = new SpriteData[list.size()]; + for (int i = 0; i < this.gameSprites.length; i++) { + this.gameSprites[i] = list.get(i); + } - if (this.level == null) { - throw new Exception("level can't be null while game is not"); + if (this.level == null) { + throw new Exception("level can't be null while game is not"); + } + /** + * encode the level map + */ + HashMap> levelMapping = this.currentGame.getCharMapping(); + this.currentLevel = new String[level.length][getWidth(level)]; + for (int i = 0; i < this.currentLevel.length; i++) { + for (int j = 0; j < this.currentLevel[i].length; j++) { + if (j >= this.currentLevel[i].length) { + // if the length of the line shorter than the maximum width + this.currentLevel[i][j] = ""; + } else { + ArrayList tempSprites = levelMapping.get(level[i].charAt(j)); + if (tempSprites == null || tempSprites.size() == 0) { + // empty location + this.currentLevel[i][j] = ""; + } else { + // encode the different sprites + this.currentLevel[i][j] = this.encodeName(tempSprites.get(0), this.shift); + for (int k = 1; k < tempSprites.size(); k++) { + this.currentLevel[i][j] += ", " + this.encodeName(tempSprites.get(k), this.shift); + } + } + } + } + } } + /** - * encode the level map + * get the width of the level + * + * @param level + * current level + * @return width of the level */ - HashMap> levelMapping = this.currentGame.getCharMapping(); - this.currentLevel = new String[level.length][getWidth(level)]; - for (int i = 0; i < this.currentLevel.length; i++) { - for (int j = 0; j < this.currentLevel[i].length; j++) { - if (j >= this.currentLevel[i].length) { - // if the length of the line shorter than the maximum width - this.currentLevel[i][j] = ""; - } else { - ArrayList tempSprites = levelMapping.get(level[i].charAt(j)); - if (tempSprites == null || tempSprites.size() == 0) { - // empty location - this.currentLevel[i][j] = ""; - } else { - // encode the different sprites - this.currentLevel[i][j] = this.encodeName(tempSprites.get(0), this.shift); - for (int k = 1; k < tempSprites.size(); k++) { - this.currentLevel[i][j] += ", " + this.encodeName(tempSprites.get(k), this.shift); + private int getWidth(String[] level) { + int width = 0; + for (int i = 0; i < level.length; i++) { + if (level[i].length() > width) { + width = level[i].length(); } - } } - } - } - } - /** - * get the width of the level - * - * @param level - * current level - * @return width of the level - */ - private int getWidth(String[] level) { - int width = 0; - for (int i = 0; i < level.length; i++) { - if (level[i].length() > width) { - width = level[i].length(); - } + return width; } - return width; - } - - /** - * encode the current sprite index to a new index - * - * @param index - * current sprite index - * @return encoded sprite index - */ - private int encodeIndex(int index, int seed) { - return index ^ seed; - } + /** + * encode the current sprite index to a new index + * + * @param index + * current sprite index + * @return encoded sprite index + */ + private int encodeIndex(int index, int seed) { + return index ^ seed; + } - /** - * encode sprite name to an encoded index - * - * @param name - * the current sprite name to be encoded - * @return encoded index for a sprite name - */ - private String encodeName(String name, int seed) { - for (int i = 0; i < this.gameSprites.length; i++) { - if (this.gameSprites[i].name.toLowerCase().trim().equals(name.toLowerCase().trim())) { - int result = encodeIndex(i, seed); - return KEYWORD + "_" + result; - } + /** + * encode sprite name to an encoded index + * + * @param name + * the current sprite name to be encoded + * @return encoded index for a sprite name + */ + private String encodeName(String name, int seed) { + for (int i = 0; i < this.gameSprites.length; i++) { + if (this.gameSprites[i].name.toLowerCase().trim().equals(name.toLowerCase().trim())) { + int result = encodeIndex(i, seed); + return KEYWORD + "_" + result; + } + } + return ""; } - return ""; - } - /** - * decode the sprite index - * - * @param value - * current encoded sprite name - * @return correct sprite name - */ - private String decodeIndex(int value, int seed) { - if((value ^ seed) < 0 || (value ^ seed) >= this.gameSprites.length){ - return ""; + /** + * decode the sprite index + * + * @param value + * current encoded sprite name + * @return correct sprite name + */ + private String decodeIndex(int value, int seed) { + if((value ^ seed) < 0 || (value ^ seed) >= this.gameSprites.length){ + return ""; + } + return this.gameSprites[value ^ seed].name; } - return this.gameSprites[value ^ seed].name; - } - - /** - * decode the sprite name - * - * @param value - * current encoded sprite name - * @return correct sprite name - */ - public String decodeName(String value, int seed) { - if(!value.contains(KEYWORD + "_")){ - return ""; + + /** + * decode the sprite name + * + * @param value + * current encoded sprite name + * @return correct sprite name + */ + public String decodeName(String value, int seed) { + if(!value.contains(KEYWORD + "_")){ + return ""; + } + int index = Integer.parseInt(value.split(KEYWORD + "_")[1]); + if((index ^ seed) < 0 || (index ^ seed) >= this.gameSprites.length){ + return ""; + } + return this.gameSprites[index ^ seed].name; } - int index = Integer.parseInt(value.split(KEYWORD + "_")[1]); - if((index ^ seed) < 0 || (index ^ seed) >= this.gameSprites.length){ - return ""; + + /** + * get an array of game sprites + * + * @return array contain all the game sprites + */ + public SpriteData[] getGameSprites() { + SpriteData[] result = new SpriteData[this.gameSprites.length]; + for (int i = 0; i < result.length; i++) { + try { + result[i] = (SpriteData) this.gameSprites[i].clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + result[i].changeSpriteName(result[i].name, this.encodeName(this.gameSprites[i].name, this.shift)); + for (int j = 0; j < result[i].sprites.size(); j++) { + result[i].changeSpriteName(result[i].sprites.get(j), this.encodeName(this.gameSprites[i].sprites.get(j), this.shift)); + } + } + + return result; } - return this.gameSprites[index ^ seed].name; - } - /** - * get an array of game sprites - * - * @return array contain all the game sprites - */ - public SpriteData[] getGameSprites() { - SpriteData[] result = new SpriteData[this.gameSprites.length]; - for (int i = 0; i < result.length; i++) { - try { - result[i] = (SpriteData) this.gameSprites[i].clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - result[i].changeSpriteName(result[i].name, this.encodeName(this.gameSprites[i].name, this.shift)); - for (int j = 0; j < result[i].sprites.size(); j++) { - result[i].changeSpriteName(result[i].sprites.get(j), this.encodeName(this.gameSprites[i].sprites.get(j), this.shift)); - } + /** + * Return the current level as a comma separated 2D Array + * + * @return a comma separated 2D Array of Sprites + */ + public String[][] getCurrentLevel() { + return this.currentLevel; } - return result; - } + /** + * Decode the rules and strings based on the seed + * + * @param rules + * current interaction rules to decode + * @param wins + * current termination rules to decode + * @param seed + * current encoding seed + * @return return decoded interaction and termination rules + */ + public String[][] modifyRules(String[] rules, String[] wins, int seed) { + ArrayList modifiedRules = new ArrayList(); + for (int i = 0; i < rules.length; i++) { + String[] parts = rules[i].split(" "); + modifiedRules.add(""); + for (int j = 0; j < parts.length; j++) { + if (parts[j].toLowerCase().contains(KEYWORD + "_")) { + String[] temp = parts[j].split(KEYWORD + "_"); + String spriteName = this.decodeIndex(Integer.parseInt(temp[1]), seed); + if(spriteName.length() > 0){ + modifiedRules.set(modifiedRules.size() - 1, modifiedRules.get(modifiedRules.size() - 1) + temp[0] + spriteName + " "); + } + else{ + Logger.getInstance().addMessage(new Message(Message.WARNING, parts[j] + " is undefined in the game.")); + } - /** - * Return the current level as a comma separated 2D Array - * - * @return a comma separated 2D Array of Sprites - */ - public String[][] getCurrentLevel() { - return this.currentLevel; - } + } else { + modifiedRules.set(modifiedRules.size() - 1, modifiedRules.get(modifiedRules.size() - 1) + parts[j] + " "); + } + } + } - /** - * Decode the rules and strings based on the seed - * - * @param rules - * current interaction rules to decode - * @param wins - * current termination rules to decode - * @param seed - * current encoding seed - * @return return decoded interaction and termination rules - */ - public String[][] modifyRules(String[] rules, String[] wins, int seed) { - ArrayList modifiedRules = new ArrayList(); - for (int i = 0; i < rules.length; i++) { - String[] parts = rules[i].split(" "); - modifiedRules.add(""); - for (int j = 0; j < parts.length; j++) { - if (parts[j].toLowerCase().contains(KEYWORD + "_")) { - String[] temp = parts[j].split(KEYWORD + "_"); - String spriteName = this.decodeIndex(Integer.parseInt(temp[1]), seed); - if(spriteName.length() > 0){ - modifiedRules.set(modifiedRules.size() - 1, modifiedRules.get(modifiedRules.size() - 1) + temp[0] + spriteName + " "); - } - else{ - Logger.getInstance().addMessage(new Message(Message.WARNING, parts[j] + " is undefined in the game.")); - } - - } else { - modifiedRules.set(modifiedRules.size() - 1, modifiedRules.get(modifiedRules.size() - 1) + parts[j] + " "); + ArrayList modifiedWins = new ArrayList(); + for (int i = 0; i < wins.length; i++) { + String[] parts = wins[i].split(" "); + modifiedWins.add(""); + for (int j = 0; j < parts.length; j++) { + if (parts[j].toLowerCase().contains(KEYWORD + "_")) { + String[] temp = parts[j].split(KEYWORD + "_"); + String spriteName = this.decodeIndex(Integer.parseInt(temp[1]), seed); + if(spriteName.length() > 0){ + modifiedWins.set(modifiedWins.size() - 1, modifiedWins.get(modifiedWins.size() - 1) + temp[0] + spriteName + " "); + } + else{ + Logger.getInstance().addMessage(new Message(Message.WARNING, parts[j] + " is undefined in the game.")); + } + } else { + modifiedWins.set(modifiedWins.size() - 1, modifiedWins.get(modifiedWins.size() - 1) + parts[j] + " "); + } + } } - } + + return new String[][] { modifiedRules.toArray(new String[modifiedRules.size()]), modifiedWins.toArray(new String[modifiedWins.size()]) }; } - ArrayList modifiedWins = new ArrayList(); - for (int i = 0; i < wins.length; i++) { - String[] parts = wins[i].split(" "); - modifiedWins.add(""); - for (int j = 0; j < parts.length; j++) { - if (parts[j].toLowerCase().contains(KEYWORD + "_")) { - String[] temp = parts[j].split(KEYWORD + "_"); - String spriteName = this.decodeIndex(Integer.parseInt(temp[1]), seed); - if(spriteName.length() > 0){ - modifiedWins.set(modifiedWins.size() - 1, modifiedWins.get(modifiedWins.size() - 1) + temp[0] + spriteName + " "); - } - else{ - Logger.getInstance().addMessage(new Message(Message.WARNING, parts[j] + " is undefined in the game.")); - } - } else { - modifiedWins.set(modifiedWins.size() - 1, modifiedWins.get(modifiedWins.size() - 1) + parts[j] + " "); - } - } + /** + * get state observation based on the interaction rules and termination + * conditions + * + * @param rules + * current interaction rules + * @param wins + * current termination conditions + * @param spriteSetStructure + * current sprite set hierarchy + * @return state observation of the current game using the new interaction + * rules and termination conditions return null when there is errors + */ + public StateObservation testRules(String[] rules, String[] wins){ + return this.testRules(rules, wins, null); } - return new String[][] { modifiedRules.toArray(new String[modifiedRules.size()]), modifiedWins.toArray(new String[modifiedWins.size()]) }; - } + /** + * get state observation based on the interaction rules and termination + * conditions + * + * @param rules + * current interaction rules + * @param wins + * current termination conditions + * @param spriteSetStructure + * current sprite set hierarchy + * @return state observation of the current game using the new interaction + * rules and termination conditions return null when there is errors + */ + public StateObservation testRules(String[] rules, String[] wins, HashMap> spriteSetStructure) { + Logger.getInstance().flushMessages(); - /** - * get state observation based on the interaction rules and termination - * conditions - * - * @param rules - * current interaction rules - * @param wins - * current termination conditions - * @param spriteSetStructure - * current sprite set hierarchy - * @return state observation of the current game using the new interaction - * rules and termination conditions return null when there is errors - */ - public StateObservation testRules(String[] rules, String[] wins){ - return this.testRules(rules, wins, null); - } - - /** - * get state observation based on the interaction rules and termination - * conditions - * - * @param rules - * current interaction rules - * @param wins - * current termination conditions - * @param spriteSetStructure - * current sprite set hierarchy - * @return state observation of the current game using the new interaction - * rules and termination conditions return null when there is errors - */ - public StateObservation testRules(String[] rules, String[] wins, HashMap> spriteSetStructure) { - Logger.getInstance().flushMessages(); + String[][] rw = this.modifyRules(rules, wins, this.shift); + HashMap msprites = new HashMap(); + for(int i=0; i> msetStructure = new HashMap>(); + if(spriteSetStructure != null){ + for(String key:spriteSetStructure.keySet()){ + msetStructure.put(key, new ArrayList()); + for(int i=0; i msprites = new HashMap(); - for(int i=0; i> msetStructure = new HashMap>(); - if(spriteSetStructure != null){ - for(String key:spriteSetStructure.keySet()){ - msetStructure.put(key, new ArrayList()); - for(int i=0; i 0) { + return null; } - } + return this.currentGame.getObservation(); } - VGDLRegistry.GetInstance().init(); - this.currentGame.loadDefaultConstr(); - this.currentGame.clearInteractionTerminationData(); - - new VGDLParser().parseSpriteSet(this.currentGame, msetStructure, msprites); - new VGDLParser().parseInteractionTermination(this.currentGame, rw[0], rw[1]); - - this.currentGame.reset(); - this.currentGame.buildStringLevel(this.level, this.random.nextInt()); - if (Logger.getInstance().getMessageCount(Message.ERROR) > 0) { - return null; + /** + * get list of errors and warnings from the system + * + * @return a list of errors and warnings type 0: warnings type 1: errors + */ + public ArrayList getErrors() { + return Logger.getInstance().getMessages(); } - return this.currentGame.getObservation(); - } - - /** - * get list of errors and warnings from the system - * - * @return a list of errors and warnings type 0: warnings type 1: errors - */ - public ArrayList getErrors() { - return Logger.getInstance().getMessages(); - } } diff --git a/src/core/logging/Logger.java b/src/core/logging/Logger.java index 095639b09c..86522b9fde 100644 --- a/src/core/logging/Logger.java +++ b/src/core/logging/Logger.java @@ -3,10 +3,10 @@ import java.util.ArrayList; public class Logger { - + private static final Logger instance = new Logger(); private ArrayList messages; - + /** * To disable and enable logger */ @@ -16,38 +16,38 @@ public class Logger { * Private constructor to enforce singleton pattern */ private Logger() { - messages = new ArrayList(); - active = true; + messages = new ArrayList(); + active = true; } /** * Returns the instance of the singleton Logger - * + * * @return the instance */ public static Logger getInstance() { - return instance; + return instance; } /** * Returns the list of errors and warnings - * + * * @return list of errors and warnings */ public ArrayList getMessages(){ - return this.messages; + return this.messages; } - + /** * Sends all messages to the console in one batch Flushes the message log * after this is done to prepare for a new game */ public void printMessages() { - System.out.println("*** Logged Messages ***"); - for (Message msg : messages) { - System.out.println(msg.toString()); - } - System.out.println("*** Logged Messages End ***"); + System.out.println("*** Logged Messages ***"); + for (Message msg : messages) { + System.out.println(msg.toString()); + } + System.out.println("*** Logged Messages End ***"); } /** @@ -55,41 +55,41 @@ public void printMessages() { * @return number of error and warning messages */ public int getMessageCount() { - return messages.size(); + return messages.size(); } - + /** * Get either error or warning messages * @param type 0 warnings, 1 errors * @return number of errors or warnings */ public int getMessageCount(int type) { - int result = 0; - for (int i=0; i getTerminationSprites() { - ArrayList result = new ArrayList(); - result.add(stype); - - return result; - } + @Override + public ArrayList getTerminationSprites() { + ArrayList result = new ArrayList(); + result.add(stype); + + return result; + } } diff --git a/src/core/termination/SpriteCounterMore.java b/src/core/termination/SpriteCounterMore.java index bf0bc20d11..317f9fd290 100644 --- a/src/core/termination/SpriteCounterMore.java +++ b/src/core/termination/SpriteCounterMore.java @@ -42,12 +42,12 @@ public boolean isDone(Game game) { return false; } - @Override - public ArrayList getTerminationSprites() { - ArrayList result = new ArrayList(); - result.add(stype); - - return result; - } + @Override + public ArrayList getTerminationSprites() { + ArrayList result = new ArrayList(); + result.add(stype); + + return result; + } } diff --git a/src/core/vgdl/Node.java b/src/core/vgdl/Node.java index bd7a7e25f6..bf18efdcd9 100644 --- a/src/core/vgdl/Node.java +++ b/src/core/vgdl/Node.java @@ -58,7 +58,7 @@ public Node(String contentLine, int indent, Node parent, int set) else parent.insert(this); } - + public Node(String contentLine, int indent, Node parent, int set, int lineNumber) { children = new ArrayList(); this.content = createContent(contentLine, set); @@ -67,7 +67,7 @@ public Node(String contentLine, int indent, Node parent, int set, int lineNumber this.parent = null; else parent.insert(this); - + this.lineNumber = lineNumber; } /** diff --git a/src/core/vgdl/VGDLParser.java b/src/core/vgdl/VGDLParser.java index f7233b81de..6d7f220b2c 100644 --- a/src/core/vgdl/VGDLParser.java +++ b/src/core/vgdl/VGDLParser.java @@ -22,599 +22,599 @@ * Java port from Tom Schaul's VGDL - https://github.com/schaul/py-vgdl */ public class VGDLParser { - /** - * Game which description is being read. - */ - public Game game; - - /** - * Current set through the game description file. - */ - public int currentSet; - - /** - * Temporal structure to hold spriteOrder (before the final array is created - * and sorted). - */ - private ArrayList spriteOrderTmp; - - /** - * Temporal structure to hold which sprites are singleton. - */ - private ArrayList singletonTmp; - - /** - * Maps integer identifier with sprite constructors - */ - private HashMap constructors; - - /** - * Set to true to print out debug information about parsing. - */ - private static boolean VERBOSE_PARSER = false; - - /** - * private Logger which logs warnings and errors - */ - private Logger logger; - - /** - * Default constructor. - */ - public VGDLParser() { - currentSet = Types.VGDL_GAME_DEF; - spriteOrderTmp = new ArrayList(); - singletonTmp = new ArrayList(); - constructors = new HashMap(); - logger = Logger.getInstance(); - } - - /** - * Parses a game passed whose file is passed by parameter. - * - * @param gamedesc_file - * filename of the file containing the game - * @return the game created - */ - public Game parseGame(String gamedesc_file) { - String[] desc_lines = new IO().readFile(gamedesc_file); - if (desc_lines != null) { - Node rootNode = indentTreeParser(desc_lines); - - // Parse here game and arguments of the first line - game = VGDLFactory.GetInstance().createGame((GameContent) rootNode.content); - game.initMulti(); - - // Parse the parameter nodes first, if any. - parseParameterNodes(rootNode); - - // Parse the nodes. - try { - parseNodes(rootNode); - } catch (Exception e) { - // TODO: Mike - } + /** + * Game which description is being read. + */ + public Game game; + + /** + * Current set through the game description file. + */ + public int currentSet; + + /** + * Temporal structure to hold spriteOrder (before the final array is created + * and sorted). + */ + private ArrayList spriteOrderTmp; + + /** + * Temporal structure to hold which sprites are singleton. + */ + private ArrayList singletonTmp; + + /** + * Maps integer identifier with sprite constructors + */ + private HashMap constructors; + + /** + * Set to true to print out debug information about parsing. + */ + private static boolean VERBOSE_PARSER = false; + + /** + * private Logger which logs warnings and errors + */ + private Logger logger; + + /** + * Default constructor. + */ + public VGDLParser() { + currentSet = Types.VGDL_GAME_DEF; + spriteOrderTmp = new ArrayList(); + singletonTmp = new ArrayList(); + constructors = new HashMap(); + logger = Logger.getInstance(); } - return game; - } - - /** - * Parses a game passed whose file is passed by parameter. - * - * @param gamedesc_file - * filename of the file containing the game - * @return the game created - */ - public Game parseGameWithParameters(String gamedesc_file, HashMap parameters) { - String[] desc_lines = new IO().readFile(gamedesc_file); - if (desc_lines != null) { - Node rootNode = indentTreeParser(desc_lines); - - // Parse here game and arguments of the first line - game = VGDLFactory.GetInstance().createGame((GameContent) rootNode.content); - game.initMulti(); - game.setParameters(parameters); - - // Parse the normal nodes, but not the parameters. - try { - parseNodes(rootNode); - } catch (Exception e) { - // TODO: Mike - } + /** + * Parses a game passed whose file is passed by parameter. + * + * @param gamedesc_file + * filename of the file containing the game + * @return the game created + */ + public Game parseGame(String gamedesc_file) { + String[] desc_lines = new IO().readFile(gamedesc_file); + if (desc_lines != null) { + Node rootNode = indentTreeParser(desc_lines); + + // Parse here game and arguments of the first line + game = VGDLFactory.GetInstance().createGame((GameContent) rootNode.content); + game.initMulti(); + + // Parse the parameter nodes first, if any. + parseParameterNodes(rootNode); + + // Parse the nodes. + try { + parseNodes(rootNode); + } catch (Exception e) { + // TODO: Mike + } + } + + return game; } - return game; - } - - /** - * Parses the parameter nodes in VGDL description for game spaces. - * - * @param rootNode - * the root VGDL node. - */ - private void parseParameterNodes(Node rootNode) { - // We parse the parameter set first: - for (Node n : rootNode.children) { - if (n.content.identifier.equals("ParameterSet")) { - parseParameterSet(n.children); - if (n.content.identifier.equals("SpriteSet")) { - try { - parseSpriteSet(n.children); - } catch (Exception e) { - logger.addMessage(new Message(1, "Sprite Set Error: " + e.toString())); - } - } else if (n.content.identifier.equals("InteractionSet")) { - try { - parseInteractionSet(n.children); - } catch (Exception e) { - logger.addMessage(new Message(1, "Interaction Set Error: " + e.getMessage())); - } - } else if (n.content.identifier.equals("LevelMapping")) { - try { - parseLevelMapping(n.children); - } catch (Exception e) { - logger.addMessage(new Message(1, "Level Mapping Error: " + e.toString())); - } - } else if (n.content.identifier.equals("TerminationSet")) { - try { - parseTerminationSet(n.children); - } catch (Exception e) { - logger.addMessage(new Message(1, "Termination Set Error: " + e.toString())); - } + /** + * Parses a game passed whose file is passed by parameter. + * + * @param gamedesc_file + * filename of the file containing the game + * @return the game created + */ + public Game parseGameWithParameters(String gamedesc_file, HashMap parameters) { + String[] desc_lines = new IO().readFile(gamedesc_file); + if (desc_lines != null) { + Node rootNode = indentTreeParser(desc_lines); + + // Parse here game and arguments of the first line + game = VGDLFactory.GetInstance().createGame((GameContent) rootNode.content); + game.initMulti(); + game.setParameters(parameters); + + // Parse the normal nodes, but not the parameters. + try { + parseNodes(rootNode); + } catch (Exception e) { + // TODO: Mike + } } - } - // logger.printMessages(); - } - } - - /** - * Parses the nodes in VGDL description. - * - * @param rootNode - * the root VGDL node. - */ - private void parseNodes(Node rootNode) throws Exception { - // Parse here the normal blocks of VGDL. - for (Node n : rootNode.children) { - if (n.content.identifier.equals("SpriteSet")) { - parseSpriteSet(n.children); - } else if (n.content.identifier.equals("InteractionSet")) { - parseInteractionSet(n.children); - } else if (n.content.identifier.equals("LevelMapping")) { - parseLevelMapping(n.children); - } else if (n.content.identifier.equals("TerminationSet")) { - parseTerminationSet(n.children); - } + + return game; } - } - - /** - * Parse a custom sprite set - * @param currentGame the current game to modify - * @param spriteStruct the current structure of the sprite set - * @param sprites the current sprites - */ - public void parseSpriteSet(Game currentGame, HashMap> spriteStruct, HashMap sprites){ - this.game = currentGame; - String template = " "; - - ArrayList msprites = new ArrayList(); - msprites.add("SpriteSet"); - for(String key:spriteStruct.keySet()){ - msprites.add(template + key + " >"); - for(int i=0; i> spriteStruct, HashMap sprites){ + this.game = currentGame; + String template = " "; + + ArrayList msprites = new ArrayList(); + msprites.add("SpriteSet"); + for(String key:spriteStruct.keySet()){ + msprites.add(template + key + " >"); + for(int i=0; i 0) { + updateSet(content); // Identify the set we are in. + char firstChar = content.charAt(0); + // figure out the indent of the line. + int indent = line.indexOf(firstChar); + last = new Node(content, indent, last, currentSet, lineNumber); + } + lineNumber++; + } + + return last.getRoot(); } - - Node rulesNode = indentTreeParser(mrules); - Node terNode = indentTreeParser(mterm); - try { - parseInteractionSet(rulesNode.children); - parseTerminationSet(terNode.children); - } catch (Exception e) { - logger.addMessage(new Message(1, "[PARSE ERROR]")); + + /** + * Updates the set we are in (game-def, spriteset, interactionset, + * levelmapping, terminationset) + * + * @param line + * line to read + */ + private void updateSet(String line) { + if (line.equalsIgnoreCase("SpriteSet")) + currentSet = Types.VGDL_SPRITE_SET; + if (line.equalsIgnoreCase("InteractionSet")) + currentSet = Types.VGDL_INTERACTION_SET; + if (line.equalsIgnoreCase("LevelMapping")) + currentSet = Types.VGDL_LEVEL_MAPPING; + if (line.equalsIgnoreCase("TerminationSet")) + currentSet = Types.VGDL_TERMINATION_SET; + if (line.equalsIgnoreCase("ParameterSet")) + currentSet = Types.VGDL_PARAMETER_SET; } - } - - /** - * Builds the tree structure that defines the game. - * - * @param lines - * array with the lines read from the game description file. - * @return the root of the final game tree - */ - public Node indentTreeParser(String[] lines) { - // By default, let's make tab as four spaces - String tabTemplate = " "; - Node last = null; - - // set the overall line number at 0 - int lineNumber = 0; - for (String line : lines) { - line.replaceAll("\t", tabTemplate); - line.replace('(', ' '); - line.replace(')', ' '); - line.replace(',', ' '); - - // remove comments starting with "#" - if (line.contains("#")) - line = line.split("#")[0]; - - // handle whitespace and indentation - String content = line.trim(); - - if (content.length() > 0) { - updateSet(content); // Identify the set we are in. - char firstChar = content.charAt(0); - // figure out the indent of the line. - int indent = line.indexOf(firstChar); - last = new Node(content, indent, last, currentSet, lineNumber); - } - lineNumber++; + + /** + * Parses the sprite set, and then initializes the game structures for the + * sprites. + * + * @param elements + * children of the root node of the game description sprite set. + */ + private void parseSpriteSet(ArrayList elements) { + // We need these 2 here: + spriteOrderTmp.add(VGDLRegistry.GetInstance().getRegisteredSpriteValue("wall")); + spriteOrderTmp.add(VGDLRegistry.GetInstance().getRegisteredSpriteValue("avatar")); + + _parseSprites(elements, null, new HashMap(), new ArrayList()); + + // Set the order of sprites. + game.initSprites(spriteOrderTmp, singletonTmp, constructors); } - return last.getRoot(); - } - - /** - * Updates the set we are in (game-def, spriteset, interactionset, - * levelmapping, terminationset) - * - * @param line - * line to read - */ - private void updateSet(String line) { - if (line.equalsIgnoreCase("SpriteSet")) - currentSet = Types.VGDL_SPRITE_SET; - if (line.equalsIgnoreCase("InteractionSet")) - currentSet = Types.VGDL_INTERACTION_SET; - if (line.equalsIgnoreCase("LevelMapping")) - currentSet = Types.VGDL_LEVEL_MAPPING; - if (line.equalsIgnoreCase("TerminationSet")) - currentSet = Types.VGDL_TERMINATION_SET; - if (line.equalsIgnoreCase("ParameterSet")) - currentSet = Types.VGDL_PARAMETER_SET; - } - - /** - * Parses the sprite set, and then initializes the game structures for the - * sprites. - * - * @param elements - * children of the root node of the game description sprite set. - */ - private void parseSpriteSet(ArrayList elements) { - // We need these 2 here: - spriteOrderTmp.add(VGDLRegistry.GetInstance().getRegisteredSpriteValue("wall")); - spriteOrderTmp.add(VGDLRegistry.GetInstance().getRegisteredSpriteValue("avatar")); - - _parseSprites(elements, null, new HashMap(), new ArrayList()); - - // Set the order of sprites. - game.initSprites(spriteOrderTmp, singletonTmp, constructors); - } - - /** - * Just modify the arrangement of the sprite render based on certain tree - * @param elements current sprite set tree - * @param parentclass previous parent in the tree (root have null parent) - */ - private void modifySpriteOrder(ArrayList elements, String parentclass) { - String prevParentClass = parentclass; - for (Node el : elements) { - SpriteContent sc = (SpriteContent) el.content; - if (!sc.is_definition) // This checks if line contains ">" - return; - - // Register this entry. - Integer intId = VGDLRegistry.GetInstance().getRegisteredSpriteValue(sc.identifier); - - // Get the class of the object - String spriteClassName = sc.referenceClass; - - // This is the class of this object - if (parentclass != null) - sc.referenceClass = parentclass; - - // If this is a leaf node, set the information on Game to create - // objects of this type. - if (el.children.size() == 0) { - if (spriteOrderTmp.contains(intId)) { - // last one counts - spriteOrderTmp.remove(intId); + /** + * Just modify the arrangement of the sprite render based on certain tree + * @param elements current sprite set tree + * @param parentclass previous parent in the tree (root have null parent) + */ + private void modifySpriteOrder(ArrayList elements, String parentclass) { + String prevParentClass = parentclass; + for (Node el : elements) { + SpriteContent sc = (SpriteContent) el.content; + if (!sc.is_definition) // This checks if line contains ">" + return; + + // Register this entry. + Integer intId = VGDLRegistry.GetInstance().getRegisteredSpriteValue(sc.identifier); + + // Get the class of the object + String spriteClassName = sc.referenceClass; + + // This is the class of this object + if (parentclass != null) + sc.referenceClass = parentclass; + + // If this is a leaf node, set the information on Game to create + // objects of this type. + if (el.children.size() == 0) { + if (spriteOrderTmp.contains(intId)) { + // last one counts + spriteOrderTmp.remove(intId); + } + spriteOrderTmp.add(intId); + } else { + // This is the parent class of the next. + if (spriteClassName != null) + parentclass = spriteClassName; + + modifySpriteOrder(el.children, parentclass); + } } - spriteOrderTmp.add(intId); - } else { - // This is the parent class of the next. - if (spriteClassName != null) - parentclass = spriteClassName; - - modifySpriteOrder(el.children, parentclass); - } } - } - - /** - * Modify the order of the sprites during rendering to another sprite set tree - * @param currentGame current game to modify - * @param elements new sprite set tree - */ - public void modifyTheSpriteRender(Game currentGame, ArrayList elements){ - this.game = currentGame; - this.modifySpriteOrder(elements, null); - - this.game.changeSpriteOrder(this.spriteOrderTmp); - } - - /** - * Recursive method to parse the tree of sprites. - * - * @param elements - * set of sibling nodes - * @param parentclass - * String that identifies the class of the parent node. If null, - * no class defined yet. - * @param parentargs - * Map with the arguments of the parent, that are inherited to - * all its children. - * @param parenttypes - * List of types the parent of elements belong to. - */ - private void _parseSprites(ArrayList elements, String parentclass, HashMap parentargs, - ArrayList parenttypes) { - HashMap args = (HashMap) parentargs.clone(); - ArrayList types = (ArrayList) parenttypes.clone(); - String prevParentClass = parentclass; - for (Node el : elements) { - SpriteContent sc = (SpriteContent) el.content; - if (!sc.is_definition) // This checks if line contains ">" - return; - - // Take the identifier of this node. - String identifier = sc.identifier; - types.add(identifier); - - // Register this entry. - Integer intId = VGDLRegistry.GetInstance().registerSprite(identifier); - constructors.put(intId, sc); // Ad the constructor for these - // objects. - - // Assign types and subtypes. - sc.assignTypes(types); - sc.subtypes.addAll(sc.itypes); - - // Get the class of the object - String spriteClassName = sc.referenceClass; - - // This is the class of this object - if (parentclass != null) - sc.referenceClass = parentclass; - - // Take all parameters and add them to the argument list. - HashMap parameters = sc.parameters; - Set> entries = parameters.entrySet(); - for (Map.Entry ent : entries) { - args.put((String) ent.getKey(), (String) ent.getValue()); - } - - // Check for singleton objects. - if (parameters.containsKey("singleton")) { - if (parameters.get("singleton").equalsIgnoreCase("true")) { - singletonTmp.add(intId); - } - } - sc.parameters = (HashMap) args.clone(); - - // If this is a leaf node, set the information on Game to create - // objects of this type. - if (el.children.size() == 0) { - if (VERBOSE_PARSER) - System.out - .println("Defining: " + identifier + " " + sc.referenceClass + " " + el.content.toString()); - - if (spriteOrderTmp.contains(intId)) { - // last one counts - spriteOrderTmp.remove(intId); - } - spriteOrderTmp.add(intId); - - // Reset the parameters to the ones from the parent - args = (HashMap) parentargs.clone(); - // Reset the types to the ones from the parent - types = (ArrayList) parenttypes.clone(); - - } else { - // This is the parent class of the next. - if (spriteClassName != null) - parentclass = spriteClassName; - - _parseSprites(el.children, parentclass, args, types); - args = (HashMap) parentargs.clone(); - types = (ArrayList) parenttypes.clone(); - parentclass = prevParentClass; - - // To my subtypes, add all from my children (recursively, this - // adds everything in my subtree). - for (Node child : el.children) { - SpriteContent childContent = (SpriteContent) child.content; - for (Integer subtype : childContent.subtypes) { - if (!sc.subtypes.contains(subtype)) - sc.subtypes.add(subtype); - } - } - } + /** + * Modify the order of the sprites during rendering to another sprite set tree + * @param currentGame current game to modify + * @param elements new sprite set tree + */ + public void modifyTheSpriteRender(Game currentGame, ArrayList elements){ + this.game = currentGame; + this.modifySpriteOrder(elements, null); + this.game.changeSpriteOrder(this.spriteOrderTmp); } - } - - /** - * Parses the interaction set. - * - * @param elements - * all interactions defined for the game. - * @throws Exception - */ - private void parseInteractionSet(ArrayList elements) throws Exception { - for (Node n : elements) { - InteractionContent ic = (InteractionContent) n.content; - ic.lineNumber = n.lineNumber; - if (ic.is_definition) // === contains ">" - { - Effect ef = VGDLFactory.GetInstance().createEffect(game, ic); - - // Get the identifiers of the first sprite taking part in the - // effect. - int obj1 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(ic.object1); - - // The second identifier comes from a list of sprites. We go one - // by one. - for (String obj2Str : ic.object2) { - int obj2 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(obj2Str); - - if (obj1 != -1 && obj2 != -1) { - Pair newPair = new Pair(obj1, obj2); - if (!game.getDefinedEffects().contains(newPair)) - game.getDefinedEffects().add(newPair); - - ArrayList collEffects = game.getCollisionEffects(obj1, obj2); - - // Add the effects as many times as indicated in its - // 'repeat' field (1 by default). - for (int r = 0; r < ef.repeat; ++r) - collEffects.add(ef); - - if (VERBOSE_PARSER) - System.out.println( - "Defining interaction " + ic.object1 + "+" + obj2Str + " > " + ic.function); - - } else if (obj1 == -1 || obj2 == -1) { - - // EOS or a TIME Effect (since VGDL 2.0) - if (obj2Str.equalsIgnoreCase("EOS")) { - game.getDefinedEosEffects().add(obj1); - game.getEosEffects(obj1).add(ef); - - } else if (ic.object1.equalsIgnoreCase("EOS")) { - game.getDefinedEosEffects().add(obj2); - game.getEosEffects(obj2).add(ef); - - } else if (ic.object1.equalsIgnoreCase("TIME") || obj2Str.equalsIgnoreCase("TIME")) { - game.addTimeEffect((TimeEffect) ef); - // unknown sprite other than an EOS or TIME effect - // is an error - } else { - System.out.println("[PARSE ERROR] interaction entry references unknown sprite: " + ic.line); - // TODO throw exception here - throw new Exception("[PARSE ERROR] interaction entry references unknown sprite. Line: " - + ic.lineNumber + " : " + ic.line); + + /** + * Recursive method to parse the tree of sprites. + * + * @param elements + * set of sibling nodes + * @param parentclass + * String that identifies the class of the parent node. If null, + * no class defined yet. + * @param parentargs + * Map with the arguments of the parent, that are inherited to + * all its children. + * @param parenttypes + * List of types the parent of elements belong to. + */ + private void _parseSprites(ArrayList elements, String parentclass, HashMap parentargs, + ArrayList parenttypes) { + HashMap args = (HashMap) parentargs.clone(); + ArrayList types = (ArrayList) parenttypes.clone(); + String prevParentClass = parentclass; + for (Node el : elements) { + SpriteContent sc = (SpriteContent) el.content; + if (!sc.is_definition) // This checks if line contains ">" + return; + + // Take the identifier of this node. + String identifier = sc.identifier; + types.add(identifier); + + // Register this entry. + Integer intId = VGDLRegistry.GetInstance().registerSprite(identifier); + constructors.put(intId, sc); // Ad the constructor for these + // objects. + + // Assign types and subtypes. + sc.assignTypes(types); + sc.subtypes.addAll(sc.itypes); + + // Get the class of the object + String spriteClassName = sc.referenceClass; + + // This is the class of this object + if (parentclass != null) + sc.referenceClass = parentclass; + + // Take all parameters and add them to the argument list. + HashMap parameters = sc.parameters; + Set> entries = parameters.entrySet(); + for (Map.Entry ent : entries) { + args.put((String) ent.getKey(), (String) ent.getValue()); } - } - if (VERBOSE_PARSER) - System.out.println("Defining interaction " + ic.object1 + "+" + obj2Str + " > " + ic.function); + // Check for singleton objects. + if (parameters.containsKey("singleton")) { + if (parameters.get("singleton").equalsIgnoreCase("true")) { + singletonTmp.add(intId); + } + } + sc.parameters = (HashMap) args.clone(); + + // If this is a leaf node, set the information on Game to create + // objects of this type. + if (el.children.size() == 0) { + if (VERBOSE_PARSER) + System.out + .println("Defining: " + identifier + " " + sc.referenceClass + " " + el.content.toString()); + + if (spriteOrderTmp.contains(intId)) { + // last one counts + spriteOrderTmp.remove(intId); + } + spriteOrderTmp.add(intId); + + // Reset the parameters to the ones from the parent + args = (HashMap) parentargs.clone(); + // Reset the types to the ones from the parent + types = (ArrayList) parenttypes.clone(); - // update game stochasticity. - if (ef.is_stochastic) { - game.setStochastic(true); - } + } else { + // This is the parent class of the next. + if (spriteClassName != null) + parentclass = spriteClassName; + + _parseSprites(el.children, parentclass, args, types); + args = (HashMap) parentargs.clone(); + types = (ArrayList) parenttypes.clone(); + parentclass = prevParentClass; + + // To my subtypes, add all from my children (recursively, this + // adds everything in my subtree). + for (Node child : el.children) { + SpriteContent childContent = (SpriteContent) child.content; + for (Integer subtype : childContent.subtypes) { + if (!sc.subtypes.contains(subtype)) + sc.subtypes.add(subtype); + } + } - } + } - } else { - System.out.println("[PARSE ERROR] bad format interaction entry: " + ic.line); - throw new Exception( - "[PARSE ERROR] bad format interaction entry. Line: " + ic.lineNumber + " : " + ic.line); - } + } } - } - - /** - * Parses the level mapping. - * - * @param elements - * all mapping units. - */ - private void parseParameterSet(ArrayList elements) { - for (Node n : elements) { - ParameterContent pc = (ParameterContent) n.content; - ((GameSpace) game).addParameterContent(pc); - pc.init(); + + /** + * Parses the interaction set. + * + * @param elements + * all interactions defined for the game. + * @throws Exception + */ + private void parseInteractionSet(ArrayList elements) throws Exception { + for (Node n : elements) { + InteractionContent ic = (InteractionContent) n.content; + ic.lineNumber = n.lineNumber; + if (ic.is_definition) // === contains ">" + { + Effect ef = VGDLFactory.GetInstance().createEffect(game, ic); + + // Get the identifiers of the first sprite taking part in the + // effect. + int obj1 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(ic.object1); + + // The second identifier comes from a list of sprites. We go one + // by one. + for (String obj2Str : ic.object2) { + int obj2 = VGDLRegistry.GetInstance().getRegisteredSpriteValue(obj2Str); + + if (obj1 != -1 && obj2 != -1) { + Pair newPair = new Pair(obj1, obj2); + if (!game.getDefinedEffects().contains(newPair)) + game.getDefinedEffects().add(newPair); + + ArrayList collEffects = game.getCollisionEffects(obj1, obj2); + + // Add the effects as many times as indicated in its + // 'repeat' field (1 by default). + for (int r = 0; r < ef.repeat; ++r) + collEffects.add(ef); + + if (VERBOSE_PARSER) + System.out.println( + "Defining interaction " + ic.object1 + "+" + obj2Str + " > " + ic.function); + + } else if (obj1 == -1 || obj2 == -1) { + + // EOS or a TIME Effect (since VGDL 2.0) + if (obj2Str.equalsIgnoreCase("EOS")) { + game.getDefinedEosEffects().add(obj1); + game.getEosEffects(obj1).add(ef); + + } else if (ic.object1.equalsIgnoreCase("EOS")) { + game.getDefinedEosEffects().add(obj2); + game.getEosEffects(obj2).add(ef); + + } else if (ic.object1.equalsIgnoreCase("TIME") || obj2Str.equalsIgnoreCase("TIME")) { + game.addTimeEffect((TimeEffect) ef); + // unknown sprite other than an EOS or TIME effect + // is an error + } else { + System.out.println("[PARSE ERROR] interaction entry references unknown sprite: " + ic.line); + // TODO throw exception here + throw new Exception("[PARSE ERROR] interaction entry references unknown sprite. Line: " + + ic.lineNumber + " : " + ic.line); + } + } + + if (VERBOSE_PARSER) + System.out.println("Defining interaction " + ic.object1 + "+" + obj2Str + " > " + ic.function); + + // update game stochasticity. + if (ef.is_stochastic) { + game.setStochastic(true); + } + + } + + } else { + System.out.println("[PARSE ERROR] bad format interaction entry: " + ic.line); + throw new Exception( + "[PARSE ERROR] bad format interaction entry. Line: " + ic.lineNumber + " : " + ic.line); + } + } } - } - - /** - * Parses the level mapping. - * - * @param elements - * all mapping units. - */ - private void parseLevelMapping(ArrayList elements) { - for (Node n : elements) { - MappingContent mc = (MappingContent) n.content; - game.getCharMapping().put(mc.charId, mc.reference); + /** + * Parses the level mapping. + * + * @param elements + * all mapping units. + */ + private void parseParameterSet(ArrayList elements) { + for (Node n : elements) { + ParameterContent pc = (ParameterContent) n.content; + ((GameSpace) game).addParameterContent(pc); + pc.init(); + } + } - } - - /** - * Parses the termination set. - * - * @param elements - * all terminations defined for the game. - * @throws Exception - */ - private void parseTerminationSet(ArrayList elements) throws Exception { - for (Node n : elements) { - TerminationContent tc = (TerminationContent) n.content; - Termination ter = VGDLFactory.GetInstance().createTermination(game, tc); - game.getTerminations().add(ter); + /** + * Parses the level mapping. + * + * @param elements + * all mapping units. + */ + private void parseLevelMapping(ArrayList elements) { + for (Node n : elements) { + MappingContent mc = (MappingContent) n.content; + game.getCharMapping().put(mc.charId, mc.reference); + } + } - } + /** + * Parses the termination set. + * + * @param elements + * all terminations defined for the game. + * @throws Exception + */ + private void parseTerminationSet(ArrayList elements) throws Exception { + for (Node n : elements) { + TerminationContent tc = (TerminationContent) n.content; + Termination ter = VGDLFactory.GetInstance().createTermination(game, tc); + game.getTerminations().add(ter); + } + + } } diff --git a/src/ontology/effects/binary/Align.java b/src/ontology/effects/binary/Align.java index 3495ea9bb8..9921d9b0ed 100644 --- a/src/ontology/effects/binary/Align.java +++ b/src/ontology/effects/binary/Align.java @@ -27,10 +27,10 @@ public Align(InteractionContent cnt) @Override public void execute(VGDLSprite sprite1, VGDLSprite sprite2, Game game) { - if(sprite1 == null || sprite2 == null){ - Logger.getInstance().addMessage(new Message(Message.WARNING, "Neither 1st not 2nd sprite can be EOS with Align interaction.")); - return; - } + if(sprite1 == null || sprite2 == null){ + Logger.getInstance().addMessage(new Message(Message.WARNING, "Neither 1st not 2nd sprite can be EOS with Align interaction.")); + return; + } sprite1.orientation = sprite2.orientation.copy(); sprite1.rect = new Rectangle(sprite2.rect.x, sprite2.rect.y, sprite1.rect.width, sprite1.rect.height); diff --git a/src/ontology/effects/binary/BounceForward.java b/src/ontology/effects/binary/BounceForward.java index 7ce8e49131..740e15c629 100644 --- a/src/ontology/effects/binary/BounceForward.java +++ b/src/ontology/effects/binary/BounceForward.java @@ -27,11 +27,11 @@ public BounceForward(InteractionContent cnt) @Override public void execute(VGDLSprite sprite1, VGDLSprite sprite2, Game game) { - if(sprite1 == null || sprite2 == null){ - Logger.getInstance().addMessage(new Message(Message.WARNING, "Neither the 1st nor 2nd sprite can be EOS with PullWithIt interaction.")); - return; - } - + if(sprite1 == null || sprite2 == null){ + Logger.getInstance().addMessage(new Message(Message.WARNING, "Neither the 1st nor 2nd sprite can be EOS with PullWithIt interaction.")); + return; + } + Vector2d dir = new Vector2d(sprite2.lastDirection()); dir.normalise(); diff --git a/src/ontology/effects/binary/PullWithIt.java b/src/ontology/effects/binary/PullWithIt.java index d0e48d3438..0f740035f7 100644 --- a/src/ontology/effects/binary/PullWithIt.java +++ b/src/ontology/effects/binary/PullWithIt.java @@ -41,10 +41,10 @@ public PullWithIt(InteractionContent cnt) @Override public void execute(VGDLSprite sprite1, VGDLSprite sprite2, Game game) { - if(sprite1 == null || sprite2 == null){ - Logger.getInstance().addMessage(new Message(Message.WARNING, "Neither the 1st nor 2nd sprite can be EOS with PullWithIt interaction.")); - return; - } + if(sprite1 == null || sprite2 == null){ + Logger.getInstance().addMessage(new Message(Message.WARNING, "Neither the 1st nor 2nd sprite can be EOS with PullWithIt interaction.")); + return; + } //Keep in the list, for the current cycle, the sprites that have triggered this event. int currentGameTime = game.getGameTick(); if(currentGameTime > lastGameTime) @@ -76,11 +76,11 @@ public void execute(VGDLSprite sprite1, VGDLSprite sprite2, Game game) } sprite1._updatePos(new Direction(v.x, v.y), (int) (sprite2.speed*gridsize)); - + if(sprite1.physicstype_id != Types.PHYSICS_GRID) - { - sprite1.rect.y = sprite2.rect.y-sprite2.rect.height; - sprite1.orientation = new Direction(sprite1.orientation.x(),0.0); + { + sprite1.rect.y = sprite2.rect.y-sprite2.rect.height; + sprite1.orientation = new Direction(sprite1.orientation.x(),0.0); } sprite1.lastrect = new Rectangle(r); diff --git a/src/tools/LevelAnalyzer.java b/src/tools/LevelAnalyzer.java index 2827cc2dff..96e504e9ef 100644 --- a/src/tools/LevelAnalyzer.java +++ b/src/tools/LevelAnalyzer.java @@ -11,439 +11,439 @@ * @author AhmedKhalifa */ public class LevelAnalyzer { - /** - * the current analyzed level - */ - private String[][] level; - - /** - * the number of sprites in the map - */ - private HashMap numberOfSprites; - /** - * Hashmap between all sprites that are on the same map location - */ - private HashMap> sameTileSprites; - - /** - * different arrays for analyzed sprites - */ - private ArrayList usefulSprites; - private ArrayList borderSprites; - - /** - * arrays for different type of sprites - */ - private ArrayList avatarSprites; - private ArrayList npcSprites; - private ArrayList immovableSprites; - private ArrayList movableSprites; - private ArrayList portalsSprites; - private ArrayList resourceSprites; - private ArrayList spawnerSprites; - - /** - * Constructor for the level analyzer where it analyze SLDescription object - * @param description the current game & level description - */ - public LevelAnalyzer(SLDescription description){ - SpriteData[] gameSprites = description.getGameSprites(); - level = description.getCurrentLevel(); - - usefulSprites = new ArrayList(); - borderSprites = new ArrayList(); - spawnerSprites = new ArrayList(); - - avatarSprites = new ArrayList(); - npcSprites = new ArrayList(); - immovableSprites = new ArrayList(); - movableSprites = new ArrayList(); - portalsSprites = new ArrayList(); - resourceSprites = new ArrayList(); - - numberOfSprites = new HashMap(); - sameTileSprites = new HashMap>(); - - for(int i=0; i numberOfSprites; + /** + * Hashmap between all sprites that are on the same map location + */ + private HashMap> sameTileSprites; + + /** + * different arrays for analyzed sprites + */ + private ArrayList usefulSprites; + private ArrayList borderSprites; + + /** + * arrays for different type of sprites + */ + private ArrayList avatarSprites; + private ArrayList npcSprites; + private ArrayList immovableSprites; + private ArrayList movableSprites; + private ArrayList portalsSprites; + private ArrayList resourceSprites; + private ArrayList spawnerSprites; + + /** + * Constructor for the level analyzer where it analyze SLDescription object + * @param description the current game & level description + */ + public LevelAnalyzer(SLDescription description){ + SpriteData[] gameSprites = description.getGameSprites(); + level = description.getCurrentLevel(); + + usefulSprites = new ArrayList(); + borderSprites = new ArrayList(); + spawnerSprites = new ArrayList(); + + avatarSprites = new ArrayList(); + npcSprites = new ArrayList(); + immovableSprites = new ArrayList(); + movableSprites = new ArrayList(); + portalsSprites = new ArrayList(); + resourceSprites = new ArrayList(); + + numberOfSprites = new HashMap(); + sameTileSprites = new HashMap>(); + + for(int i=0; i()); + } + + for(int y=0; y()); + + /** + * convert an arraylist of spritedata to a normal array + * @param list the input arraylist + * @return the output array equivalent to the list + */ + private SpriteData[] convertToArray(ArrayList list){ + SpriteData[] array = new SpriteData[list.size()]; + for(int i=0; i list, int lowThreshold, int highThreshold){ + ArrayList temp = new ArrayList(); + + for(int i=0; i highThreshold){ + continue; } - } + + temp.add(s); } - } + + return convertToArray(temp); + } + + /** + * Get avatar sprite data + * @param inMap if he is defined in the map or not + * @return array of all avatars that specify the input parameters + */ + public SpriteData[] getAvatars(boolean inMap){ + + return inMap?getSpriteData(avatarSprites, 1, this.getArea()):getSpriteData(avatarSprites, 0, this.getArea()); + } + + /** + * get all npcs that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest percentage + * @param highThreshold the maximum percentage + * @return array of all npcs that specify the input parameters + */ + public SpriteData[] getNPCs(double lowThreshold, double highThreshold){ + return getSpriteData(npcSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); + } + + /** + * get all npcs that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest number of sprites + * @param highThreshold the maximum number of sprites + * @return array of all npcs that specify the input parameters + */ + public SpriteData[] getNPCs(int lowThreshold, int highThreshold){ + return getSpriteData(npcSprites, lowThreshold, highThreshold); + } + + /** + * get all npcs that either in map or not + * @param inMap if npc is defined in the map or not + * @return array of all npcs that specify the input parameters + */ + public SpriteData[] getNPCs(boolean inMap){ + return inMap?getSpriteData(npcSprites, 1, this.getArea()):getSpriteData(npcSprites, 0, this.getArea()); + } + + /** + * get all immovables that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest percentage + * @param highThreshold the maximum percentage + * @return array of all immovables that specify the input parameters + */ + public SpriteData[] getImmovables(double lowThreshold, double highThreshold){ + return getSpriteData(immovableSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); + } + + /** + * get all immovables that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest number + * @param highThreshold the maximum number + * @return array of all immovables that specify the input parameters + */ + public SpriteData[] getImmovables(int lowThreshold, int highThreshold){ + return getSpriteData(immovableSprites, lowThreshold, highThreshold); + } + + /** + * get all immovables that either in the map or not + * @param inMap the sprite should be in the map + * @return array of all immovables that specify the input parameters + */ + public SpriteData[] getImmovables(boolean inMap){ + return inMap?getSpriteData(immovableSprites, 1, this.getArea()):getSpriteData(immovableSprites, 0, this.getArea()); + } + + /** + * get all movables that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest percentage + * @param highThreshold the maximum percentage + * @return array of all movables that specify the input parameters + */ + public SpriteData[] getMovables(double lowThreshold, double highThreshold){ + return getSpriteData(movableSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); + } + + /** + * get all movables that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest number + * @param highThreshold the maximum number + * @return array of all movables that specify the input parameters + */ + public SpriteData[] getMovables(int lowThreshold, int highThreshold){ + return getSpriteData(movableSprites, lowThreshold, highThreshold); + } + + /** + * get all movables that are either in the map or not + * @param inMap the sprite should be in the map + * @return array of all movables that specify the input parameters + */ + public SpriteData[] getMovables(boolean inMap){ + return inMap?getSpriteData(movableSprites, 1, this.getArea()):getSpriteData(movableSprites, 0, this.getArea()); + } + + /** + * get all portals that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest percentage + * @param highThreshold the maximum percentage + * @return array of all portals that specify the input parameters + */ + public SpriteData[] getPortals(double lowThreshold, double highThreshold){ + return getSpriteData(portalsSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); } - } - - /** - * get spritedata using its name - * @param gameSprites list of all spritedata in the game - * @param spriteName the current spritename used in searching - * @return the current spritedata corresponding to the - * spritename or null if doesn't exist - */ - private SpriteData getSpriteData(SpriteData[] gameSprites, String spriteName){ - for(int i=0; i list){ - SpriteData[] array = new SpriteData[list.size()]; - for(int i=0; i list, int lowThreshold, int highThreshold){ - ArrayList temp = new ArrayList(); - - for(int i=0; i highThreshold){ - continue; - } - - temp.add(s); + + /** + * get all border objects that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest percentage + * @param highThreshold the maximum percentage + * @return array of all border sprites that specify the input parameters + */ + public SpriteData[] getBorderObjects(double lowThreshold, double highThreshold){ + return getSpriteData(borderSprites, (int)(lowThreshold*this.getArea()), (int)(highThreshold*this.getArea())); + } + + /** + * get all border objects that are in between lowThreshold and highThreshold percentages + * @param lowThreshold the lowest number + * @param highThreshold the maximum number + * @return array of all border sprites that specify the input parameters + */ + public SpriteData[] getBorderObjects(int lowThreshold, int highThreshold){ + return getSpriteData(borderSprites, lowThreshold, highThreshold); } - - return convertToArray(temp); - } - - /** - * Get avatar sprite data - * @param inMap if he is defined in the map or not - * @return array of all avatars that specify the input parameters - */ - public SpriteData[] getAvatars(boolean inMap){ - - return inMap?getSpriteData(avatarSprites, 1, this.getArea()):getSpriteData(avatarSprites, 0, this.getArea()); - } - - /** - * get all npcs that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest percentage - * @param highThreshold the maximum percentage - * @return array of all npcs that specify the input parameters - */ - public SpriteData[] getNPCs(double lowThreshold, double highThreshold){ - return getSpriteData(npcSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); - } - - /** - * get all npcs that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest number of sprites - * @param highThreshold the maximum number of sprites - * @return array of all npcs that specify the input parameters - */ - public SpriteData[] getNPCs(int lowThreshold, int highThreshold){ - return getSpriteData(npcSprites, lowThreshold, highThreshold); - } - - /** - * get all npcs that either in map or not - * @param inMap if npc is defined in the map or not - * @return array of all npcs that specify the input parameters - */ - public SpriteData[] getNPCs(boolean inMap){ - return inMap?getSpriteData(npcSprites, 1, this.getArea()):getSpriteData(npcSprites, 0, this.getArea()); - } - - /** - * get all immovables that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest percentage - * @param highThreshold the maximum percentage - * @return array of all immovables that specify the input parameters - */ - public SpriteData[] getImmovables(double lowThreshold, double highThreshold){ - return getSpriteData(immovableSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); - } - - /** - * get all immovables that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest number - * @param highThreshold the maximum number - * @return array of all immovables that specify the input parameters - */ - public SpriteData[] getImmovables(int lowThreshold, int highThreshold){ - return getSpriteData(immovableSprites, lowThreshold, highThreshold); - } - - /** - * get all immovables that either in the map or not - * @param inMap the sprite should be in the map - * @return array of all immovables that specify the input parameters - */ - public SpriteData[] getImmovables(boolean inMap){ - return inMap?getSpriteData(immovableSprites, 1, this.getArea()):getSpriteData(immovableSprites, 0, this.getArea()); - } - - /** - * get all movables that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest percentage - * @param highThreshold the maximum percentage - * @return array of all movables that specify the input parameters - */ - public SpriteData[] getMovables(double lowThreshold, double highThreshold){ - return getSpriteData(movableSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); - } - - /** - * get all movables that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest number - * @param highThreshold the maximum number - * @return array of all movables that specify the input parameters - */ - public SpriteData[] getMovables(int lowThreshold, int highThreshold){ - return getSpriteData(movableSprites, lowThreshold, highThreshold); - } - - /** - * get all movables that are either in the map or not - * @param inMap the sprite should be in the map - * @return array of all movables that specify the input parameters - */ - public SpriteData[] getMovables(boolean inMap){ - return inMap?getSpriteData(movableSprites, 1, this.getArea()):getSpriteData(movableSprites, 0, this.getArea()); - } - - /** - * get all portals that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest percentage - * @param highThreshold the maximum percentage - * @return array of all portals that specify the input parameters - */ - public SpriteData[] getPortals(double lowThreshold, double highThreshold){ - return getSpriteData(portalsSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); - } - - /** - * get all portals that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest number - * @param highThreshold the maximum number - * @return array of all portals that specify the input parameters - */ - public SpriteData[] getPortals(int lowThreshold, int highThreshold){ - return getSpriteData(portalsSprites, lowThreshold, highThreshold); - } - - /** - * get all portals that are in between lowThreshold and highThreshold percentages - * @param inMap the sprite should be in the map - * @return array of all portals that specify the input parameters - */ - public SpriteData[] getPortals(boolean inMap){ - return inMap?getSpriteData(portalsSprites, 1, this.getArea()):getSpriteData(portalsSprites, 0, this.getArea()); - } - - /** - * get all resources that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest percentage - * @param highThreshold the maximum percentage - * @return array of all resources that specify the input parameters - */ - public SpriteData[] getResources(double lowThreshold, double highThreshold){ - return getSpriteData(resourceSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); - } - - /** - * get all resources that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest number - * @param highThreshold the maximum number - * @return array of all resources that specify the input parameters - */ - public SpriteData[] getResources(int lowThreshold, int highThreshold){ - return getSpriteData(resourceSprites, lowThreshold, highThreshold); - } - - /** - * get all resources that are in between lowThreshold and highThreshold percentages - * @param inMap the sprite should be in the map - * @return array of all resources that specify the input parameters - */ - public SpriteData[] getResources(boolean inMap){ - return inMap?getSpriteData(resourceSprites, 1, this.getArea()):getSpriteData(resourceSprites, 0, this.getArea()); - } - - /** - * get all spawners that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest percentage - * @param highThreshold the maximum percentage - * @return array of all spawners that specify the input parameters - */ - public SpriteData[] getSpawners(double lowThreshold, double highThreshold){ - return getSpriteData(spawnerSprites, (int)(lowThreshold * this.getArea()), (int)(highThreshold * this.getArea())); - } - - /** - * get all spawners that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest number - * @param highThreshold the maximum number - * @return array of all spawners that specify the input parameters - */ - public SpriteData[] getSpawners(int lowThreshold, int highThreshold){ - return getSpriteData(spawnerSprites, lowThreshold, highThreshold); - } - - /** - * get all spawners that are in between lowThreshold and highThreshold percentages - * @param inMap the sprite should be in the map - * @return array of all spawners that specify the input parameters - */ - public SpriteData[] getSpawners(boolean inMap){ - return inMap?getSpriteData(spawnerSprites, 1, this.getArea()):getSpriteData(spawnerSprites, 0, this.getArea()); - } - - /** - * get all border objects that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest percentage - * @param highThreshold the maximum percentage - * @return array of all border sprites that specify the input parameters - */ - public SpriteData[] getBorderObjects(double lowThreshold, double highThreshold){ - return getSpriteData(borderSprites, (int)(lowThreshold*this.getArea()), (int)(highThreshold*this.getArea())); - } - - /** - * get all border objects that are in between lowThreshold and highThreshold percentages - * @param lowThreshold the lowest number - * @param highThreshold the maximum number - * @return array of all border sprites that specify the input parameters - */ - public SpriteData[] getBorderObjects(int lowThreshold, int highThreshold){ - return getSpriteData(borderSprites, lowThreshold, highThreshold); - } - - /** - * get the number of times a certain sprite appear in the map - * @param spriteName the name of the sprite - * @return number of times this spritename appear in the level - */ - public double getNumberOfObjects(String spriteName){ - if(numberOfSprites.containsKey(spriteName)){ - return numberOfSprites.get(spriteName); + + /** + * get the number of times a certain sprite appear in the map + * @param spriteName the name of the sprite + * @return number of times this spritename appear in the level + */ + public double getNumberOfObjects(String spriteName){ + if(numberOfSprites.containsKey(spriteName)){ + return numberOfSprites.get(spriteName); + } + + return 0; + } + + /** + * get all the sprites that are on the same tile with a certain sprite + * @param spriteName the name of the sprite + * @return list of all sprites that share the same tile with the specified spritename + */ + public SpriteData[] getSpritesOnSameTile(String spriteName){ + return convertToArray(sameTileSprites.get(spriteName)); } - - return 0; - } - - /** - * get all the sprites that are on the same tile with a certain sprite - * @param spriteName the name of the sprite - * @return list of all sprites that share the same tile with the specified spritename - */ - public SpriteData[] getSpritesOnSameTile(String spriteName){ - return convertToArray(sameTileSprites.get(spriteName)); - } } diff --git a/src/tracks/ruleGeneration/RuleGenMachine.java b/src/tracks/ruleGeneration/RuleGenMachine.java index f7975f8786..e6e4913d16 100644 --- a/src/tracks/ruleGeneration/RuleGenMachine.java +++ b/src/tracks/ruleGeneration/RuleGenMachine.java @@ -34,378 +34,378 @@ */ public class RuleGenMachine { - /** - * Reads and launches a game for a human to be played. Graphics always on. - * - * @param original_game - * original game description file. - * @param generated_game - * generated game description file. - * @param level_file - * file with the level to be played. - */ - public static double[] playOneGame(String original_game, String generated_game, String level_file, String actionFile, int randomSeed) { + /** + * Reads and launches a game for a human to be played. Graphics always on. + * + * @param original_game + * original game description file. + * @param generated_game + * generated game description file. + * @param level_file + * file with the level to be played. + */ + public static double[] playOneGame(String original_game, String generated_game, String level_file, String actionFile, int randomSeed) { String agentName = "tracks.singlePlayer.tools.human.Agent"; boolean visuals = true; return runOneGame(original_game, generated_game, level_file, visuals, agentName, actionFile, randomSeed, 0); - } - - /** - * Reads and launches a game for a bot to be played. Graphics can be on or - * off. - * - * @param original_game - * original game description file. - * @param generated_game - * generated game description file. - * @param level_file - * file with the level to be played. - * @param visuals - * true to show the graphics, false otherwise. - * @param agentNames - * names (inc. package) where the tracks are otherwise. - * Names separated by space. - * @param actionFile - * filename of the files where the actions of these players, for - * this game, should be recorded. - * @param randomSeed - * sampleRandom seed for the sampleRandom generator. - * @param playerID - * ID of the human player - */ - public static double[] runOneGame(String original_game, String generated_game, String level_file, boolean visuals, String agentNames, - String actionFile, int randomSeed, int playerID) { - VGDLFactory.GetInstance().init(); // This always first thing to do. - VGDLRegistry.GetInstance().init(); - - if (CompetitionParameters.OS_WIN) - { - System.out.println(" * WARNING: Time limitations based on WALL TIME on Windows * "); } - // First, we create the game to be played.. - Game toPlay = new VGDLParser().parseGame(generated_game); - Node n = new VGDLParser().indentTreeParser(new tools.IO().readFile(original_game)); - for(Node c:n.children){ - if(c.content instanceof SpriteContent){ - new VGDLParser().modifyTheSpriteRender(toPlay, c.children); - break; - } - } - toPlay.buildLevel(level_file, randomSeed); - - // Warm the game up. - ArcadeMachine.warmUp(toPlay, CompetitionParameters.WARMUP_TIME); - - // Create the players. - String[] names = agentNames.split(" "); - int no_players = toPlay.no_players; - if (no_players > 1 && no_players != names.length) { - // We fill with more human players - String[] newNames = new String[no_players]; - System.arraycopy(names, 0, newNames, 0, names.length); - for (int i = names.length; i < no_players; ++i) - newNames[i] = "tracks.multiPlayer.tools.human.Agent"; - names = newNames; - } + /** + * Reads and launches a game for a bot to be played. Graphics can be on or + * off. + * + * @param original_game + * original game description file. + * @param generated_game + * generated game description file. + * @param level_file + * file with the level to be played. + * @param visuals + * true to show the graphics, false otherwise. + * @param agentNames + * names (inc. package) where the tracks are otherwise. + * Names separated by space. + * @param actionFile + * filename of the files where the actions of these players, for + * this game, should be recorded. + * @param randomSeed + * sampleRandom seed for the sampleRandom generator. + * @param playerID + * ID of the human player + */ + public static double[] runOneGame(String original_game, String generated_game, String level_file, boolean visuals, String agentNames, + String actionFile, int randomSeed, int playerID) { + VGDLFactory.GetInstance().init(); // This always first thing to do. + VGDLRegistry.GetInstance().init(); + + if (CompetitionParameters.OS_WIN) + { + System.out.println(" * WARNING: Time limitations based on WALL TIME on Windows * "); + } - boolean humans[] = new boolean[no_players]; - boolean anyHuman = false; + // First, we create the game to be played.. + Game toPlay = new VGDLParser().parseGame(generated_game); + Node n = new VGDLParser().indentTreeParser(new tools.IO().readFile(original_game)); + for(Node c:n.children){ + if(c.content instanceof SpriteContent){ + new VGDLParser().modifyTheSpriteRender(toPlay, c.children); + break; + } + } + toPlay.buildLevel(level_file, randomSeed); + + // Warm the game up. + ArcadeMachine.warmUp(toPlay, CompetitionParameters.WARMUP_TIME); + + // Create the players. + String[] names = agentNames.split(" "); + int no_players = toPlay.no_players; + if (no_players > 1 && no_players != names.length) { + // We fill with more human players + String[] newNames = new String[no_players]; + System.arraycopy(names, 0, newNames, 0, names.length); + for (int i = names.length; i < no_players; ++i) + newNames[i] = "tracks.multiPlayer.tools.human.Agent"; + names = newNames; + } - // System.out.println("Number of players: " + no_players); + boolean humans[] = new boolean[no_players]; + boolean anyHuman = false; - Player[] players; - if (no_players > 1) { - // multi player games - players = new AbstractMultiPlayer[no_players]; - } else { - // single player games - players = new AbstractPlayer[no_players]; - } + // System.out.println("Number of players: " + no_players); - for (int i = 0; i < no_players; i++) { + Player[] players; + if (no_players > 1) { + // multi player games + players = new AbstractMultiPlayer[no_players]; + } else { + // single player games + players = new AbstractPlayer[no_players]; + } - humans[i] = isHuman(names[i]); - anyHuman |= humans[i]; + for (int i = 0; i < no_players; i++) { + + humans[i] = isHuman(names[i]); + anyHuman |= humans[i]; + + if (no_players > 1) { + // multi player + players[i] = ArcadeMachine.createMultiPlayer(names[i], actionFile, toPlay.getObservationMulti(), + randomSeed, i, humans[i]); + } else { + // single player + players[i] = ArcadeMachine.createPlayer(names[i], actionFile, toPlay.getObservation(), randomSeed, + humans[i]); + } + + if (players[i] == null) { + // Something went wrong in the constructor, controller + // disqualified + if (no_players > 1) { + // multi player + toPlay.getAvatars()[i].disqualify(true); + } else { + // single player + toPlay.disqualify(); + } + + // Get the score for the result. + return toPlay.handleResult(); + } + } - if (no_players > 1) { - // multi player - players[i] = ArcadeMachine.createMultiPlayer(names[i], actionFile, toPlay.getObservationMulti(), - randomSeed, i, humans[i]); - } else { - // single player - players[i] = ArcadeMachine.createPlayer(names[i], actionFile, toPlay.getObservation(), randomSeed, - humans[i]); - } + // Then, play the game. + double[] score; + if (visuals) + score = toPlay.playGame(players, randomSeed, anyHuman, playerID); + else + score = toPlay.runGame(players, randomSeed); - if (players[i] == null) { - // Something went wrong in the constructor, controller - // disqualified - if (no_players > 1) { - // multi player - toPlay.getAvatars()[i].disqualify(true); - } else { - // single player - toPlay.disqualify(); + // Finally, when the game is over, we need to tear the players down. + ArcadeMachine.tearPlayerDown(toPlay, players, actionFile, randomSeed, true); + + // This, the last thing to do in this method, always: + toPlay.handleResult(); + toPlay.printResult(); + + return toPlay.getFullResult(); + } + + /** + * create a new game file using the new generated rules + * @param gameFile current game file + * @param levelFile current level file + * @param ruleGenerator current rule generator + * @param modifiedFile the resulted game file + * @param randomSeed random seed used in encoding game sprites + * @return true if everything worked fine, false otherwise + */ + public static boolean generateRules(String gameFile, String levelFile, String ruleGenerator, String modifiedFile, int randomSeed) { + VGDLFactory.GetInstance().init(); + VGDLRegistry.GetInstance().init(); + + // First, we create the game to be played.. + Game toPlay = new VGDLParser().parseGame(gameFile); + String[] lines = new IO().readFile(levelFile); + + try { + SLDescription sl = new SLDescription(toPlay, lines, randomSeed); + AbstractRuleGenerator generator = createRuleGenerator(ruleGenerator, sl); + String[][] rules = getGeneratedRules(sl, toPlay, generator); + HashMap> spriteSetStructure = generator.getSpriteSetStructure(); + rules = sl.modifyRules(rules[0], rules[1], randomSeed); + + SpriteData[] data = sl.getGameSprites(); + HashMap msprites = new HashMap(); + for(int i=0; i> msetStructure = new HashMap>(); + if(spriteSetStructure != null){ + for(String key:spriteSetStructure.keySet()){ + msetStructure.put(key, new ArrayList()); + for(int i=0; i 0){ + msetStructure.get(key).add(decodedName); + } + } + } + } + + saveGame(gameFile, modifiedFile, rules, msetStructure, msprites); + } catch (Exception e) { + toPlay.disqualify(); + toPlay.handleResult(); + toPlay.printResult(); + System.out.println(e.getMessage()); + + return false; } - // Get the score for the result. - return toPlay.handleResult(); - } + return true; } - // Then, play the game. - double[] score; - if (visuals) - score = toPlay.playGame(players, randomSeed, anyHuman, playerID); - else - score = toPlay.runGame(players, randomSeed); - - // Finally, when the game is over, we need to tear the players down. - ArcadeMachine.tearPlayerDown(toPlay, players, actionFile, randomSeed, true); - - // This, the last thing to do in this method, always: - toPlay.handleResult(); - toPlay.printResult(); - - return toPlay.getFullResult(); - } - - /** - * create a new game file using the new generated rules - * @param gameFile current game file - * @param levelFile current level file - * @param ruleGenerator current rule generator - * @param modifiedFile the resulted game file - * @param randomSeed random seed used in encoding game sprites - * @return true if everything worked fine, false otherwise - */ - public static boolean generateRules(String gameFile, String levelFile, String ruleGenerator, String modifiedFile, int randomSeed) { - VGDLFactory.GetInstance().init(); - VGDLRegistry.GetInstance().init(); - - // First, we create the game to be played.. - Game toPlay = new VGDLParser().parseGame(gameFile); - String[] lines = new IO().readFile(levelFile); - - try { - SLDescription sl = new SLDescription(toPlay, lines, randomSeed); - AbstractRuleGenerator generator = createRuleGenerator(ruleGenerator, sl); - String[][] rules = getGeneratedRules(sl, toPlay, generator); - HashMap> spriteSetStructure = generator.getSpriteSetStructure(); - rules = sl.modifyRules(rules[0], rules[1], randomSeed); - - SpriteData[] data = sl.getGameSprites(); - HashMap msprites = new HashMap(); - for(int i=0; i> msetStructure = new HashMap>(); - if(spriteSetStructure != null){ - for(String key:spriteSetStructure.keySet()){ - msetStructure.put(key, new ArrayList()); - for(int i=0; i 0){ - msetStructure.get(key).add(decodedName); - } - } - } - } - - saveGame(gameFile, modifiedFile, rules, msetStructure, msprites); - } catch (Exception e) { - toPlay.disqualify(); - toPlay.handleResult(); - toPlay.printResult(); - System.out.println(e.getMessage()); - - return false; - } - - return true; - } - - - /// PRIVATE METHODS - - /** - * @param ruleGenerator rule generatord - * @param sl Level Description - * @return The rule generator created - * @throws RuntimeException - */ - protected static AbstractRuleGenerator createRuleGenerator(String ruleGenerator, SLDescription sl) - throws RuntimeException { - AbstractRuleGenerator generator = null; - try { - // Get the class and the constructor with arguments - // (StateObservation, long). - Class controllerClass = Class.forName(ruleGenerator) - .asSubclass(AbstractRuleGenerator.class); - Class[] gameArgClass = new Class[] { SLDescription.class, ElapsedCpuTimer.class }; - Constructor controllerArgsConstructor = controllerClass.getConstructor(gameArgClass); - - // Determine the time due for the controller creation. - ElapsedCpuTimer ect = new ElapsedCpuTimer(); - ect.setMaxTimeMillis(CompetitionParameters.RULE_INITIALIZATION_TIME); - - // Call the constructor with the appropriate parameters. - Object[] constructorArgs = new Object[] { sl, ect.copy() }; - generator = (AbstractRuleGenerator) controllerArgsConstructor.newInstance(constructorArgs); - - // Check if we returned on time, and act in consequence. - long timeTaken = ect.elapsedMillis(); - if (ect.exceededMaxTime()) { - long exceeded = -ect.remainingTimeMillis(); - System.out.println("Generator initialization time out (" + exceeded + ")."); - - return null; - } else { - System.out.println("Generator initialization time: " + timeTaken + " ms."); - } - - // This code can throw many exceptions (no time related): - - } catch (NoSuchMethodException e) { - e.printStackTrace(); - System.err - .println("Constructor " + ruleGenerator + "(StateObservation,long) not found in controller class:"); - System.exit(1); - - } catch (ClassNotFoundException e) { - System.err.println("Class " + ruleGenerator + " not found for the controller:"); - e.printStackTrace(); - System.exit(1); - - } catch (InstantiationException e) { - System.err.println("Exception instantiating " + ruleGenerator + ":"); - e.printStackTrace(); - System.exit(1); - - } catch (IllegalAccessException e) { - System.err.println("Illegal access exception when instantiating " + ruleGenerator + ":"); - e.printStackTrace(); - System.exit(1); - } catch (InvocationTargetException e) { - System.err.println("Exception calling the constructor " + ruleGenerator + "(StateObservation,long):"); - e.printStackTrace(); - System.exit(1); - } - - return generator; - } - - - /** - * run the generator to get new rules - * @param sl current game sprites and level description object - * @param game current game object - * @param generator current rule generator - * @return the new interaction rules and termination conditions - */ - private static String[][] getGeneratedRules(SLDescription sl, Game game, AbstractRuleGenerator generator) { - ElapsedCpuTimer ect = new ElapsedCpuTimer(); - ect.setMaxTimeMillis(CompetitionParameters.RULE_ACTION_TIME); - - String[][] rules = generator.generateRules(sl, ect.copy()); - - if (ect.exceededMaxTime()) { - long exceeded = -ect.remainingTimeMillis(); - - if (ect.elapsedMillis() > CompetitionParameters.LEVEL_ACTION_TIME_DISQ) { - // The agent took too long to replay. The game is over and the - // agent is disqualified - System.out.println("Too long: " + "(exceeding " + (exceeded) + "ms): controller disqualified."); - rules = new String[1][1]; - } else { - System.out.println("Overspent: " + "(exceeding " + (exceeded) + "ms): applying Empty Level."); - rules = new String[1][1]; - } - } - - return rules; - } - - /** - * Recursive function to save game tree and replace the old rules with the new rules - * @param n current Node that need to be printed - * @param level current level in the tree - * @param w current writer object - * @param rules array of interaction rules or terminations - * @throws IOException thrown when a problem happens during writing - */ - private static void saveTree(Node n, int level, BufferedWriter w, String[][] rules, HashMap> setStructure, HashMap sprites) throws IOException{ - String template = " "; - String message = ""; - for(int i=0; i controllerClass = Class.forName(ruleGenerator) + .asSubclass(AbstractRuleGenerator.class); + Class[] gameArgClass = new Class[] { SLDescription.class, ElapsedCpuTimer.class }; + Constructor controllerArgsConstructor = controllerClass.getConstructor(gameArgClass); + + // Determine the time due for the controller creation. + ElapsedCpuTimer ect = new ElapsedCpuTimer(); + ect.setMaxTimeMillis(CompetitionParameters.RULE_INITIALIZATION_TIME); + + // Call the constructor with the appropriate parameters. + Object[] constructorArgs = new Object[] { sl, ect.copy() }; + generator = (AbstractRuleGenerator) controllerArgsConstructor.newInstance(constructorArgs); + + // Check if we returned on time, and act in consequence. + long timeTaken = ect.elapsedMillis(); + if (ect.exceededMaxTime()) { + long exceeded = -ect.remainingTimeMillis(); + System.out.println("Generator initialization time out (" + exceeded + ")."); + + return null; + } else { + System.out.println("Generator initialization time: " + timeTaken + " ms."); + } + + // This code can throw many exceptions (no time related): + + } catch (NoSuchMethodException e) { + e.printStackTrace(); + System.err + .println("Constructor " + ruleGenerator + "(StateObservation,long) not found in controller class:"); + System.exit(1); + + } catch (ClassNotFoundException e) { + System.err.println("Class " + ruleGenerator + " not found for the controller:"); + e.printStackTrace(); + System.exit(1); + + } catch (InstantiationException e) { + System.err.println("Exception instantiating " + ruleGenerator + ":"); + e.printStackTrace(); + System.exit(1); + + } catch (IllegalAccessException e) { + System.err.println("Illegal access exception when instantiating " + ruleGenerator + ":"); + e.printStackTrace(); + System.exit(1); + } catch (InvocationTargetException e) { + System.err.println("Exception calling the constructor " + ruleGenerator + "(StateObservation,long):"); + e.printStackTrace(); + System.exit(1); + } + + return generator; } - w.write(message + n.content.line.trim() + "\n"); - if(n.content instanceof InteractionContent){ - for(int i=0; i CompetitionParameters.LEVEL_ACTION_TIME_DISQ) { + // The agent took too long to replay. The game is over and the + // agent is disqualified + System.out.println("Too long: " + "(exceeding " + (exceeded) + "ms): controller disqualified."); + rules = new String[1][1]; + } else { + System.out.println("Overspent: " + "(exceeding " + (exceeded) + "ms): applying Empty Level."); + rules = new String[1][1]; + } + } + + return rules; } - else if(n.content instanceof TerminationContent){ - for(int i=0; i> setStructure, HashMap sprites) throws IOException{ + String template = " "; + String message = ""; + for(int i=0; i msprites = new ArrayList(); + for(String key:setStructure.keySet()){ + msprites.add(template + key + " >"); + for(int i=0; i msprites = new ArrayList(); - for(String key:setStructure.keySet()){ - msprites.add(template + key + " >"); - for(int i=0; i> setStructure, HashMap sprites) { + try { + if (modifiedFile != null) { + BufferedWriter writer = new BufferedWriter(new FileWriter(modifiedFile)); + String[] gameLines = new tools.IO().readFile(gameFile); + Node n = new VGDLParser().indentTreeParser(gameLines); + saveTree(n, 0, writer, rules, setStructure, sprites); + writer.close(); + } + } catch (IOException e) { + e.printStackTrace(); } - } - for(String value:sprites.values()){ - msprites.add(template + value.trim()); - } - for(String value:msprites){ - w.write(message + value + "\n"); - } } - else{ - for (int i = 0; i < n.children.size(); i++) { - saveTree(n.children.get(i), level + 1, w, rules, setStructure, sprites); - } + + private static final boolean isHuman(String agentName) { + if (agentName.equalsIgnoreCase("tracks.multiPlayer.tools.human.Agent") + || agentName.equalsIgnoreCase("tracks.singlePlayer.tools.human.Agent")) + return true; + return false; } - } - - /** - * Save the result of the rule generations - * @param gameFile current game file - * @param modifiedFile current new game file - * @param rules the generated rules - */ - private static void saveGame(String gameFile, String modifiedFile, String[][] rules, HashMap> setStructure, HashMap sprites) { - try { - if (modifiedFile != null) { - BufferedWriter writer = new BufferedWriter(new FileWriter(modifiedFile)); - String[] gameLines = new tools.IO().readFile(gameFile); - Node n = new VGDLParser().indentTreeParser(gameLines); - saveTree(n, 0, writer, rules, setStructure, sprites); - writer.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - private static final boolean isHuman(String agentName) { - if (agentName.equalsIgnoreCase("tracks.multiPlayer.tools.human.Agent") - || agentName.equalsIgnoreCase("tracks.singlePlayer.tools.human.Agent")) - return true; - return false; - } } diff --git a/src/tracks/ruleGeneration/TestRuleGeneration.java b/src/tracks/ruleGeneration/TestRuleGeneration.java index 6093c1a5a1..127754b881 100644 --- a/src/tracks/ruleGeneration/TestRuleGeneration.java +++ b/src/tracks/ruleGeneration/TestRuleGeneration.java @@ -57,7 +57,7 @@ public static void main(String[] args) { String game = generateRulePath + games[gameIdx] + ".txt"; String level1 = gamesPath + games[gameIdx] + "_lvl" + levelIdx + ".txt"; String recordGameFile = generateRulePath + games[gameIdx] + "_ggame.txt"; - + // 1. Generate rules (Interaction and Terminations) for a fixed level if(RuleGenMachine.generateRules(game, level1, constructiveRuleGenerator, recordGameFile, seed)){ // RuleGenMachine.playOneGame(game, recordGameFile, level1, recordActionsFile, seed); diff --git a/src/tracks/ruleGeneration/constructiveRuleGenerator/RuleGenerator.java b/src/tracks/ruleGeneration/constructiveRuleGenerator/RuleGenerator.java index e37bcc7da0..052cf26ba1 100644 --- a/src/tracks/ruleGeneration/constructiveRuleGenerator/RuleGenerator.java +++ b/src/tracks/ruleGeneration/constructiveRuleGenerator/RuleGenerator.java @@ -15,522 +15,522 @@ * @author AhmedKhalifa */ public class RuleGenerator extends AbstractRuleGenerator{ - /** - * a Level Analyzer object used to analyze the game sprites - */ - private LevelAnalyzer la; - - /** - * array of different interactions that movable objects (contains also npcs) can do when hitting the walls - */ - private String[] movableWallInteraction = new String[]{"stepBack", "flipDirection", "reverseDirection", - "turnAround", "wrapAround"}; - - /** - * percentages used to decide - */ - private double wallPercentageProb = 0.5; - private double spikeProb = 0.5; - private double doubleNPCsProb = 0.5; - private double harmfulMovableProb = 0.5; - private double firewallProb = 0.1; - private double scoreSpikeProb = 0.1; - private double randomNPCProb = 0.5; - private double spawnedProb = 0.5; - private double bomberProb = 0.5; - - /** - * a list of suggested interactions for the generated game - */ - private ArrayList interactions; - /** - * a list of suggested temination conditions for the generated game - */ - private ArrayList terminations; - - /** - * the sprite that the generator think is a wall sprite - */ - private SpriteData wall; - /** - * array of all door sprites - */ - private ArrayList exit; - /** - * array of all collectible sprites - */ - private ArrayList collectible; - /** - * a certain unmovable object that is used as a collectible object - */ - private SpriteData score; - /** - * a certain unmovable object that is used as a spike object - */ - private SpriteData spike; - - /** - * random object used in generating different games - */ - private Random random; - - /** - * Array of all different types of harmful objects (can kill the player) - */ - private ArrayList harmfulObjects; - /** - * Array of all different types of fleeing NPCs - */ - private ArrayList fleeingNPCs; - - /** - * Constructor that initialize the constructive algorithm - * @param sl SLDescription object contains information about the - * current game and level - * @param time the amount of time allowed for initialization - */ - public RuleGenerator(SLDescription sl, ElapsedCpuTimer time){ - //Initialize everything - la = new LevelAnalyzer(sl); - - interactions = new ArrayList(); - terminations = new ArrayList(); - - random = new Random(); - harmfulObjects = new ArrayList(); - fleeingNPCs = new ArrayList(); - collectible = new ArrayList(); - - //Identify the wall object - wall = null; - SpriteData[] temp = la.getBorderObjects((1.0 * la.getPerimeter()) / la.getArea(), this.wallPercentageProb); - if(temp.length > 0){ - wall = temp[0]; - for(int i=0; i interactions; + /** + * a list of suggested temination conditions for the generated game + */ + private ArrayList terminations; + + /** + * the sprite that the generator think is a wall sprite + */ + private SpriteData wall; + /** + * array of all door sprites + */ + private ArrayList exit; + /** + * array of all collectible sprites + */ + private ArrayList collectible; + /** + * a certain unmovable object that is used as a collectible object + */ + private SpriteData score; + /** + * a certain unmovable object that is used as a spike object + */ + private SpriteData spike; + + /** + * random object used in generating different games + */ + private Random random; + + /** + * Array of all different types of harmful objects (can kill the player) + */ + private ArrayList harmfulObjects; + /** + * Array of all different types of fleeing NPCs + */ + private ArrayList fleeingNPCs; + + /** + * Constructor that initialize the constructive algorithm + * @param sl SLDescription object contains information about the + * current game and level + * @param time the amount of time allowed for initialization + */ + public RuleGenerator(SLDescription sl, ElapsedCpuTimer time){ + //Initialize everything + la = new LevelAnalyzer(sl); + + interactions = new ArrayList(); + terminations = new ArrayList(); + + random = new Random(); + harmfulObjects = new ArrayList(); + fleeingNPCs = new ArrayList(); + collectible = new ArrayList(); + + //Identify the wall object + wall = null; + SpriteData[] temp = la.getBorderObjects((1.0 * la.getPerimeter()) / la.getArea(), this.wallPercentageProb); + if(temp.length > 0){ + wall = temp[0]; + for(int i=0; i(); - temp = la.getPortals(true); - for(int i=0; i tempList = new ArrayList(); - score = null; - spike = null; - temp = la.getImmovables(1, (int)(scoreSpikeProb * la.getArea())); - if (temp.length > 0) { - if (wall == null) { - score = temp[random.nextInt(temp.length)]; - spike = temp[random.nextInt(temp.length)]; - } - else { - tempList = new ArrayList(); - SpriteData[] relatedSprites = la.getSpritesOnSameTile(wall.name); - for (int i = 0; i < temp.length; i++) { - for (int j = 0; j < relatedSprites.length; j++) { - if (!temp[i].name.equals(relatedSprites[j].name)) { - tempList.add(temp[i]); + + //identify the exit sprite + exit = new ArrayList(); + temp = la.getPortals(true); + for(int i=0; i " + action); - } - - //Get the interaction between all movable objects (including npcs) with wall or EOS - action = movableWallInteraction[random.nextInt(movableWallInteraction.length)]; - if(isFireWall){ - action = "killSprite"; - } - temp = la.getMovables(false); - for (int i = 0; i < temp.length; i++) { - interactions.add(temp[i].name + " " + wallName + " > " + action); - } - action = movableWallInteraction[random.nextInt(movableWallInteraction.length)]; - if(isFireWall){ - action = "killSprite"; - } - temp = la.getNPCs(false); - for (int i = 0; i < temp.length; i++) { - interactions.add(temp[i].name + " " + wallName + " > " + action); - } - } - - /** - * get the interactions of all sprites with resource sprites - */ - private void getResourceInteractions(){ - SpriteData[] avatar = la.getAvatars(false); - SpriteData[] resources = la.getResources(true); - - //make the avatar collect the resources - for(int i=0; i collectResource"); - } + //identify the score and spike sprites + ArrayList tempList = new ArrayList(); + score = null; + spike = null; + temp = la.getImmovables(1, (int)(scoreSpikeProb * la.getArea())); + if (temp.length > 0) { + if (wall == null) { + score = temp[random.nextInt(temp.length)]; + spike = temp[random.nextInt(temp.length)]; + } + else { + tempList = new ArrayList(); + SpriteData[] relatedSprites = la.getSpritesOnSameTile(wall.name); + for (int i = 0; i < temp.length; i++) { + for (int j = 0; j < relatedSprites.length; j++) { + if (!temp[i].name.equals(relatedSprites[j].name)) { + tempList.add(temp[i]); + } + } + if(relatedSprites.length == 0){ + tempList.add(temp[i]); + } + } + + score = tempList.get(random.nextInt(tempList.size())); + spike = tempList.get(random.nextInt(tempList.size())); + } + } } - } - - /** - * get the interactions of all sprites with spawner sprites - */ - private void getSpawnerInteractions(){ - SpriteData[] avatar = la.getAvatars(false); - SpriteData[] spawners = la.getSpawners(true); - - //make the spawned object harmful to the avatar with a chance to be useful - if(random.nextDouble() < spawnedProb){ - for (int i = 0; i < avatar.length; i++) { - for (int j = 0; j < spawners.length; j++) { - for (int k = 0; k < spawners[j].sprites.size(); k++) { - harmfulObjects.add(spawners[j].sprites.get(k)); - interactions.add(avatar[i].name + " " + spawners[j].sprites.get(k) + " > killSprite"); - } + + /** + * Check if this spritename is the avatar + * @param spriteName the input sprite name + * @return true if its the avatar or false otherwise + */ + private boolean isAvatar(String spriteName){ + SpriteData[] avatar = la.getAvatars(false); + for(int i=0; i killSprite scoreChange=1"); - } + + /** + * get the interactions of everything with wall sprites + */ + private void getWallInteractions(){ + String wallName = "EOS"; + if (wall != null) { + wallName = wall.name; + } + //Is walls acts like fire (harmful for everyone) + boolean isFireWall = this.random.nextDouble() < firewallProb && + wall != null && fleeingNPCs.size() == 0; + + //Avatar interaction with wall or EOS + String action = "stepBack"; + if(isFireWall){ + action = "killSprite"; + } + SpriteData[] temp = la.getAvatars(false); + for (int i = 0; i < temp.length; i++) { + interactions.add(temp[i].name + " " + wallName + " > " + action); + } + + //Get the interaction between all movable objects (including npcs) with wall or EOS + action = movableWallInteraction[random.nextInt(movableWallInteraction.length)]; + if(isFireWall){ + action = "killSprite"; + } + temp = la.getMovables(false); + for (int i = 0; i < temp.length; i++) { + interactions.add(temp[i].name + " " + wallName + " > " + action); + } + action = movableWallInteraction[random.nextInt(movableWallInteraction.length)]; + if(isFireWall){ + action = "killSprite"; + } + temp = la.getNPCs(false); + for (int i = 0; i < temp.length; i++) { + interactions.add(temp[i].name + " " + wallName + " > " + action); } - } } - } - - /** - * get the interactions of all sprites with immovable sprites - */ - private void getImmovableInteractions(){ - SpriteData[] avatar = la.getAvatars(false); - - //If we have a score object make the avatar can collect it - if(score != null){ - for(int i=0; i killSprite scoreChange=1"); - } + + /** + * get the interactions of all sprites with resource sprites + */ + private void getResourceInteractions(){ + SpriteData[] avatar = la.getAvatars(false); + SpriteData[] resources = la.getResources(true); + + //make the avatar collect the resources + for(int i=0; i collectResource"); + } + } } - - //If we have a spike object make it kill the avatar with a change to be a super collectible sprite - if (spike != null && !spike.name.equalsIgnoreCase(score.name)) { - if (random.nextDouble() < spikeProb) { - harmfulObjects.add(spike.name); - for (int i = 0; i < avatar.length; i++) { - interactions.add(avatar[i].name + " " + spike.name + " > killSprite"); + + /** + * get the interactions of all sprites with spawner sprites + */ + private void getSpawnerInteractions(){ + SpriteData[] avatar = la.getAvatars(false); + SpriteData[] spawners = la.getSpawners(true); + + //make the spawned object harmful to the avatar with a chance to be useful + if(random.nextDouble() < spawnedProb){ + for (int i = 0; i < avatar.length; i++) { + for (int j = 0; j < spawners.length; j++) { + for (int k = 0; k < spawners[j].sprites.size(); k++) { + harmfulObjects.add(spawners[j].sprites.get(k)); + interactions.add(avatar[i].name + " " + spawners[j].sprites.get(k) + " > killSprite"); + } + } + } } - } - else { - for (int i = 0; i < avatar.length; i++) { - collectible.add(spike.name); - interactions.add(spike.name + " " + avatar[i].name + " > killSprite scoreChange=2"); + else{ + for (int i = 0; i < avatar.length; i++) { + for (int j = 0; j < spawners.length; j++) { + for (int k = 0; k < spawners[j].sprites.size(); k++) { + interactions.add(spawners[j].sprites.get(k) + " " + avatar[i].name + " > killSprite scoreChange=1"); + } + } + } } - } } - } - - /** - * get the interactions of all sprites with avatar sprites - */ - private void getAvatarInteractions(){ - SpriteData[] avatar = la.getAvatars(false); - - //Kill the avatar bullet kill any harmful objects - for(int i=0; i killSprite scoreChange=1"); - interactions.add(avatar[i].sprites.get(k) + " " + harmfulObjects.get(j) + " > killSprite"); + + /** + * get the interactions of all sprites with immovable sprites + */ + private void getImmovableInteractions(){ + SpriteData[] avatar = la.getAvatars(false); + + //If we have a score object make the avatar can collect it + if(score != null){ + for(int i=0; i killSprite scoreChange=1"); + } + } + + //If we have a spike object make it kill the avatar with a change to be a super collectible sprite + if (spike != null && !spike.name.equalsIgnoreCase(score.name)) { + if (random.nextDouble() < spikeProb) { + harmfulObjects.add(spike.name); + for (int i = 0; i < avatar.length; i++) { + interactions.add(avatar[i].name + " " + spike.name + " > killSprite"); + } + } + else { + for (int i = 0; i < avatar.length; i++) { + collectible.add(spike.name); + interactions.add(spike.name + " " + avatar[i].name + " > killSprite scoreChange=2"); + } + } } - } - } - } - - /** - * get the interactions of all sprites with portal sprites - */ - private void getPortalInteractions() { - SpriteData[] avatar = la.getAvatars(false); - SpriteData[] portals = la.getPortals(true); - - //make the exits die with collision of the player (going through them) - for (int i = 0; i < avatar.length; i++) { - for (int j = 0; j < exit.size(); j++) { - interactions.add(exit.get(j).name + " " + avatar[i].name + " > killSprite"); - } } - //If they are Portal type then u can teleport toward it - for (int i = 0; i < portals.length; i++) { - for (int j = 0; j < avatar.length; j++) { - if (portals[i].type.equalsIgnoreCase("Portal")) { - interactions.add(avatar[j].name + " " + portals[i].name + " > teleportToExit"); + + /** + * get the interactions of all sprites with avatar sprites + */ + private void getAvatarInteractions(){ + SpriteData[] avatar = la.getAvatars(false); + + //Kill the avatar bullet kill any harmful objects + for(int i=0; i killSprite scoreChange=1"); + interactions.add(avatar[i].sprites.get(k) + " " + harmfulObjects.get(j) + " > killSprite"); + } + } } - } } - } - - /** - * get the interactions of all sprites with npc sprites - */ - private void getNPCInteractions(){ - SpriteData[] avatar = la.getAvatars(false); - SpriteData[] npc = la.getNPCs(false); - - for(int i=0; i killSprite scoreChange=1"); + + /** + * get the interactions of all sprites with portal sprites + */ + private void getPortalInteractions() { + SpriteData[] avatar = la.getAvatars(false); + SpriteData[] portals = la.getPortals(true); + + //make the exits die with collision of the player (going through them) + for (int i = 0; i < avatar.length; i++) { + for (int j = 0; j < exit.size(); j++) { + interactions.add(exit.get(j).name + " " + avatar[i].name + " > killSprite"); + } } - } - else if (npc[i].type.equalsIgnoreCase("bomber") || npc[i].type.equalsIgnoreCase("randombomber")) { - //make the bomber harmful for the player - for(int j=0; j killSprite"); + //If they are Portal type then u can teleport toward it + for (int i = 0; i < portals.length; i++) { + for (int j = 0; j < avatar.length; j++) { + if (portals[i].type.equalsIgnoreCase("Portal")) { + interactions.add(avatar[j].name + " " + portals[i].name + " > teleportToExit"); + } + } } - //make the spawned object harmful - if(this.random.nextDouble() < bomberProb){ - for (int j = 0; j < npc[i].sprites.size(); j++) { - harmfulObjects.add(npc[i].sprites.get(j)); - interactions.add(avatar[j].name + " " + npc[i].sprites.get(j) + " > killSprite"); - } + } + + /** + * get the interactions of all sprites with npc sprites + */ + private void getNPCInteractions(){ + SpriteData[] avatar = la.getAvatars(false); + SpriteData[] npc = la.getNPCs(false); + + for(int i=0; i killSprite scoreChange=1"); + } + } + else if (npc[i].type.equalsIgnoreCase("bomber") || npc[i].type.equalsIgnoreCase("randombomber")) { + //make the bomber harmful for the player + for(int j=0; j killSprite"); + } + //make the spawned object harmful + if(this.random.nextDouble() < bomberProb){ + for (int j = 0; j < npc[i].sprites.size(); j++) { + harmfulObjects.add(npc[i].sprites.get(j)); + interactions.add(avatar[j].name + " " + npc[i].sprites.get(j) + " > killSprite"); + } + } + //make the spawned object useful + else{ + for (int j = 0; j < npc[i].sprites.size(); j++) { + interactions.add(npc[i].sprites.get(j) + " " + avatar[j].name + " > killSprite scoreChange=1"); + } + } + } + else if (npc[i].type.equalsIgnoreCase("chaser") || npc[i].type.equalsIgnoreCase("AlternateChaser") + || npc[i].type.equalsIgnoreCase("RandomAltChaser")) { + //make chasers harmful for the avatar + for(int j=0; j killSprite"); + } + } + else{ + if(random.nextDouble() < doubleNPCsProb){ + interactions.add(npc[i].sprites.get(j) + " " + npc[i].name + " > killSprite"); + } + else{ + interactions.add(npc[i].sprites.get(j) + " " + npc[i].name + " > transformTo stype=" + npc[i].name); + } + + } + } + } + else if (npc[i].type.equalsIgnoreCase("randomnpc")) { + //random npc are harmful to the avatar + if(this.random.nextDouble() < randomNPCProb){ + for (int j = 0; j < avatar.length; j++) { + harmfulObjects.add(npc[i].name); + interactions.add(avatar[j].name + " " + npc[i].name + " > killSprite"); + } + } + //random npc are userful to the avatar + else{ + for (int j = 0; j < avatar.length; j++) { + collectible.add(npc[i].name); + interactions.add(npc[i].name + " " + avatar[j].name + " > killSprite scoreChange=1"); + } + } + } } - //make the spawned object useful - else{ - for (int j = 0; j < npc[i].sprites.size(); j++) { - interactions.add(npc[i].sprites.get(j) + " " + avatar[j].name + " > killSprite scoreChange=1"); - } + } + + /** + * get the interactions of all sprites with movable sprites + */ + private void getMovableInteractions(){ + SpriteData[] movables = la.getMovables(false); + SpriteData[] avatar = la.getAvatars(false); + SpriteData[] spawners = la.getSpawners(false); + + for(int j=0; j killSprite"); + } + } + else{ + for(int i=0; i killSprite scoreChange=1"); + } + } + } } - } - else if (npc[i].type.equalsIgnoreCase("chaser") || npc[i].type.equalsIgnoreCase("AlternateChaser") - || npc[i].type.equalsIgnoreCase("RandomAltChaser")) { - //make chasers harmful for the avatar - for(int j=0; j killSprite"); + } + + /** + * get the termination condition for the generated game + */ + private void getTerminations(){ + //If you have a door object make it the winning condition + if(exit.size() > 0){ + SpriteData door = null; + for(int i=0; i killSprite"); + + if(door != null){ + terminations.add("SpriteCounter stype=" + door.name + " limit=0 win=True"); } - else{ - interactions.add(npc[i].sprites.get(j) + " " + npc[i].name + " > transformTo stype=" + npc[i].name); + //otherwise pick any other exit object + else if(collectible.size() > 0){ + terminations.add("SpriteCounter stype=collectible limit=0 win=True"); } - - } } - } - else if (npc[i].type.equalsIgnoreCase("randomnpc")) { - //random npc are harmful to the avatar - if(this.random.nextDouble() < randomNPCProb){ - for (int j = 0; j < avatar.length; j++) { - harmfulObjects.add(npc[i].name); - interactions.add(avatar[j].name + " " + npc[i].name + " > killSprite"); - } + else { + //If we have feeling NPCs use them as winning condition + if (fleeingNPCs.size() > 0) { + terminations.add("SpriteCounter stype=fleeing limit=0 win=True"); + } + else if(harmfulObjects.size() > 0 && this.la.getAvatars(true)[0].sprites.size() > 0){ + terminations.add("SpriteCounter stype=harmful limit=0 win=True"); + } + //Otherwise use timeout as winning condition + else { + terminations.add("Timeout limit=" + (500 + random.nextInt(5) * 100) + " win=True"); + } } - //random npc are userful to the avatar - else{ - for (int j = 0; j < avatar.length; j++) { - collectible.add(npc[i].name); - interactions.add(npc[i].name + " " + avatar[j].name + " > killSprite scoreChange=1"); - } + + //Add the losing condition which is the player dies + if(harmfulObjects.size() > 0){ + SpriteData[] usefulAvatar = this.la.getAvatars(true); + for(int i=0; i> getSpriteSetStructure() { + HashMap> struct = new HashMap>(); + + if(fleeingNPCs.size() > 0){ + struct.put("fleeing", new ArrayList()); } - } - for(int i=0; i killSprite"); - } + + if(harmfulObjects.size() > 0){ + struct.put("harmful", new ArrayList()); } - else{ - for(int i=0; i killSprite scoreChange=1"); - } + for(int i=0; i 0){ - SpriteData door = null; - for(int i=0; i 0){ + struct.put("collectible", new ArrayList()); } - } - - if(door != null){ - terminations.add("SpriteCounter stype=" + door.name + " limit=0 win=True"); - } - //otherwise pick any other exit object - else if(collectible.size() > 0){ - terminations.add("SpriteCounter stype=collectible limit=0 win=True"); - } - } - else { - //If we have feeling NPCs use them as winning condition - if (fleeingNPCs.size() > 0) { - terminations.add("SpriteCounter stype=fleeing limit=0 win=True"); - } - else if(harmfulObjects.size() > 0 && this.la.getAvatars(true)[0].sprites.size() > 0){ - terminations.add("SpriteCounter stype=harmful limit=0 win=True"); - } - //Otherwise use timeout as winning condition - else { - terminations.add("Timeout limit=" + (500 + random.nextInt(5) * 100) + " win=True"); - } - } - - //Add the losing condition which is the player dies - if(harmfulObjects.size() > 0){ - SpriteData[] usefulAvatar = this.la.getAvatars(true); - for(int i=0; i> getSpriteSetStructure() { - HashMap> struct = new HashMap>(); - - if(fleeingNPCs.size() > 0){ - struct.put("fleeing", new ArrayList()); - } - for(int i=0; i 0){ - struct.put("harmful", new ArrayList()); - } - for(int i=0; i 0){ - struct.put("collectible", new ArrayList()); - } - for(int i=0; i usefulSprites; - /** - * the avatar sprite name - */ - private String avatar; - /** - * Random object to help in generation - */ - private Random random; - /** - * Parameter used to fix the number of interations in the game - */ - private int FIXED = 5; + /** + * Array contains all the simple interactions + */ + private String[] interactions = new String[] { "killSprite", "killAll", "killIfHasMore", "killIfHasLess", + "killIfFromAbove", "killIfOtherHasMore", "spawnBehind", "stepBack", "spawnIfHasMore", "spawnIfHasLess", + "cloneSprite", "transformTo", "undoAll", "flipDirection", "transformToRandomChild", "updateSpawnType", + "removeScore", "addHealthPoints", "addHealthPointsToMax", "reverseDirection", "subtractHealthPoints", + "increaseSpeedToAll", "decreaseSpeedToAll", "attractGaze", "align", "turnAround", "wrapAround", + "pullWithIt", "bounceForward", "teleportToExit", "collectResource", "setSpeedForAll", "undoAll", + "reverseDirection", "changeResource" }; + /** + * A list of all the useful sprites in the game without the avatar + */ + private ArrayList usefulSprites; + /** + * the avatar sprite name + */ + private String avatar; + /** + * Random object to help in generation + */ + private Random random; + /** + * Parameter used to fix the number of interations in the game + */ + private int FIXED = 5; - /** - * This is a random rule generator - * - * @param sl - * contains information about sprites and current level - * @param time - * amount of time allowed - */ - public RuleGenerator(SLDescription sl, ElapsedCpuTimer time) { - this.usefulSprites = new ArrayList(); - this.random = new Random(); - String[][] currentLevel = sl.getCurrentLevel(); + /** + * This is a random rule generator + * + * @param sl + * contains information about sprites and current level + * @param time + * amount of time allowed + */ + public RuleGenerator(SLDescription sl, ElapsedCpuTimer time) { + this.usefulSprites = new ArrayList(); + this.random = new Random(); + String[][] currentLevel = sl.getCurrentLevel(); - // Just get the useful sprites from the current level - for (int y = 0; y < currentLevel.length; y++) { - for (int x = 0; x < currentLevel[y].length; x++) { - String[] parts = currentLevel[y][x].split(","); - for (int i = 0; i < parts.length; i++) { - if (parts[i].trim().length() > 0) { - // Add the sprite if it doesn't exisit - if (!usefulSprites.contains(parts[i].trim())) { - usefulSprites.add(parts[i].trim()); + // Just get the useful sprites from the current level + for (int y = 0; y < currentLevel.length; y++) { + for (int x = 0; x < currentLevel[y].length; x++) { + String[] parts = currentLevel[y][x].split(","); + for (int i = 0; i < parts.length; i++) { + if (parts[i].trim().length() > 0) { + // Add the sprite if it doesn't exisit + if (!usefulSprites.contains(parts[i].trim())) { + usefulSprites.add(parts[i].trim()); + } + } + } } - } } - } + this.usefulSprites.add("EOS"); + this.avatar = this.getAvatar(sl); } - this.usefulSprites.add("EOS"); - this.avatar = this.getAvatar(sl); - } - /** - * convert the arraylist of string to a normal array of string - * - * @param list - * input arraylist - * @return string array - */ - private String[] getArray(ArrayList list) { - String[] array = new String[list.size()]; - for (int i = 0; i < list.size(); i++) { - array[i] = list.get(i); - } + /** + * convert the arraylist of string to a normal array of string + * + * @param list + * input arraylist + * @return string array + */ + private String[] getArray(ArrayList list) { + String[] array = new String[list.size()]; + for (int i = 0; i < list.size(); i++) { + array[i] = list.get(i); + } - return array; - } + return array; + } - /** - * Get the avatar sprite from SLDescription - * - * @param sl - * SLDescription object contains all the game info - * @return the avatar sprite name - */ - private String getAvatar(SLDescription sl) { - SpriteData[] sprites = sl.getGameSprites(); - for (int i = 0; i < this.usefulSprites.size(); i++) { - SpriteData s = this.getSpriteData(sprites, this.usefulSprites.get(i)); - if (s != null && s.isAvatar) { - return this.usefulSprites.get(i); - } + /** + * Get the avatar sprite from SLDescription + * + * @param sl + * SLDescription object contains all the game info + * @return the avatar sprite name + */ + private String getAvatar(SLDescription sl) { + SpriteData[] sprites = sl.getGameSprites(); + for (int i = 0; i < this.usefulSprites.size(); i++) { + SpriteData s = this.getSpriteData(sprites, this.usefulSprites.get(i)); + if (s != null && s.isAvatar) { + return this.usefulSprites.get(i); + } + } + return ""; } - return ""; - } - /** - * Get SpriteData for certain sprite name - * - * @param sprites - * list of all game sprites - * @param name - * current sprite name - * @return current sprite data - */ - private SpriteData getSpriteData(SpriteData[] sprites, String name) { - for (int i = 0; i < sprites.length; i++) { - if (sprites[i].name.equalsIgnoreCase(name)) { - return sprites[i]; - } + /** + * Get SpriteData for certain sprite name + * + * @param sprites + * list of all game sprites + * @param name + * current sprite name + * @return current sprite data + */ + private SpriteData getSpriteData(SpriteData[] sprites, String name) { + for (int i = 0; i < sprites.length; i++) { + if (sprites[i].name.equalsIgnoreCase(name)) { + return sprites[i]; + } + } + + return null; } - return null; - } + /** + * Generate random interaction rules and termination conditions + * + * @param sl + * contains information about sprites and current level + * @param time + * amount of time allowed + */ + @Override + public String[][] generateRules(SLDescription sl, ElapsedCpuTimer time) { + ArrayList interaction = new ArrayList(); + ArrayList termination = new ArrayList(); - /** - * Generate random interaction rules and termination conditions - * - * @param sl - * contains information about sprites and current level - * @param time - * amount of time allowed - */ - @Override - public String[][] generateRules(SLDescription sl, ElapsedCpuTimer time) { - ArrayList interaction = new ArrayList(); - ArrayList termination = new ArrayList(); + // number of interactions in the game based on the number of sprites + int numberOfInteractions = (int) (this.usefulSprites.size() * (0.5 + 0.5 * this.random.nextDouble())); + if (this.FIXED > 0) { + numberOfInteractions = this.FIXED; + } + for (int i = 0; i < numberOfInteractions; i++) { + // get two random indeces for the two sprites in the interaction + int i1 = this.random.nextInt(this.usefulSprites.size()); + int i2 = (i1 + 1 + this.random.nextInt(this.usefulSprites.size() - 1)) % this.usefulSprites.size(); + // add score change parameter for interactions + String scoreChange = ""; + if(this.random.nextBoolean()){ + scoreChange += "scoreChange=" + (this.random.nextInt(5) - 2); + } + // add the new random interaction that doesn't produce errors + interaction.add(this.usefulSprites.get(i1) + " " + this.usefulSprites.get(i2) + " > " + + this.interactions[this.random.nextInt(this.interactions.length)] + " " + scoreChange); + sl.testRules(getArray(interaction), getArray(termination)); + while(sl.getErrors().size() > 0){ + interaction.remove(i); + interaction.add(this.usefulSprites.get(i1) + " " + this.usefulSprites.get(i2) + " > " + + this.interactions[this.random.nextInt(this.interactions.length)] + " " + scoreChange); + sl.testRules(getArray(interaction), getArray(termination)); + } + } + // Add a winning termination condition + if (this.random.nextBoolean()) { + termination.add("Timeout limit=" + (800 + this.random.nextInt(500)) + " win=True"); + } else { + String chosen = this.usefulSprites.get(this.random.nextInt(this.usefulSprites.size())); + termination.add("SpriteCounter stype=" + chosen + " limit=0 win=True"); + } + // Add a losing termination condition + termination.add("SpriteCounter stype=" + this.avatar + " limit=0 win=False"); - // number of interactions in the game based on the number of sprites - int numberOfInteractions = (int) (this.usefulSprites.size() * (0.5 + 0.5 * this.random.nextDouble())); - if (this.FIXED > 0) { - numberOfInteractions = this.FIXED; - } - for (int i = 0; i < numberOfInteractions; i++) { - // get two random indeces for the two sprites in the interaction - int i1 = this.random.nextInt(this.usefulSprites.size()); - int i2 = (i1 + 1 + this.random.nextInt(this.usefulSprites.size() - 1)) % this.usefulSprites.size(); - // add score change parameter for interactions - String scoreChange = ""; - if(this.random.nextBoolean()){ - scoreChange += "scoreChange=" + (this.random.nextInt(5) - 2); - } - // add the new random interaction that doesn't produce errors - interaction.add(this.usefulSprites.get(i1) + " " + this.usefulSprites.get(i2) + " > " + - this.interactions[this.random.nextInt(this.interactions.length)] + " " + scoreChange); - sl.testRules(getArray(interaction), getArray(termination)); - while(sl.getErrors().size() > 0){ - interaction.remove(i); - interaction.add(this.usefulSprites.get(i1) + " " + this.usefulSprites.get(i2) + " > " + - this.interactions[this.random.nextInt(this.interactions.length)] + " " + scoreChange); - sl.testRules(getArray(interaction), getArray(termination)); - } + return new String[][] { getArray(interaction), getArray(termination) }; } - // Add a winning termination condition - if (this.random.nextBoolean()) { - termination.add("Timeout limit=" + (800 + this.random.nextInt(500)) + " win=True"); - } else { - String chosen = this.usefulSprites.get(this.random.nextInt(this.usefulSprites.size())); - termination.add("SpriteCounter stype=" + chosen + " limit=0 win=True"); - } - // Add a losing termination condition - termination.add("SpriteCounter stype=" + this.avatar + " limit=0 win=False"); - - return new String[][] { getArray(interaction), getArray(termination) }; - } } diff --git a/src/tracks/singlePlayer/Test.java b/src/tracks/singlePlayer/Test.java index 049600e5a0..377179c48e 100644 --- a/src/tracks/singlePlayer/Test.java +++ b/src/tracks/singlePlayer/Test.java @@ -65,7 +65,7 @@ public static void main(String[] args) { int seed = new Random().nextInt(); // Game and level to play - int gameIdx = 0; + int gameIdx = 2; int levelIdx = 0; // level names from 0 to 4 (game_lvlN.txt). String game = gamesPath + games[gameIdx] + ".txt"; String level1 = gamesPath + games[gameIdx] + "_lvl" + levelIdx + ".txt"; @@ -76,10 +76,10 @@ public static void main(String[] args) { // executed. null if not to save. // 1. This starts a game, in a level, played by a human. - // ArcadeMachine.playOneGame(game, level1, recordActionsFile, seed); + ArcadeMachine.playOneGame(game, level1, recordActionsFile, seed); // 2. This plays a game in a level by the controller. - ArcadeMachine.runOneGame(game, level1, visuals, sampleRHEAController, recordActionsFile, seed, 0); +// ArcadeMachine.runOneGame(game, level1, visuals, sampleRHEAController, recordActionsFile, seed, 0); // 3. This replays a game from an action file previously recorded