Tek Eye Logo

Tek Eye

C# Dice Roll Code with Stats

This article provides some C# dice rolling code (with some dice images and a dice rolling sound). It has an easy to use C# dice class. The dice rolling class can be used when developing a simple C# dice game, or for any code that needs one or more dice. This includes using the code for a dice rolling simulator, demonstrating C# random number and probability concepts, or just needing a C# dice roll method for a program. The dice class collects some stats on the rolls performed. This can be useful for some applications.

Note: It is correct to say one die and two dice, but it is common to use dice for singular and plural. That's what this article will do.

C# Dice Roll Code

To skip the tutorial part of the article, scroll down to all the source code at the end of the article. There is a download of the C# dice roll app code as a zip file. The code includes a Visual Studio (VS) solution. The C# code in this article was developed using Microsoft Visual Studio Community 2019.

Note: When you download VS files from the Internet, Windows may block their use due to security concerns. This may cause a message to display, for example, that a file has a mark of the web. This will need removing via the properties of the file. Use Windows File Explorer to open the file's properties and unblock the file. This may need to be done for multiple files.

Use a C# Windows Forms Application for the Dice Roll Code

This tutorial will use a single Form Windows application with a C# dice class. Start a new C# Windows Form Application in VS. If you need to get started with VS see the Tek Eye article Hello World in C#, A Starting WinForms Example. For this tutorial the VS solution and C# project was called Dice_Roll. The starting form was renamed from Form1 to FrmDiceRoll, and the form's Text set to Dice Rolling Simulator.

The User Interface (UI) to test the dice roll code is shown above. This can be created by dragging controls from the Toolbox in VS onto the starting form. Alternatively, download the code in the provided zip file and open the solution in VS to browse the code. For this tutorial a GroupBox was added to the form, a PictureBox was dropped onto the GroupBox, along with twenty labels to display the dice class stats. The PictureBox displays a dice face image matching the value rolled. The GroupBox was then copied and pasted on the form and edited to create the UI for the second dice. The second GroupBox's Visible property is set to false as the application can roll one or two dice, but starts with one.

A CheckBox determines if one or two dice are displayed. When checked it makes the second GroupBox's visible property true (and false again when unchecked). A Button is added to perform the dice roll, clicking the dice images will also perform the dice roll.

The Dice Rolling C# Class

A C# class contains all the code needed for a dice roll. The Dice class is added to the project (if not familiar with adding a class file use the Project and Add Class menu option). If your application requires only one dice then it can be made a static class. Four class variables are needed, a long array to hold a count of each number rolled, an instance of the Random class to generate the random values of the dice roll, and two integers to hold the rolled numbers, and the previously rolled number:

public class Dice
{
    //Store number of rolls of each number
    long[] rolls = { 0, 0, 0, 0, 0, 0 };
    //Use random for rolling
    readonly Random roller = new Random();
    //Store the last rolled number
    int lastRoll = 0;
    //Store the previously rolled number
    int previousRoll = 0;
}

The Dice class has a RollNumber method to perform the dice roll, added before the closing bracket. It saves the last roll to the previous roll integer, calls the Next method on the random class to generate the dice roll, and updates the number counts in the long array:

public int RollNumber()
{
    //Save previous number
    previousRoll = lastRoll;
    //Roll the dice (die!)
    lastRoll = roller.Next(0, 6) + 1;
    //Update all rolls
    rolls[lastRoll - 1]++;
    return lastRoll;
}

The remaining properties and methods retrieve the rolled number, previous number and various stats. Here, using Linq notation (add using System.Linq; to the top of the class file):

//Get last rolled number
public int LastRoll => lastRoll;

The above is the same as:

//Get last rolled number
public int LastRoll()
{
    return lastRoll;
}

The same for the previous rolled value and the counts of the rolls.

//Get previous rolled number
public int PreviousRoll => previousRoll;
//Totals of each number rolled
public long[] Rolls => rolls;

The total number of rolls performed is the sum of each number rolled (returned using a Linq expression):

//Total of all rolls performed
public long TotalRolls => rolls.Sum();

