Can't add values to List - C# [duplicate] - c#

This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 8 years ago.
Many times I had to create lists of structures to store my data in C#. But this time, I have an error, "Index Out of Range". I don't quite understand why, since I already did similar projects, but I would be very appreciated if someone could help me.
class mng
{
int day = 0;
List<Despesas> dias = new List<Despesas>();
public struct Despesas
{
public double transportes;
public double alimentacao;
public double vestuario;
public double agua;
public double luz;
public double educacao;
}
public mng ()
{
}
(This is where I get the error)
public void showMessage()
{
for (int i = 0; i < 31; i++)
{
MessageBox.Show("Água: " + dias[i].agua + "\nTransportes: " + dias[i].transportes);
}
}
and on Form1:
double transportes = Convert.ToDouble(txtTransportes.Text);
double agua = Convert.ToDouble(txtAgua.Text);
mng mngV = new mng(transportes, agua, educacao);
if (day < 31)
{
button1.Enabled = false;
//this is the button that enables the ShowMessage() Method.
}
else
{
button1.Enabled = true;
}
I never execute the method showMessage() before the List has 31 values, so why is it out of Index? I tried to search on the site first but couldn't find any questions with a similar problem although there are a lot with the same error.
I changed the overload constructor to:
public mng(double transportes, double agua)
{
Despesas dia = new Despesas();
dia.transportes = transportes;
dia.agua = agua;
dias.Add(dia);
MessageBox.Show("Added: " + dias.Count);
day++;
}
and guess what, the dias.Count is always 1. I don't understand why...

Try changing your method to:
public void showMessage()
{
for (int i = 0; i < dias.Count; i++)
{
MessageBox.Show("Água: " + dias[i].agua + "\nTransportes: " + dias[i].transportes);
}
}

What about trying this:
public void showMessage()
{
for (int i = 0; i < dias.Count; i++)
{
MessageBox.Show("Água: " + dias[i].agua + "\nTransportes: " + dias[i].transportes);
}
}
or even better:
public void showMessage()
{
foreach(var d in dias)
{
MessageBox.Show(... + d.agua + .... + d.transportes);
}
}

Just change your code this way:
for (int i = 0; i < dias.Count; i++)
And you can check it under the debugger to verify how many items are there in the array when the loop is running.

make sure that dias has 31 values.you can use foreach instead of for as it will give the the same result with much better performance
foreach(var item in dias )
{
MessageBox.Show("Água: " + item.agua + "\nTransportes: " + item.transportes);
}
if you are using for- than problem is because your list might not filled properly have less items

Related

Finding odd or even in an C# array

I'm supposed to create a method that takes an array and tells if the number is odd or even. I think I'm close to the answer but when I ran the code, it popped up with "Index is outside the bounds of the array". Is there a way to fix that?
private static string OddOrEven(int[] integerArray, string[] numAssign)
{
foreach (int i in integerArray)
{
if (integerArray[i] % 2==0)
{
numAssign[i] = " is even";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
else
{
numAssign[i] = " is odd";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
}
return "";
}
I'm still new to c# so any help is really appreciated.
Your mistake here is with how foreach works. I'll provide a different example to help you understand:
List<Person> people = GetPeople();
foreach (Person p in people)
{
Console.WriteLine(p.Name);
}
As you can see, the variable in the foreach actually receives each item, not its index. It's just that you have a list of int so it's not so obvious for you.
It seems like you want a regular for loop:
for(int i = 0; i < integerArray.Length; ++i)
{
if (integerArray[i] % 2==0)
{
numAssign[i] = " is even";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
else
{
numAssign[i] = " is odd";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
}
The next curious thing is your return returnValue; - the if statement can only ever enter one or the other, so it will always return a string for the first item only. It won't go on to the second, third, fourth, etc. item as it has already left the method before the loop has a chance to move on to the next value.
Speculation
I expect you want an array of results like this:
private static string[] OddOrEven(int[] integerArray)
{
string[] resultValues = new string[integerArray.Length];
for (int i = 0; i < integerArray.Length; ++i)
{
if (integerArray[i] % 2==0)
{
string numAssign = " is even";
resultValues[i] = integerArray[i] + numAssign;
}
else
{
string numAssign = " is odd";
resultValues[i] = integerArray[i] + numAssign;
}
}
return resultValues;
}
Note that I've removed the numAssign incoming array from the method parameters, and now just build it within the method itself.
This would produce a result like this.

selecting dropdown item to get info from a html element is very slow selenium chromedriver

I am trying to scrape data from product page in wish.com (https://www.wish.com/c/58b56224d1675a12c859d21c)
when you change the dropdown box item of color or size the price changes so I wanted to scrape all possible combinations of color and size and save the right price for each combination.
I used the following code:
ChromeDriver CD = new ChromeDriver();
CD.Navigate().GoToUrl(URL);
Actions actions = new Actions(CD);
MessageBox.Show("Start");
var SC = CD.FindElementsByXPath("//*[#id=\"fancy-select-options-size\"]/li");
var CC = CD.FindElementsByXPath("//*[#id=\"fancy-select-options-color\"]/li");
var PP = CD.FindElementByXPath("//*[#id=\"product-content\"]/div[2]/div[3]/div[1]/div[2]/span[1]");
for (int i = 1; i < SC.Count; i++)
{
actions.MoveToElement(SC[i]).Click().Perform();
for(int j=0; j<CC.Count;j++)
{
actions.MoveToElement(CC[j]).Click().Perform();
Debug.Write(i.ToString() + " :: " + j.ToString() + " = " + CD.FindElementByXPath("//*[#id=\"product-content\"]/div[2]/div[3]/div[1]/div[2]/span[1]").Text + '\n');
}
}
MessageBox.Show("FINISH");
but it turned out to be wrong and running very slow.
Question: Is there anyway to get the data I want faster than that?
That page design is a hot mess... anyway... when I tackle things like this where actions are repeated, it's best to write functions for the repeatable actions like getting the price, setting the color, etc. Here are the list of functions
public static int getNumberOfColorOptions()
{
return driver.findElements(By.cssSelector("#fancy-select-color li.fancy-select-option")).size();
}
public static int getNumberOfSizeOptions()
{
return driver.findElements(By.cssSelector("#fancy-select-options-size li.fancy-select-option")).size();
}
public static String getPrice()
{
return driver.findElement(By.cssSelector("span.price")).getText();
}
public static void setColorByIndex(int index)
{
driver.findElement(By.id("fancy-select-color")).click();
driver.findElements(By.cssSelector("#fancy-select-color li.fancy-select-option")).get(index).click();
}
public static void setSizeByIndex(int index)
{
driver.findElement(By.id("fancy-select-size")).click();
driver.findElements(By.cssSelector("#fancy-select-options-size li.fancy-select-option")).get(index).click();
}
and here is the code to loop through the color and size choices and write out the price.
String url = "https://www.wish.com/c/58b56224d1675a12c859d21c";
driver.navigate().to(url);
// always start at 1 since the first option is "Choose a XXX..."
for (int sizeIndex = 1; sizeIndex < getNumberOfSizeOptions(); sizeIndex++)
{
setSizeByIndex(sizeIndex);
for (int colorIndex = 1; colorIndex < getNumberOfColorOptions(); colorIndex++)
{
setColorByIndex(colorIndex);
System.out.println(getPrice());
}
}
I wasn't able to test the code because you have to sign up for an account but this should get you pretty close. You may need to add some waits in there.

Checking if instance is null VS calling empty function (C#)

Introduction
So I was making a game, thinking how do I structure and update all my game objects. Do I (case 1) create a simple GameObj as a parent class and put some physics in virtual Update method, some default drawing in virtual Draw, etc, and make every other object (wall, enemy, player...) be the child, OR do I (case 2) use components as described in this article. In short, the writer explains that we could make interfaces for user input, physics update and draw (lets stop at those 3) and describe our GameObj with preprogrammed instances of these interfaces.
Now, in both cases I will get a loop of GameObj class.
In case 1 it would probably look something like this
// in Update function of the level class
for(int i = 0; i < gameObjList.Count; i++)
{
gameObjList[i].Update();
}
And in case 2, something like this
// in UpdatePhysics function of the level class
for(int i = 0; i < gameObjList.Count; i++)
{
gameObjList[i].PhysicComponent.Update();
}
And so on (in case 2) for other interfaces such as InputComponent.Update and DrawComponent.Draw (or CollisionComponent.Check(gameObj[x]), I dunno).
Reasons listed are ment to be inside a level class that takes care of all of our game objects
Reasons to consider if ( x != null )
In both cases we (could) have a situation where we need to call if ( x != null ). In case 1 we maybe don't want to delete and add to the gameObjList all the time, but recycle the instances, so we set them to null without doing something along the lines of gameObjList.Remove(x). In case 2 maybe we want to be able not to set some of the components, so we'd have to ask if (gameObjList[i].someComponent != null) to be able to call gameObjList[i].someComponent.Update().
Reasons to consider calling empty function
Also in both cases, we could just call an empty function (e.g. public void myFunction(){}). Lets consider the self explanatory Wall class. It exists just to be there. Id doesn't update, but it does have a certain relation to other GameObjs. Also, some of it's children in case 1, like a lets say MovingWall or Platform would have some sort of update. As for case 2, we could always declare a default, empty class of someComponent whose Update function would be empty, and so an instance of this class would be set to our GameObj component if none is set in the constructor. Maybe something like this
public GameObj(IPhysicsComponent physicsComponent, ...){
if(physicsComponent == null)
physicsComponent = PhysicsComponent.Default;
this.physicsComponent = physicsComponent;
}
Research
Now, I didn't find what would be the most efficient thing to do in a game engine we are building here. Here are some examples I just tested (note some of them are just for reference):
1. empty loop
2. empty function
3. if(x != null) x.empyFunction(); x is always null
4. x?.emptyFunction(); x is always null
5. if(x != null) x.empyFunction(); x is not null
6. x?.emptyFunction(); x is not null
7. myClass.staticEmptyFunction();
These 7 points are tested 100 000 times, 10 000 times. The code below is the code that I tested with. You can run in locally, change some of the static variables, and the result will appear in "result.txt" in the folder where you ran the program. Here is the code :
public enum TimeType
{
emptyLoop = 1,
loopEmptyFunction = 2,
loopNullCheck = 3,
loopNullCheckShort = 4,
loopNullCheckInstanceNotNull = 5,
loopNullCheckInstanceNotNullShort = 6,
loopEmptyStaticFunction = 7
}
class myTime
{
public double miliseconds { get; set; }
public long ticks { get; set; }
public TimeType type { get; set; }
public myTime() { }
public myTime(Stopwatch stopwatch, TimeType type)
{
miliseconds = stopwatch.Elapsed.TotalMilliseconds;
ticks = stopwatch.ElapsedTicks;
this.type = type;
}
}
class myClass
{
public static void staticEmptyFunction() { }
public void emptyFunction() { }
}
class Program
{
static List<myTime> timesList = new List<myTime>();
static int testTimesCount = 10000;
static int oneTestDuration = 100000;
static void RunTest()
{
Stopwatch stopwatch = new Stopwatch();
Console.Write("TEST ");
for (int j = 0; j < testTimesCount; j++)
{
Console.Write("{0}, ", j + 1);
myClass myInstance = null;
// 1. EMPTY LOOP
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)1));
stopwatch.Reset();
// 3. LOOP WITH NULL CHECKING (INSTANCE IS NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
if (myInstance != null)
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)3));
stopwatch.Reset();
// 4. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance?.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)4));
stopwatch.Reset();
myInstance = new myClass();
// 2. LOOP WITH EMPTY FUNCTION
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)2));
stopwatch.Reset();
// 5. LOOP WITH NULL CHECKING (INSTANCE IS NOT NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
if (myInstance != null)
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)5));
stopwatch.Reset();
// 6. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NOT NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance?.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)6));
stopwatch.Reset();
// 7. LOOP WITH STATIC FUNCTION
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myClass.staticEmptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)7));
stopwatch.Reset();
}
Console.WriteLine("\nDONE TESTING");
}
static void GetResults()
{
// SUMS
double sum1t, sum2t, sum3t, sum4t, sum5t, sum6t, sum7t,
sum1m, sum2m, sum3m, sum4m, sum5m, sum6m, sum7m;
sum1t = sum2t = sum3t = sum4t = sum5t = sum6t = sum7t =
sum1m = sum2m = sum3m = sum4m = sum5m = sum6m = sum7m = 0;
foreach (myTime time in timesList)
{
switch (time.type)
{
case (TimeType)1: sum1t += time.ticks; sum1m += time.miliseconds; break;
case (TimeType)2: sum2t += time.ticks; sum2m += time.miliseconds; break;
case (TimeType)3: sum3t += time.ticks; sum3m += time.miliseconds; break;
case (TimeType)4: sum4t += time.ticks; sum4m += time.miliseconds; break;
case (TimeType)5: sum5t += time.ticks; sum5m += time.miliseconds; break;
case (TimeType)6: sum6t += time.ticks; sum6m += time.miliseconds; break;
case (TimeType)7: sum7t += time.ticks; sum7m += time.miliseconds; break;
}
}
// AVERAGES
double avg1t, avg2t, avg3t, avg4t, avg5t, avg6t, avg7t,
avg1m, avg2m, avg3m, avg4m, avg5m, avg6m, avg7m;
avg1t = sum1t / (double)testTimesCount;
avg2t = sum2t / (double)testTimesCount;
avg3t = sum3t / (double)testTimesCount;
avg4t = sum4t / (double)testTimesCount;
avg5t = sum5t / (double)testTimesCount;
avg6t = sum6t / (double)testTimesCount;
avg7t = sum7t / (double)testTimesCount;
avg1m = sum1m / (double)testTimesCount;
avg2m = sum2m / (double)testTimesCount;
avg3m = sum3m / (double)testTimesCount;
avg4m = sum4m / (double)testTimesCount;
avg5m = sum5m / (double)testTimesCount;
avg6m = sum6m / (double)testTimesCount;
avg7m = sum7m / (double)testTimesCount;
string fileName = "/result.txt";
using (StreamWriter tr = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + fileName))
{
tr.WriteLine(((TimeType)1).ToString() + "\t" + avg1t + "\t" + avg1m);
tr.WriteLine(((TimeType)2).ToString() + "\t" + avg2t + "\t" + avg2m);
tr.WriteLine(((TimeType)3).ToString() + "\t" + avg3t + "\t" + avg3m);
tr.WriteLine(((TimeType)4).ToString() + "\t" + avg4t + "\t" + avg4m);
tr.WriteLine(((TimeType)5).ToString() + "\t" + avg5t + "\t" + avg5m);
tr.WriteLine(((TimeType)6).ToString() + "\t" + avg6t + "\t" + avg6m);
tr.WriteLine(((TimeType)7).ToString() + "\t" + avg7t + "\t" + avg7m);
}
}
static void Main(string[] args)
{
RunTest();
GetResults();
Console.ReadLine();
}
}
When I put all the data in excel and made a chart, it looked like this (DEBUG):
EDIT - RELEASE version. I guess this answers my question.
The questions are
Q1. What approach to use to be more efficient?
Q2. In what case?
Q3. Is there official documentation on this?
Q4. Did anybody else test this, maybe more intensively?
Q5. Is there a better way to test this (is my code at fault)?
Q6. Is there a better way around the problem of huge lists of instances that need to be quickly and efficiently updated, as in - every frame?
EDIT Q7. Why does the static method take so much longer to execute in the release version?
As #grek40 suggested, I did another test where I called myClass.staticEmptyFunction(); 100 times before starting the test so that it can be cashed. I also did set testTimesCount to 10 000 and oneTestDuration to 1 000 000. Here are the results:
Now, it seems much more stable. Even the little differences you can spot I blame on my google chrome, excel and deluge running in the background. The questions I asked I asked because I thought that there would be a greater difference, but I guess that the optimisation worsk much much better than I expected. I also guess that nobody did this test because they probably knew that there's C behind it, and that people did amasing work on the optimisation.

