Philipp Penalber
Philipp Penalber

Reputation: 31

Creating a tic-tac-toe program using a 2-D array and functions in C

In my code I have a total of ten functions and I was only able to fully code two of them and i have my main function all set up. The other functions I am completely lost on. It would be a huge help if you can add example coding and explanations so I could get a better understanding.

Here is my code:

#include <stdio.h>
#define SIZE 3

/* main function */
int main ()
{
    char board[SIZE][SIZE];
    int row, col;

    clear_table (board);
    display_table (board);

    do 
   {
        get_player1_mover (board, row, col);
        generate_player2_move (board, row, col);
    } while (check_end_of_game (board) == false);
    print_winner (board);

    return 0;
}

/* display table function */
void display_table (int board[][SIZE], int SIZE)
{
    int row, col;
    printf ("The current state of the game is:\n");
    for (row = 0; row < SIZE; row++) 
    {
        for (col = 0; col < SIZE; col++) 
        {
            char board[row][col];
            board[row][col] = '_';
            printf ("%c ", board[row][col]);
        }
        printf ("\n");
    }

}

/* clear table function */
void clear_table (int board[][SIZE], int SIZE)
{
    int row, col;
    char board[row][col];
    for (row = 0; row < SIZE; row++) {
        for (col = 0; col < SIZE; col++) {
            if (board[row][col] == 'x' || array[row][col] == 'o') {
                board[row][col] = '_';
            }
        }
    }

}

