Looping through a dictionary<int, int[]> and getting unexpected results - c#

I have been working with C# and Visual Studio creating an app to assist with my Game Mastering.
Working on this part of the app, I am having trouble getting the answer I expect.
I have tried several different methods of giving the "weights" including (current) Dictionary<int, int[]>, jaggered array, multiple arrays, and I've found that a Dictionary is going to be simplest.
I'm expecting that when I click a button, it runs the following code to produce ONE result, but I am getting anywhere from 3-5 results.
challenge1_click is the button click event:
private void challenge1_Click(object sender, EventArgs e)
{
Dictionary<int, int[]> weights = new Dictionary<int, int[]>() {
{ 30, new int[]{5,0,0,0,0}},
{ 60, new int[]{0,4,0,0,0}},
{ 70, new int[]{0,0,3,0,0}},
{ 95, new int[]{0,0,0,3,0}},
{ 100,new int[]{0,0,0,0,1}}
};
Random one = new Random();
Random two = new Random();
int d100 = RollDice(100, one);
int[] results = IndividualTreasure(weights, d100);
TreasureResults(results);
}
private int[] IndividualTreasure(Dictionary<int, int[]> weights, int d100)
{
int cp = 0, sp = 0, gp = 0, ep = 0, pp = 0;
Random num = new Random();
foreach (KeyValuePair<int, int[]> entry in weights)
{
if (d100 <= entry.Key)
{
for (int i = 0; i < entry.Value.Length; i++)
{
if (entry.Value[i] > 0)
{
switch (i)
{
case 0:
for (int j = 0; j < entry.Value[i]; j++)
{
int randNum = RollDice(6, num);
cp += randNum;
}
break;
case 1:
for (int j = 0; j < entry.Value[i]; j++)
{
int randNum = RollDice(6, num);
sp += randNum;
}
break;
case 2:
for (int j = 0; j < entry.Value[i]; j++)
{
int randNum = RollDice(6, num);
gp += randNum;
}
break;
case 3:
for (int j = 0; j < entry.Value[i]; j++)
{
int randNum = RollDice(6, num);
ep += randNum;
}
break;
case 4:
for (int j = 0; j < entry.Value[i]; j++)
{
int randNum = RollDice(6, num);
pp += randNum;
}
break;
}
}
}
}
}
int[] result = new int[5] { cp, sp, gp, ep, pp };
return result;
}
private void TreasureResults(int[] results)
{
int cp = results[0];
int sp = results[1];
int gp = results[2];
int ep = results[3];
int pp = results[4];
lbl_cp_amount.Text = cp.ToString();
lbl_sp_amount.Text = sp.ToString();
lbl_gp_amount.Text = gp.ToString();
lbl_ep_amount.Text = ep.ToString();
lbl_pp_amount.Text = pp.ToString();
}
The button click is linked to a form button so it is only being called once. The results I'm getting should be:
If d100 <= the dictionary key, loop through the values and find any value over 0 and do that many random rolls.
When I press the button, the code is behaving as if it's running through all of the keys, and returning multiple results.