Storing the count of each number rolled allows the totals for each number can be calculated using Linq:

//Total value of all rolled numbers
public long[] TotalsOfRolledNumbers => rolls.Select((number, index) => number * (index + 1)).ToArray();

Where Select stores the rolls array value in number and its index in index for each rolls entry, and for each entry performs the calculation number * (index + 1). This calculation produces the total value of that number's rolls (e.g. if 2 is rolled twice, stored in roll[1], then the calculation is 2 * (1 + 1), which is 4, i.e. 2 rolled twice. The ToArray is needed because Select returns an IEnumerable.

Having calculated the totals of rolled numbers, the grand total and mean value can be calculated:

//Total of all values rolled
public long TotalValues => TotalsOfRolledNumbers.Sum();
//Mean number rolled (double cast required to prevent integer only division)
public double MeanValueRolled => TotalValues / (double)TotalRolls;

Loading the Dice Face Images and Dice Rolling Sound

The images used for the dice faces, and the dice rolling sound, are the same resources used in the Tek Eye article Android Dice Roller Source Code for Apps. The dice code in this tutorial is for a common six sided dice, each side of the cube (each face) has one of the numbers from one to six. Here six PNG images are used to show the dice roll result. Plus, there is a 3D image shown when the dice is rolled. The same 3D image is used for the app icon. The dice images are from Open Clip Art Library user rg1024.

1st Dice Face for the Dice Roller Source Code2nd Dice Face for the Dice Roller Source Code3rd Dice Face for the Dice Roller Source Code4th Dice Face for the Dice Roller Source Code5th Dice Face for the Dice Roller Source Code6th Dice Face for the Dice Roller Source Code3D Dice for the Dice Roller Source Code

The sound of a dice roll is by Mike Koenig and is from SoundBilble.com. However, the dice rolling sound has been converted from a MP3 to a Windows WAV file for the SoundPlayer class. The sound file and dice images are all added to the project and the Build Action set to Embedded Resource, meaning they will be added to the final executable file.

A Bitmap array stores the images and the SoundPlayer is created at the module level in the form:

//Dice faces
Bitmap[] faces = new Bitmap[7]; //includes an image for rolling
SoundPlayer play = new SoundPlayer();   //For the dice roll sound

In the form constructor the dice images are loaded and the SoundPlayer configured with the WAV file. The images and sound files are in the same directory as the app's project file. The name of a media file then follows the apps namespace (Dice_Roll in this case), e.g., for one.png, the name of the image for the first face of the dice, it is referenced as Dice_Roll.one.png. A 3d dice is displayed when the dice is rolled (using dice3d160.png).

public FrmDiceRoll()
{
    InitializeComponent();
    //Load images for the dice
    Assembly prog = Assembly.GetExecutingAssembly();
    faces[0] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.dice3d160.png"));
    faces[1] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.one.png"));
    faces[2] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.two.png"));
    faces[3] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.three.png"));
    faces[4] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.four.png"));
    faces[5] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.five.png"));
    faces[6] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.six.png"));
    //Load sound file
    play.Stream = prog.GetManifestResourceStream("Dice_Roll.shake_dice.wav"); 
}

The top of the form file has System.Media and System.Reflection added:

using System.Media;
using System.Reflection;

When the form loads the two picture boxes (here called PBDice1 and PBDice2) are used to show the roll results, they are initialised with a dice roll image:

private void FrmDiceRoll_Load(object sender, EventArgs e)
{
    //Put an image in the picture box to start
    PBDice1.Image = faces[0];
    PBDice2.Image = faces[0];
}

Rolling the Dice and Displaying the Result

In this tutorial one or two dice can be rolled, therefore, two instances of the dice class are required. The dice class can be declared for as many dice as required for your application. A long variable is used to count rolled doubles.

Dice dice1 = new Dice();
Dice dice2 = new Dice();
static long doubles = 0;    //Count doubles when two dice

The dice can then be rolled and the number displayed.

