Goals for this homework

  • Write a class from the start
  • Use C# Collections

You are expected to complete this assignment individually. If you need help, you are invited to come to office hours and/or ask questions on piazza. Clarification questions about the assignments may be asked publicly. Once you have specific bugs related to your code, make the posts private.

Another note about Piazza. Piazza is your community resource - please use those as discussions amongst yourselves. We are not monitoring it all day, rather we each have check-in times once a day. Therefore, you need to start early enough to wait for feedback and/or build a vibrant, supportive community that helps each other while we are completing other necessary tasks (research, developing assignments, preparing for lecture, performing advising tasks, etc.).

A note about submission: We have changed how it expects the files in order to be compatible with github. We're still figuring out the exact file structure it wants. Put your work in the following directory: CS209Homework2. Zip the directory with the files in it.

In this homework, you'll add to the sprite we created.

You should submit several files for this assignment ( Sprite.cs, TestSprite.cs, TestPoint.cs, Point.cs, testsprite.txt, testpoint.txt Makefile). You will submit your work in a zip file to Gradescope.

Error Handling

Error handling capabilities vary by language, and what you want to do in an error varies by the situation. When an error occurs in a function, the question becomes, what should you do, and how do you notify the caller that an error occurred?

In C#, there is a construct for this. We'll use this when calling functions that use it but, right now, we won't implement them ourselves. This is an exercise because if you write a function, and it's used in a variety of different circumstances, it is bad programming practice to determine within the function what will be done. For example, one program might want to exit, whereas another might want to notify the user that there was bad input and to try again.

In this course, we will print the error message in a special way (see below). If there is an opportunity, we will designate a specific return value for an error condition. If there is no available return value, then we will exit from within the function.

  Console.Writeline("error: too many widgets for the number of grommets");
  Console.Writeline("error: need ten boondoggles, but only have" + num_bds);

Sometimes, these lines will be followed by exit(1); This immediately exits the program and returns a code. If you were writing a large program, you might assign a different code to each type of error that would result in an exit.

Makefile

Because you are adding a second set of files to your directory, you need to adjust your Makefile. You are going to be asked to make a new class, Point, which Sprite uses. Therefore, the compile line will look like this:
TestSprite.exe: TestSprite.cs Point.cs Sprite.cs
	mcs TestSprite.cs Sprite.cs Point.cs
To compile, type:
make TestSprite.exe

Set Up

The first thing to do is to create a skeleton project that will minimally execute. In the future, you will be expected to create it for yourself. A skeleton has the following in it:
  • Step 1: In one file, put in the class and method declarations. In the body, print the fact that it is not yet implemented and return with the right type. For example:
    public float surface_area_cylinder(float height, float radius)
    {
    	Console.WriteLine("surface_area_cylinder not yet implemented");
    	return 0.0;
    }
    
  • Step 2: Create the test file with the Main method. For each method, put in a single call. For example:
    public static void Main(string[] args)
    {
    	float fval;
    	LabXMethods lxm = new LabXMethods();
    
    	fval = lxm.surface_area_cylinder(3.5, 7.9);
    }
    

First get this compiling and running. It won't do anything useful, but this will mean that your code will compile and execute with our infrastructure. This must work in order to get any points in this course. Do this first, not last.

Reading from a file

Because the sprite state is more complex, you'll need to store the state in a file (well, the inventory items, anyway). You will need to place this code in TestSprite.cs to read in the initial state of a sprite. Here is how you read from a file.

Here is code to read the lines of a file into an array of strings.

        // Read each line of the file into a string array. Each element
        // of the array is one line of the file.
        string[] lines = System.IO.File.ReadAllLines(@"C:\Users\Public\TestFolder\WriteLines2.txt");

        // Display the file contents by using a foreach loop.
	// this is just for illustrative and debugging purposes
        System.Console.WriteLine("Contents of WriteLines2.txt = ");
        foreach (string line in lines)
        {
            // Use a tab to indent each line of the file.
            Console.WriteLine("\t" + line);
        }
Here is code to parse a string into different pieces, split by spaces.

	string phrase = "The quick brown fox jumps over the lazy dog.";
	string[] words = phrase.Split(' ');

	foreach (var word in words)
	{
	    System.Console.WriteLine($"<{word}>");
	}
Hopefully, you can take those examples and figure out how to divide the line and feed that data into new sprites.

Point Class

The first thing you will do is create a Point class to hold the x, y, z coordinate of the object. This class will have the following methods. Point has three private variables: XCoor, YCoor, and ZCoor.
  • public Point()
    Constructor. Set to (0, 0, 0)
    Error conditions: None
  • public Point(int x, int y, int z)
    Constructor. Set to (x, y, z)
    Error conditions: None
  • public void SetLocation(int x, int y, int z)
    Set to (x, y, z)
    Error conditions: None
  • public void SetX(int x)
    Standard setter. Set x coordinate to x
    Error conditions: None
  • public void SetY(int y)
    Standard setter. Set y coordinate to y
    Error conditions: None
  • public void SetZ(int z)
    Standard setter. Set z coordinate to z
    Error conditions: None
  • public int GetX()
    Standard getter. Return x coordinate
    Error conditions: None
  • public int GetY()
    Standard getter. Return y coordinate
    Error conditions: None
  • public int GetZ()
    Standard getter. Return z coordinate
    Error conditions: None
  • public float CalculateDistance(Point p)
    Calculate distance between this Point and input argument p
    Error conditions: None
  • public override bool Equals(Object obj)
    Define what it means for two Points to be equal. Look at the Sprite Equals for the pattern of how to code it. Two points are equal if all three member variables are equal.
    Error conditions: return false if anything other than equal. No error message.
  • public override int GetHashCode()
    Again, use the Sprite code as a guide. Perform an xor of the three variables. Error conditions: none
  • Also, update your Sprite code to use Point for the location instead of the separate XCoor, YCoor, and ZCoor.

