3

I have created a tic tac toe program that works in that it allows a player to select a move in a 2d array by selecting the cords, then the computer makes a move.

The program works, but the computer's move is sequential rather then random and will always select the next available space in the array. Now that I have the game working, I want to improve the program into three levels of difficulty:

Easy = Randomly generated move by computer Medium = Randomly generated move by computer that checks to block player and complete line Hard = Selection of optimal move every time through recursion

How I can get the computer to randomly select a set of cords in my array?

(My current basic for loop for computers move)

static void Computermove(char[,] gamegrid, char fin)
    {

        Console.WriteLine("\nComputer's turn");
        Console.ReadKey();

        int x = 0;
        int y = 0;
        for (x = 0; x < 2; x++)
        {
            for (y = 0; y < 2; y++)
                if (gamegrid[x, y] == ' ') break;
            if (gamegrid[x, y] == ' ') break;
        }

        if (x * y == 9)
        {
            fin = 'X';
        }
        else
            gamegrid[x, y] = 'O';

    } // End Computermove
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Mark Searle
  • 55
  • 1
  • 7

3 Answers3

2

Create a new instance of the Random class and use the Next() method to create the two random numbers representing the coordinates.

Here's the code:

var r = new Random();

var randomX = r.Next(3);
var randomY = r.Next(3);

Update:

Here's how the method could look like:

static void Computermove(char[,] gamegrid, char fin)
{
    if (!ContainsEmptyCells(gamegrid))
    {
        // table is full; probably nobody won
        return;
    }

    bool goodRandomCoordinateFound = false;

    int row = 0, column = 0;

    var random = new Random();

    while (!goodRandomCoordinateFound)
    {
        row = random.Next(3);
        column = random.Next(3);

        if(gamegrid[row, column] == ' ')
            goodRandomCoordinateFound = true;
    }

    gamegrid[row, column] = 'O';
}

I found the problem that was causing the StackOverflowException. It is a pretty subtle one, but the conclusion is that when retrying to generate random coordinates, the same instance of Random should be used, instead of creating a new one.

This is because Random does not really generate truly random numbers. When a new Random() instance is created, it is initialized with a seed value that is based on the current time.

If you create multiple instances of Random with the same seed value, they will create the same random numbers stream.

In our example, in case we needed new random coordinates to be generated, a new instance of Random was created without specifying a seed, so the seed was using the current time. Due to the fact that the random instances were created extremely quickly, the seed value was the same, therefore the random values were the same, causing infinite recursion.

I've rewritten the method to reuse the random instance, which causes subsequent calls to Next(3) to yield other values than the ones we currently have.

Cristian Lupascu
  • 39,078
  • 16
  • 100
  • 137
  • Thanks for this. I now have the program selecting the random position as I wanted. I do have a error though where it breaks if its left with winning moves? – Mark Searle Nov 17 '12 at 18:26
  • static void Computermove(char[,] gamegrid, char fin) { var random = new Random(); int row = random.Next(2); int column = random.Next(2); if (gamegrid[row, column] != ' ') { Computermove(gamegrid,fin); } else { gamegrid[row,column] = 'O'; } } // End Computermove – Mark Searle Nov 17 '12 at 18:27
  • An unhandled exception of type 'System.StackOverflowException' occurred – Mark Searle Nov 17 '12 at 18:35
  • Alright, I see now. This happens because there are probably no empty cells and `Computermove` gets called recursively infinitely. In this case, I think you should test if there are empty cells at the beginning of the method. – Cristian Lupascu Nov 17 '12 at 18:37
  • Hmm I see I was using // if (row * column == 9) { fin = 'X'; } else gamegrid[x, y] = 'O'; // but cannot get this to work now – Mark Searle Nov 17 '12 at 18:45
  • Thanks for all your help btw! The code you provided is still getting the same error. – Mark Searle Nov 17 '12 at 18:58
  • let me know what is the value of the `gamegrid` parameter for which you get the error – Cristian Lupascu Nov 17 '12 at 19:00
  • static void initialise_game_grid(char[,] gamegrid) { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { gamegrid[x, y] = ' '; } } // End Loop } // End initialise_game_grid – Mark Searle Nov 17 '12 at 19:09
  • @MarkSearle I finally figured it out. Please see the edit to my answer. – Cristian Lupascu Nov 17 '12 at 19:35
  • That's it! Great job and thanks for the explanation I don't think I ever would have found the reason for that error. – Mark Searle Nov 17 '12 at 19:55
0

Since the computer can't chose all fields, you need a 2-Step process

  • count the number of free fields (=:N)
  • create a random number in the range 0..N-1
  • use this number to chose a field
Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
0

Keep a list of free coordinates, whenever a coordinate is picked by either player or AI remove it from the list. Randomize based on the number of items in the list, so if there are 5 entries in the list generate a random number between 1 and 5, pick the coordinate out of the list.

Or simpler keep track of the number of free coordinates, example you have 5 free coordinates generate a number 1-5 and just iterate over the board to get to the 5th position

Tommy Grovnes
  • 4,126
  • 2
  • 25
  • 40