Exercises in this lecture   Go to the notes, in which this exercise belongs -- Keyboard shortcut: 'u'   Alphabetic index   Course home   

Exercise solution:
Additional Die events


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:

using System;
using System.Collections.Generic;

public class Die {
  public delegate void Notifier(string message);  // A delegate type

  private int numberOfEyes;
  private Random randomNumberSupplier; 
  private int maxNumberOfEyes;
  private List<int> history;
  public event Notifier twoSixesInARow;       
  public event Notifier fullHouse;       

  public int NumberOfEyes{
     get {return numberOfEyes;}
  }

  public Die (): this(6){}

  public Die (int maxNumberOfEyes){
    randomNumberSupplier = new Random(unchecked((int)DateTime.Now.Ticks));
    this.maxNumberOfEyes = maxNumberOfEyes;
    numberOfEyes = randomNumberSupplier.Next(1, maxNumberOfEyes + 1);
    history = new List<int>();
    history.Add(numberOfEyes);
  }
    
  public void Toss (){
    numberOfEyes = randomNumberSupplier.Next(1,maxNumberOfEyes + 1);
    history.Add(numberOfEyes);
    if (DoWeHaveTwoSixesInARow(history))
       twoSixesInARow("Two sixes in a row");
    if (DoWeHaveFullHouse(history))
       fullHouse("You have a Full House");
  }

  private bool DoWeHaveTwoSixesInARow(List<int> history){
    int histLength = history.Count;
    return histLength >= 2 && 
           history[histLength-1] == 6 && 
           history[histLength-2] == 6;
  }



  private bool DoWeHaveFullHouse(List<int> history){
    int d1 = 0, d2 = 0,   // number of eyes of the two dies involved in the full house. 0 means uninitialized.
        n1 = 0, n2 = 0,   // how many do we have of each.
        histLength = history.Count;
    if (histLength >= 5){
      for (int i = -5; i <= -1; i++){    // consult history of last 5 tosses
        if      (d1 == 0) {d1 = history[histLength + i]; n1 = 1;}  // the first toss determines d1
        else if (d2 == 0 && d1 != history[histLength + i])
                          {d2 = history[histLength + i]; n2 = 1;}  // a later toss, typically the second, determines d2
        else if (d1 == history[histLength + i]) n1++;
        else if (d2 == history[histLength + i]) n2++;
        else return false;                                         // if we ever come here we have encountered non-full-house toss
      }
      return (n1 == 2 && n2 == 3) || (n1 == 3 && n2 == 2);
   } else return false;
  }
       
  public override String ToString(){
    return String.Format("Die[{0}]: {1}", maxNumberOfEyes, NumberOfEyes);
  }
}

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.

using System;

class diceApp {

  public static void Main(){

    Die d1 = new Die();

    d1.twoSixesInARow += 
     delegate (string mes){
       Console.WriteLine(mes);
     };

    d1.fullHouse += 
     delegate (string mes){
       Console.WriteLine(mes);
     };

    int doubleSixes = 0;

    d1.twoSixesInARow += 
     delegate (string mes){   // counts how many times we get
       doubleSixes++;         // two sixes in a row
     };

    for(int i = 1; i < 1000; i++){
      d1.Toss();
      Console.WriteLine("{0}: {1}", i, d1.NumberOfEyes);  
    }

    Console.WriteLine("Number of two sixes in a row: {0}.", doubleSixes);

 }
}

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.