Sprite Class

After changing your Sprite to use Point instead of separate variables for XCoor, YCoor, and ZCoor, you will add inventory functionality to your Sprite class. There will be a full inventory (everything that is in their "backpack") The inventory is stored in name, number pairs. The name is the name of the item and the number is the number of that item they are holding. For example, if they are holding 3 small potions, inventory shows ("SmallPotion",3). as well as 6 quick slots (everything they can use with a single keystroke). The full inventory will be a dictionary, whereas the 6 quick slots will be an array. You need to implement the following functions.

  • Sprite()
    Add initialization of the inventory and quick slots to empty for all constructors
  • Equals()
    update the code to include checking the inventory and quick slots
  • void AddItem(string item)
    add a single item to the inventory. The string contains only the name of the item. If the item is already there, increment the number. If the item is not there, add it with number 1. Error condition: None
  • bool HasItem(string item)
    return true if the item is in the inventory, false if not. Error condition: None
  • void PutItemInQuickSlot(string item, uint slot)
    If slot < 6, attempt to put in quick slot.
    • If quick slot already has something, replace it with new item. Item is still in inventory. You are not removing something from the inventory, merely indicating which items can be utilized in a single keystroke by the user of the game. Therefore, the quantity of item is still the same as in the inventory.
    • If that item is already in a different quickslot, swap the items in the two slots (that is, if it's in slot 2, and the method is called with slot 4, swap the contents of swap 2 and 4).
    • If the quickslot number is 6 or greater, do nothing.
  • string GetItemInQuickSlot(uint slot)
    If slot < 6, and there is an item in that slot, return the item
    If there is no item in that slot, or the number is too large, then return a null pointer. Make sure to check for the null pointer in your test function before calling any method on the returned object.
  • void PrintInventory()
    Print the contents of the inventory. It must print out like this:
    Console.WriteLine(""+i+": ("+item+", "+count+")");
    That is, it must have a counter that increments each item (i), then print the item name, then print the number of that item in the inventory.
  • void PrintQuickSlots()
    Print the contents of the quick slots. It must print out like this:
    Console.WriteLine(""+i+": ("+item+", "+count+")");
    That is, it must have a counter that increments each item (i), then print the item name, then print the number of that item in the quick slots. The counts are based on the inventory - you need not store the quantity in the array.

    If a specific slot is empty, then print #: empty

Testing



For testing Point, the general test line will look like this:
TestPoint.exe start_state expected_end_state test# inputs expected_ret_val
We will have the following tests for Point functions:
  • SetLocation: TestPoint.exe x y z x y z 0 newx newy newz
  • SetX: TestPoint.exe x y z x y z 1 newx
  • SetY: TestPoint.exe x y z x y z 2 newy
  • SetZ: TestPoint.exe x y z x y z 3 newz
  • GetX: TestPoint.exe x y z x y z 4 x
  • GetY: TestPoint.exe x y z x y z 5 y
  • GetZ: TestPoint.exe x y z x y z 6 z
  • CalculateDistance: TestPoint.exe x y z x y z 7 otherx othery otherz distance
  • Equals: TestPoint.exe x y z x y z 8 otherx othery otherz result
  • You are not required to test GetHashCode
For testing, the general test line will look like this:
TestSprite.exe start_state expected_end_state test# inputs expected_ret_val
The start state is given in the following order for sprites:
x, y, z, horiz, vert, health, shield, items.txt
where items.txt lists the items in the inventory and, if applicable, quick slots.
  • AddItem: TestSprite.exe x y z h v h s items.txt x y z h v h s items2.txt 0 item
  • HasItem: TestSprite.exe x y z h v h s items.txt x y z h v h s items.txt 1 item ret_val
  • PutItemInQuickSlot: TestSprite.exe x y z h v h s items.txt x y z h v h s items2.txt 2 item quickslot
  • GetItemInQuickSlot: TestSprite.exe x y z h v h s items.txt x y z h v h s items.txt 3 quickslot item
  • PrintInventory: TestSprite.exe x y z h v h s items.txt x y z h v h s items.txt 4 expected_output.txt
  • PrintQuickSlots: TestSprite.exe x y z h v h s items.txt x y z h v h s items.txt 5 expected_output.txt

Submit

Note: Starting from this homework forward, you will need to put your files in a subdirectory named CS209Homework2. This change was made to accommodate students who want to keep their files in github.