//Roll the dice
private void ButRoll_Click(object sender, EventArgs e)
{
    //Dice sound
    play.Play();
    //Roll the dice and update display
    PBDice1.Image = faces[dice1.RollNumber()];
}

Using Async and Await to Enable UI Feedback

Ideally, when the dice is rolled the 3D dice image is displayed to show the roll taking place:

//Clear previous roll image
PBDice1.Image = faces[0];
//Dice sound
play.Play();
//Roll the dice and update display
PBDice1.Image = faces[dice1.RollNumber()];

However, this will not work as the UI thread cannot update the picture box whilst the new roll is executed. To overcome this issue the roll is performed on another thread using async and await. The new async roll method inserts a short delay to ensure the user sees the 3D dice image:

//Background roll, with pause, to allow a UI change
private async Task<int> Roll()
{
    //Brief pause
    await Task.Delay(500);
    //Roll dice
    return dice1.RollNumber();
}

The roll button click is updated to support the async and await:

 //Roll the dice
private async void ButRoll_Click(object sender, EventArgs e)
{
    //Clear previous roll image
    PBDice1.Image = faces[0];
    //Dice sound
    play.Play();
    //Roll the dice and update display
    PBDice1.Image = faces[await dice1.RollNumber()];
}

Full C# Dice Rolling App Code

The full code for the dice rolling app can be downloaded as a zip file for opening in VS. The code shown her does not include the form designer code. If reproducing the dice app form yourself see the app screen at the top of the article for the layout. The names of the controls will need to be set appropriately (see the UpdateStats() function).

The dice roll class code covers all the basic functionality of a dice, and can be adapted for other dice sizes:

using System;
using System.Linq;

namespace Dice_Roll
{
    public class Dice
    {
        //Store number of rolls of each number
        long[] rolls = { 0, 0, 0, 0, 0, 0 };
        //Use random for rolling
        readonly Random roller = new Random();
        //Store the last rolled number
        int lastRoll = 0;
        //Store the previously rolled number
        int previousRoll = 0;
        //Perform a dice roll
        public int RollNumber()
        {
            //Save previous number
            previousRoll = lastRoll;
            //Roll the dice (die!)
            lastRoll = roller.Next(0, 6) + 1;
            //Update all rolls
            rolls[lastRoll - 1]++;
            return lastRoll;
        }
        //Get last rolled number
        public int LastRoll => lastRoll;
        //Get previous rolled number
        public int PreviousRoll => previousRoll;
        //Totals of each number rolled
        public long[] Rolls => rolls;
        //Total of all rolls performed
        public long TotalRolls => rolls.Sum();
        //Total value of all rolled numbers
        public long[] TotalsOfRolledNumbers => rolls.Select((number, index) => number * (index + 1)).ToArray();
        //Total of all values rolled
        public long TotalValues => TotalsOfRolledNumbers.Sum();
        //Mean number rolled (double cast required to prevent integer only division) 
        public double MeanValueRolled => TotalValues / (double)TotalRolls;
    }
}

The app's form includes options for one or two dice, the click function for the roll button can be assigned to the picture boxes click function to enable a dice roll by clicking the dice images:

