-1

I started C and I am trying to write a tic tac toe with an opponent which searches a random number between 1 to 9 and then fill the slot with “O”. However, when the random number detects an occupied slot, it will continue to fill other empty slots without giving the player the turn. How do I resolve this?

I made two arrays, one for the game screen, one for the memory of the slots.

I’m sorry I couldn’t chuck out the code since I thought it’s all important and is there any better way to do this? Sorry for my writing style if it is a bit confusing, and I think there are unimportant variables.

Here is my code:

#include <stdio.h>
#include <stdlib.h> 
#include <time.h>

char values[3][4] = {  // screen board
    {46, 46, 46,'\n'},
    {46, 46, 46,'\n'},
    {46, 46, 46,'\n'}
};

double memory[3][4] = { // memory board to put values
    {0, 0, 0,'\n'},
    {0, 0, 0,'\n'},
    {0, 0, 0,'\n'}
};

int player(int i, char values[3][4]) {
    int input;

    printf("enter position: ");
    scanf("%i", &input);

    int x = (((input) / 3.3) - 3) * -1; //  important math to convert to num
    int y = (input + 2) % 3;            //  important math to convert to num

    if (memory[x][y] == 0) {
        values[x][y] = 'X';
        memory[x][y] = 1;

        printf("%s", values);
        getchar();
        return 0;
        getchar();
    } else {
        printf("Wrong!, choose another line\n");
        printf("%s", values);

        getchar();

        player(i, values);
    }
}


int opponent(char values[3][4]) {  //function opponent
    int count = 0;
    srand(time(NULL));

    int random = (rand() % 9) + 1;   // create random number

    for (count = 0; count < 9; count++) {
        int x = (((random) / 3.3) - 3) * -1;
        int y = (random + 2) % 3;

        if (memory[x][y] == 0) {  // if memory is empty, do the following, loop stucks here
            values[x][y] = 'O';
            memory[x][y] = 2;

            printf("Opponent Move\n");
            printf("%s", values);

            count++;

            return 0;
        } else {            // if memory is not 0, do this. Error starts here
            getchar();
            printf("Move is %i", random);

            opponent(values);       // it calls itself to do a loop, 
        }
    }
}

int main() {
    int input;
    int i = 2;;

    for (i = 2; i < 9; i++) {   
        player(i, values);  //Player goes first
        getchar();
        opponent(values);   
    }
}
Lactobacillus
  • 27
  • 1
  • 1
  • 7

1 Answers1

0

Instead of having two independent values and memory, use an enum array to represent the game map.

enum Square { VACANT, X, O } squares[3][3], move = X;

It is initialised according to The initialization of static variables in C.

You probably need a function to decide if a player has won,

/* Checks if the player who's move it was won. */
static int is_win(void) {
    return (squares[0][0]==move && squares[0][1]==move && squares[0][2]==move)||
        (squares[1][0]==move && squares[1][1]==move && squares[1][2]==move)||
        (squares[2][0]==move && squares[2][1]==move && squares[2][2]==move);
    /* Etc. */
}

As well as a function for printing the board,

static const char letters[] = { '/', 'X', 'O' };

static void print_board(void) {
    printf("%c %c %c\n%c %c %c\n%c %c %c\n",
        letters[squares[0][0]], letters[squares[0][1]], letters[squares[0][2]],
        letters[squares[1][0]], letters[squares[1][1]], letters[squares[1][2]],
        letters[squares[2][0]], letters[squares[2][1]], letters[squares[2][2]]);
}

The code as you have it shadows the global state with parameters to the functions. This is very confusing. Think about whether you need the parameter to do the function's job. When one has complicated states that are defined in multiple files, it's probably best to have a agglomeration game object, but for simple games I think it's fine to have a global state.

Instead of playing until 7 moves, use a simple state machine to keep track of the game state. One can typedef the functions (How do function pointers in C work?) player and opponent and put them in a static array to simplify greatly the game loop. Consider,

/* Move returns whether we should continue. */
typedef int (*Move)(void);

/* Implements Move. */
static int player(void) {
    printf("player:\n");
    /* FIXME: player move. */
    return is_win() ? 0 : (move = O, 1);
}

/* Implements Move. */
static int opponent(void) {
    printf("opp:\n");
    /* FIXME: Chose randomly from all of it's allowed moves? */
    return is_win() ? 0 : (move = X, 1);
}

static const Move states[] = { 0, &player, &opponent };

Then your main is just,

int main(void) {
    while(states[move]()) print_board();
    printf("%c wins.\n", letters[move]);
    return 0;
}

Edit: Definitely have a state where it's a tie, perhaps when there are no moves left.

Neil
  • 1,767
  • 2
  • 16
  • 22
  • Thank you very much. I'll learn this code as i haven't learn about enum and statics. – Lactobacillus Nov 10 '18 at 05:24
  • One could skip defining `static` in this example and it would compile fine; apart from performance issues, it's use is self-documenting; `static` data and functions are not and cannot be called from other files, and it's use is associated with the file, (strictly, compilation unit); sort of `private`. https://stackoverflow.com/questions/572547/what-does-static-mean-in-c. `enum`: https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Enumerations. – Neil Nov 11 '18 at 20:30