Description
1. Introduction In this project you will extend the Agents and Spaces assignment to include two new features: • Each space will have an image associated with it that will be shown when the agent moves into that space. • The information about spaces and portals will be stored in a configuration file that is external to the Java program itself. That means that it no longer requires Java programming skill to create a new set of spaces and portals.
Also, you will be given the opportunity to create some images of your own to use as visual representations of the spaces that you create.
Those of you familiar with games can think of the Java program as the game engine, and the configuration file as a single level. Right now only one configuration file is allowed.
2. Due Date This project is due by midnight at the end of the day on Sunday, March 29, 2015. A penalty of 20% per day will be deducted from your grade, starting at 12:00:01am. See this link for additional information.
3. Value This program is worth a maximum of 20 points. See the grading rubric at the end for a breakdown of the values of different parts of this project.
4. Objectives Here are some objectives of this assignment: • for loops • Data conversion from textual specification into interconnected objects. • A bit of GUI programming. • Using some built-in classes, even if you don’t know how they work. Think about it: you can use anything as long as you know how the interface to that thing works. You don’t need to know how a car or a computer works in order to use it. The same is true for Java classes.
2
• Using external jar files in Eclipse.
5. Background This is a reasonable place to mention this: please place comment blocks in ALL your class files, not just the Main class file.
5.1. Private methods In this assignment I have you create several private methods. This is unusual, because usually methods are public. The reason I have you make the methods private is because they’re not needed outside the class in which they are created. If they can be made private, then they should be made private. Don’t expose internal features of a class unless you know that you should, meaning a variable or method should be private unless you know that it should be public.
5.2. INI files I have written a Java library that you will use for this project (a library is a collection of classes that is not by itself a complete program). It allows your program to load configuration data from an external file. The the data in the file follows the INI format that Microsoft Windows uses. You can read Wikipedia’s article about INI files here.
The format of the data in the file is simple. A file has sections. Each section has a header in square brackets, and under each section there are properties (or key = value pairs), like this:
[section] key = value
The Ini class library loads an INI file from disk and stores it in memory, and builds a logical structure from the sections in the file. You can query the Ini structure for what the section names are, what properties are found in a specific section, what the value is for a given key in a given section. You can also add or change properties and have the new INI file written back to disk.
The data stored in the INI file is rudimentary, but it contains enough information to make your simulation configurable through this INI file, which is separate from the program class files. In this project you will write a ConfigLoader class that will convert the INI file into a collection of spaces and portals, just like what happens in your main method now.
You can even send your INI file to a friend, and your friend can run your simulation without re-compiling the Java program.
3
This is what my main method used to look like:
Space classroom = new Space(); classroom.setName(“classroom”); classroom.setDescription(“a large lecture hall”); Space sidewalk = new Space(); sidewalk.setName(“sidewalk”); sidewalk.setDescription(“a plain concrete sidewalk with weeds growing through the cracks”); Portal door = new Portal(); door.setName(“door”); door.setDirection(“outside”); door.setDestination(sidewalk); classroom.setPortal(door); Agent student = new Agent(); student.setName(“Harry Potter”); student.setLocation(classroom);
But now it looks like this:
File configFile = new File(“data”, “config.ini”); ConfigLoader cl = new ConfigLoader(configFile); Agent a = cl.load(); CommandInterpreter.run(a);
This is what my config.ini file looks like:
[spaces] classroom = a large lecture hall sidewalk = a plain concrete sidewalk with weeds growing through the cracks [images] classroom = classroom.jpg sidewalk = sidewalk.jpg [portals] door = outside [exits] classroom = door [destinations] door = sidewalk [agents] Harry Potter = classroom
4
[start] agent = Harry Potter
This is the format of each section: • spaces: list each space in the form spaceName = spaceDescription • portals: list each portal in the form portalName = destinationDescription • exits: this connects spaces to their exit portals, the form is spaceName = portalName • destinations: this connects portals to their destinations, the form is portalName = destinationSpaceName • agents: list each agent in the form agentName = startSpaceName • start: list the starting agent in the form agent = startingAgentName
Note that for each exit in the exits section, the left hand side must refer to a space listed in the spaces section and the right hand side must be a portal listed in the portals section.
For each destination in the destinations section, the left hand side must be a portal in the portals section and the right hand side must be a space in the spaces section.
The start agent must be an agent listed in the agents section.
I know what you’re thinking, but right now the simulation does not handle more than one agent. 😉
Getting values from the Ini instance If you call the get method on the Ini instance, it will return the value (right hand side) associated with a specific key (left hand side). For instance, have a look at the spaces section:
[spaces] classroom = a large lecture hall sidewalk = a plain concrete sidewalk with weeds growing through the cracks
Assume that you have the Ini instance stored in a variable called ini. The get method is used to retrieve the value associated with a key:
File iniFile = new File(“data”, “config.ini”); Ini ini = new Ini(iniFile); // loads the ini file
String section = “spaces”; String key = “classroom”; String value = ini.get(section, key);
5
The value variable will then contain the string “a large lecture hall”.
Note that the Ini instance stores only strings. In this assignment you will need to analyze the strings to build instances of Space, Portal, and Agent, and also connect them together.
6. Assignment Read through all of the subsections in this section before you start, to make sure you understand how you must proceed with the assignment.
6.1. Copy HW 3 Summary This project extends the previous assignment.
Do this Start Eclipse and make a copy of your HW 3 project. If your HW 3 project does not work, contact your TA to obtain a working copy of the project.
6.2. Modify Space class Summary It is not good programming to always rely on using a default constructor in a class, only to fill in the member variables later using setter methods. Instead, it is better to write a constructor that lets you supply more information when you create an instance.
Do this Add a private member variable to hold the name of the image that is to be associated with this space. The name of the image will be a String. Eclipse will complain that this member variable is not used. That’s fine for now. You will use it later.
Add a getter for this new member variable. Do not add a setter (once the file name has been stored in the instance, we do not ever need to change it).
Add a constructor to this class that has one parameter for each member variable. Inside the constructor, store the arguments into the member variables. I will refer to this as a full, simple constructor. It is full in that it has one parameter for each member variable, and it is simple in that all it does is store the arguments into the member variables.
The order in which you place the parameters in the parameter list is irrelevant, as is the order of the member variables in the class.
6
Change the main method so that it uses this new constructor for the Space class. For instance, for one Space instance I have these three statements in my main method:
Space classroom = new Space(); classroom.setName(“classroom”); classroom.setDescription(“a large lecture hall”);
These should be replaced with this one method:
Space classroom = new Space(“classroom”, “a large lecture hall”, null, null);
Be sure to remove the calls to the setter methods, as I have done. Do not actually delete the setter methods from the classes.
Notice that I don’t yet know what the portal and the image name are, so I use null in those positions in the argument list. Later you will write a class that will provide all four arguments when it creates a Space instance.
Testing After you change all the constructors, run the program again to be sure it works the same as it did before.
6.3. Modify Portal class Summary You will write a constructor for the Portal class as you did with the Space class.
Do this Write a full, simple constructor for the Portal class (it should have 3 parameters).
Change the main method so that this new constructor is used, and that there are no setters called on your Portal instances.
You will still need to call the setPortal method on your Space instances.
Testing Test your program again to be sure it still works the same way.
6.4. Modify Agent class Summary You will write a constructor for the Agent class as you did with the Space and Portal
7
classes.
Do this Write a full, simple constructor for the Agent class (it should have 2 parameters).
Change the main method so that this new constructor is used, and that there are no setters called on your Agent instance.
After making this modification, the only setter methods called in the main method are the ones to set the portals of the spaces.
Testing Test your program again to be sure it still works the same way.
6.5. Create a data folder Summary This project will require the use of several data files. These will be stored in a data folder in your project folder.
Do this Right click on the project in Eclipse and select New Folder. Make sure that the project is selected in the project list. Enter the folder name data. Click Finish.
Right click on the data folder and create a sub-folder named images.
Testing Just have a look to make sure that your folder arrangement is similar to mine:
6.6. Store some images in that folder Summary You will incorporate some images into your project. Later you will add some methods that display the image associated with whatever space the agent is in.
Do this
8
Download these two image files and store them in the data/images folder in Eclipse. https://dl.dropboxusercontent.com/u/2234170/courses/CSE1102/images/classroom.jpg https://dl.dropboxusercontent.com/u/2234170/courses/CSE1102/images/sidewalk.jpg
You can drag & drop the image files right into Eclipse, then choose the option to copy the images.
Go back into the main method and add the image names to the Space constructors. Do not supply the full path, only the name of the image file as it appears in the data/images folder. Here’s one of the Space constructors in my program:
Space classroom = new Space(“classroom”, “a large lecture hall”, “classroom.jpg”, null);
Testing Again, just verify that the files are in the folder (yes, it was previously homework 4):
6.7. Use the imagewindow jar file Summary I have written the classes that will do the work of displaying the images. All you need to do is install the jar file and then call the right methods at the right time.
Do this Download this file and place it in your ExternalLibs folder in Eclipse. https://dl.dropbox.com/u/2234170/courses/CSE1102/jars/imagewindow-1.0.jar See section 5.3 in project 2 (Robot Grid) if you need instructions on how to do this.
PLEASE NOTE: Don’t just include the jar file in the build path. Instead, you should set up a path variable for this called IMAGEWINDOW. That way when your TA loads your project into Eclipse, your project will refer to the variable, which will point to where the jar file is on his computer instead of where it is on your computer, which is undoubtedly in a different place. View this video to learn how to set up a variable for the imagewindow jar file. https://dl.dropbox.com/u/2234170/courses/CSE1102/videos/EclipseVar.mov
9
After you set up the jar file, create an ImageWindow instance in the main method and store it in a variable (the class is in jeff.imagewindow). It should be very easy. There is only a default constructor for this class. Supply this variable as an argument to the CommandInterpreter.run method. This means that you must also add it as a parameter in the CommandInterpreter.run method. Do that now.
Write a private static void method in the CommandInterpreter class called _showImage (I like to use underscores with private methods, too). This method should have two parameters: an ImageWindow and an Agent. Get the name of the image associated with the agent’s space, then display the image by using these three statements:
File imageDir = new File(“data”, “images”); File imageFile = new File(imageDir, imageName); imageWindow.loadImage(imageFile);
Where imageName is defined by you in this method, and imageWindow is the parameter.
Back in the run method, call the _showImage method just before the do loop starts.
In the part of the if/else ladder where you handle the “go” command, after you call the usePortal method, call the _showImage method the same way you did before the do loop. This will cause the image to change each time the agent moves.
Testing Run the program. You should see your program running in the console, but an additional window should appear showing the image for the current space. This is what mine looks like:
10
Hmm, this is terribly inconvenient. Eclipse covers the image window each time you need to type in the console. We’ll fix that next.
6.8. Use the textconsole jar file Summary I have written another jar file for you to use. This one places the console in a window that is separate from Eclipse. This way you can have the image window and the console window both on top of Eclipse at the same time.
The console that I have created provides these methods that you will can use: • void print(String) • void println(String) • String readLine()
Do this Download and install the textconsole jar file from this link: https://dl.dropbox.com/u/2234170/courses/CSE1102/jars/textconsole-1.0.jar Add a new variable in the build path for this jar file. Call it TEXTCONSOLE.
In the main method create an instance of TextConsole and store it in a variable (the class is in jeff.textconsole), but in order to do this you will need to call the static method TextConsole.create() instead of calling new TextConsole(). [Nerd stuff, not on the exam: The TextConsole instance must be created inside a concurrent thread, so the TextConsole.create method spawns a new thread, creates a new instance, and then returns the instance. You can look at the Java source code in the jar file if you like.]
11
Pass the text console instance as an argument to the run method. This means you must add yet another parameter to the CommandInterpreter.run method.
Inside the run method, replace every System.out with the name of the text console variable. For example, in my run method, the text console parameter variable is called textConsole, so I will change this statement:
System.out.println(agent.getName() + ” is in ” + agent.getLocation().toString());
to this:
textConsole.println(agent.getName() + ” is in ” + agent.getLocation().toString());
Also add a TextConsole parameter to the Agent.usePortal method, and change the System.out there also. Eclipse indicates that there is now an error in the CommandInterpreter.run method, but its suggestion how to correct the error should be the right one (a TextConsole instance must be supplied as an argument to the usePortal method).
Now with the text console you no longer need to use the Scanner. Get rid of the Scanner and change the call to kbd.next() (or however you called the next method) to be textConsole.readLine().
Finally, in the run method but below the end of the loop, add this statement:
System.exit(0);
Just by typing the quit command the run method’s loop ends, but the text console does not end because it runs in a concurrent thread [beyond scope of this course]. The call to System.exit(0) ensures that the thread is terminated.
Testing Test it. It should work.
12
6.9. Use the ini jar file Summary The ini jar file contains an Ini class that I have written for you that will load configuration data from a file and store it in memory. All the data is stored as strings. It is your responsibility to convert the configuration data into actual Spaces, Portals, and an Agent.
Do this Yep, another jar file. This is the one I discussed in the background section of this document. https://dl.dropbox.com/u/2234170/courses/CSE1102/jars/ini-1.0.jar Add a new variable in the build path for this jar file. Call it INIFILE.
Create a class called ConfigLoader. Start with this definition:
public class ConfigLoader { private Ini _ini; private HashMap