
engine.core.MarioForwardModel Maven / Gradle / Ivy
package engine.core;
import java.util.ArrayList;
import engine.helper.EventType;
import engine.helper.GameStatus;
import engine.helper.SpriteType;
public class MarioForwardModel {
private static final int OBS_SCENE_SHIFT = 16;
// Generic values
public static final int OBS_NONE = 0;
public static final int OBS_UNDEF = -42;
// Common between scene detail level 0 and scene detail level 1
public static final int OBS_SOLID = OBS_SCENE_SHIFT + 1;
public static final int OBS_BRICK = OBS_SCENE_SHIFT + 6;
public static final int OBS_QUESTION_BLOCK = OBS_SCENE_SHIFT + 8;
public static final int OBS_COIN = OBS_SCENE_SHIFT + 15;
// Scene detail level 0
public static final int OBS_PYRAMID_SOLID = OBS_SCENE_SHIFT + 2;
public static final int OBS_PIPE_BODY_RIGHT = OBS_SCENE_SHIFT + 21;
public static final int OBS_PIPE_BODY_LEFT = OBS_SCENE_SHIFT + 20;
public static final int OBS_PIPE_TOP_RIGHT = OBS_SCENE_SHIFT + 19;
public static final int OBS_PIPE_TOP_LEFT = OBS_SCENE_SHIFT + 18;
public static final int OBS_USED_BLOCK = OBS_SCENE_SHIFT + 14;
public static final int OBS_BULLET_BILL_BODY = OBS_SCENE_SHIFT + 5;
public static final int OBS_BULLET_BILL_NECT = OBS_SCENE_SHIFT + 4;
public static final int OBS_BULLET_BILL_HEAD = OBS_SCENE_SHIFT + 3;
public static final int OBS_BACKGROUND = OBS_SCENE_SHIFT + 47;
public static final int OBS_PLATFORM_SINGLE = OBS_SCENE_SHIFT + 43;
public static final int OBS_PLATFORM_LEFT = OBS_SCENE_SHIFT + 44;
public static final int OBS_PLATFORM_RIGHT = OBS_SCENE_SHIFT + 45;
public static final int OBS_PLATFORM_CENTER = OBS_SCENE_SHIFT + 46;
// Scene detail level 1
public static final int OBS_PLATFORM = OBS_SCENE_SHIFT + 43;
public static final int OBS_CANNON = OBS_SCENE_SHIFT + 3;
public static final int OBS_PIPE = OBS_SCENE_SHIFT + 18;
// Scene detail level 2
public static final int OBS_SCENE_OBJECT = OBS_SCENE_SHIFT + 84;
// Common between enemies detail level 0 and 1
public static final int OBS_FIREBALL = 16;
// Enemies Detail 0
public static final int OBS_GOOMBA = 2;
public static final int OBS_GOOMBA_WINGED = 3;
public static final int OBS_RED_KOOPA = 4;
public static final int OBS_RED_KOOPA_WINGED = 5;
public static final int OBS_GREEN_KOOPA = 6;
public static final int OBS_GREEN_KOOPA_WINGED = 7;
public static final int OBS_SPIKY = 8;
public static final int OBS_SPIKY_WINGED = 9;
public static final int OBS_BULLET_BILL = 10;
public static final int OBS_ENEMY_FLOWER = 11;
public static final int OBS_MUSHROOM = 12;
public static final int OBS_FIRE_FLOWER = 13;
public static final int OBS_SHELL = 14;
public static final int OBS_LIFE_MUSHROOM = 15;
// Enemies Detail 1
public static final int OBS_STOMPABLE_ENEMY = 2;
public static final int OBS_NONSTOMPABLE_ENEMY = 8;
public static final int OBS_SPECIAL_ITEM = 12;
// Enemies Detail 2
public static final int OBS_ENEMY = 1;
public static int getSpriteTypeGeneralization(SpriteType sprite, int detail) {
switch (detail) {
case (0):
switch (sprite) {
case MARIO:
return OBS_NONE;
default:
sprite.getValue();
}
case (1):
switch (sprite) {
case MARIO:
return OBS_NONE;
case FIREBALL:
return OBS_FIREBALL;
case MUSHROOM:
case LIFE_MUSHROOM:
case FIRE_FLOWER:
return OBS_SPECIAL_ITEM;
case BULLET_BILL:
case SHELL:
case GOOMBA:
case GOOMBA_WINGED:
case GREEN_KOOPA:
case GREEN_KOOPA_WINGED:
case RED_KOOPA:
case RED_KOOPA_WINGED:
return OBS_STOMPABLE_ENEMY;
case SPIKY:
case SPIKY_WINGED:
case ENEMY_FLOWER:
return OBS_NONSTOMPABLE_ENEMY;
default:
return OBS_NONE;
}
case (2):
switch (sprite) {
case FIREBALL:
case MARIO:
case MUSHROOM:
case LIFE_MUSHROOM:
case FIRE_FLOWER:
return OBS_NONE;
default:
return OBS_ENEMY;
}
}
return OBS_UNDEF;
}
public static int getBlockValueGeneralization(int tile, int detail) {
if (tile == 0) {
return OBS_NONE;
}
switch (detail) {
case (0):
switch (tile) {
// invisble blocks
case 48:
case 49:
return OBS_NONE;
// brick blocks
case 6:
case 7:
case 50:
case 51:
return OBS_BRICK;
// ? blocks
case 8:
case 11:
return OBS_QUESTION_BLOCK;
}
return tile + OBS_SCENE_SHIFT;
case (1):
switch (tile) {
// invisble blocks
case 48:
case 49:
// body for jumpthrough platform
case 47:
return OBS_NONE;
// solid blocks
case 1:
case 2:
case 14:
return OBS_SOLID;
// bullet bill blocks
case 3:
case 4:
case 5:
return OBS_CANNON;
// pipe blocks
case 18:
case 19:
case 20:
case 21:
return OBS_PIPE;
// brick blocks
case 6:
case 7:
case 50:
case 51:
return OBS_BRICK;
// ? blocks
case 8:
case 11:
return OBS_QUESTION_BLOCK;
// coin
case 15:
return OBS_COIN;
// Jump through platforms
case 44:
case 45:
case 46:
return OBS_PLATFORM;
}
return OBS_NONE;
case (2):
switch (tile) {
// invisible blocks
case 48:
case 49:
// body for jumpthrough platform
case 47:
return OBS_NONE;
}
// everything else is "something", so it is 100
return OBS_SCENE_OBJECT;
}
return OBS_UNDEF;
}
/**
* The width of the observation grid
*/
public final int obsGridWidth = MarioGame.tileWidth;
/**
* The height of the observation grid
*/
public final int obsGridHeight = MarioGame.tileHeight;
private MarioWorld world;
// stats
private int fallKill;
private int stompKill;
private int fireKill;
private int shellKill;
private int mushrooms;
private int flowers;
private int breakBlock;
/**
* Create a forward model object
*
* @param world the current level world that is being used. This class hides the
* world object so the agents won't cheat.
*/
public MarioForwardModel(MarioWorld world) {
this.world = world;
}
/**
* Create a clone from the current forward model state
*
* @return a clone from the current forward model state
*/
public MarioForwardModel clone() {
MarioForwardModel model = new MarioForwardModel(this.world.clone());
model.fallKill = this.fallKill;
model.stompKill = this.stompKill;
model.fireKill = this.fireKill;
model.shellKill = this.shellKill;
model.mushrooms = this.mushrooms;
model.flowers = this.flowers;
model.breakBlock = this.breakBlock;
return model;
}
/**
* Advance the forward model using the action array
*
* @param actions a list of all the button states
*/
public void advance(boolean[] actions) {
this.world.update(actions);
for (MarioEvent e : this.world.lastFrameEvents) {
if (e.getEventType() == EventType.FIRE_KILL.getValue()) {
this.fireKill += 1;
}
if (e.getEventType() == EventType.STOMP_KILL.getValue()) {
this.stompKill += 1;
}
if (e.getEventType() == EventType.FALL_KILL.getValue()) {
this.fallKill += 1;
}
if (e.getEventType() == EventType.SHELL_KILL.getValue()) {
this.shellKill += 1;
}
if (e.getEventType() == EventType.COLLECT.getValue()) {
if (e.getEventParam() == SpriteType.FIRE_FLOWER.getValue()) {
this.flowers += 1;
}
if (e.getEventParam() == SpriteType.MUSHROOM.getValue()) {
this.mushrooms += 1;
}
}
if (e.getEventType() == EventType.BUMP.getValue() && e.getEventParam() == OBS_BRICK
&& e.getMarioState() > 0) {
this.breakBlock += 1;
}
}
}
/**
* Get the current state of the running game
*
* @return GameStatus the current state (WIN, LOSE, TIME_OUT, RUNNING)
*/
public GameStatus getGameStatus() {
return this.world.gameStatus;
}
/**
* The percentage of distance traversed between mario and the goal
*
* @return value between 0 to 1 to indicate the percentage of distance traversed
*/
public float getCompletionPercentage() {
return this.world.mario.x / (this.world.level.exitTileX * 16);
}
/**
* Get the current level dimensions
*
* @return the first value is level width and second is level height
*/
public float[] getLevelFloatDimensions() {
return new float[]{this.world.level.width, this.world.level.height};
}
/**
* Get the remaining time before the game timesout
*
* @return the number of time ticks before timeout each frame removes 30 frames
*/
public int getRemainingTime() {
return this.world.currentTimer;
}
/**
* Get mario position
*
* @return the actual mario position in the current state
*/
public float[] getMarioFloatPos() {
return new float[]{this.world.mario.x, this.world.mario.y};
}
/**
* Get mario velocity
*
* @return the actual mario velocity in the current state
*/
public float[] getMarioFloatVelocity() {
return new float[]{this.world.mario.xa, this.world.mario.ya};
}
/**
* If mario can press the jump button while in the air to reach higher areas
*
* @return true if the agent can press the button longer and false otherwise
*/
public boolean getMarioCanJumpHigher() {
return this.world.mario.jumpTime > 0;
}
/**
* Get the current mario mode
*
* @return the current mario mode (0-small, 1-large, 2-fire)
*/
public int getMarioMode() {
int value = 0;
if (this.world.mario.isLarge) {
value = 1;
}
if (this.world.mario.isFire) {
value = 2;
}
return value;
}
/**
* Get to know if mario is touching the ground.
*
* @return true if mario is touching the ground and false otherwise
*/
public boolean isMarioOnGround() {
return this.world.mario.onGround;
}
/**
* Get to know if mario is able to jump
*
* @return true if mario can jump and false otherwise
*/
public boolean mayMarioJump() {
return this.world.mario.mayJump;
}
/**
* Get a 3x float list that contain the type of enemies, x position, y position
*
* @return an array of 3 floats that contain the enemy type, x position, y
* position for each enemy sprite
*/
public float[] getEnemiesFloatPos() {
ArrayList enemiesAlive = this.world.getEnemies();
float[] enemyPos = new float[enemiesAlive.size() * 3];
for (int i = 0; i < enemiesAlive.size(); i++) {
enemyPos[3 * i] = enemiesAlive.get(i).type.getValue();
enemyPos[3 * i + 1] = enemiesAlive.get(i).x;
enemyPos[3 * i + 2] = enemiesAlive.get(i).y;
}
return enemyPos;
}
/**
* get the number of enemies killed in the game
*
* @return number of enemies killed in the game
*/
public int getKillsTotal() {
return this.fallKill + this.fireKill + this.shellKill + this.stompKill;
}
/**
* get the number of enemies killed by fireballs
*
* @return number of enemies killed by fireballs
*/
public int getKillsByFire() {
return this.fireKill;
}
/**
* get the number of enemies killed by stomping
*
* @return number of enemies killed by stomping
*/
public int getKillsByStomp() {
return this.stompKill;
}
/**
* get the number of enemies killed by a koopa shell
*
* @return number of enemies killed by a koopa shell
*/
public int getKillsByShell() {
return this.shellKill;
}
/**
* get the number of enemies that fell from the game screen
*
* @return the number of enemies that fell from the game screen
*/
public int getKillsByFall() {
return this.fallKill;
}
/**
* get the number 100 coins collected by mario
*
* @return number of 100 coins collected by mario
*/
public int getNumLives() {
return this.world.lives;
}
/**
* get the number of mushroom collected by mario
*
* @return the number of collected mushrooms by mario
*/
public int getNumCollectedMushrooms() {
return this.mushrooms;
}
/**
* get the number of fire flowers collected by mario
*
* @return the number of collected fire flowers by mario
*/
public int getNumCollectedFireflower() {
return this.flowers;
}
/**
* get the number of coins collected by mario
*
* @return the number of collected coins by mario
*/
public int getNumCollectedCoins() {
return this.world.coins;
}
/**
* get the number of destroyed bricks by large or fire mario
*
* @return the number of destroyed bricks by large or fire mario
*/
public int getNumDestroyedBricks() {
return this.breakBlock;
}
/**
* Get the tile location of mario with respect to the screen
*
* @return the x and y location of mario on the screen as tile values
*/
public int[] getMarioScreenTilePos() {
return new int[]{(int) ((this.world.mario.x - this.world.cameraX) / 16), (int) (this.world.mario.y / 16)};
}
/**
* The current screen status as a 2D tile grid around the center of screen with
* scene detail value 1 and enemy detail value of 0
*
* @return 2D grid that have all the information about all objects on the screen
*/
public int[][] getScreenCompleteObservation() {
return this.getScreenCompleteObservation(1, 0);
}
/**
* The current enemies on the screen as a 2D tile grid around the center of
* screen with a detail value of 0
*
* @return 2D grid where each tile contain either 0 to indicate no enemy or a
* number to indicate a certain enemy. Look at SpriteTypes for enemy
* values (Detail 0).
*/
public int[][] getScreenEnemiesObservation() {
return this.getScreenEnemiesObservation(0);
}
/**
* The current objects (not enemies) on the screen as a 2D tile grid around the
* center of screen with a detail value of 1
*
* @return 2D grid where each tile contain either 0 which means it is empty or a
* value that reflect the type of the tile in that area. Look at
* TileTypes for the meaning of values (Detail 1)
*/
public int[][] getScreenSceneObservation() {
return this.getScreenSceneObservation(1);
}
/**
* The current screen status as a 2D tile grid around mario with scene detail
* value 1 and enemy detail value of 0
*
* @return 2D grid that have all the information about all objects on the screen
*/
public int[][] getMarioCompleteObservation() {
return this.getMarioCompleteObservation(1, 0);
}
/**
* The current enemies on the screen as a 2D tile grid around mario with a
* detail value of 0
*
* @return 2D grid where each tile contain either 0 to indicate no enemy or a
* number to indicate a certain enemy. Look at SpriteTypes for enemy
* values (Detail 0).
*/
public int[][] getMarioEnemiesObservation() {
return this.getMarioEnemiesObservation(0);
}
/**
* The current objects (not enemies) on the screen as a 2D tile grid around
* mario with a detail value of 1
*
* @return 2D grid where each tile contain either 0 which means it is empty or a
* value that reflect the type of the tile in that area. Look at
* TileTypes for the meaning of values (Detail 1)
*/
public int[][] getMarioSceneObservation() {
return this.getMarioSceneObservation(1);
}
/**
* The current screen status as a 2D tile grid around the center of screen
*
* @param sceneDetail the detail level of the scene: 0 all detail, 1 less detailed, 2
* binary detail
* @param enemyDetail the detail level of the current enemies: 0 all details, 1 less
* detailed, 2 binary detail
* @return 2D grid that have all the information about all objects on the screen
*/
public int[][] getScreenCompleteObservation(int sceneDetail, int enemyDetail) {
return this.world.getMergedObservation(this.world.cameraX + MarioGame.width / 2, MarioGame.height / 2,
sceneDetail, enemyDetail);
}
/**
* The current enemies on the screen as a 2D tile grid around the center of
* screen
*
* @param detail the detail level of the current enemies: 0 all details, 1 less
* detailed, 2 binary detail
* @return 2D grid where each tile contain either 0 to indicate no enemy or a
* number to indicate a certain enemy. Look at SpriteTypes for enemy
* values (Detail 0).
*/
public int[][] getScreenEnemiesObservation(int detail) {
return this.world.getEnemiesObservation(this.world.cameraX + MarioGame.width / 2, MarioGame.height / 2, detail);
}
/**
* The current objects (not enemies) on the screen as a 2D tile grid around the
* center of screen
*
* @param detail the detail level of the scene: 0 all detail, 1 less detailed, 2
* binary detail
* @return 2D grid where each tile contain either 0 which means it is empty or a
* value that reflect the type of the tile in that area. Look at
* TileTypes for the meaning of values (Detail 1)
*/
public int[][] getScreenSceneObservation(int detail) {
return this.world.getSceneObservation(this.world.cameraX + MarioGame.width / 2, MarioGame.height / 2, detail);
}
/**
* The current screen status as a 2D tile grid around mario
*
* @param sceneDetail the detail level of the scene: 0 all detail, 1 less detailed, 2
* binary detail
* @param enemyDetail the detail level of the current enemies: 0 all details, 1 less
* detailed, 2 binary detail
* @return 2D grid that have all the information about all objects on the screen
*/
public int[][] getMarioCompleteObservation(int sceneDetail, int enemyDetail) {
return this.world.getMergedObservation(this.world.mario.x, this.world.mario.y, sceneDetail, enemyDetail);
}
/**
* The current enemies on the screen as a 2D tile grid around mario
*
* @param detail the detail level of the current enemies: 0 all details, 1 less
* detailed, 2 binary detail
* @return 2D grid where each tile contain either 0 to indicate no enemy or a
* number to indicate a certain enemy. Look at SpriteTypes for enemy
* values (Detail 0).
*/
public int[][] getMarioEnemiesObservation(int detail) {
return this.world.getEnemiesObservation(this.world.mario.x, this.world.mario.y, detail);
}
/**
* The current objects (not enemies) on the screen as a 2D tile grid around
* mario
*
* @param detail the detail level of the scene: 0 all detail, 1 less detailed, 2
* binary detail
* @return 2D grid where each tile contain either 0 which means it is empty or a
* value that reflect the type of the tile in that area. Look at
* TileTypes for the meaning of values (Detail 1)
*/
public int[][] getMarioSceneObservation(int detail) {
return this.world.getSceneObservation(this.world.mario.x, this.world.mario.y, detail);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy