Adventure game

The adventure game is textural based, but the main part of the assignment is pull data from files to build up the adventure environment so that nothing as such is hard coded apart from the main options like QUIT, HELP etc.

You have different parts of the adventure game to build up, reading in of the rooms that the user will move around, the adventure objects to pick up file to read in (and place within the rooms in the adventure game) and you are also able to pick up the items as well. To start with I am going to do the reading in of the files (if present)

Here is part of the room file, it starts with the room ID number, then the small name followed by the description (finishing with “—–“) and, last but not least, is the movement options and the room ID to move to, e.g WEST 2 means if you go WEST you will end up in room ID 2


1
Outside building
You are standing at the end of a road before a small brick
building. A small stream flows out of the building and
down a gully to the south. A road runs up a small hill
to the west.
-----
WEST 2
UP 2

here is how I am reading in the main room file, the readPassEmpty is another function that will read passed any empty lines and return the first non empty string from within the file, the readInLine will read just one line at a time (with all error checking). the returnRoom is what I am going to return back to the main adventure class that will add the rooms read into a ArrayList.

String st = readPassedEmpty(rd);
if (st== null) return null;
returnRoom.roomNumber = Integer.parseInt(st);
returnRoom.roomName = readInLine(rd);
String readIn;
while(true) {
	readIn = readInLine(rd);
	if (readIn.indexOf("-----")>=0) break;
	returnRoom.roomDescription.add(readIn);
}
while (true)
{
	readIn = readInLine(rd);
	if (readIn == null) break;
	if (readIn.equals("")) break;
	returnRoom.roomMotionTable.add(getMotionTable(readIn));
}

To break the movement roomID (/options) part of the file into parts, I used the split function within the String class, you pass in a regular expression, in this case [ ]+ which means any space [ ] and + means 1 or more times e.g. if there is one space between movement or 5 then it will classes as the same thing, and if there is any options attached to the roomID e.g. you needs to have KEYS

String[] split = st.split("[ ]+");
dir = split[0];
int indexOf =split[1].indexOf("/");

reading in the adventure room objects and also the synonyms is very similar in that I either break the synonym into a regular expression searching for the “=” and thus linking the left value to the right value within a ArrayList of synonyms. The adventure objects, I just read in there values and add the objects to the required room, for example the file looks like

KEYS
a set of keys
3

where the KEYS is the object, “a set of keys” is the long description, and 3 is the roomID to place the items into.

Movement around the adventure

To move around the adventure game, the user types in the direction (or there is some hidden options) and then the adventure game will move to that required place and the way that I thought about this was to get all of the movement options within that room, see if the player has requested any of these movement options and move that player to the next room, but if there is a option/requirement (e.g. KEYS) to access that room then see if the player has them within his user objects. Else if there is no movement that the user requested just output a error and return -1 (which means no update).

private int movePlayer(String player, int roomID)
{
	AdvMotionTableEntry[] moves = advRooms.get(roomID-1).getMotionTable();
	for (int i = 0; i < moves.length; i++)
	{
		if (moves[i].getDirection().equals(player))
		{
			String keyName =moves[i].getKeyName();
			if (keyName != null)
			{
				int objectPlace = getObjectIndexUsers(keyName);
				if (objectPlace >=0)
					return moves[i].getDestinationRoom();
			} else
				return moves[i].getDestinationRoom();
		}
	}
	println("There is no way to move in that direction.");
	return -1;
}

the getObjectIndexUsers is just a function that will scan though the users objects and search for the key, if one found return that key index, else return -1 as below.

private int getObjectIndexUsers(String keyName)
{
	for (int i =0; i < userObjects.size(); i++)
	{
		if (userObjects.get(i).getName().equals(keyName))
			return i;
	}
	return -1;
}

if you download the zip file you will notice that the most of game loop is within the mainGame function, what happens in there is to

  • whilst not finished
  • display the room – short or long description – if required
  • set the room to be classed as visited (for the short/long description to be displayed)
  • check for the room is FORCED – and thus to not request the users input and move
  • If not FORCED request the users input for the movement
  • With the users request, process the request to either TAKE/DROP MOVE QUIT etc options
  • If none of the standard requested, see if it was a movement request e.g. WEST/NORTH/DOWN etc.
  • Then if the roomID = 0, the game is finished, either win/lose
  • repeat

