Creating a new universe - BuggleInc/PLM GitHub Wiki
This page will teach you how to write new universes in PLM. For that, we will reimplement the Hanoi world (available in the recursion lesson) step-by-step. This lesson covers quite advanced topics and suppose that you are fluent in Java and confident with the use of the PLM framework already. If not, you probably want to take another lesson before.
What is an universe
Every PLM universe is composed of 4 main components:
- The world: it contains the state of the universe.
- The view: it allows to draw the world and the entities on the screen.
- The entity ancestor: the code written by the student will derive from this class, which contains some state specific to the entity, and every accessor to let the entity interact with its world.
- The entity interactive control panel: this is the little panel displayed under the world view in the PLM interface. It allows to interactively control the selected entity. As you can see from the existing universes, this is optional. If you don't provide any, the panel will remain blank, preventing the users from interactively controlling the entities.
In addition, designing a new universe without instanciating is not very helpful. So you probably want to design a new exercise where your universe comes to play. For every details on adding exercises, please check Teacher-documentation-adapting-the-content. Here is what you need to know for now:
- Lessons are just a list of exercise that can be taken by the students in the order they want. In each lesson, you find a class called Main, which simply contains a constructor adding each exercise of the lesson.
- Each exercise object is in charge of instantiating the worlds used, set them up (adding walls and baggles in BuggleWorld, or changing the elevation and adding lamps in the LightBotWorld, etc), and populate them with entities correctly setup (location, color, etc).
- Most of the exercises also provide a specific answer entity that can solve the exercise. It serve both to compute the initial content of the code editor, and to compute the objective world. Please see Teacher-documentation-adapting-the-content for more details.
The very first element you want to write in a new PLM universe is a partial world implementation including the internal state. Later, you will complete the World class to provide entities ways to interact and modify their world, and we will also implement the other elements of the universe.
Before you jump in writing your World implementation, you should understand the big PLM picture, and how worlds are used internally.
PLM worlds big picture
As you know, every PLM exercise can contain one or several worlds, each containing one or several entities. The code written by the student is executed in the entities, which must interact with their world to change it from its initial state to its goal state.
This multiplication of worlds and entities is used to test the student code in several conditions. It is thus similar to test cases, aiming at full testing coverage of the student code.
Technically, in a given exercise, for every world accessible from the relevant combobox, there is three World objects. They live in jlm.core.lesson.Exercise
:
protected World [] initialWorld; protected World [] currentWorld; protected World [] answerWorld;
The line number of the combobox gives the index to use in these arrays. Each initialWorld
is created by the exercise constructor.
currentWorld
is the one displayed in the "World" tab of the interface. At the beginning, it is a plain copy of the initialWorld
, but it gets modified when the student uses the interactive controls or when the program gets run. The "Reset" button reset it to be a perfect copy of the initial world.
answerWorld
is the one displayed by the "Objective" world. Basically, it's a copy of the initial world, on which we let the specific answer entity of this exercise run. This default behavior can be overloaded by exercises, but you'll probably never have to do so unless you do very strange kind of exercises (as for the lightbot universe, for example).
Implementing basic Worlds
The internal use of Worlds hidden, but the important point is that every World object has extend the jlm.universe.World
class and define the following methods and constructors:
- a copy constructor which is used to copy initial worlds into
currentWorld
andanswerWorld
. Its argument must be of the exact same type than the class itself, not Object (this is because we use Java introspection mechanism to search for such a constructor of the class). For example, if you create aTotoWorld
, your copy constructor must be declared as this: public TotoWorld(TotoWorld other) {...} // Correct public TotoWorld(Object other) {...} // FALSE public TotoWorld(World other) {...} // also FALSE The content of this constructor is usually a simple call to thesuper(World w)
constructor, but this constructor cannot be omitted. - One or several regular constructors initializing the state of the object. They will be used by the exercise constructor to instantiate your world. Since you usually write both the world and the lessons, you are completely free to specify the parameters you want to your constructor. It should use the
super(String name)
constructor to setup the very basic elements of your world. Optionally, you may also want to use thesetDelay(int delay)
method to change the initial animation delay. For example, theSortingWorld
set this to 1 to speed animations up. This is the delay in milliseconds between each animation step during a continuous run. - A reset() method taking one World as parameter, and in charge of copying the state of the parameter into the current world. This is naturally used when you press the "Reset" button, or at the beginning of each run.
The length of this method naturally depends on the complexity of your world state. In Hanoi, there is only 3 slots containing a list of disc so that will be quite easy, but this can be quite complicated for complex worlds such as
BuggleWorld
.
Allowing the graphical rendering of Worlds
Some specific steps naturally must be taken so that PLM can graphically display your world. For that, you must write a specific class extending jlm.universe.WorldView
, and provide some protected methods so that the View can retrieve the state to display.
(To be continued)