6.1 Interval indexer
The Interval type represents an oriented interval [from - to] of integers. We use the Interval example to illustrate the overloading of operators. If you have not already done so, read about the idea behind the struct Interval in the course teaching material. In the client of struct Interval we use an indexer to access elements of the interval. For some interval i, the expression i[0] should access the from-value of i, and i[i.Length-1] should access the to-value of i. Where, precisely, is the indexer used in the given client class? Add the indexer to the struct Interval (getter only) which accesses element number j (0 <= j <= i.Length) of an interval i. Hint: Be careful to take the orientation of the interval into account. Does it make sense to program a setter of this indexer? |
Solution
Here follows the class Interval with an indexer (getter only).
I do not find that a setter would make sense. A setter would compromise the non-mutability of Interval. |
6.2 An interval overlap operation
In this exercise we continue our work on struct Interval, which we have used to illustrate overloaded operators in C#. Add an Interal operation that finds the overlap between two intervals. Your starting point should be the struct Interval. In the version of struct Interval, provided as starting point for this exercise, intervals may be empty. Please analyze the possible overlappings between two intervals. There are several cases that need consideration. The fact that Interval is oriented may turn out to be a complicating factor in the solution. Feel free to ignore the orientation of intervals in your solution to this exercise. Which kind of operation will you chose for the overlapping operation in C# (method, property, indexer, operator)? Before you program the operation in C# you should design the signature of the operation. Program the operation in C#, and test your solution in an Interval client program. You may chose to revise the Interval client program from the teaching material. |
Solution
I clearly recommend to implement the overlapping operation as a method in C#. As a supplementary notation, we may provide operator notation for the overlap method, for instance I & J. In the solution shown below, we have overloaded the & operator. Given two intervals I and J the following cases need considerations:
For practical programming purposes case 1 can be split into
Similarly, case 4 can be split into
Here is my version of type Interval with the extensions for interval overlapping (for oriented intervals).
The new property Orientation determines the orientatin of an interval (0, 1, or -1). The method OverlapWith implements the solution to the exercise. Here is a simple client of struct Interval:
|
6.3 Finding and sorting elements in an array
In this exercise we will work with searching and sorting in arrays. To be concrete, we work on an array of type Point, where Point is the type we have been programming in earlier exercises. Via this exercise you are supposed to learn how to pass a delegate to a method such as Find and Sort. The purpose of passing a delegate to Find is to specify which point we are looking for. Make an array of Point objects. You can, for instance, use this version of class Point. You can also use a version that you wrote as solution to one of the previous exercises. Use the static method System.Array.Find to locate the first point in the array that satisfies the condition: The sum of the x and y coordinates is (very close to) zero The solution involves the programming of an appropriate delegate in C#. The delegate must be a Point predicate: a method that takes a Point as parameter and returns a boolean value. Next, in this exercise, sort the list of points by use of one of the static Sort methods in System.Array. Take a look at the Sort methods in System.Array. There is an overwhelming amount of these! We will use the one that takes a Comparison delegate, Comparison<T>, as the second parameter. Please find this method in your documentation browser. Why do we need to pass a Comparison predicate to the Sort method? Comparison<Point> is a delegate that compares two points, say p1 and p2. Pass an actual delegate parameter to Sort in which p1 <= p2 if and only if p1.X + p1.Y <= p2.X + p2.Y Please notice that a comparsion between p1 and p2 must return an integer. A negative integer means that p1 is less than p2. Zero means that p1 is equal to p2. A positive integer means that p1 is greater than p2. Test run you program. Is your Point array sorted in the way you excepts? |
Solution
using System; class FindInArray{ public static bool NullPoint(Point p){ return Math.Abs(p.X + p.Y) <= 0.0001; } public static void Main(){ /* An array of points: */ Point[] points = { new Point(1,2), new Point(-1,2), new Point(-2,2), new Point(-4,5), new Point(-5,5), new Point(5,5), new Point(-5,-5) }; /* Solution with anonymous delegate: */ Point fp = Array.Find(points, delegate(Point p){ return Math.Abs(p.X + p.Y) <= 0.0001;} ); if (fp != null) Console.WriteLine("We found point: {0}", fp); else Console.WriteLine("We did not find a point"); /* Solution with a named static method: */ Point fp1 = Array.Find(points, NullPoint); if (fp1 != null) Console.WriteLine("We found point: {0}", fp1); else Console.WriteLine("We did not find a point"); /* Finding all desired points: */ Point[] pts = Array.FindAll(points, NullPoint); Console.WriteLine("We found these points:"); foreach(Point p in pts) Console.WriteLine(p); /* Sorting the points as desired: */ Array.Sort(points, delegate(Point p1, Point p2){ if (p1.X + p1.Y < p2.X + p2.Y) return -1; else if (p1.X + p1.Y == p2.X + p2.Y) return 0; else return 1; }); Console.WriteLine("Sorted points:"); foreach(Point p in points) Console.WriteLine(p); } } |
6.4 How local are local variables and formal parameters?
When we run the following program
we get this output
Explain! |
Solution
Here is the program (again):
and its output:
There are obviously two variables called factor in this program: (1) The static (global) variable factor, and the formal parameter factor of MakeMultiplier. According to normal wisdom, the formal parameter factor is a local variable which only exists during the call of MakeMultiplier. In addition, it is common wisdom that free names of functions are bound in the context of the function definitions, not in the context of funcion calls. Thus, in the the anonymous function delegate(double input){return input * factor;} the free name factor is bound to the formal parameter of MakeMultiplier, and never to more global variables of the same name. (A free name in a function is a name which is used in the function, but not defined in the function). These observations contradict each other. In C#, local variables of a function may survive the activation of the function. Thus, the the formal parameter factor (bound to 3.0) is available in the WriteLine statements of Main. In C#, this is often called captured outer variables. The function delegate(double input){return input * factor;} gives rise to a closure, which holds on to its free names (here the variable factor). |
6.5 Additional Die events
In this exercise we add yet another method to the existing event i class Die, and we add another event to Die. In the Die event example, we have a public event called twoSixesInARow which is triggered if a die shows two sixes in a row. In the sample client program we add an anonymous method to this event which reports the string parameter of the event on standard output. Add yet another method to the twoSixesInARow event which counts the number of times 'two sixes in a row' appear. For this purpose we need - quite naturally - an integer variable for counting. Where should this variable be located relative to the 'counting method': Will you place the variable inside the new method, inside the Die class, or inside the client class of the Die? Add a similar event called fullHouse, of the same type Notifier, which is triggered if the Die tosses a full house. A full house means (inspired from the rules of Yahtzee) two tosses of one kind and three tosses of another kind - in a row. For instance, the toss sequence 5 6 5 6 5 leads to a full house. Similarly, the 1 4 4 4 1 leads to a full house. The toss sequence 5 1 6 6 6 6 5 does not contain a full house sequence, and the toss sequence 6 6 6 6 6 is not a full house. Be sure to test-drive the program and watch for triggering of both events. |
Solution
The method DoWeHaveFullHouse is the most challenging. It searches the last five entries of the history list. It needs to find out which eyes make up the full house, and how many occurrences of these eyes have been encountered. Here comes my version of the Die class:
It should be noticed that 'instances of full house' may overlap each other. Here follows the sample Die client class, where we add methods to the public events in class Die.
The variable doubleSixes is a local variable in Main in diceApp. This variable is in the scope of the anonymous function which increases the variable doubleSixes. |
Generated: Monday February 7, 2011, 12:16:15