The rest of the code is very similar in nature to the above code, looping through arrays and checking for conditions, it was a interesting game assignment I thought, I am going to do the CS106B next, which is a course that you write code in C++ (but only on a MAC/Windows PC). Shall do some posts of there assignments.

I used ArrayList to store the rooms etc into, because they allow for good access to the data in. I have included the full source code of the assignment and also the assignment PDF file within the ZIP file attached.

HTML Elements and altering them

With javascript you can alter the different elements within the HTML page, which is great when you are doing things like AJAX and you just want to alter one part of the page and not the whole page.

All you need to do is to get the element that you want to “talk” to and then alter that HTML tags element parts, so lets say that you have a HTML P tag

  <p id="hideme">

you can get that element within a variable for javascript to talk to it via

     var elem = document.getElementById("hideme");

and now you can alter all parts of that HTML P tag, e.g. the style, the inner HTML text (which is the text within the <p>innerHTML</p> tags) which gives you allot more things to do on the page that allows more of a desktop feel to the site over a static page that you need to send back and forth to the server.

Of course you cannot alter any internal parts of the HTML tag that do not exist e.g. for the HTML Input there is no innerHTML because it only has a value (the text within the input box) so if you try and do that some web browsers will error/stop/or just ignore.

Here is the full source code that will alter a HTML P style to red and also the innerHTML, and also a lower one will hide and then show the text within a HTML P tag whilst altering the link to show either “click here to hide me”/”click here to show me”, which once again helps users to now what to do.

<html>
<head>
<script language="javascript">
  function hideme()
  {
     var elem = document.getElementById("hideme");
     var elema= document.getElementById("hidemea");
 
     if (elem.style.display == "none")
     {
	elem.style.display = "block";
	elema.innerHTML = "click to hide me";
     }
     else
     {
	elem.style.display = "none";
	elema.innerHTML = "click to show me";
     }
  }
 
  function start()
  {
    var inputElem = document.getElementById("thewords");
    // you cannot alter the innerHTML of a input tag because it does not have any!!.
    // some browsers will error here because you cannot alter the innerHTML of a input tag
    //inputElem.innerHTML = "somewhere";
    // but you can alter the HTML A tag value because that is what input has
    inputElem.value = "genux was here!";
 
    var para = document.getElementById("paragraph");
    para.innerHTML = "I have changed the text within the paragraph!!!.. yeppy.. and also the colour to red ";
    // you also have access to the style(s) attached to that HTML tag, in this case the color 
    para.style.color = "red";
  }
</script>
</head>
<body>
  <input id="thewords"/>
  <a onclick="javascript:start()">Click me</a>
  <p id="paragraph">
  some text within the paragraph
  </p>
  <p id="hideme">
  hideme after the click below<br/>
  you can alter the style e.g. style.display = value<br/>
  and also alter the innerHTML - as I am altering the HTML A tag below text from hide/show me
  </p>
  <a id="hidemea" onclick="javascript:hideme()">click to hide me</a>
</body>
</html>

with using more javascript on pages, you need to have a way of keeping details of the updates on a page if you browse away from that page and come back which is where some problems could arise. So you just need to freshen up on your HTML tags and what they are capable of doing and have fun 🙂

Prototypes

Prototypes are a great thing with javascript, and they really come into there own with ajax and jQuery. A prototype basically it extends the present functional aspects. So lets say that you have a basic shape of animal (legs, head etc) and then you want to extend that basic shape with the option if the animal can fly then you can write a prototype to extend that, the prototype can either be a function or a variable so for example

// variable
animal.prototype.flyable = false;
// function
animal.prototype.canFly = function() {
     return this.flyable;
}

the “this.” means access the variables/functions within the main type (in this case it would be the animal as the main type).

in the example I am just altering some text within a HTML input tag, to start with I am creating a function (that I will extend later) and create a local (this.) variable that points to the element passed by using the document object, afterwards set the value equal to “hi from the parent”. I called it the parent because it is the main type,

  function nameing(elem)
  {
      this.theelem = document.getElementById(elem);
      this.theelem.value = "hi from the parent";
  }

then to extend this type, you start with the typename.prototype.extension_name, so the examples below will either return the value from the document element value that was setup in the “parent” / main type, and also the setText function will set the text to the document element.

  nameing.prototype.getText = function() 
  {
    return this.theelem.value;
  }