using System;
using System.Drawing;
using System.Media;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Dice_Roll
{
    public partial class FrmDiceRoll : Form
    {
        //Dice faces
        Bitmap[] faces = new Bitmap[7]; //includes an image for rolling
        SoundPlayer play = new SoundPlayer();   //For the dice roll sound
        //Supports two dice
        Dice dice1 = new Dice();
        Dice dice2 = new Dice();
        static long doubles = 0;    //Count doubles when two dice

        public FrmDiceRoll()
        {
            InitializeComponent();
            //Load images for the dice
            Assembly prog = Assembly.GetExecutingAssembly();
            faces[0] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.dice3d160.png"));
            faces[1] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.one.png"));
            faces[2] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.two.png"));
            faces[3] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.three.png"));
            faces[4] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.four.png"));
            faces[5] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.five.png"));
            faces[6] = new Bitmap(prog.GetManifestResourceStream("Dice_Roll.six.png"));
            //Load sound file
            play.Stream = prog.GetManifestResourceStream("Dice_Roll.shake_dice.wav"); 
        }

        private void FrmDiceRoll_Load(object sender, EventArgs e)
        {
            //Put an image in the picture box to start
            PBDice1.Image = faces[0];
            PBDice2.Image = faces[0];
        }

        //Roll the dice
        private async void ButRoll_Click(object sender, EventArgs e)
        {
            //Only one roll at a time
            ButRoll.Enabled = false;
            PBDice1.Enabled = false;
            PBDice2.Enabled = false;
            //Clear previous roll image
            PBDice1.Image = faces[0];
            if (ChkOneOrTwo.Checked)
                //Roll dice two as well
                PBDice2.Image = faces[0];
            //Dice sound
            play.Play();
            //Roll the dice and update display
            PBDice1.Image = faces[await Roll()];
            if(ChkOneOrTwo.Checked)
                //Roll dice two as well
                PBDice2.Image = faces[dice2.RollNumber()];
            UpdateStats();
            //Can roll again
            PBDice2.Enabled = true;
            PBDice1.Enabled = true;
            ButRoll.Enabled = true;
        }

        //Background roll, with pause, to allow a UI change
        private async Task<int> Roll()
        {
            //Brief pause
            await Task.Delay(500);
            //Roll dice
            return dice1.RollNumber();
        }

        //Update the various stats available
        void UpdateStats()
        {
            LblTotalNumRolls1.Text = dice1.TotalRolls.ToString();
            LblOnes1.Text = dice1.Rolls[0].ToString();
            LblTwos1.Text = dice1.Rolls[1].ToString();
            LblThrees1.Text = dice1.Rolls[2].ToString();
            LblFours1.Text = dice1.Rolls[3].ToString();
            LblFives1.Text = dice1.Rolls[4].ToString();
            LbLSixes1.Text = dice1.Rolls[5].ToString();
            LblSumRolls1.Text = dice1.TotalValues.ToString();
            LblMeanValue1.Text = dice1.MeanValueRolled.ToString();
            LblPreviousRoll1.Text = dice1.PreviousRoll.ToString();
            //See if two dice are being rolled
            if (ChkOneOrTwo.Checked)
            {
                //Update Dice Two Stats
                LblTotalNumRolls2.Text = dice2.TotalRolls.ToString();
                LblOnes2.Text = dice2.Rolls[0].ToString();
                LblTwos2.Text = dice2.Rolls[1].ToString();
                LblThrees2.Text = dice2.Rolls[2].ToString();
                LblFours2.Text = dice2.Rolls[3].ToString();
                LblFives2.Text = dice2.Rolls[4].ToString();
                LblSixes2.Text = dice2.Rolls[5].ToString();
                LblSumRolls2.Text = dice2.TotalValues.ToString();
                LblMeanValue2.Text = dice2.MeanValueRolled.ToString();
                LblPreviousRoll2.Text = dice2.PreviousRoll.ToString();
                if (dice1.LastRoll == dice2.LastRoll)
                    LblTotalDoubles.Text= (++doubles).ToString();
            }
        }

        //Show second dice?
        private void ChkOneOrTwo_CheckedChanged(object sender, EventArgs e)
        {
            if (ChkOneOrTwo.Checked)
                GrpDice2.Visible = true;
            else
                GrpDice2.Visible = false;
        }
    }
}

See Also

Author:  Published:  

ShareSubmit to TwitterSubmit to FacebookSubmit to LinkedInSubmit to redditPrint Page

Do you have a question or comment about this article?

(Alternatively, use the email address at the bottom of the web page.)

markdown CMS Small Logo Icon ↓markdown↓ CMS is fast and simple. Build websites quickly and publish easily. For beginner to expert.


Articles on:

Android Programming and Android Practice Projects, HTML, VPS, Computing, IT, Computer History, ↓markdown↓ CMS, C# Programming, Using Windows for Programming


Free Android Projects and Samples:

Android Examples, Android List Examples, Android UI Examples



Tek Eye Published Projects