Mario AI
Overview
The MarioAI project aims to allow school and university students to learn artificial intelligence in a entertaining context. Students merely require a Java IDE or their choice and the MarioAI .jar file that is produced with the maven build. Students can then use the provided API to implement an AI agent. A simple rules-based algorithm can easily be created within 10 minutes.
Setup
Setting up the IDE
Download the marioAI-<version>.jar from the repository. Create a new project in the IDE of your choice and include the MarioaAI.jar as a project dependency.
Eclipse
In Eclipse this can be achieved by right-clicking on the project → build path → Java build path. In the libraries tab click on "Add External JARs" and select the marioAI-<version>.jar
IntelliJ IDEA
In the menu click File → Project Structure → Libraries → "+" and select the marioAI-<version>.jar
Creating a Basic Agent
Create a new class that extends the Class MarioAiAgent. The MarioAiAgent class specifies two abstract methods which need to be implemented as can be seen in the snippet below.
public class Demo extends MarioAiAgent {
@Override
public String getName() {
return "Demo Agent";
}
@Override
public MarioInput doAiLogic() {
moveRight();
return getMarioInput();
}
public static void main(String[] args) {
MarioAiRunner runner = new MarioAiRunnerBuilder()
.addAgent(new Demo())
.setLevelConfig(LevelConfig.LEVEL_1)
.construct();
runner.run();
}
Add a main method as shown in the snippet and start MarioAI by running the method from your IDE. A window should open which show Mario walking right in a flat level.
MarioAI
User Interface
The user interface shows information on the current state of the game which can be useful to observe, including the current score as shown in the bottom left hand corner. The size of the window can be increased or decreased by pressing the +/- keys. To reset the window size, press #. More functions that can be accessed can be found the the chapter "Keyboard Functions" below.
Keyboard Functions
While MarioAI is running you can trigger the following functions from your keyboard
Function/Toggle | Key |
---|---|
Increase window size | + |
Decrease window size | - |
Reset window size | # |
Increase FPS | j |
Decrease FPS | k |
Reset FPS to default (24) | l |
Toggle pause | p |
Pause and advance to next frame (i.e. tick()) | t |
Toggle path visualisation | o |
Pause game and show current level state in console | i |
MarioAI API
The MarioAI API is quite extensive. The following three chapters "Controlling Mario", "Reading the Environment" and "Configuration" will provide an overview of the most important aspects of the API. For more information, please refer to the JavaDocs provided in the jar file.
Controlling Mario
Controlling Mario is fairly straightfoward. There is a method that can be called for each action mario can carry out (i.e. move right, move left, jump and sprint/shoot fireballs. Please note that the last two actions are mapped to the same button in the game, as in the original game. To carry out one or more actions, simply call the associated method in the API
Action | Corresponding API method |
---|---|
Move right | moveRight() |
Move left | moveLeft() |
Jump | jump() |
Sprint | sprint() |
Shoot | shoot() |
@Override
public MarioInput doAiLogic() {
moveRight();
sprint();
jump();
return getMarioInput();
}
Reading the environment
Reading Mario's environment via the MarioAI API can be achieved either via convinience methods or via more advanced methods. Let's begin by looking at the convienience methods provided by MarioAI which allow for quickly creating a simple rules-based AI algorithm (i.e. if this, do that).
Environment Query | Method |
---|---|
Is there a brick (i.e. unpassable object) ahead? | isBrickAhead() |
Is there an enemy ahead? | isEnemyAhead() |
Is there a deep slope ahead? | isDeepSlopeAhead() |
Is Mario falling (i.e. has a positive y-vector) | isFalling() |
Is there a hole ahead (i.e. a hole which will kill Mario)? | isHoleAhead() |
Is there a question brick above Mario? | isQuestionbrickAbove() |
Running & Configuration
You can run your Agent by using the MarioAiRunner class. The simplest way of obtaining a Runner to run your agent is using the builder MarioAiRunnerBuilder . You can specify different parameters with the corresponding methods. For example you can pass an instance of your agent to the builder object with addAgent(). Then you can construct a MarioAiRunner instance with the builder and the method construct(). By calling the method run() of the newly created MarioAiRunner, you can start a run with your agent.
MarioAI offers many ways of customizing the level for your purposes. The simplest way to configure the game is to simply use preconfigured levels provided in the enums provided in LevelConfig and set it as used level of the builder with setLevelConfig().
public static void main(String[] args) {
MarioAiRunner runner = new MarioAiRunnerBuilder()
.addAgent(new Demo())
.setLevelConfig(LevelConfig.LEVEL_1)
.construct();
runner.run();
}
If you would like to specify your own level (including the type of level, enemies, difficulty, etc. ) you can use the many paramenters that can be passed to the constructor of LevelConfig described below
Parameter | Usage |
---|---|
seed | The seed of the generated level layout. Using the same seed will result in the same level layout. |
presetDiffulty | A value which specifies the difficulty by influencing the amount of enemies which are spawned. |
type | Sets the type of level (i.e. OVERGROUND, UNDERGROUND, CASTLE) |
enemies | Toggles enemies |
bricks | Toggles bricks |
coins | Toggles coins |
length | The length of the level. |
odds | Array with length of 5, determines the percentage of level parts [STRAIGHT, HILLS, TUBES, HOLES, BULLETBILL] |
Evaluation
You can evaluate how well your agent performed in the level by either reading the score at the end of the level from the UI, the console or the logs. Alternatively you can read the current score from the API using the getActualScore() method within the agent.
The following table shows all rewards and penalties that can be accrued during the level.
Event or Condition | Reward/Penalty |
---|---|
Reach the end of the level | +1024 points |
Remaining time at the end of the level | +8 points per second left |
Distance passed | +1 point per distance unit |
Collecting coins | +16 per coin |
Defeated enemies | +42 per enemy |
... by stomping | +12 points |
... by hitting with a shell | +17 points |
... by fireball | +4 points |
Collecting non-coin items (i.e. fire-flowers, mushrooms) | +58 per item |
Getting hit by enemy or projectile | -42 per hit |