C# : how do I correctly clone a List<> to onther

I have a two list one is original and other one is copy of original one
List<Button> buttonList; // this is the original list
List<Button> copyButtonList;// this is the copy of button list; this use to sort the list
I want to sort the copyButtonList according to my custom insertion sort where I written in separate class
I clone the original list to copy list following way(s) and sorted it
copyButtonList = buttonList.ToList();
String s = SortEngine.insertionSort(copyButtonList);
msgList.Items.Add(s);
I also try following ways
copyButtonList = new List<Button>(buttonList);
and
foreach (var b in buttonList) {
copyButtonList.Add(b);
}
after that I tried to print the two list as follows
foreach(var b in buttonList){
msgList.Items.Add(b.Text);
}
foreach(var b in copyButtonList){
msgList.Items.Add(b.Text);
}
in the above three situations both list are sorted :(
I want just sort the copyButtonList only, Can anyone point out the my mistakes I done here ?
Updated : my insertion sort algorithm is below
public static String insertionSort(List<Button> button)
{
String key;
int i = 0;
int j;
String s = "";
for (j = 1; j < button.Count; j++)
{
key = button.ElementAt(j).Text;
i = j - 1;
while (i >= 0 && int.Parse(button.ElementAt(i).Text) > int.Parse(key))
{
button.ElementAt(i + 1).Text = button.ElementAt(i).Text;
i = i - 1;
}
button.ElementAt(i + 1).Text = key;
if (i == -1)
{
s=(button.ElementAt(i + 1).Text + " is the starting Item, keep this in before " + button.ElementAt(i + 2).Text);
}
else if (i == j - 1)
{
s=(button.ElementAt(i + 1).Text + " is the last Item, keep this in after " + button.ElementAt(i).Text);
}
else
{
s=(button.ElementAt(i + 1).Text + " is between " + button.ElementAt(i).Text + " and " + button.ElementAt(i + 2).Text);
}
}
if (button.Count == 1)
{
s= ("This is the first Item");
}
return s;
}
Actually speising's question is not dumb.
Since you are not changing the Button there is not need for deep cloning.
Your problem is probably somewhere else.
Here is an example
public class Customer
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
public class CustomerComparer : IComparer<Customer>
{
public int Compare(Customer x, Customer y)
{
return x.Name.CompareTo(y.Name);
}
}
void Print()
{
List<Customer> l1 = new List<Customer>();
l1.Add(new Customer() { Name="aa"});
l1.Add(new Customer() { Name = "cc" });
l1.Add(new Customer() { Name = "bb" });
List<Customer> l2 = new List<Customer>(l1);
l2.Sort(new CustomerComparer());
foreach (var item in l1)
Console.WriteLine(item);
Console.WriteLine();
foreach (var item in l2)
Console.WriteLine(item);
Console.ReadLine();
}
This prints
aa
cc
bb
and then
aa
bb
cc
Update
Your ARE changing the button so you need a deep copy.Use this to create the new list
using System.Linq;
copyButtonList = buttonList.Select(ee => new Button() { Text= ee.Text}).ToList();
By "Changing the button" i mean lines like this
button.ElementAt(i + 1).Text = key;
You may have 2 lists but they both "point"/have the same objects.When you change the Text of a button in list 1 it means that the object is changed also in list 2.
You need to understand what is a value type and what is a reference type and their differences. Here are some links that will help you
http://www.albahari.com/valuevsreftypes.aspx
What is the difference between a reference type and value type in c#?
Also run the following console application on your pc and see what is printed
using System;
public struct Point
{
public int X;
public Point(int initialValue) { X = initialValue; }
}
class Program
{
static void Main(string[] args)
{
Point point1 = new Point(5);
Console.WriteLine("Before:" + point1.X);
ChangePoint(point1);
Console.WriteLine("After:" + point1.X);
Console.ReadLine();
}
private static void ChangePoint(Point p)
{
p.X = 20;
}
}
Then just change the word "struct" to "class" and see what is printed.
You get different result because structs are value types and classes are reference types.
Your sorting algorithm modifies the Buttons, which are the same in both lists. if you really want to do it that way, you need to deep copy the objects, ie. make copies or each button, not just their references.
but a much better solution to sort the list would be to just sort the list, ie. switch the elements indices. (like button[i+1]=button[i])
You can use method mentioned here
List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);
oldList.ForEach((item)=>
{
newList.Add(new YourType(item));
});

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);
}
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);
}
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.

Categories

Resources