this is how I set up the object by calling new on the main type with passing in the element that I want to link to the object.

  // sets up the link with the 'thewords' id element within the html page
    var name = new nameing('thewords');

it is all very similar to other object languages, where you reference the object itself by using the “this.” syntax.

Below is the full html code that you can copy-paste into your favourite text editor and then open up in a web browser to see what you think.

<html>
<head>
<script language="javascript">
// a prototype 
  function nameing(elem)
  {
      this.theelem = document.getElementById(elem);
      this.theelem.value = "hi from the parent";
  }
 
  nameing.prototype.getText = function() 
  {
    return this.theelem.value;
  }
 
  nameing.prototype.setText = function(newText)
  {
    this.theelem.value = newText;
  }
 
 
  function start()
  {
  // sets up the link with the 'thewords' id element within the html page
    var name = new nameing('thewords');
    // since the call above will set the 'thewords' to equal "hi from the parent"
    alert(name.getText());
    // now we are setting the text
    name.setText("genux was here");
    // and again outputting the text again
    alert(name.getText());
  }
 
 
</script>
</head>
<body>
  <input id="thewords"/>
  <a onclick="javascript:start()">Click me</a>
</body>
</html>

FacePamphlet – Extensions

This is the extensions part, but after reading the extensions and one of them was converting from using the acm.graphics library to using the java.xswing library – (GCanvas – JPanel) then since the assignment 6 looks very interesting I am going to leave that one for another day because only had about 1 hour to do this extension.

The extensions

  • Search for some friends with key words e.g. part of the name
  • status line on 2-x lines
  • change the middle gcanvas to a jpanel – NOTE not going to do at present
  • friend finder – friends that you could link to from your friends already

Search for some friends with key words e.g. part of the name

To search for names that are already in the users list but you type in part of there name, then I have added in the search to the friends request button action and if no friend is found with that name then do a possible search of different names with the request as a search within each name. Of course do not want to add in the user that I am logged in as and any friends that the current user already has as friends, below is the java code that implements this

			Message = "Error : "+ ex.getMessage() + " Possible names : ";
			String[] possibleNames = repository.getUsers();
			for (int i =0; i < possibleNames.length; i++)
			{
				if (possibleNames[i].indexOf(requested) >= 0)
				{
					if (!possibleNames[i].equals(homeUserID))
					{
						// if not already my friend
						if (!repository.isMyFriend(possibleNames[i]))
							Message += possibleNames[i];
					}
				}
			}

status line on 2-x lines

How I implemented this was to create a array of GLabel which are an array length of the status line divided by the centre display texture width (CENTERTEXTWIDTH) e.g. so that if there is a status line of “genux is burping” then there would only be one array length but if the line was allot longer then there would be a X array length. Also since we do not want to break the word across two lines, I searched for the space after the centre display texture width and then cut the line there instead of in the middle of the word and then placed the rest of the sentence on the next line (that is where the endSpace integer value comes into play).

	if (statusCentre != null) 
		for (int i =0; i < statusCentre.length; i++)
		remove(statusCentre[i]);
	String theStatus = repository.getProperty(usersID + FILE_STATUS);
	if (theStatus != null)
	{
		theStatus = usersID + " is " + theStatus;
		int endSpace =0;
		int statusSize = (theStatus.length() / CENTERTEXTWIDTH)+1;
		statusCentre = new GLabel[statusSize];
		for (int i =0 ; i < statusSize; i++)
		{
			// endSpace = get the last space words and only output full words
			String outString = theStatus.substring((i * CENTERTEXTWIDTH) + endSpace);
			if (outString.length() > CENTERTEXTWIDTH)
			{
				// find the closet space
				int end = outString.indexOf(" ",CENTERTEXTWIDTH);
				outString = outString.substring(0,end); //CENTERTEXTWIDTH);
				endSpace += end-CENTERTEXTWIDTH;
			}
			statusCentre[i] = new GLabel(outString);
			statusCentre[i].setLocation(FPConstants.LEFT_MARGIN, FPConstants.STATUS_TOP+(i * statusCentre[i].getHeight()));
			statusCentre[i].setFont(FPConstants.STATUS_FONT);
			add(statusCentre[i]);
		}
	}

friend finder – friends that you could link to from your friends already

