I'm running this class and method
public class DiceRoll
{
static Random _r =new Random();
public int Random6()
{
int n = _r.Next(1, 7);
return n;
}
}
I'm trying to use it inside an if statement in another class like so:
if (input == "d6")
{
int dice = diceRoll.Random6();
Console.WriteLine(dice);
}
my question is this. If I call diceRoll.Random6(); with a multiplier like this diceRoll.Random6() * 2; Is it creating two random numbers and adding them or is it just taking one and multiplying it by two?
I think it's probably the latter but I just wanted to check before I got into convoluted programming.
If it is the latter is there a way to make my program call multiple instances of Random6 without going diceRoll.Random6() + diceRoll.Random6(); That works ok for doing it twice but if I want to do it four or six times it'll become inelegant.
Thanks in advance.
Call the method from within a loop
int result = 0;
for(int i = 0; i < 10; i++)
{
result += Random6();
}
It just generates 1 random number then multiplies it by 2
you can just do it in a loop, or if you want to be fancy
var sum = Enumerable.Range(1, 6).Sum(x => diceRoll.Random6())
which you might want to break down into...
var rolls = Enumerable.Range(1, 6).Select(x => diceRoll.Random6()).ToList();
var sumOfRolls = rolls.Sum();
that way you have the sum and a list of each individual roll.
Related
I am looking to generate a random number between two 2 digit numbers and if the random number is one of the numbers from the set, then ignore this number and re-randomize it. I am facing issue with the looping part. That is, if the number from the list is found twice, it would not loop again.
How do I achieve this?
public float[] nums_to_ignore = new float[] {64.0f, 80.0f, 90.0f, 92.0f, 85.0f, 73.0f, 86.0f};
public float random_num;
void Start()
{
random_num = Random.Range(60.0f, 95.0f);
for(int i = 0; i<nums_to_ignore.Length;i++)
{
if(random_num == nums_to_ignore[i])
{
random_num = Random.Range(60.0f, 95.0f); //Keep looping till you get a number not from the list
}
}
}
It would be more efficient to use a HashSet<float> for your numbers to ignore, as HashSet<T>.Contains has O(1) complexity.
You can continue to repeat your random generation using a do..while loop:
public HashSet<float> nums_to_ignore
= new HashSet<float> { 64.0f, 80.0f, 90.0f, 92.0f, 85.0f, 73.0f, 86.0f };
public float random_num;
void Start()
{
do random_num = Random.Range(60.0f, 95.0f);
while (nums_to_ignore.Contains(random_num));
}
The above would still work if you keep nums_to_ignore as a float[], but Enumerable.Contains has O(n) complexity.
Update
As pointed out by #derHugo, float values are approximations, and equality comparisons may yield incorrect results.
Fortunately, Unity has a method that is designed for comparing floats in this way: Mathf.Approximately:
void Start()
{
do random_num = Random.Range(60.0f, 95.0f);
while (nums_to_ignore.Any(n => Mathf.Approximately(n, random_num)));
}
Unfortunately, this means that GetHashCode cannot be used reliably with float, and the benefits of hashing cannot be achieved.
id go about it like this
Random random = new Random();
List<int> numbers = new List<int>();
int min = 60, max = 95;
for (int i = 0; i <= 100; i++)
{
int num;
do
num = random.Next(min,max);
while (numbers.Contains(num));
numbers.Add(num);
}
you can replace random.next by unitys Random.Range, i was sleeping on you using unity. the for i 0 to 100 loop was just there as an example how to fill the list you can easily replace it with a methode instead
I have been practicing c# nowadays and decided to write a code that converts any decimal to any base representation for practice purpose. And i have some troubles. Since i want to practice i decided to do it with an additional function where calculations take place. First i wanted to use an array to keep my result. But since ,at the beginning, i do not know the length of the array i could not define it.So i decided to use list(somehow i assumed undeclared slots are 0 as default). This is what i end up with.
class MainClass
{
static double number;
static double baseToConvert;
static int counter = 0;
static List<double> converted = new List<double>();
public static void Main(string[] args)
{
Console.WriteLine("Enter a decimal");
number = double.Parse(Console.ReadLine());
Console.WriteLine("Enter a base you want to convert to");
baseToConvert = double.Parse(Console.ReadLine());
ConverterToBase(number);
for (int i = converted.Count - 1; i >= 0; i--)
{
Console.WriteLine(converted[i]);
}
Console.ReadLine();
}
public static void ConverterToBase(double x)
{
double temp = x;
while (x >= baseToConvert)
{
x /= baseToConvert;
counter++;
}
converted[counter] = x;
counter = 0;
if (temp - x * Math.Pow(baseToConvert, Convert.ToDouble(counter)) >= baseToConvert)
{
ConverterToBase(temp - x * Math.Pow(baseToConvert, Convert.ToDouble(counter)));
}
else
{
converted[0] = temp - x * Math.Pow(baseToConvert, Convert.ToDouble(counter));
}
}
}
But after i write inputs console gets stuck without an error. My guess is that since i do not have any elements in the list " converted[counter] " does not make sense. But i do not know maybe the problem is somewhere else.
My question is not about the way i calculate the problem(Of course any suggestions are welcomed). I just want to know what i am doing wrong and how i can handle such situation(unknown array size , use of list , accessing a variable,array,.. etc from another method... ).
Thanks.
My previous answer was wrong as pointed out by #Rufus L. There is no infinite for loop. However upon further review, there seems to be an infinite recursion going on in your code in this line:
if (temp - x * Math.Pow(baseToConvert, Convert.ToDouble(counter)) >= baseToConvert)
{
ConverterToBase(temp - x * Math.Pow(baseToConvert, Convert.ToDouble(counter)));
}
ConverterToBase calls itself and there seems to be no base case nor return statement to end the recursion.
In the method named "ConverterToBase(double x)" you want to set value of 0 element. But you didn't add any element. The converted is Empty.
Firstly add value or values to your list.
So this is my code right now, and I need help so it won't makes duplicates. I need this for school so if you could explain a little bit too it would be helpful. Btw don't care about the comments it's on Swedish
int temp;
int[] myArray = new int[20]; // Array med 20 tal
Random random = new Random(); // Skapar metoden "Random"
for (int i = 0; i < myArray.Length; i++) // Forloop med 20 positioner
{
myArray[i] = random.Next(1, 100); // Ger random värden till dessa 20 positionerna
for (int j = 0; j < myArray.Length; j++)
{
if (myArray[i] > myArray[j]) // Array [i] större än Array [j]
{
//temp = myArray[j];
//myArray[j] = myArray[i];
//myArray[i] = temp;
}
}
Console.Write(myArray[i] + " ");
}
you can try linq to .Distinct() and to convert it to array use .ToArray()
var s = { 5, 7, 7, 4, 3};
var q = s.Distinct().ToArray();
At it's simplest, it looks like you probably want to
private static Random rng = new Random(); //class level definition
var myArray = Enumerable.Range(1, 20).OrderBy(X => rng.Next()).ToArray();
Alternatively, if this is for school and you need to justify your code... fill an array with the numbers 1 to 20, then use a Fisher-Yates shuffle to randomise the order of the array.
See: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Since the array has exatly the size of the random value range (which is 20), you will get every number exactly once. It's easiest to create every number once using Enumerable.Range and only change the order in which they appear.
Changing the order can be done by OrderBy(), while random is used here.
This is all based on IEnumerable<T>. So it needs to be put into an array, which is simply done by calling ToArray().
public int[] RandomlyOrderedValues()
{
Random random = new Random();
return Enumerable.Range(1, 20).OrderBy(x => random.Next()).ToArray();
}
I'm not your teacher but hope you still play around by yourself, read the docs and finally express it in your own words.
Changed question, now the random range is larger than the array size.
It's always best to work with IEnumerable<T>, there you get the most powerful tools.
// let's create inifite number of random values:
// note that the Random instance needs to be created only once,
// so it's put into a field.
private Random random = new Random();
public IEnumerable<int> InfiniteRandomValues()
{
while (true)
{
yield return random.Next(1, 100);
}
}
public int[] GetUniqueRandomValues(int numberOfValues)
{
return InfiniteRandomValues()
// only uninque values
.Distinct()
// generate the requested number of distinct values
.Take(numberOfValues)
// put it into an array.
.ToArray();
}
How does it work? When you create random values, you don't know how many it will be, because you cannot know how many duplicates it will create. A generator for an infinite number of values has certainly enough values. Think of it as a factory. Only when the IEnumerable is iterated, the values are created.
This is called "deferred execution". Only when you iterate the IEnumerable, the values are requested by the source.
Distinct works like this. It returns only as many distinct values as are requested by its caller.
Which is Take. This one reduces the number of items that are taken, but still doesn't iterate itselves.
ToArray finally iterates its source and pulls as many values as there are. Read it backwards now: It takes all values from Take, which returns 20. Itselves it takes 20 values from Distinct, which iterates its source until it got 20 distinct values. Distinct takes its values from the InifiteRandomNumbers factory and can take as many as it needs.
When you finally understand how these things work, you can use it quite intuitively.
Another, more classic implemenation
private int[] GetRandomValues()
{
Random random = new Random();
int[] values = new int[20];
for(int i = 0; i < 20; i++)
{
// create random values until you found a distinct oune.
int nextValue;
do
{
nextValue = random.Next(1, 100);
} while (ContainsValue(values, i, nextValue))
values[i] = nextValue;
}
return values;
}
// When adding the values to a List instead of an array, it would be
// much easier, but need copying the vlaues to the array at the end.
// When using the array directly, you have to know which values you
// already generated, because it's initialized with zero.
// This method checks wether the value is in the array within
// the items until endIndex.
private bool ContainsValue(int[] values, int endIndex, int valueToFind)
{
// simple linq way:
// return values.Take(endIndex).Contains(valueToFind);
// classic way:
for(int i = 0; i < endIndex; i++)
{
if (values[i] = valueToFind) return true;
}
return false;
}
I am trying to create an infinite map of 1 and 0's procedurally generated by PRNG but only storing a grid of 7x7 which is viewable. e.g. on the screen you will see a 7x7 grid which shows part of the map of 1's and 0's and when you push right it then shifts the 1's and 0's across and puts the next row in place.
If you then shift left as it is pseudo randomly generated it regenerates and shows the original. You will be able to shift either way and up and down infinitely.
The problem I have is that the initial map does not look that random and the pattern repeats itself as you scroll right or left and I think it is something to do with how I generate the numbers. e.g. you could start at viewing x=5000 and y= 10000 and therefore it need to generate a unique seed from these two values.
(Complexity is the variable for the size of the viewport)
void CreateMap(){
if(complexity%2==0) {
complexity--;
}
if (randomseed) {
levelseed=Time.time.ToString();
}
psuedoRandom = new System.Random(levelseed.GetHashCode());
offsetx=psuedoRandom.Next();
offsety=psuedoRandom.Next();
levellocation=psuedoRandom.Next();
level = new int[complexity,complexity];
middle=complexity/2;
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
int hashme=levellocation+offsetx+x*offsety+y;
psuedoRandom = new System.Random(hashme.GetHashCode());
level[x,y]=psuedoRandom.Next(0,2);
}
}
}
This is what I use for left and right movement,
void MoveRight(){
offsetx++;
for (int x=0;x<complexity-1;x++){
for (int y=0;y<complexity;y++){
level[x,y]=level[x+1,y];
}
}
for (int y=0;y<complexity;y++){
psuedoRandom = new System.Random(levellocation+offsetx*y);
level[complexity-1,y]=psuedoRandom.Next(0,2);
}
}
void MoveLeft(){
offsetx--;
for (int x=complexity-1;x>0;x--){
for (int y=0;y<complexity;y++){
level[x,y]=level[x-1,y];
}
}
for (int y=0;y<complexity;y++){
psuedoRandom = new System.Random(levellocation+offsetx*y);
level[0,y]=psuedoRandom.Next(0,2);
}
}
To distill it down I need to be able to set
Level[x,y]=Returnrandom(offsetx,offsety)
int RandomReturn(int x, int y){
psuedoRandom = new System.Random(Whatseedshouldiuse);
return (psuedoRandom.Next (0,2));
}
Your problem I think is that you are creating a 'new' random in loops... don't redeclare inside loops as you are... instead declare it at class level and then simply use psuedoRandom.Next e.g. See this SO post for an example of the issue you are experiencing
instead of re-instantiating a Random() class at every iteration like you are doing:
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
int hashme=levellocation+offsetx+x*offsety+y;
psuedoRandom = new System.Random(hashme.GetHashCode());
level[x,y]=psuedoRandom.Next(0,2);
}
}
do something more like
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
// Give me the next random integer
moreRandom = psuedoRandom.Next();
}
}
EDIT: As Enigmativity has pointed out in a comment below this post, reinstiating at every iteration is also a waste of time / resources too.
P.S. If you really need to do it then why not use the 'time-dependent default seed value' instead of specifying one?
I'd use SipHash to hash the coordinates:
It's relatively simple to implement
It takes both a key (seed for your map) and a message (the coordinates) as inputs
You can increase or decrease the number of rounds as a quality/performance trade-off.
Unlike your code, the results will be reproducible across processes and machines.
The SipHash website lists two C# implementations:
https://github.com/tanglebones/ch-siphash
https://github.com/BrandonHaynes/siphash-csharp
I've play a bit to create rnd(x, y, seed):
class Program
{
const int Min = -1000; // define the starting point
static void Main(string[] args)
{
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
Console.Write((RND(x, y, 123) % 100).ToString().PadLeft(4));
Console.WriteLine();
}
Console.ReadKey();
}
static int RND(int x, int y, int seed)
{
var rndX = new Random(seed);
var rndY = new Random(seed + 123); // a bit different
// because Random is LCG we can only move forward
for (int i = Min; i < x - 1; i++)
rndX.Next();
for (int i = Min; i < y - 1; i++)
rndY.Next();
// return some f(x, y, seed) = function(rnd(x, seed), rnd(y, seed))
return rndX.Next() + rndY.Next() << 1;
}
}
It works, but ofc an afwul implementation (because Random is LCG), it should give a general idea though. It's memory efficient (no arrays). Acceptable compromise is to implement value caching, then while located in certain part of map surrounding values will be taken from cache instead of generating.
For same x, y and seed you will always get same value (which in turn can be used as a cell seed).
TODO: find a way to make Rnd(x) and Rnd(y) without LCG and highly inefficient initialization (with cycle).
I solved it with this, after all of you suggested approaches.
void Drawmap(){
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
psuedoRandom = new System.Random((x+offsetx)*(y+offsety));
level[x,y]=psuedoRandom.Next (0,2);
}
}
Ok so I know to generate a random number one would create a method such as this:
private int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
Now lets say instead of having it take two numbers example:
RandomNumber(4, 25);
I want it to make the max a value that will be determined, example:
RandomNumber(0, Alist.Count);
Is there any way to do this? I tried making AList.Count = another int number and putting that in but to no avail.
Yes, RandomNumber(0, Alist.Count) will work perfectly. However, instead of making a function for that, you should be using one instance of Random:
Random r = new Random();
DoSomething(r.Next(0, Alist.Count));
DoSomething(r.Next(0, Alist.Count));
DoSomething(r.Next(0, Alist.Count));
// etc., whatever you want.
Edit: So you want a random element from a list?
Random r = new Random();
Alist[r.Next(0, Alist.Count)] // There's your random element.
In light of the comments in minitech's answer I thought I'd give my own spin on returning random indexes from a list - feel free to take it or leave it ;).
Personally I'd declare an extension method for O(n) shuffling a list (using a Fisher-Yates shuffle):
public static class ListExtensions
{
public static List<T> Shuffle<T>(this List<T> list, Random random)
{
if (list == null) throw new ArgumentNullException("list");
if (random == null) throw new ArgumentNullException("random");
for (int i = list.Count - 1; i >= 1; i--)
{
int j = random.Next(0, i + 1);
T temp = list[i];
list[i] = list[j];
list[j] = temp;
}
return list; // best made a void method, but for examples I'll return list.
}
}
And then if reordering the original list is acceptable, simply call:
Alist.Shuffle(new Random());
If reordering is not acceptable, and I want a random list of unique indexes I'd use:
List<int> indexes = Enumerable.Range(0, Alist.Count).ToList().Shuffle(new Random());
Or I could create a new list, with the original elements shuffled:
var shuffledList = Alist.ToList().Shuffle(new Random());
It's a pretty versatile extension method, perhaps worth adding to one's arsenal.
No, you would not create a method like that. Consider:
int num1 = RandomNumber(1, 6);
int num2 = RandomNumber(1, 6);
Almost all of the times, the two variables will end up having the same value. If you create Random instances too close in time, they will get the seed from the same clock tick, and end up giving you the same sequence of numbers.
Anyway, you can very well use Alist.Count in a call to a method, but you can't assign a number to it. You would have to add items to the list to change the Count property:
List<int> Alist = new List<int> { 1, 2, 3 };
int index = RandomNumber(0, Alist.Count);
here you go, this should do the trick. this will take your list and sort it in random order:
list = list.OrderBy( itm => Guid.NewGuid() ).ToList();