I`m facing with the problem of putting char in random position.
I have a table full of dots and I have to replace 30% of these dots with *
Size: 10x5
I used function Random.
Random rnd = new Random();
if (rnd.Next() % 10 > 3)
Console.Write(". ");
else
Console.Write("* ");
Everything is in 2 loops which hold Length and Height of table (10x5).
But it only makes PROBABILITY of 30% to make * instead of .
It takes good position but every time I start a program there is different amount of *.
It should just have 16 of * (17 - if rounded) every time I start the program
How should I suppose to make 30% always instead of probability?
You have 50 dots. calculate 50*30/100, it becomes 15.
Then generate 15 unique random numbers within range of 0 to 50. those numbers are indexes you have to replace . with *
var indexes = Enumerable.Range(0,50).OrderBy(x => rng.Next()).Take(50*30/100).ToList();
If you are working with 2d index, its fairly easy to convert 1d index into 2d index.
var i = index % 5;
var j = index / 5;
According to what #KonradRudolph said if you don't want to use OrderBy you can check out other ways to shuffle array (or create randomized set) posted here Best way to randomize an array with .NET
Here is more efficient way using Fisher-Yates algorithm that I suggest you to use instead of using OrderBy
var indexes = Enumerable.Range(0, 50).ToArray();
RandomExtensions.Shuffle(rng, indexes);
Write code that does the following:
Declare an array with x * y elements
Populate the entire array with .
Declare a loop with 0.30 * x * y iterations
For each iteration, change a randomly selected element from . to * (you must keep looking until you find one that isn't already a *)
Output the array, x elements per line
Imagine your array to be just 50 elements and forget about the rectangular shape for now. How would you approach that? Declare X dots and 50-X stars, then randomly order them. Like you would randomly order a 1->50 list of numbers.
Now how to randomly order a list of 1->50 numbers? One simple and intuitive way is imagining shuffling cards. Go through the loop and for each position obtain a random number in 1->50. Swap elements chosen (say for i=1 we got random number 7 => swap elements 1 and 7).
Here, you simply need to map this rectangle to those 50 points, which is trivial enough for 2D.
I would randomly select 30% of the possible positions
// create char array
int arrayRows = 5;
int arrayCols = 10;
char[,] arr= new char[arrayRows ,arrayCols];
// populate array with dots
for (int i = 0; i < arrayRows; i++)
{
for (int j = 0; j < arrayCols; j++)
{
arr[i,j] = '.';
}
}
Random rnd = new Random();
int numberOfPossiblePositions = arrayRows * arrayCols;
int k = 0;
while (k < numberOfPossiblePositions * 0.3) {
int position = rnd.Next(numberOfPossiblePositions);
int colIndex = position / 10;
int rowIndex = position % 10;
// if the cell already has * try again
if (arr[rowIndex,colIndex] == '*') {
continue;
}
arr[rowIndex,colIndex] = '*';
k++;
}
Create an array that holds x*y/3 starts and the rest are dots. order by random and iterate through it.
This is the array:
Enumerable.Range(0, count).Select(i => new {Text = "*", Order = rnd.Next() })
.Concat(Enumerable.Range(0, x*y - count)
.Select(i=>new { Text = ".", Order = rnd.Next() }))
.OrderBy(i => i.Order).Select(i=>i.Text).ToList();
And this is the code for iteration:
Random rnd = new Random();
int x = 10;
int y = 5;
int count = x*y/3;
var allPlaces =
Enumerable.Range(0, count).Select(i => new {Text = "*", Order = rnd.Next() })
.Concat(Enumerable.Range(0, x*y - count)
.Select(i=>new { Text = ".", Order = rnd.Next() }))
.OrderBy(i => i.Order).Select(i=>i.Text).ToList();
for (var i = 0; i < x; x++)
{
for (var j = 0; j < y; j++) { Console.Write(allPlaces[i*j + j]); }
Console.WriteLine();
}
Related
This question already has answers here:
2d Array in C# with random numbers
(2 answers)
Closed 4 years ago.
How do you print and save random values in array using Random.
So I need to have 10x10 table of rows containing random values from 0-9 but I seem to can't find a way how to get them printed!
int[,] mas = new int[9,9];
Random rand = new Random();
for (int i = 0; i <mas.Length; i++)
{
mas[i] = rand.Next(0,9);
Console.WriteLine(mas[i]);
for (int k = 0; k < mas.Length; k++)
{
mas[k] = rand.Next(0,9);
Console.WriteLine(mas[k]);
}
}
You have a small issue in your code: The array you create has two dimensions (int[9,9]). Therefore, whenever you want to read or write a cell, you need to provide two coordinates. You only set mas[i] or mas[k].
You should use max[i,k] instead in the inner loop. That way, every combination of coordinates will be tried out.
Unrelated: You mention you want a 10x10 grid of cells, but declare int[9,9]. While array indexing starts at 0, the size starts at 1. For example, if you create an array a = int[2], then it only contains entries at int[0] and int[1].
Similarly, the maximum parameter of the Random.Next(...) function is exclusive, so to get the value 9, you need to pass the maximum value 10.
If you want 2D array (i.e. you have two coordinates: lines - i and columns - j), nested loops is usual choice:
Random rand = new Random();
int[,] mas = new int[9, 9];
for (int i = 0; i < mas.GetLength(0); ++i)
for (int j = 0; j < mas.GetLength(1); ++j)
mas[i, j] = rand.Next(0, 10); // 10 will not be included, range [0..9]
Let's print the array:
for (int i = 0; i < mas.GetLength(0); ++i) {
for (int j = 0; j < mas.GetLength(1); ++j) {
Console.Write(mas[i, j]);
Console.Write(' '); // <- delimiter between columns
}
Console.WriteLine(); // <- delimiter between lines
}
Also, note that mas.length returns the overall length of the array, which will give you an IndexOutOfRangeException using your Code. Use mas.GetLength instead of mas.length
myArray.GetLength(0) -> Gets first dimension size
myArray.GetLength(1) -> Gets second dimension size
So your Code would look like this:
int[,] mas = new int[9, 9];
Random rand = new Random();
for (int i = 0; i < mas.GetLength(0); i++)
{
for (int k = 0; k < mas.GetLength(1); k++)
{
mas[i, k] = rand.Next(0, 9);
Console.Write(mas[i, k] + " ");
}
Console.WriteLine();
}
Probably like this
int[,] mas = new int[10, 10];
Random rand = new Random();
for (int i = 0; i < mas.GetLength(0); i++)
{
for (int k = 0; k < mas.GetLength(1); k++)
{
mas[i,k] = rand.Next(0, 9);
Console.Write(mas[i,k]);
}
Console.WriteLine("\n");
}
There are many things wrong with your code,
You dont know how indexing works - you want array of 10 times 10 but you create one with 9 times 9.
You need to specify both dimenstion when adding number to array.
Also,
Consolo.Writeline(string);
Will always write new line, something you dont want since you want to print 10 numbers, then new line with another then etc.
I tried to find 2 or more same elements from array x and then that duplicate to add into new array Y
So if i have in x array number like: 2,5,7,2,8 I want to add numbers 2 into y array
int[] x = new int[20];
Random rnd = new Random();
int[] y = new int[20];
int counter = 0;
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 15);
for (int j=i+1; j< x.Length; j++)
{
if (x[i] == x[j])
{
y[counter] = x[i];
Console.WriteLine("Repeated numbers are " + y[counter]);
counter++;
}
else
{
Console.WriteLine("There is no repeated numbers, numbers that are in x are " + x[i]);
}
break;
}
}
But having problems with that, when it come to the if loop it doesn't want to proceed with executing if loop (even if condition is true)
If someone could give me some suggestion, that would be helpful, thank you
There are various logical errors in your use of for. You should work more on your logic, because while libraries can be learnt by rote, logical errors are more something that is inside you.
int[] x = new int[20];
Random rnd = new Random(5);
// You don't know the length of y!
// So you can't use arrays
List<int> y = new List<int>();
// First initialize
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 15);
}
// Then print the generated numbers, otherwise you won't know what numbers are there
Console.WriteLine("Numbers that are in x are: ");
for (int i = 0; i < x.Length; i++)
{
Console.WriteLine(x[i]);
}
// A blank line
Console.WriteLine();
// Then scan
for (int i = 0; i < x.Length; i++)
{
for (int j = i + 1; j < x.Length; j++)
{
if (x[i] == x[j])
{
y.Add(x[i]);
Console.WriteLine("Repeated numbers is " + x[i]);
}
}
}
// Success/failure in finding repeated numbers can be decided only at the end of the scan
if (y.Count == 0)
{
Console.WriteLine("There is no repeated numbers");
}
I've put some comments in the code (plus the changes)
And for debugging purpose, I suggest you use a fixed Random sequence. new Random(5) (or any other number) will return the same sequence every time you launch your program.
Note that if there are multiple repetitions of a number, like { 4, 4, 4 } then the y array will be { 4, 4 }
at first:
why do u use the 'break;' ?
second:
in the first for - loop u assign a random number to x[i]
but then in the nested second loop
u already ask x[j] to check for same values (but that doesn't exist yet)
there are so many ways to check if values are equal,
but i like your approach:
so what i would suggest:
make a for - loop and assign all the random numbers to int[] x
then think again how u can evaluate
x[0] = x[1] or x[2] or x[3] ...
Try to use Linq to find the duplicate in the Array
int[] x = new int[] { 2, 5, 7, 2, 8 };
int[] y;
var result = x.GroupBy(item => item)
.Select(grp => new { key = grp.Key, Count = grp.Count() });
y = result.Where(res => res.Count > 1).Select(res => res.key).ToArray();
int[] array = new int[5] {1,2,3,4,4};
List<int> duplitcateList = array.Where(x => array.Where(y => y == x).Count() > 1).Distinct().ToList();
or you can replace last line of above code with below.
List<int> duplitcateList = array.
GroupBy(x => x).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
above code is using Linq.
suppose your first array (in question x) is array.
Linq will first check for all elements in to list which occur more then once, and select them distinctly and store it to duplicateList
if you need an array at the, you can simply convert this list to array by doing this,
int[] yArray = duplitcateList.ToArray();
Make use of linq in your code , as below
//first populate array x
var duplicates= xArray.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => y.Key)
.ToArray();
linq query above make use of groupby and find duplicate i.e. element occuring more then one time in you array and then you select those element and return result
I think this will will be the most understandable solution without complicated extension methods:
int[] x = new int[20];
// there can be at most 10 duplicates in array of length of 20 :)
// you could use List<int> to easily add elements
int[] y = new int[10];
int counter = 0;
Random rnd = new Random();
// fill the array
for (int i = 0; i < x.Length; i++)
x[i] = rnd.Next(1, 15);
// iterate through distinct elements,
// otherwise, we would add multiple times duplicates
foreach (int i in x.Distinct())
// if the count of an elements is greater than one, then we have duplicate
if(x.Count(n => n == i) > 1)
{
y[counter] = i;
counter++;
}
Im new to programming and struggling with this task:
In array X [20] random numbers from 1 to 30 are entered, in array Y enter only odd numbers from array X.
Print down Y.
int[] x = new int[20];
Random rnd = new Random();
int counter = 0;
int[] y;
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 30);
if (x[i] % 2 !=0 )
{
y = new int[counter];
counter++;
y[counter] = x[i];
}
}
foreach (int number in y)
{
Console.WriteLine(number);
}
Im having problems to fill Y array with odd numbers without defining length of Y, I tried with adding counter but getting some errors all the time,
If someone can help me with some suggestions that would be helpful, thank you!
This looks like homework, so I guess using a more appropriate collection such as a List<int> is out of the question, just as using Linq.
At y = new int[counter]; you're reinitializing the array. This happens each iteration, so your final array only holds the latest added value, and all values before that will be set to their default: 0.
You could've seen this by debugging your code by setting breakpoints, stepping through the code and inspecting your variables. You could then also have provided a more proper problem description than "getting some errors".
If you know the input is never larger than 20, you can initialize the output array to the same size and keep a counter of how many values you copied (the latter of which you already do).
Then when printing, only print the elements up till that count with a for loop instead of foreach.
So something like this:
int[] x = new int[20];
int[] y = new int[x.Length];
Random rnd = new Random();
int counter = 0;
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 30);
if (x[i] % 2 != 0)
{
y[counter] = x[i];
counter++;
}
}
for (int i = 0; i < counter; i++)
{
Console.WriteLine(y[i]);
}
Your problem is that you create a new y array for each odd number you find. You need to create the array only once and then fill it.
Since you don't know how many odd numbers there will be, I suggest to use a List<int> instead:
int[] x = new int[20];
Random rnd = new Random();
List<int> y = new List<int>(); // create the list before the loop
for (int i = 0; i < x.Length; i++)
{
x[i] = rnd.Next(1, 30);
if (x[i] % 2 !=0 )
y.Add(x[i]); // add odd number to list
}
foreach (int number in y)
{
Console.WriteLine(number);
}
See, In your case you are not aware about the number of odd numbers in that random array. so Array will not be a right choice here if you are following the current implementation. If you want the output as array, then Why not a simple LINQ with Where like this example:
First you collect all random numbers to your array as you are doing currently:
int[] randomIntegers = new int[20];
Random rnd = new Random();
for (int i = 0; i < randomIntegers.Length; i++)
{
randomIntegers[i] = rnd.Next(1, 30);
}
Now you have the all random numbers in x now perform the following operation:
int[] oddValues = randomIntegers.Where(a=> a % 2 !=0).ToArray();
I have a 2D array for a lottery I am creating. Basically it's a set of 2 integers:
int[,] coupon = new int[rowAmount, numAmount];
Where rowAmount is the amount of rows, and numAmount is the amount of numbers in that row.
Now I need to select the numbers for each row, however there may not be duplicates of a number within a specific row.
for (int r = 0; r < rowAmount; ++r)
{
for (int n = 0; n < numAmount; ++n)
{
userNum = lotRng.Next(1, numAmount * rngMult);
while (COUPON CONTAINS DUPLICATE NUMBER ON SECOND SPOT )
{
userNum = lotRng.Next(1, numAmount * rngMult);
}
coupon[r, n] = userNum;
}
}
My issue is the while part, I cannot figure out how to check if coupon contains the userNum on the second slot(The numAmount slot). For lists and stuff I used to just do list.Contains() but that doesn't seem to work on here.
Depending on the size of your array is wether it makes sense to optimize performance.
Depending on that one possibility would be to sort the array and use Array.BinarySearch .
You have to sort your array for that.
https://msdn.microsoft.com/en-us/library/2cy9f6wb(v=vs.110).aspx
So you have a number of possibilities to optimize data structure.
Solution with an array of lists is one of my favourites for this. It's very similar to my other with jagged arrays but faster- because List search is most efficient and Linq searches are not.
const int rowAmount = 1000;
const int numAmount=1000;
const int rngMult = 10;
Random lotRng = new Random();
var coupon = new List<int>[rowAmount];
int userNum;
for (int r = 0; r < rowAmount; r++)
{
coupon[r]= new List<int>();
for (int n = 0; n < numAmount; ++n)
{
do userNum = lotRng.Next(1, numAmount * rngMult);
while (coupon[r].Contains(userNum));
coupon[r].Add(userNum);
}
}
Of course it would be also possible to use a list of lists (kind of 2D lists), if necessary.
var couponLoL = new List<List<int>>();
The following quick and dirty way show a possible way of copying a 2D array to a list, but not to recommend here for several reasons (loop, boxing for value types):
var coupon= new int[rowAmount,numAmount];
[..]
do userNum = lotRng.Next(1, numAmount * rngMult);
while (coupon.Cast<int>().ToList().Contains(userNum));
In this special case it makes even less sense, because this would look in the whole 2D array for the double value. But it is worth knowing how to convert from 2D to 1D array (and then in a list).
Solution with 2D jagged arrays: If you want to access rows and columns in C#, a jagged array is very convenient and unless you care very much how effient the array ist stored internally, jagged array are to recommend strongly for that.
Jagged arrays are simply arrays of arrays.
const int rowAmount = 1000;
const int numAmount=1000;
const int rngMult = 10;
int userNum;
Random lotRng = new Random();
var coupon = new int[rowAmount][];
for (int r = 0; r < rowAmount; r++)
{
coupon[r] = new int[numAmount];
for (int n = 0; n < numAmount; ++n)
{
do userNum = lotRng.Next(1, numAmount * rngMult);
while (Array.Exists(coupon[r], x => x == userNum));
coupon[r, n] = userNum;
}
}
The above function Array.Exists works only for 1 dimension what is enough here, and needs no Linq. The same as above with Linq method .Any :
while (coupon[r].Any(x => x == userNum));
If you would have to search in two dimensions for a double value, you would need a loop more again, but still on nested loop level less than without this.
Linq is elegant, but normally not the fastest method (but you would have to handle with very big arrays of multi-million sizes for that to matter).
For other possibilities of using Linq, look for example here:
How to use LINQ with a 2 dimensional array
Another idea would be to make one-dimensional array of size rowAmount*numAmount.
It needs a little bit of thinking, but allows most simple and fastest access of searching.
Solution with loops in an array. Not elegant, but you could refactor the search loops in an own method to look better. But as a second point, in this case a linear search like shown is not a really fast solution either.
Only inner part of the 2 for-loops, not full code (as in other answers by me here):
bool foundDup;
do
{
userNum = lotRng.Next(1, numAmount * rngMult);
foundDup = false;
for (var x = 0; x < coupon.GetLength(1); x++) //Iterate over second dimension only
if (coupon[r, x] == userNum)
{ foundDup = true;
break;
}
} while (foundDup);
coupon[r, n] = userNum;
In the special context of this question, you can optimize the loop:
for (var x = 0; x < n; x++)
As you say in your comment you need to check all n fields vs. your new userNum. You can solve this with the following code:
for (int r = 0; r < rowAmount; ++r)
{
for (int n = 0; n < numAmount; ++n)
{
userNum = lotRng.Next(1, numAmount * rngMult);
for (int x = 0; x < coupon.GetLength(1); x++) //Iterate over your second dimension again
{
while (coupon[r,x] == userNum)
{
userNum = lotRng.Next(1, numAmount * rngMult);
}
}
coupon[r, n] = userNum;
}
}
For a randomized tic-tac-toe game simulator, I need to utilize a 2D array to simulate a round between 2 players. To fill the array, I've been using a simple randomizer to generate a random number between 0 and 1.
//create 2D array
const int ROWS = 3;
const int COLS = 3;
int[,] tictactoeArray = new int[ROWS, COLS];
//create random variable
Random rand = new Random();
//method to fill array with random values between 0 and 1.
private void RandomizeArray(ref int[,] iArray)
{
for (int row = 0; row < ROWS; row++)
{
for (int col = 0; col < COLS; col++)
{
tictactoeArray[row, col] = rand.Next(2);
}
}
}
But when I use a random number generator like this, I occasionally end up with an impossible combination of values in relation to tic-tac-toe. As in the value 1 will occur 6 or more times, and make the game unfair for the other "player". I've done extensive searching, but haven't found a way to (more or less) evenly distribute the 2 values. Any suggestions?
You need to simulate the turns of player. instead of randomly generating 1 or 2, you can follow the below algorithm only assume
0. initialize all 9 positions with 0 on tic-tac-toe board
1. select a number between 0 to 8 randomly. ( which denotes one of 9 positions)
2. put 1 in that position
3. select another number between 0 to 8 randomly ( if it collides with number previously selected pull other random number.
4. put 2 in that position.
5. repeat till all the 9 positions are filled.
Approach 2 ..
create a Linked list of 9 numbers (from 1 to 9).
draw a number (name it x) between 1 to size of the Set ( which will be 9 for first draw)
read the value at the position 'x' and put 1 in that position
remove the element at position x
draw another number x ( between 1 to 8 this time ) and put 2 in that position.
remove the element at position x.
keep doing till linked list is empty.
It seems simpler just to pre-create the x's and o's in a 1 dimensional array and then randomly shuffle them like so
//Both X and O always get at least 4 moves
List<int> common = new List<int> { 0, 0, 0, 0, 1, 1, 1, 1 };
//Either X or O gets a 5th move, make this equally likely
Random rand = new Random();
common.Add(rand.Next(0, 2));
//Randomly shuffle the X's and O's, this creates a completed tic tac toe board
//This can have more than one winner since we aren't stopping when someone wins
//as would normally be done
var randomBoard = common.OrderBy(x => rand.Next()).ToArray();
//Convert to a 2 dimensional array if desired
int[,] twoDRandomBoard = new int[3, 3];
for (int i = 0; i < randomBoard.Length; i++)
twoDRandomBoard[i / 3, i%3] = randomBoard[i];
You will end up with some boards having two "winners", but this is the way it has to be if you assume the entire board is full which is what you are showing in your question. If you want to stop once someone wins then that will be different, but this will work for a random complete board.
The literal answer to the question title would be something like this:
var random = new Random();
var randomValues = new[] { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 } // enough values to fill board
.Select(x => new { Weight = random.Next(), Value = x }) // add random weight
.OrderBy(x => x.Weight) // order by weight to create random sort
.Take(9) // only need 9 of the 10 values
.ToList();
var ticTacToeBoard = new int[3, 3];
var index = 0;
for (int row = 0; row < 3; row++) // fill the two-dimensional array
{
for (int column = 0; column < 3; column++)
{
ticTacToeBoard[row, column] = randomValues[index].Value;
index++;
}
}
Most of the time, this "random without replacement" technique will result in a possible ending game board, however, you'll occasionally get a game board with 3 zeroes and 3 ones in a row, which would not be valid. To solve that, you could put the above code in a loop and only exit the loop in the case of a valid game board.
That said, I agree that #meetthakkar's approach to actually simulate a game would more sense for this particular problem.
Okay, I might be a little confused but it doesn't make sense to have a tic-tac-toe board represented with 1 or 0 being populated from that start, maybe 1 or 2.
Would recommend doing the following :
private static ThreadLocal<Random> rand = new ThreadLocal<Random>(()=>new Random());
const int PLAYER_ONE = 1;
const int PLAYER_TWO = 2;
//color decided by who goes first in tic-tac-toe?
private static int playingColor;
private static void PlayRound(int[][] board)
{
var playableCoords = new List<Tuple<int,int>>();
for(int x=0;x<board.Length;x++)
for(int y=0;y<board[x].Length;y++)
if(board[x][y] == 0)
playableCoords.Add(Tuple.Create(x,y));
//check for a terminal board state before you do this method
if(!playableCoords.Any()) return;
var randm = rand.Value;
var vl = playableCoords[ randm.Next(playableCoords.Count - 1) ];
board[vl.Item1][vl.Item2] = playingColor ;
}
There are more efficient ways to do this, if you were dealing with a board with a lot of possible combinations then I would suggest keeping a record of available spots and taking from there, but for a 3x3 game don't see the need to do that.
If you want to do this until it is full just do this :
var board = new int[3][3];
for(int i=0;i<9;i++)
{
playingColor = (i%1)+1;
PlayRound(board);
}
Doesn't really make sense to me but that is how you would simulate a game.
void RandomizeArray(ref int[,] iArray)
{
for (int row = 0; row < ROWS; row++)
{
for (int col = 0; col < COLS; col++)
{
Random rand = new Random();
tictactoeArray[row, col] = rand.Next(2);
}
}
}
please put Random rand = new Random() into the funcion body.
Maybe better every times it make a new rand .