/* check table full function */
/* return True if board is full */
/* return False if board is not full */
check_table_full (int board[][SIZE], int SIZE)
{

/* update table function */
/* updates board with player moves */
/* return nothing */
void update_table (int board[][SIZE], int SIZE) 
{

/* check legal option function */
/* True if legal, False if not */
/* if move is within bounds of board or on empty cell */
check_legal_option (int board[][SIZE], int SIZE) 
{

/* generate player2(computer) move function */
/* generate a random move */
/* update board */
/* print out current state of board */
void generate_player2_move (int board[][SIZE], int SIZE) 
{

/* check three in a row function */
/* return zero if draw */
/* return one if player1 has three in a row */
/* return two if player2 has three in a row */
check_three_in_a_row (int board[][SIZE], int SIZE) 
{

/* check end of game function */
/* return True if game ended */
/* return false if game continues */
check_end_of_game (int board[][SIZE], int SIZE) 
{


/* get player 1 move function */
/* if given move is not valid get another move */
/* update board */
/* print out board */
void get_player1_move (int board[][SIZE], int SIZE) 
{
    int row, col;
    printf
        ("Player 1 enter your selection [row, col]: ");
    scanf ("%d,%d", &row, &col);
    char board[row][col];
    board[row][col] = 'o';
    printf ("The current state of the game is:\n");


/* print winner function */
void print_winner (int board[][SIZE], int SIZE) 
{

The functions I've completed are display_table and the clear_table and I almost completed get_player1_move but I am stuck with how to make sure it prints out table.

Upvotes: 0

Views: 5186

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84561

It is apparent you are stuck on understanding your function declarations and where you have used int and where you have used char. (types matter).

Before addressing anything else, the No. 1 thing you can do to let your compiler help you code is to enable compiler warnings. That means at minimum for gcc/clang, add -Wall -Wextra as compiler options (recommend: -Wall -Wextra -pedantic -Wshadow), for VS (cl.exe) use /W3 and -- do not accept code until it compiles cleanly without warning! Your compiler will tell you the exact line (and many times the column) where it sees problematic code. Let the compiler help you write better code.

Next, you use the constant SIZE to provide the dimensions for your board. Good! If you need a constant -- #define one or more -- as you have. Understand, when you define a constant, it has file scope, it can be seen and used within any function within that file (or within any file that includes the header in which the constant is defined). As such, there is no need to pass SIZE as a parameter to your functions. They know what SIZE is, e.g.:

void display_table (char board[][SIZE]);
void clear_table (char board[][SIZE]);

Next, you cannot re-declare char board[row][col]; as you have in clear_table(). That declaration "shadows" the declaration of board from main() that you pass a parameter, e.g. void clear_table (char board[][SIZE]);. (thus the advice of including the -Wshadow compiler option to warn you when you try something that creative....) The same applied to display_table.

When you re-declare board in clear_table (e.g. char board[row][col];) and then use board in clear_table, you are updating the re-declared board that is local to the function (and is thus destroyed when the function returns), so the changes are never seen back in main().

Further, you declare board as type char in main(), e.g.

    char board[SIZE][SIZE] = {{0}}; /* initialize all variables */

but then attempt to pass board as type int, e.g.

void display_table (int board[][SIZE], int SIZE) {

Your parameter needs to match your declaration type.

With those simple adjustments and cleaning up your clear_table and display_table just a tad, you could do something like:

/* display table function */
void display_table (char board[][SIZE])
{
    int row, col;
    printf ("\nThe current state of the game is:\n");
    for (row = 0; row < SIZE; row++) {
        for (col = 0; col < SIZE; col++) {
            putchar (' ');
            if (board[row][col])
                putchar (board[row][col]); /* use putchar for a single char */
            else
                putchar ('_');
        }
        putchar ('\n');
    }

}
/* clear table function */
void clear_table (char board[][SIZE])
{
    int row, col;
    // char board[row][col]; /* don't redeclare board */
                             /* your compiler should be screaming warnings */

    for (row = 0; row < SIZE; row++)
        for (col = 0; col < SIZE; col++)
            board[row][col] = '_';      /* just clear, no need to check */

}

Now simply make sure you provide a prototype of the functions above main() in your file so main() knows of the existence of both functions before they are called in main() (alternatively, you could just move the definition of both functions above main()). (a function must be declared before it can be used -- that means above the function where it is called in a "top down read" of the file)

Your code for both functions wasn't that far off, you were just missing a few implementation details (rules). To provide a working clear_table and display_table (along with a cheezy diagonal_x function to initialize the diagonal to all 'x' and the remainder to 'o', you could do:

#include <stdio.h>

#define SIZE 3     /* if you need a constant, #define one (Good!) */

void display_table (char board[][SIZE]);
void clear_table (char board[][SIZE]);

/* cheezy init funciton */
void diagonal_x (char (*board)[SIZE])
{
    for (int row = 0; row < SIZE; row++)
    for (int col = 0; col < SIZE; col++)
        if (row == col)
            board[row][col] = 'x';
        else
            board[row][col] = 'o';
}

int main (void)     /* no comment needed, main() is main() */
{
    char board[SIZE][SIZE] = {{0}}; /* initialize all variables */

    clear_table (board);        /* set board to all '_' */
    display_table (board);      /* output board */

    diagonal_x (board);         /* init board to diagonal_x */
    display_table (board);      /* output board */

    /* 
    do {
        get_player1_mover (board, row, col);
        generate_player2_move (board, row, col);
    } while (check_end_of_game (board) == false);
    print_winner (board);
    */

    return 0;
}

/* display table function */
void display_table (char board[][SIZE])
{
    int row, col;
    printf ("\nThe current state of the game is:\n");
    for (row = 0; row < SIZE; row++) {
        for (col = 0; col < SIZE; col++) {
            putchar (' ');
            if (board[row][col])
                putchar (board[row][col]); /* use putchar for a single char */
            else
                putchar ('_');
        }
        putchar ('\n');
    }

}
/* clear table function */
void clear_table (char board[][SIZE])
{
    int row, col;
    // char board[row][col]; /* don't redeclare board */
                             /* your compiler should be screaming warnings */

    for (row = 0; row < SIZE; row++)
        for (col = 0; col < SIZE; col++)
            board[row][col] = '_';      /* just clear, no need to check */

}

(note: whether you include enclosing '{' and '}' on loops or conditionals with only a single expression is up to you. It may help keep things straight for you -- up to you)

Also note, you can pass board as a pointer-to-array of char [SIZE], e.g. char (*board)[SIZE] as well as char board[][SIZE], they are equivalent.

Example Use/Output

Note: I added a space before each character in the board to make the display a little more readable -- you can remove it if you like.

$ ./bin/checkerinit

The current state of the game is:
 _ _ _
 _ _ _
 _ _ _

The current state of the game is:
 x o o
 o x o
 o o x

This should get your going. Let me know if you have further questions.

Upvotes: 1

Related Questions