The friend finder, the way that I thought about this was everyone is a friend of the course CS106A, so using the repository getUsers it will return a array of users, so all I did was created a function that takes the current users friend array and also the friends of the course array and then just found the users that was in the course array list and not in current users list and returned that as a array (e.g. there could be more than one un-friended user), I did not implement any double click on the FPScrollableList because it will just be using the friend request method and as stated before I am looking at the assignment 6 and it is looking interesting :).

Below is how I used the throw away users of the intersection of both arrays (my friends and the course friends)

	// return a string array of names that are within the main group courseF and not in my friends group
	// could do a random return of different similar names with X as the maximum to return
	// but since a simple example then probably not needed ?
	private String[] returnNames(String[] myF, String[] courseF)
	{
		String[] returnS;
		int diff = courseF.length - myF.length;
		// equals 1 because the courseF would include the userID name as well
		if (diff == 1)
			returnS = new String[0];
		else
		{
			returnS = new String[diff-1];
			int insertI =0;
			// find the names that are not in myF and then insert into the returnS
			for (int i=0; i < courseF.length; i++)
			{
				Boolean inI = true;
				for (int j =0; j < myF.length;j++)
				{
					if (courseF[i].equals(myF[j]))
					{
						inI = false;
						break;
					}
				}
				if (inI && (!courseF[i].equals(homeUserID))) 
					returnS[insertI++] = courseF[i]; 
			}
		}
		return returnS;
	}

I have included the source code in the zip file attached with also the assignment and running interface.

FacePamphlet

This is FacePamphlet, that is a very simple incarnation of facebook (social network of people).

There are some milestones that allow you to head towards, like a stepping stone to figure out the path to take to get the assignment done. Here are the milestones and also some code that will be linked into the milestones

Milestone 1: Create the west side panel

To create the panels with the data, then need to pull some data from the files that are present on the filesystem. Things like the name of the user is stored in a file and also friends, requests of friends etc, so to create for example below the list of friends that I would have, the repository class is already created and that “talks” to the filesystem to get the data in question (either locally in my case, and also in the testing phrasing of the assignment) but if you changed it to a network setup then it would get the data from a remote server. I have created a few private variables that will store the different parts of the graphics user interface so that I can “talk” to them with just referencing there name, which makes it allot more easier to update there details in the future.

Below the first code will get the full user name from the repository and add it to the WEST panel and then it will retrieve the list of names of friends into a String array and then cycle through to add them to the friends list on the WEST panel again.

		usersName = new JButton(repository.getProperty(userID + FILE_NAME));
		add(usersName, WEST);
 
		friendsList = new FPScrollableList();
		// add to the friends list
		myFriends = repository.getMyFriends();
		for (int i=0; i < myFriends.length; i++)
			friendsList.add(myFriends[i]);
		add(new JLabel("Friends:"), WEST);
		add(friendsList,WEST);

Milestone 2 – interactors

Interactors with the different parts of the GUI is nice and a good way is using the above code, e.g. using private variables that can be able to talk to when we get clicks from the GUI on buttons and want to find out which item was clicked, also since we are using some stanford custom code like FPScrollableList, FPScollableTextArea which you have to add the listens and also tell the called function what command (in string text) has been called.

		friendsList.addActionListener(this);
		friendsList.setActionCommand(VISIT);

the VISIT is a static final string so that encase any thing is altered just alter it once (it equals = “VISITS”)

Milestone 3: Create the center panel

The centre panel creates the basic information of the user, but also displays a graphical image and also error reporting with status updates as well. With the graphics object the graphics is saved within a string format, which using the FPTools has a graphics to string converter, but to rescale the image I am seeing if the height/width is beyond centre size then alter the image by the size that is available divided by the size of the graphical object.

		if (picCentre.getHeight() > FPConstants.MAX_IMAGE_HEIGHT)
		{
			double newHeight = FPConstants.MAX_IMAGE_HEIGHT / picCentre.getHeight();
			picCentre.scale(newHeight);
		}
		if (picCentre.getWidth() > CENTERWIDTH)
		{
			double newWidth = CENTERWIDTH/ picCentre.getWidth();
			picCentre.scale(newWidth);
		}
		picCentre.setLocation(FPConstants.LEFT_MARGIN, FPConstants.IMAGE_TOP);
		add(picCentre);

