Reflection – Calling functions

With c++ you can call functions as a reference instead of the actual name, as long as the reference is linked to the function itself (I did a post about it function pointers and also within csharp delegates)

To start with, we need to sort out what function we want to use to call, I am going to pick a function that returns a value and also passes parameters (kinder covers all aspects really), so this is going to be the function

public String addsTogether(String st1, String st2)

So to start off , lets build up the parameters to pass to the function, we have two string parameters, so we need to have a array of 2 strings.

String[] passingParameters = { new String("genux"), new String("was here")};

Now we need to setup a link to the function that we want to call, we setup a class instance with using the forName (which is the function name). Also because the function takes 2 String parameters we need to setup blank classes that are both Strings in types.

Class callingClass = Class.forName("CallMethodClass");
 
Class[] callingParameters = new Class[2];
callingParameters[0] = String.class;
callingParameters[1] = String.class;

this is the main part, this is the link, we create a Method (from the java.lang.reflect package) that links to the class function/method “addsTogether” (the function at the start of this post) and also the parameters type and length (2 strings).

Method callingMethod = callingClass.getMethod("addsTogether", callingParameters);

that is about it, all we need to do is to call the function now and that is it, so we use the Method link above variables invoke method, this takes the class that the function is wrapped within and also the parameters that we want to send to the function (method and function are kinder interchangeable) and that is about it. Since the returning value is a String (and we know this) we will need to case the returning type into that by using (String) otherwise it would be a type of Object (the base object type in java)

String result = (String)callingMethod.invoke(new CallMethodClass(), passingParameters);

Here is the source code in full (Save as CallMethodClass.java if you want to compile it up)

import java.lang.reflect.Method;
 
public class CallMethodClass {
 
	// adds together the two strings with inserting a space between them
	public String addsTogether(String st1, String st2)
	{
		return st1.concat(new String(" ").concat(st2));
	}
 
	public static void main(String[] args) {
		try
		{
			String[] passingParameters = { new String("genux"), new String("was here")};
			// setup the link to the class to call
			Class callingClass = Class.forName("CallMethodClass");
			// passing parameters to the callingClass, the method has two String parameters
			Class[] callingParameters = new Class[2];
			callingParameters[0] = String.class;
			callingParameters[1] = String.class;
			// and now setup the method to call
			Method callingMethod = callingClass.getMethod("addsTogether", callingParameters);
 
			// call the method and get the return (convert to a String)
			// pass in the parameters here, when calling (invoking) the method
			String returnValue = (String)callingMethod.invoke(new CallMethodClass(), passingParameters);
 
			// and now output the result
			System.out.println("OUTPUT : "+returnValue);
		} catch (Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
}

here is the output of the program

OUTPUT : genux was here

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.

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.

Dice Game – Part 2

Dice Game – Part 2.

And here are the Extensions

  • Add a high score feature. Save the top ten highest scores and names to a file and make it persistent between runs of the program. Read the file when you start and print out the hall of fame. If a player gets a score that preempts one of the early high scores, congratulate them and update the file before you quit so it is recorded for next time.
  • Incorporate the bonus scores for multiple Yahtzees in a game. As long as you have not entered a 0 in the Yahtzee box, the rules of the game give you a bonus chip worth 100 points for each additional Yahtzee you roll during the same game.
  • Beef up your Yahtzee to the variant called “Triple Yahtzee.” In this variant, each player manages three simultaneous scorecard columns, as if they were playing for three players at once. The player can assign a roll to any one of their three columns. All entries are scored normally with respect to categories and validity, but the values in the second column are doubled, and the third column values are tripled. The player

Yahtzee

Yahtzee

Category 9 – Full house

Once again, I am going to bubble sort (bubble sort at the bottom of this post) the dice values, so that I can check to see if there are 3 of the same values and 2 of other values that are the same. This is very similar to counting how many values are the same with three/four of a kind, but this time need to make sure that there are only 3 / 2 split of different values, and for the scoring value we only need to return true/false since the value if it is a full house it is 25 points or 0 for nothing.

So, the way that I have done it, is with checking to see if values are the same within the array (whilst scanning from the start to end) and if they are increment the count (counting of similar values), if the values changes then check to see if the count is equal to 3 or 2 (which is the full house requirements) and if so set a boolean value to true and keep on checking. To get to return true, need to see if both the 3 and 2 boolean values are true then we know that we have a full house.

	// need to check for 3 of the same value and then 2 of the same value
	private Boolean checkFullHouse(int[] dice)
	{
		int count =1;
		Boolean found3 = false, found2 = false;
		for (int i=1; i < YahtzeeConstants.N_DICE;i++)
		{
			if (dice[i] == dice[i-1]) 
				count++;
			else
			{
				if (count == 3)
					found3 = true;
				else if (count == 2)
					found2 = true;
				count=1;
			}
		}
		if (count == 3)
			found3 = true;
		else if (count == 2)
			found2 = true;
		if (found3 && found2) return true;
		return false;
	}

Categories 10,11 – Small/Large straight

The last two are very similar and because once again I am using the bubble sort to organise the array into a order then we just need to check the array by going through it from start to finish checking to make sure that the value before is 1 minus the present value in the array ( e.g. array being 3,4,5, present value is the 4 and the previous value is 3 which is correct), then add up these correct placements within the array and if the consecutive values are either 4 (small straight) or 5 (large straight) return true or false accordingly.

	// consecutiveValues = how many in a straight line
	private Boolean checkStraight(int[] dice, int consecutiveValues)
	{
		int inLine =1;
		for (int i =1; i < YahtzeeConstants.N_DICE; i++)
		{
			if ((dice[i-1]+1) == dice[i]) inLine++;
		}
		if (inLine >= consecutiveValues) return true;
		return false;
	}

The main thing within the program is to make sure that you are always accounting for the difference with the categories numbers (which start from 1) and the scoring values (which start from 0) or the dice numbers (which start from 0 again), of course could make the size of those arrays 1 bigger.

To create the score array and also so we know what is a score value of 0 or not, then the score array is setup with all values of -1.

	/* setup the scores to a value of -1, default value */
	private void setupScores(int[][] scoresSetup, int playersNum, int totalValues)
	{
		for (int i=0; i < playersNum; i++)
			for (int j=0; j < totalValues;j++)
				scoresSetup[i][j] = -1;
	}

So that when you are selecting a category to place the score of your dice and you try to select a category already selected, then just need to check the score for -1 and if so we know it is a category not already used.

	private Boolean updateScore(int[] scoresUpdate, int category, int score)
	{
		// default is -1, since cannot get this score value
		if (scoresUpdate[category] == -1)
		{
			scoresUpdate[category] = score;
			return false;
		}
		else
		{
			display.printMessage("Category already selected, please select another");
			return true;
		}
	}

Also within the source code, I have included a cheat mode so that you can insert the values of the dice in runtime (when you are asked about the number of players type in -99 and the cheat mode is activated and there is only 1 player setup).

The next post is the extensions of this assignment.

Yahtzee

Yahtzee, over the next two posts going to explain about the thoughts behind working out the categories within the game, e.g. yahtzee, straight etc. And then in the 3rd post I am going to do the extensions of the assignment.

So to start with here are the different types of categories that the 5 dice can fall into with also there score associated value. ( the number at the start is the category that the dice would fall into)

  • 1. Ones. Any dice configuration is valid for this category. The score is equal to the sum of all of the 1