While checking if the d100 was less than or equal to the entry.Key, I wasn't checking to make sure that it wasn't larger than the previous key also. So if it was less than the first key, it was also then less than they rest of the keys so I had to add in the following:
int previousKey = 0;
foreach (KeyValuePair<int, int[]> entry in weights)
{
int knownKey = entry.Key;
if (d100 <= knownKey && d100 > previousKey)
{
previousKey = entry.Key;
My apologies to those that read this and got extremely confused.

Related

How can I fill array with unique random numbers with for-loop&if-statement?

I'm trying to fill one dimensional array with random BUT unique numbers (No single number should be same). As I guess I have a logical error in second for loop, but can't get it right.
P.S I'm not looking for a more "complex" solution - all I know at is this time is while,for,if.
P.P.S I know that it's a really beginner's problem and feel sorry for this kind of question.
int[] x = new int[10];
for (int i = 0; i < x.Length; i++)
{
x[i] = r.Next(9);
for (int j = 0; j <i; j++)
{
if (x[i] == x[j]) break;
}
}
for (int i = 0; i < x.Length; i++)
{
Console.WriteLine(x[i);
}
Here is a solution with your code.
int[] x = new int[10];
for (int i = 0; i < x.Length;)
{
bool stop = false;
x[i] = r.Next(9);
for (int j = 0; j <i; j++)
{
if (x[i] == x[j]) {
stop = true;
break;
}
}
if (!stop)
i++;
}
for (int i = 0; i < x.Length; i++)
{
Console.WriteLine(x[i]);
}
A simple trace of the posted code reveals some of the issues. To be specific, on the line…
if (x[i] == x[j]) break;
if the random number is “already” in the array, then simply breaking out of the j loop is going to SKIP the current i value into the x array. This means that whenever a duplicate is found, x[i] is going to be 0 (zero) the default value, then skipped.
The outer i loop is obviously looping through the x int array, this is pretty clear and looks ok. However, the second inner loop can’t really be a for loop… and here’s why… basically you need to find a random int, then loop through the existing ints to see if it already exists. Given this, in theory you could grab the same random number “many” times over before getting a unique one. Therefore, in this scenario… you really have NO idea how many times you will loop around before you find this unique number.
With that said, it may help to “break” your problem down. I am guessing a “method” that returns a “unique” int compared to the existing ints in the x array, may come in handy. Create an endless while loop, inside this loop, we would grab a random number, then loop through the “existing” ints. If the random number is not a duplicate, then we can simply return this value. This is all this method does and it may look something like below.
private static int GetNextInt(Random r, int[] x, int numberOfRandsFound) {
int currentRand;
bool itemAlreadyExist = false;
while (true) {
currentRand = r.Next(RandomNumberSize);
itemAlreadyExist = false;
for (int i = 0; i < numberOfRandsFound; i++) {
if (x[i] == currentRand) {
itemAlreadyExist = true;
break;
}
}
if (!itemAlreadyExist) {
return currentRand;
}
}
}
NOTE: Here would be a good time to describe a possible endless loop in this code…
Currently, the random numbers and the size of the array are the same, however, if the array size is “larger” than the random number spread, then the code above will NEVER exit. Example, if the current x array is set to size 11 and the random numbers is left at 10, then you will never be able to set the x[10] item since ALL possible random numbers are already used. I hope that makes sense.
Once we have the method above… the rest should be fairly straight forward.
static int DataSize;
static int RandomNumberSize;
static void Main(string[] args) {
Random random = new Random();
DataSize = 10;
RandomNumberSize = 10;
int numberOfRandsFound = 0;
int[] ArrayOfInts = new int[DataSize];
int currentRand;
for (int i = 0; i < ArrayOfInts.Length; i++) {
currentRand = GetNextInt(random, ArrayOfInts, numberOfRandsFound);
ArrayOfInts[i] = currentRand;
numberOfRandsFound++;
}
for (int i = 0; i < ArrayOfInts.Length; i++) {
Console.WriteLine(ArrayOfInts[i]);
}
Console.ReadKey();
}
Lastly as other have mentioned, this is much easier with a List<int>…
static int DataSize;
static int RandomNumberSize;
static void Main(string[] args) {
Random random = new Random();
DataSize = 10;
RandomNumberSize = 10;
List<int> listOfInts = new List<int>();
bool stillWorking = true;
int currentRand;
while (stillWorking) {
currentRand = random.Next(RandomNumberSize);
if (!listOfInts.Contains(currentRand)) {
listOfInts.Add(currentRand);
if (listOfInts.Count == DataSize)
stillWorking = false;
}
}
for (int i = 0; i < listOfInts.Count; i++) {
Console.WriteLine(i + " - " + listOfInts[i]);
}
Console.ReadKey();
}
Hope this helps ;-)
The typical solution is to generate the entire potential set in sequence (in this case an array with values from 0 to 9). Then shuffle the sequence.
private static Random rng = new Random();
public static void Shuffle(int[] items)
{
int n = list.Length;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
int temp = items[k];
items[k] = items[n];
items[n] = temp;
}
}
static void Main(string[] args)
{
int[] x = new int[10];
for(int i = 0; i<x.Length; i++)
{
x[i] = i;
}
Shuffle(x);
for(int i = 0; i < x.Length; i++)
{
Console.WritLine(x[i]);
}
}
//alternate version of Main()
static void Main(string[] args)
{
var x = Enumerable.Range(0,10).ToArray();
Shuffle(x);
Console.WriteLine(String.Join("\n", x));
}
You can simply do this:
private void AddUniqueNumber()
{
Random r = new Random();
List<int> uniqueList = new List<int>();
int num = 0, count = 10;
for (int i = 0; i < count; i++)
{
num = r.Next(count);
if (!uniqueList.Contains(num))
uniqueList.Add(num);
}
}
Or:
int[] x = new int[10];
Random r1 = new Random();
int num = 0;
for (int i = 0; i < x.Length; i++)
{
num = r1.Next(10);
x[num] = num;
}

calling merge sort c#

I wrote a merge sort program, but I have problems calling It from another class. I need help. For some reason after I enter the size and the max number a get a black screen in the output. I believe that the solution is pretty easy, but I can't find the solution by myself
This is the class where It sorts the numbers
class MergeSort
{
public int[] Sort(int[] unsortedSequence)
{
int[] left;
int[] right;
int[] result = new int[unsortedSequence.Length];
if (unsortedSequence.Length <= 1)
return unsortedSequence;
int midPoint = unsortedSequence.Length / 2;
left = new int[midPoint];
if (unsortedSequence.Length % 2 == 0)
right = new int[midPoint];
else
right = new int[midPoint + 1];
for (int i = 0; i < midPoint; i++)
left[i] = unsortedSequence[i];
int x = 0;
for (int i = midPoint; i < unsortedSequence.Length; i++)
{
right[x] = unsortedSequence[i];
x++;
}
left = Sort(left);
right = Sort(right);
result = merge(left, right);
return result;
}
public static int[] merge(int[] left, int[] right)
{
int resultLength = right.Length + left.Length;
int[] result = new int[resultLength];
int indexLeft = 0, indexRight = 0, indexResult = 0;
while (indexLeft < left.Length || indexRight < right.Length)
{
if (indexLeft < left.Length && indexRight < right.Length)
{
if (left[indexLeft] <= right[indexRight])
{
result[indexResult] = left[indexLeft];
indexLeft++;
indexResult++;
}
else
{
result[indexResult] = right[indexRight];
indexRight++;
indexResult++;
}
}
else if (indexLeft < left.Length)
{
result[indexResult] = left[indexLeft];
indexLeft++;
indexResult++;
}
else if (indexRight < right.Length)
{
result[indexResult] = right[indexRight];
indexRight++;
indexResult++;
}
}
return result;
}
}
And this is the class where I'm trying to call the mergesort
class Program
{
static void Main(string[] args)
{
Console.Write("How Many Random Numbers Would you like to Generate : ");
int n = Convert.ToInt32(Console.ReadLine());
Console.Write("What is the Maximum Random Number Would you like to Generate : ");
int max = Convert.ToInt32(Console.ReadLine());
Console.Clear();
int[] unsortedSequence = generateRandomSequence(n, max);
MergeSort mergeSortEngine = new MergeSort();
int[] mergeSortedArray = mergeSortEngine.Sort(unsortedSequence);
Console.Write("Output for Merge Sort: \n\n");
OutputSequence(mergeSortedArray);
Console.WriteLine("\n\nPress Any Key to Continue...");
Console.ReadKey();
Console.Clear();
Because you didn't provide them, I wrote the missing generateRandomSequence() and OutputSequence methods in order to test your code and I can't reproduce your issue. Perhaps you should compare these to your own:
static int[] generateRandomSequence(int count, int max)
{
Random rn = new Random();
int[] seq = new int[count];
for (int i = 0; i < count; ++i)
{
seq[i] = rn.Next(0, max + 1);
}
return seq;
}
static void OutputSequence(int[] array)
{
for (int i = 0; i < array.Length; ++i)
{
if (i > 0)
{
Console.Write(", ");
}
Console.Write(array[i]);
}
Console.WriteLine();
}
Output from your code using the above methods:
It looks like you missing generateRandomSequence(n, max);
It might be like
public static int[] generateRandomSequence(int n, int max)
{
var rnd = new Random();
int[] seq = new int[n];
for (int ctr = 0; ctr < n; ctr++)
{
seq[ctr] = rnd.Next(1, max + 1);
}
return seq;
}
Then, in Program/Test class after Console.Write("Output for Merge Sort: \n\n"); you can iterate with foreach loop to display the sorted array.
foreach (var item in mergeSortedArray)
{
Console.WriteLine("{0}", item);
}
//OutputSequence(mergeSortedArray);

sum middle number with jagged array in C#

I write some code with jagged array but when i sum middle number program not working and i cant fix it...:
public class JaggedArray
{
public static void Array()
{
int[][] arrayOfArray = ArrayOfArray();
var tong = 0;
for (var i = 1; i < arrayOfArray.Length; i++)
{
for (var j = 0; j < arrayOfArray[i].Length; j++)
{
var bienTam = arrayOfArray[i].Length;
var tamThoi = j;
if (bienTam%2==0&&tamThoi==bienTam/2)
{
tamThoi++;
tong += arrayOfArray[i][tamThoi];
}
}
}
OutPut(arrayOfArray, tong);
}
private static int[][] ArrayOfArray()
{
Random ngauNhien = new Random();
int[][] arrayOfArray = new int[13][];
for (var i = 0; i <arrayOfArray.Length; i++)
{
arrayOfArray[i] = new int[i];
for (var j = 0; j < arrayOfArray[i].Length; j++)
{
arrayOfArray[i][j] = ngauNhien.Next(0, 99); //throw exception
}
}
return arrayOfArray;
}
can someone explain reason why i wrong and how ti fix it?
The problem you are solving is the one Linq is very good for:
int[][] arrayOfArray = new int[][] {
new[] {1, 2, 3}, // 2 is the middle item
new[] {4, 5} // in case of tie, let 5 (right) be the middle item
new[] {7}, // 7
new int[] {}, // should be ignored
};
// 2 + 5 + 7 == 14
var result = arrayOfArray
.Where(line => line != null && line.Length > 0)
.Sum(line => line[line.Length / 2]);
So I've got it compiling:
public class JaggedArray
{
public static void Array()
{
int[][] arrayOfArray = ArrayOfArray();
var tong = 0;
for (var i = 1; i < arrayOfArray.Length; i++)
{
for (var j = 0; j < arrayOfArray[i].Length; j++)
{
var bienTam = arrayOfArray[i].Length;
var tamThoi = j;
if (j % 2 == 0 && j / 2 == bienTam / 2)
{
tamThoi++;
// You need to check here that tamThoi isn't
// outside the bounds of your array
if (tamThoi >= arrayOfArray[i].Length)
{
continue;
}
tong += arrayOfArray[i][tamThoi];
}
}
}
}
private static int[][] ArrayOfArray()
{
Random ngauNhien = new Random();
int[][] arrayOfArray = new int[13][];
for (var i = 0; i < 13; i++)
{
arrayOfArray[i] = new int[i];
// here you're better off using i
// instead of the arrayOfArray[i].Length - because you know the length
for (var j = 0; j < i; j++)
{
arrayOfArray[i][j] = ngauNhien.Next(0, 99);
}
}
return arrayOfArray;
}
}
You can make this far more succinct with LINQ.

Create number for random and non repeat

i'm code:
Random rand = new Random();
int[] arr = new int[4];
for (int i = 0; i < 4; i++)
{
for (int k = 0; k < 4; k++)
{
int rad = rand.Next(1, 5);
if (arr[k] != rad)
arr[i] = rad;
}
}
for (int i = 0; i < 4; i++)
MessageBox.Show(arr[i].ToString());
I wanna production numbers from 1 to 4 am and unequal with each other.
tnx.
Think it the other way round:
instead of:
generating a number and then check it if it is not duplicate
you make it such that:
you already have a set of non-duplicate numbers, then you take it
one-by-one - removing the possibilities of duplicates.
Something like this will do:
List<int> list = Enumerable.Range(1, 4).ToList();
List<int> rndList = new List<int>();
Random rnd = new Random();
int no = 0;
for (int i = 0; i < 4; ++i) {
no = rnd.Next(0, list.Count);
rndList.Add(list[no]);
list.Remove(list[no]);
}
The result is in your rndList.
This way, no duplicate will occur.
Create an array with unique elements and then shuffle it, like in the code below, it will shuffle an array in uniformly random order it uses Fisher-Yates shuffle algorithm:
int N = 20;
var theArray = new int[N];
for (int i = 0; i < N; i++)
theArray[i] = i;
Shuffle(theArray);
public static void Shuffle(int[] a) {
if (a == null) throw new ArgumentNullException("Array is null");
int n = a.Length;
var theRandom = new Random();
for (int i = 0; i < n; i++) {
int r = i + theRandom.Next(n-i); // between i and n-1
int temp = a[i];
a[i] = a[r];
a[r] = temp;
}
}
Explanation and template version of algorithm could be found in this post with nice answer from Jon Skeet.
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
T[] elements = source.ToArray();
// Note i > 0 to avoid final pointless iteration
for (int i = elements.Length-1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
T tmp = elements[i];
elements[i] = elements[swapIndex];
elements[swapIndex] = tmp;
}
// Lazily yield (avoiding aliasing issues etc)
foreach (T element in elements)
{
yield return element;
}
}
Create a list containing the numbers you want, then shuffle them:
var rnd = new Random();
List<int> rndList = Enumerable.Range(1, 4).OrderBy(r => rnd.Next()).ToList();
If you want an array instead of a list:
var rnd = new Random();
int[] rndArray = Enumerable.Range(1, 4).OrderBy(r => rnd.Next()).ToArray();
int[] arr = new int[5];
int i = 0;
while (i < 5)
{
Random rand = new Random();
int a = rand.Next(1,6);
bool alreadyexist = false;
for (int j = 0; j < 5; j++)
{
if (a == arr[j])
{
alreadyexist = true;
}
}
if (alreadyexist == false)
{
arr[i] = a;
i++;
}
}
for (int k = 0; k < 5; k++)
{
MessageBox.Show(arr[k].ToString());
}

How do i return sum from a class

Im writing a program where the user writes how many times he want to throw x-number dice and how many sides they going to have.
But i cant figure out how to return the sum om the number on each dice game..
this is the main code:
static void Main(string[] args)
{
List<Dice> _Dice = new List<Dice>();
int a = 0;
int ggr = int.Parse(Interaction.InputBox("How many times do you want to repeat:"));
while (a != ggr)
{
int xChoice = int.Parse(Interaction.InputBox("How many dice do you want to throw:"));
int yChoice = int.Parse(Interaction.InputBox("Write how many sides the dice will have:"));
_Dice.Add(new Dice(xChoice,yChoice));
a++;
}
int e = 1;
foreach (var item in _Dice)
{
Interaction.MsgBox(string.Format("Result off game {0}: {1}", e++, item.ToString()));
}
}
This is the Dice class:
static int _xChoice, _yChoice;
static int[,] dice = new int[_xChoice, _yChoice];
public int Tostring()
{
int a = 0;
foreach (var item in dice)
{
a+=item;
}
return a;
}
void throw()
{
Random r = new Random();
for (int i = 0; i <dice.GetLength(0); i++)
{
for (int j = 0; j < dice.GetLength(1); j++)
{
dice[i, j] = r.Next(1, _yChoice);
}
}
}
public Dice(int Xchoice, int Ychoice)
{
_xChoice = Xchoice;
_yChoice = Ychoice;
}
Just for completeness, what you are asking for is the sum of items of a 2D array:
int total = Enumerable.Range(0, _xChoice).Sum(s => Enumerable.Range(0, _yChoice).Sum(p => dice[s, p]));
Well you can do it like this:
void throw()
{
Random r = new Random();
for (int i = 0; i <dice.GetLength(0); i++)
{
int totalSum = 0;
for (int j = 0; j < dice.GetLength(1); j++)
{
dice[i, j] = r.Next(1, _yChoice);
totalSum += dice[i, j];
}
// Here you display totalSum for game with index i.
}
}

Categories