2

in this program, i want to replace three 'N's at random location with three 'O's. i've tried to use a forloop to achieve that however, the amount of 'O' that i get is inconsistent. i'm not exactly sure which part went wrong...

static char grid[][];
public static void Board()
{
    Random rn = new Random();
    grid = new char [3][3];
    for(int row = 0; row<grid.length; row++)
    {
        for(int col = 0; col<grid.length; col++)
        {
        grid[row][col] = 'N';     
            for(int i = 0; i<3; i++)
            {
            grid[rn.nextInt(3)][rn.nextInt(3)] = 'O';  
            }
        System.out.print(grid[row][col]);   
        }
        System.out.println();
    }       
}
4
  • If you want to replace 3 cells in the grid why do you use nested loops at all? Just one loop should be sufficient, i.e. loop until you set 3 Os, e.g. by randomly choosing one, checking whether it contains something other than an O and then setting it, while if it contains an O already you take another one until you set 3 Os. Of course this might loop a long time if the same cells are chosen so you might want to keep track of those that are still available. Commented Aug 10, 2016 at 9:18
  • 1
    @john the is a bug on your limit in your inner for loop. This work actually, because you have the same number of rows than columns. you should check col against grid[row].length. And @Eran answer is the good one Commented Aug 10, 2016 at 9:19
  • Please note that changing the title of your question to closed thread- solved is not an acceptable way to mark that your question was answered. If you got the answer you were looking for, you should mark that answer as accepted (click the check mark next to it). Commented Aug 11, 2016 at 7:20
  • @Eran oh i see, i've already marked it thanks alot! Commented Aug 11, 2016 at 9:49

4 Answers 4

2

You need to separate your loops.

First initialize the array with Ns, and then replace 3 Ns :

for(int row = 0; row<grid.length; row++) {
    for(int col = 0; col<grid[row].length; col++) {
        grid[row][col] = 'N'; 
    }
}
for(int i = 0; i<3; i++) {
    grid[rn.nextInt(3)][rn.nextInt(3)] = 'O';  
}

Running the for(int i = 0; i<3; i++) inside the inner initialization loop causes 3 random cells to be assigned O 3x3 times, and these cells can later be overwritten with N, since you are doing it before the initialization is done.

You should also note that the cells assigned by grid[rn.nextInt(3)][rn.nextInt(3)] = 'O' may not be 3 unique cells, so you might still end up with less than 3 Os.

You can replace the second loop with a while loop to ensure that exactly 3 cells are replaced :

int i = 0;
while(i < 3) {
    int x = rn.nextInt(3);
    int y = rn.nextInt(3);
    if (grid[x][y] != 'O') {
        grid[x][y] = 'O';
        i++;
    }  
}
Sign up to request clarification or add additional context in comments.

5 Comments

as mentioned by @john, there's still a slight typo there in the inner loop - should be grid[row].length
also theoretically the while loop could be infinite.
@Drgabble Yep, that's a better practice in general, though for square arrays it makes no difference.
@Drgabble you would have to by very unlucky for that to happen.
yes true! But still better practice not to I would say
1

Sometimes a little bit of abstraction makes things much easier.

Why do random stuff within your loop? Your constraint is that you want exactly three out of nine array indexes to be "different. Thus: don't iterate the array and call the random function in there.

Simply create random numbers in the range from (0,8) until you got three different values; and then update the corresponding indexes within your array.

You see, the tricky part is about exactly three; that could be achieved with code like:

Set<Integer> randomIndexesToChange = new HashSet<>();
while (randomIndexesToChange.size() < 3) {
 randomIndexesToChange.put( ... another random number from (0, 8) );
}

Or as RealSceptic suggested, you create a collection object that simply contains all indexes from 0 to 8; and then you use shuffle; to then pick the first three:

List<Integer> allIndexes = Arrays.asList(0, 1, ...
Collections.shuffle(allIndexes);
// now allIndexes is in random order
// so allIndexes.get(0) gives you the first index that should be O

...

1 Comment

It would be better to use shuffle then to "generate random numbers until you got three different values" which can theoretically be an endless loop. The idiom is - create a collection with the serial numbers, shuffle it, take as many as you need from the shuffled collection.
0

Another approach to fill your grid with 3 random Os would be to do it right upon initialization:

int numOs = 3; 
for(int row = 0; row<grid.length; row++) {
  for(int col = 0; col<grid[row].length; col++) {
    if( numOs > 0 && randomConditionForO() ) {
       grid[row][col] = 'O'; 
       numOs--;
    } else {
       grid[row][col] = 'N';
    }
  }
}

randomConditionForO() could be anything like rn.nextInt() % 2 == 0 etc. If you want to provide a probability for setting an O, let's say 25%, you could use something like rn.nextInt(100) < 25 or rn.nextFloat() < 0.25f.

The problem here, however, would be that you could get less than 3 Os due to the randomness off the condition so you might want to counter that. One way might be to provide a count for the Ns as well and increase probability for an O accordingly.

Example:

int numOs = 3;
int numNs = gridSize - numOs; //gridSize would be 3x3 = 9 in your example 
for(int row = 0; row<grid.length; row++) {
  for(int col = 0; col<grid[row].length; col++) {
    if( numOs > 0 && rn.nextInt(numNs + 1) < numOs ) {
       grid[row][col] = 'O'; 
       numOs--;
    } else {
       grid[row][col] = 'N';
       numNs--;
    }
  }
}

Here rn.nextInt(numNs + 1) < numOs would mean that the probability to chose an O increases with each chosen N and decreases with each chosen O. Since nextInt(bound) will return an integer between 0 (inclusive) and bound (exclusive) we need to pass in numNs + 1 so that if there are no more Ns available we use the bound 1 and since it is exclusive we'll always get 0, which is smaller than numOs as long as there are Os available (thus getting 100% probability).

Comments

-1

Building on @GhostCats answer:

static char grid[][];
public static void Board()
{
    int width=3, height=3;

    // create new array filled with 'N'
    grid = new char [width][height];
    for(char[] col: grid)
        Arrays.fill(col, 'N');

    // create list of all possible indexes
    List<Integer> index = IntStream.range(0,width*height).boxed()
                                     .collect(Collectors.asList());
    Collections.shuffle(index);

    // replace first three indexes with 'O'
    for(int i=0; i<3; i++)
        grid[index.get(i)/width][index.get(i)%width] = 'O';    
}

Requires Java 8.

3 Comments

Not the downvoter, but you haven't actually tested your code, have you? You refer to row when you declared col. And also, building on someone else's answer, though it should be mentioned, is not sufficient - your answer should stand on its own, thus it should explain what's going on. And better mention that you are relying on Java 8 as well.
Just posting code based on someone else's answer looks a lot like you want to profit from their effort. Also an answer should not just contain a block of code but should also explain what has been done and why. Otherwise it's hard for the OP to learn something (and this clearly looks like a learning exercise).
Sure thing, thanks for the feedback. My thoughts were that it added enough to be considered it's own answer, and had enough comments to explain how it worked. I'll be more verbose in future.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.