This project allows to test several AI techniques for the implementation of Intelligent Behaviours.
The simulation environment is a fork of the sourcecode created by Philipp Rohlfshagen, David Robles and Simon Lucas of the University of Essex for a competition that took place in the IEEE Computational Intelligence and GamesConference 2016.
The goal is to provide a simulation environment for teaching and research purposes. This environment is currently used in the subject Engineering of Intelligent Behaviours at the School of Computing of the Universidad Complutense de Madrid.
The implementation available at this web page has been developed by Prof. Juan A. Recio-García from the original project, correcting bugs, including batch evaluation and components for the development of Finite State Machines, Logic Rules, Fuzzy Logic and Case-based Reasoning.
The goal of Ms Pac-Man is to obtain the highest possible score by eating all the pills and power pills in the maze (and thus advancing to the next stage). Each pill eaten scores 10 points, each power pill is worth 50 points. Ms Pac-Man's quest is opposed by the four ghosts: Blinky (red), Pinky (pink), Inky (green) and Sue (brown). At the start of each level, the ghosts start in the lair in the middle of the maze and, after some idle time, enter the maze in their pursuit of Ms Pac-Man. Their goal is to eat Ms Pac-Man and each time this happens, a life is lost and Ms Pac-Man and the ghosts return to their initial positions; the time spent by the ghosts in the lair decreases as the player progresses to higher levels.
There are four power pills in each of the four mazes, which, when eaten, reverse the direction of the ghosts and turn them blue; they may now be eaten for extra points. The score for eating each ghost in succession immediately after a power pill has been consumed starts at 200 points and doubles each time, for a total of 200+400+800+1600=3000 additional points. Any ghost that has been eaten re-appears in the lair and emerges soon after, once again chasing Ms Pac-Man. If a second power pill is consumed while some ghosts remain edible, the ghost score is reset to 200; if the level is cleared while the ghosts remain edible, play continuous immediately to the next level.
The goal of a Ms Pac-Man controller is to maximise the score of the game. In the competition, it is the average score against multiple ghost teams that counts and the winning controller is the one which obtains the highest total average score.
The goal of a ghost-team controller is to minimise the average score obtained agains t it by the different Ms Pac-Man controllers. The winning ghost team will be team with the lowest average score against it.
An introductory step-by-step tutorial of the envirnoment can be downloaded here (in Spanish)
This file also contains a description of the methods in the Game class (in Spanish).
MsPacMan Engine
and unzip it in a convenient location on your computer.To implement your behaviours, the classes you need to extend are:
pacman.controllers.PacmanController
pacman.controllers.GhostController
These files extend Controller.java
. You will need to provide code for the getMove(Game game, long timeDue)
method.
The getMove()
Method
In order to create a controller, you need to provide code for the method:
getMove(Game game, long timeDue)
.
In the case of Ms Pac-Man, this method returns an element of the MOVE enumeration found in Constants.java. The elements are:
MOVE.UP
MOVE.RIGHT
MOVE.DOWN
MOVE.LEFT
MOVE.NEUTRAL
In the case of the ghosts, this method returns an EnumMap
that maps every element from the enumeration GHOST
to MOVE
:
GHOST.BLINKY
GHOST.PINKY
GHOST.INKY
GHOST.SUE
To calculate a good move, you can query the game object to access information about the game state. The long timeDue indicates the system time the next move is due. You have 40ms per game tick to provide a response.
The Game object
Every game tick, your controller receives a copy of the current game state via the getMove()
method. The game object contains all the information required to make an informed decision. The class Game.java is the only class you need to be concerned with (you may also need to know about Constants.java, which holds all the game's enumerations and constants). The game is represented as an adjacency graph: you move from one node to another throughout the game. Nodes are referred to by their indices, and Pills and powerpills are located on specific nodes throughout the maze.
Whenever the getMove(-)
method gets called, you receive a new copy of the game and the time the move is due. Query the game state using its many methods to obtain information about the pills, powerpills, positions of Pac-Man and the Ghosts etc. The game also provides numerous additional helper methods to obtains things like shortest paths or moves to take to approach a specific target.
pacman.Executor
class. It can be configured with several options: Partial Observation (PO), tick limit, visual representation, etc. Here you can find an example: ExecutorTest.java. You can also configure the HumanController
to control MsPacMan with the keyboard.
Batch evaluation is provided by classes es.ucm.fdi.ici.PacManEvaluator
and es.ucm.fdi.ici.PacManParallelEvaluator
. These classes allows to repeat simulations several times with different behaviours. The first one executes them linearly whereas the second one, runs simulation using parallel threads. Both are configured through a config.properties
file, where you can define trials (repetitions), if partial visibility is enabled and the teams to evaluate. Here you can find an example of configuration file and a simple class to run the evaluation
In order to organize a contest with several teams, we also provide the es.ucm.fdi.ici.PacManSequentialContestEvaluator
and es.ucm.fdi.ici.PacManParallelContestEvaluator
that include visual interface to broadcast the competition live. When competition is over, it allows to play a "SuperCup" with the best MsPacMan and Ghosts teams.
To debug your behaviours use GameView.addLines()
and GameView.addPoints()
methods. Here you can see an example:
public MOVE getMove(Game game, long timeDue) {
//Show lines to PPills
int[] activePowerPills=game.getActivePowerPillsIndices();
for(int i=0;i<activePowerPills.length;i++)
GameView.addLines(game,Color.CYAN,game.getPacmanCurrentNodeIndex(),activePowerPills[i]);
//Show way to ghosts
for(Constants.GHOST g: Constants.GHOST.values()) {
int ghost = game.getGhostCurrentNodeIndex(g);
int mspacman = game.getPacmanCurrentNodeIndex();
if(game.getGhostLairTime(g)<=0)
GameView.addPoints(game,colours[g.ordinal()],game.getShortestPath(ghost,mspacman));
}
return allMoves[rnd.nextInt(allMoves.length)];
}
The FSM extension allows to implement Hierarchical Finite State Machines to define the behaviour of the MsPacMan and the Ghosts. It includes a plugable graphical interface to debug and inspect the FMSs.
A simple example of FSM is provided in the downloads section, together with the library, source code, and the graphical observer. The main elements of the FSM implementation are:
Input
. Abstract class to encapsulate the input variables required to evaluate the transitions and apply the actions over the game. It follows a template pattern where the constructor calls the parseInput()
abstract method. Here, subclasses must extract from the game the required information.
State
. Interface for FSM states. Each state is responsible of executing an action over the Game object (inside Input) and according to other input variables. SimpleStates
contain an action to be executed when the state is activated, and CompoundStates
store internally another FSM.
Transition
. Evaluates the game input to change to another state. Each state is associtated with several transitions to other states in the FSM implementation.FSM
. Is the implementation of a generic Finite State Machine. The add(State source, Transition transition, State target)
method defines its structure. The MOVE run(Input in)
executes a tick on the FSM, evaluating any out transition from the current state according to the input. If a transition is applicable, it changes to the target state and executes it. If no transitions are available or applicable, executes the action of the current state.
FSMObserver
. Defines the interface for classes that want to receive the events of the FSM. The library provides console and graphical observersThe extension allows to implement, by a CLIPS program, the behaviour of the MsPacMan and the Ghosts. It includes a plugable graphical interface to inspect the facts, and example to debug rules.
Input
. Abstract class to encapsulate the input variables required for logic process. Subclasses must implement the abstract method parseInput()
. The data should be prepared for the input variables of the .clp file, the objects templates
with attributes slot
. The variables are been offered in getFacts()
method in a Collection<String>
variable.
rules.clp
. CLIPS file program, which has two blocks, the templeantes
and the rules
. In templates
we define the input variables, the output variable (the action) and auxiliary variables. The logic that has to be applied it is defined by the rules
and those are been described in the facts that have to converge so the rule can be executed.
RuleEngine
. This class manage the execution of the CLIPS program. It does the insertion of the facts to the application with the method assertFacts(Collection<String> facts)
and the reset of the cases. Execute the CLIPS program with run()
, waiting for finishing of the application of all posible rules. If someone asserts a solution, the method returns the action to release in the game.
The extension allows to implement fuzzy logic program to define the behaviour of the MsPacMan and the Ghosts with partial visibility. It includes a plugable graphical interface to inspect the input and output variables.
Action
. The class that implements Action encapsulate the id
variable, which is managed by actionselector. It's important to assign a single id value for every action.
ActionSelector
. Class with the responsibility of managing the set of actions defined initially. Given the String id
of an action, execute a loop in this set to search the action with the same id, returning the class that implements that action.
Input
. Abstract class to encapsulate the input variables required for fuzzy logic. Subclasses must implement the abstract method parseInput()
and the returned data must follow the format defined in .fcl file, in section of VAR_INPUTS
. The data processed in Map<String, Double>, the name of the variable and double value. The map is returned in getFuzzyValues()
method.
GhostsFuzzy
. The class that implements the ghost controller logic, to be affected by the partial visibility, it should extend the POGhostController
instead of GhostController
. Besides, the visibility is not shared between the ghosts so they don't have the same information and they can't comunicate through GhostController
.
FuzzyEngine
. This class executes the fuzzy logic described in the file .fcl, to do this it calls to jFuzzyLogic
, which is an open source fuzzy logic library. The important method that manages the information and returns the result of the program in run(HashMap<String, Double>)
and it return the ActionResult returned by ActionSelector.
File.fcl
. It`s where the fuzzy logic program is. This program defines variables and rules. We have the variables split in two types, input and output, the input variables have to be fuzzifyed
and the output variables must to be defuzzifyed
. The rules are agruped in the RULEBLOCK
and they define how the inputs variables are combined so they assign the output values.
The extension allows to implement Case-based reasoning (CBR) to define the behaviour of the MsPacMan and the Ghosts.
Input
. Abstract class to encapsulate the input variables contemplated for the state of the game. Subclasses must implement the abstract method parseInput()
in which one must to configure/set the values of variables of description of the case. The data should prepare the input variables of the .clp file, the objects templates
with attributes slot
. It should have the same variables which are defined in the correspond Description class and it must be set in the the CBRQuery
that returns in method getQuery()
.
CachedLinearCaseBase
. It can be find the cbr cases cached which improve the management efficient of getting the cases. There are 3 differents sets of cases, the working cases which are the ones applied in this game, the original cases which are the cases loaded from the CBR database, and the cases pending to remove, which are the ones that can add cases to eliminate them.
In adition, when there are lots of cases, the working cases can be divided and be treated with sets indexed. For example, defining a new struct with cases by juctions, by mazes or by pair <juction, maze>.
CBREngine
. Class that implements StandarCBR and forces to implement some methods that manage important functionalities.
The principal variables this class have are the following: the CustomPlainConnector
, the CachedLinearCaseBase
, the StorageManager
and the ActionSelector
.
First, in method configure()
with connector, this class loads the data from general database by the plaintextconfig.xml configuration and with it configures the StorageManager and the CachedLinearCaseBase.As soon as we start the game, it executes the precycle()
which initialize the CachedLinearCaseBase.
For each uptade of the game, it executes the method cycle(CBRQuery)
.
This method implements the principal process of cbr cicle and it gets the similar cases to the actual one. From those cases the method will get the "best" Solution and configure it in a global variable. We create and insert a new CBRCase in the StorageManager in the method cycle(CBRQuery).
Lastly, when the game is over, it will execute the postcycle()
and close the database of the cases.
Solution
. Class, part of the CBRCases, which one contains the String that represents the action that was applied in the case.
Result
. Class, part of the CBRCases, which one contains how "good" or "bad" the solution was in the case associated.
plaintextconfig.xml
. XML file that descrives the variables to process into Description, Result and Solution of a CBRCase.
Here you can find the downloads of MsPacMan Vs Ghosts:
MsPacMan Engine | Full engine including evaluation classes and adaptors to implement controllers | MsPacManEngine-4.0.0.zip |
FSM Example | Simple example that shows how to implement behaviours using Finite State Machines | ICI-FSMexample.zip |
Fuzzy Example | Simple example that shows how to implement behaviours using Fuzzy Logic | ICI-FuzzyExample.zip |
Rules Example | Simple example that shows how to implement behaviours using Logic Rules (it requires JESS library, not included) | ICI-RulesExample.zip |
CBR Example | Simple example that shows how to implement behaviours using Case-based Reasoining (through the jCOLIBRI CBR engine) | ICI-CBRExample.zip |
Training Teams 22-23: Algorithmic implementation | Teams developed by students in 2022-23 using an algorithmic implementation. These teams can be used to train your behaviours | ici-c2223-practica1.jar |
Training Teams 22-23: FSM implementation | Teams developed by students in 2022-23 using Finite State Machines. These teams can be used to train your behaviours | ici-c2223-practica2.jar |
Training Teams 21-22: Algorithmic implementation | Teams developed by students in 2020-21 using an algorithmic implementation. These teams can be used to train your behaviours | ici-c2122-practica1.jar |
Training Teams 21-22: FSM implementation | Teams developed by students in 2021-22 using Finite State Machines. These teams can be used to train your behaviours | ici-c2122-practica2.jar |
Training Teams 20-21: Algorithmic implementation | Teams developed by students in 2020-21 using an algorithmic implementation. These teams can be used to train your behaviours | ici.c2021.practica1.jar |
Training Teams 20-21: FSM implementation | Teams developed by students in 2020-21 using Finite State Machines. These teams can be used to train your behaviours | ici.c2021.practica2.jar |