updating the error messages I am using a function that takes the message as string and then just output the message, I am removing object and then just re-creating it and placing on the area specified in the FPConstants class. (you could test to see if there is any message length and thus create the infoMessage object)

	private void updateErrorMessage(String message)
	{
		if (infoMessage !=null) remove(infoMessage);
		infoMessage = new GLabel(message);
		infoMessage.setFont(FPConstants.INFO_MESSAGE_FONT);
		infoMessage.setColor(FPConstants.INFO_MESSAGE_COLOR);
		infoMessage.setLocation(FPConstants.LEFT_MARGIN, FPConstants.APPLICATION_HEIGHT - FPConstants.BOTTOM_MARGIN);
		add(infoMessage);
	}

Milestone 4: Implement the interactors

Here is the interactor for when you click on requesting a friend, or press enter on the friends name text box (getActionCommand), to start with I am getting the text of the friends and seeing if there is any friends with the same name already in my friends list, else if not then send a request. I have include the error reporting and also the message string is the error string that is being sent back to inform the user what is being happening.

	if ((event.getSource() == friendRequestButton) || event.getActionCommand().equals(FRIENDREQUEST))
		{
			String requested = friendRequest.getText();
			if (requested.length() > 0)
			{
				try 
				{
					if (repository.isMyFriend(requested))
						Message = requested + " is already your friend";
					else
					{
						repository.requestFriend(requested);
						Message = "Requested friend : " + requested;
					}
					repository.setProperty(homeUserID + FILE_LOG , "Requested friend " + requested);
				}
				catch (NullPointerException ex)
				{
					Message = "Not sure of name ? "+ requested + " : error : "+ ex.getMessage();
				}
				catch (ErrorException ex)
				{
					Message = "Not sure of name ? "+ requested + " : error : "+ ex.getMessage();
				}
			}
			friendRequest.setText("");
		}

Milestone 5: Shift over to the networked repository

Since I am running on the local PC, then I cannot connect to the Stanford server to test with, so will just guess that it is working :).

I also did implement a basic logging of the last actioned, in the users repository directory, and also if a user updates there pending friends request list and another user is viewing there FacePamphlet account and the friends list is updated then it will report the new friend in the status messages.

Going to implement in the extensions

  • Search for some friends with key words e.g. part of the name
  • status line on 2-x lines
  • change the middle gcanvas to a jpanel
  • friend finder – friends that you could link to from your friends already

Shall post extension next.

C# – Console Parameters test

As from my previous post on c++ console parameters, I thought that I would do one with c# (c sharp) as well, just to show the difference in the languages as well.

Compared to c++ where you cannot use the “==” (is equal to) operation because in c++ that is comparing two different memory locations and not the value within the left/right hand variables. Well in c# you can, there is a Equals method as well that you can use, but either or works fine, so in the example code below here is the main part, where I am comparing against a console parameter equalling -h (normally the help)

if (args[i].Equals("-h")) Console.WriteLine("-h option selected(equals)");
if (args[i]=="-h") Console.WriteLine("-h option selected (==)");

both of them are fine to use as you can see from the output at the bottom of the post, both will print out that “-h option selected”, best to use the Equals though.

Here is the full source code

using System;
 
namespace consoletest
{
	class MainClass
	{
		public static void Main (string[] args)
		{
			for (int i = 0; i < args.Length; i++)
			{
				Console.WriteLine("args " + i + " : " + args[i]);								
				if (args[i].Equals("-h")) Console.WriteLine("-h option selected(equals)");
				if (args[i]=="-h") Console.WriteLine("-h option selected (==)");
			}
		}
	}
}

and here is the output using mono as the .Net runtime environment, as you can see both -h has been outputed

mono consoletest.exe -h here
args 0 : -h
-h option selected(equals)
-h option selected (==)
args 1 : here

Console parameters

Someone asked me the other day when you are checking the console parameters for any passing in options how come something like

if (argv[i] == "-t")

does not work, well it does make sense when you look at it, but because the “-t” is actually a char[] (a string) then this would occupy a place in memory and thus you are checking against memory locations which unless you are very very very lucky, this would never come out correct, you need to use the string compare (strcmp) function as below

#include <iostream>
#include <string.h>
 
using namespace std;
 
int main(int argc, char** argv)
{
 for (int i =0 ; i < argc; i++)
 {
// output argument that was passed in.
   cout << argv[i] << endl;
// compare with "-t" option
   if (strcmp(argv[i],"-t")==0) cout << "the -t option" << endl;
 }
 return 0;
}

and the output would be something like

./consolet -t 40
./consolet
-t
the -t option
40