5

I am trying to develop Tic Tac Toe game where player 1 will click one button to put "X" and later player 2(Computer) will put "O" to other buttons randomly on first step.For that I need to create a random number between 0-8 except the one clicked by player 1.

I am using following code to generate random number

Random random=new Random();
int number=random.nextInt(9);
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • 1
    Hint: Keep track of the previously generated number(s). – devnull Mar 02 '14 at 14:09
  • Do you have any expectation on the distribution of values? – Stefano Sanfilippo Mar 02 '14 at 14:10
  • Does the random number provider need to be thread safe? – fge Mar 02 '14 at 14:10
  • `I need to create a random number between 0-8 except the one clicked by player 1` actually you need to avoid **all numbers clicked by user and by computer** you need like an array to track all occupied locations, and generate a number that fit in the remaining locations – Yazan Mar 27 '16 at 07:28

8 Answers8

4

If you want random numbers from 0 to 8 with one value excluded, then there are really 8 possible values, not 9. So generate a random number from 0 to 7 — random.nextInt(8) — and if the result is greater than or equal to your excluded value, add 1 to it.

Wyzard
  • 33,849
  • 3
  • 67
  • 87
1

I'd pre-generate the list of random number, and then just allocate from it. e.g.

// Initialize the list:
List<Integer> numbers;

public void init() {
    numbers = new LinkedList<Integer>(9);
    for (int i = 0; i < 9; ++i) { 
        numbers.add(i);
    }
}

public int nextSelectNumber() {
    int index = random.nextInt (numbers.size());
    return numbers.get(index);
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
1

You don't need just a random rumber between 0 and 8 except the last one the player selected, you need a random number from the list of options you have. This may vary since human and computer will choose different (random?) numbers. This is not as easy as other people already answered. An option may be using a List<Integer> for the job that saves the current options to choose. Based on the code provided in @Mureinik's answer:

class TicTacToeCells {
    private static final int MAX_CELLS = 9;
    private List<Integer> cells;
    private Random random;

    public void init() {
        random = new Random();
        cells = new ArrayList<Integer>(MAX_CELLS);
        for (int i = 0; i < MAX_CELLS; ++i) { 
            numbers.add(i);
        }
    }

    //for human moves
    public boolean canPickCell(int cellToPick) {
        return cells.contains(cellToPick);
    }

    public int pickCellByComputer() {
        int index = random.nextInt(cells.size());
        return cells.get(index);
    }

    public void pickCell(int cellToPick) {
        cells.remove(cellToPick);
        //further logic to display the move or something else...
    }
}
Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
1

Do nextint(availableSpaces) and take that result as an ordinal, i.e. 3 means the third available position

Jaime Agudo
  • 8,076
  • 4
  • 30
  • 35
1

You'll eventually need to worry about removing more than one position, so it's best to keep track of a collection of available positions. Some pseudo-code for a possible solution:

//when you first run the game
List<Integer> availablePositions = new ArrayList<Integer>();
for (int i =0; i<boardSize; i++)
   availablePositions.add(i);

//when you click on a board
availablePositions.remove(myPosition)

//when you have the computer pick a position
Random rand = new Random();
int  n = rand.nextInt(availablePositions.size());   //gets a number between 0 and remaining number of positions

int pickedPosition = availablePositions.get(pickedPosition); //get computer's position
availablePositions.remove(pickedPosition);  //remove computer's position from available options
0

You could use the following:

    int alreadyPickedNumber=3 //Number to exclude
    int number=random.nextInt(9);
    while(number==alreadyPickedNumber){
         number=random.nextInt(9);
    }
ltalhouarne
  • 4,586
  • 2
  • 22
  • 31
0

Keep track of the already generated numbers. For instance:

@ThreadSafe
public final class TicTacToeNumberChooser
{
    private final Random random = new Random();
    // Default initialization value for boolean arrays is false
    private final boolean[] picked = new boolean[9];
    private int nrPicked = 0;

    public synchronized int randomPick()
    {
        if (nrPicked == 9)
            throw new IllegalStateException();

        int ret;
        while (true) {
            ret = random.nextInt(9);
            if (picked[ret])
                continue;
        }
        picked[ret] = true;
        nrPicked++;
        return ret;
    }

    public synchronized boolean isPicked(final int number)
    {
        return picked[number];
    }

    public synchronized void doPick(final int number)
    {
        if (picked[number])
            throw new IllegalStateException();
        picked[number] = true;
        nrPicked++;
    }
}
fge
  • 119,121
  • 33
  • 254
  • 329
0

Let the numbers be 0-8 and "set used" has used numbers in it. Then chose a number in range 0 to (8-used.size()) and then traverse through set to find number at that index.

int get_random_int(set<int>& used) {
    int no_of_numbers = 8 - used.size();     
    int index = rand() % no_of_numbers;
    int target = 0;
    for (int i = 0; i <= index;) {
         if (used.find(target) == used.end()) i++;
         target++;
    }
    return target;
}

There are many similar methods to do it. I think this will give you a perfectly random pick from remaining numbers.

THUNDEROCK
  • 76
  • 2
  • 5