morris295
morris295

Reputation: 547

Counting the frequency of dice rolls

I've written an event handler for a C# windows form project that simulates 100 rolls of two dice and returns the sum of the two dice for each roll. The code does three things for each of these sums, it places it in a RichTextBox called "rollDisplay", it writes the sum to a text file, and it adds the sum to a list of integers called "rolls". All of that is working fine, but now I need to count the frequency of each of the sums, and show these frequencies in a ListBox. As the code below indicates, I'm using eleven different counter variables, and eleven distinct strings to add to the ListBox. What I have below works, but it's really quite ugly, and seems to me like a really inefficient way of doing this.

My question is. Can anyone suggest a cleaner way of doing this? The assignment requires that I have eleven separate counters to identify the frequency of the dice rolls, so I can't use Linq as I saw suggested by several other questions, but I'm really quite uncertain that this is the best way to accomplish what I need.

private void Roll_Click(object sender, EventArgs e)
    {
        int roll = 0, hitTwo = 0, hitThree = 0, hitFour = 0, hitFive = 0, hitSix = 0, hitSeven = 0, hitEight = 0,
            hitNine = 0, hitTen = 0, hitEleven = 0, hitTwelve = 0;
        String freq1, freq2, freq3, freq4, freq5, freq6, freq7, freq8, freq9, freq10, freq11;
        StreamWriter file = new StreamWriter("dicerolls.txt", true);
        List<int> rolls = new List<int>();

        for (int i = 0; i < 100; i++)
        {
            dieUno.setSide(dieUno.roll());
            dieDuo.setSide(dieDuo.roll());

            int diceTotal = dieUno.getSide() + dieDuo.getSide();
            rolls.Add(diceTotal);
            rollDisplay.AppendText(diceTotal.ToString() + "\u2028");

            try
            {
                file.WriteLine(diceTotal.ToString());
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        file.Close();  

        for (int i = 0; i < rolls.Count; i++)
        {
            roll = rolls[i];

                if(roll==2)
                { hitTwo++; }
                else if(roll==3)
                { hitThree++; }
                else if(roll==4)
                { hitFour++; }
                else if(roll==5)
                { hitFive++; }
                else if(roll==6)
                { hitSix++; }
                else if(roll==7)
                { hitSeven++; }
                else if(roll==8)
                { hitEight++; }
                else if(roll==9)
                { hitNine++; }
                else if (roll == 10)
                { hitTen++; }
                else if (roll == 11)
                { hitEleven++; }
                else if (roll == 12)
                { hitTwelve++; }
        }

        freq1 = " 2 Occurs: " + hitTwo + " times"; freq2 = " 3 Occurs: " + hitThree + " times"; freq3 = " 4 Occurs: " + hitFour + " times";
        freq4 = " 5 Occurs: " + hitFive + " times"; freq5 = " 6 Occurs: " + hitSix + " times"; freq6 = " 7 Occurs: " + hitSeven + " times";
        freq7 = " 8 Occurs: " + hitEight + " times"; freq8 = " 9 Occurs: " + hitNine + " times"; freq9 = " 10 Occurs: " + hitTen + " times";
        freq10 = " 11 Occurs: " + hitEleven + " times"; freq11 = " 12 Occurs: " + hitTwelve + " times";


        frequency.Items.Add(freq1); frequency.Items.Add(freq2); frequency.Items.Add(freq3); frequency.Items.Add(freq4); frequency.Items.Add(freq5);
        frequency.Items.Add(freq6); frequency.Items.Add(freq7); frequency.Items.Add(freq8); frequency.Items.Add(freq9); frequency.Items.Add(freq10);
        frequency.Items.Add(freq11);
    }

Upvotes: 0

Views: 1988

Answers (2)

Nicholas Carey
Nicholas Carey

Reputation: 74187

Here you go. One 6-sided dice roller. It knows nothing about user interface. It exposes almost nothing about its internal implementation.

class SixSidedDiceRoller
{
  private static readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
  private SortedDictionary<int,int> frequencyTable;
  private List<Tuple<int,int,int>> rollHistory;

  public int Count { get { return rollHistory.Count; } }

  public IEnumerable<Tuple<int , int , int>> RollHistory
  {
    get { return rollHistory.AsReadOnly(); }
  }

  public IEnumerable<Tuple<int,int>> FrequencyTable
  {
    get
    {
      return frequencyTable.Select(
        x => new Tuple<int,int>(x.Key,x.Value)
        ) ;
    }
  }

  public SixSidedDiceRoller()
  {

    rollHistory = new List<Tuple<int , int , int>>();

    // initialize the frequency table
    for ( int i = 2 ; i <= 12 ; ++i )
    {
      frequencyTable[i] = 0;
    }

    return;
  }

  public int RollDice()
  {
    int d1 = RollDie();
    int d2 = RollDie();
    int n  = d1 + d2;

    rollHistory.Add( new Tuple<int , int , int>( d1 , d2 , n ) );
    ++frequencyTable[n];

    return n;
  }

  private int RollDie()
  {
    byte[] octets = new byte[1];
    rng.GetBytes( octets );
    int die = 1 + ( octets[0] % 6 );
    return die;
  }

}

Shouldn't be too hard to wire that up to a windows app, wpf app, web app, console app, etc.

Upvotes: 0

Austin Salonen
Austin Salonen

Reputation: 50215

Roll_Click does way too much work.

First, create a GatherSamples function.

int[] GatherSamples()
{
    var rolls = new List<int>();

    // roll dice ...

    return rolls.ToArray();
}

Then a DisplayRolls method

void DisplayRolls(int[] rolls)
{
     // output to your control      
}

... and a WriteToDisk method

void WriteToDisk(int[] rolls, string file)
{
    using (var writer = new StreamWriter(file))  // research C# using if you don't understand this
    {
        ...
    }
}

... then do your frequency analysis

string[] AnalyzeRolls(int[] rolls)
{
    // though I don't approve of 11 counters, use them here

    return new [] { "2 occurs " ... };
}

... then call it like so:

foreach(var analysis in AnalyzeRolls(rolls))
{
    frequency.Items.Add(analysis);
}

Upvotes: 1

Related Questions