views:

85

answers:

4

I'm learning C, so decided to try and make a Tic Tac Toe game, using ASCII art as the table.

I don't have much yet...

#include <stdio.h> 

#define WIDTH 2;

#define HEIGHT 2;

int main (int argc, char *argv[]) {

    printf("Welcome to Tic Tac Toe!\n\n");

    int width = WIDTH;
    int height = HEIGHT;

    // Make grid

    for (int y = 0; y <= height; y++) {

        for (int x = 0; x <= width; x++) {

            printf("%d%d", x, y);

            if (x != width) {
                printf("||");
            }

        }


        if (y != height) {
            printf("\n");

            for (int i = 0; i < (width + (width * 4)); i++) {
                printf("=");
            }

            printf("\n");
        } else {
            printf("\n");
        }


    }

    // Ask for user input

    printf("Please enter the cell where you would like to place an X, e.g. for example the first top left cell is '00'\n");

}

When ran on the command line, I get this output

Welcome to Tic Tac Toe!

00||10||20
==========
01||11||21
==========
02||12||22
Please enter the cell where you would like to place an X, e.g. for example the first top left cell is '00'

Now, when I figure out how to get input of more than one char (I only know how to use getchar() for getting individual chars so far, though that might work OK for this example), I'd like to loop through again and place an X for the corresponding cell.

Should I write a function for printing the table, which takes arguments such as 'int markerX, int markerY` to place the X?

How would I then store the position of the marker so I could check if the game is won or not?

Is my Choose which cell to place marker the best way to ask for user input for a game on the command line?

Thanks!

A: 

It's probably a good idea to store your game status in some data structure--I'd recommend a two-dimensional array of chars that store whether player 1 or player 2 has placed a marker there.

char board[WIDTH][HEIGHT];

Then after you initialize each element in the array, you can access whether or not there is a marker there with

board[1][2]

for example if you wanted to get the marker at 1, 2.

Now each time the board changes, you can write a function that prints out the board again using a nested for-loop like you did before, except now you'll be accessing the 2d array instead.

Zanneth
A: 

You can't currently reference the cells because you don't store the values anywhere. You need to create a variable to store the value in a cell. To modify the value of a cell all you would need to do is change the value of the associated variable and re-draw the table.

To make things easier, you might write a draw_table function that draws the tic-tac-toe board using the current value of your variables.

If you are only using getch for input, then you might refer to your cells as 1-9 instead of using a two-digit number. This might also make it easier to keep track of your variables, you can call them cell1, cell2, etc. You can also use an array, but that might be too complicated if you are just starting out.

bta
+3  A: 

Right now you've done a pretty good job of figuring out how to output a tic-tac toe board to the screen, but what you are currently lacking is a model of your tic-tac board in memory that your program can modify and use to reprint the current status of the board.

Typically, whenever you have a 2 dimensional grid of elements to model, the simplest model to represent these is a 2-dimensional array. You can define one like this:

int board[WIDTH][HEIGHT]

Then you can access the current state of any element on the board by referencing it by it's index (which always goes from 0-1 less than the number of elements in the array, like so:

int element = board[0][1]

To re-output the board to the user, you may want to implement a function that prints out the board, including its current state. Once that function exists, you can always call that in your code without needing to repeat yourself.

Finally, you'll need to implement a loop. while is the structure most suited to this - it loops until a condition is true.

int shouldExit = 0;
while (shouldExit == 0) {
    printBoard();
    getPlayerInput();
    updateBoard();

    // you can set shouldExit to 1 if the game is over 
    // (someone won, or the player inputted something that indicates they want to quit.
}
Ryan Brunner
This is great info, thanks! I'll let you know how I get on, I'm sure I have a few more questions about this in me!
alex
If I place `drawTable()` as its own function, should I then make the `int board` variable global?
alex
You can either pass it in as an argument to your function, or define it globally. Generally speaking, you should aim to avoid global variables. In this particular case, because the board is central to nearly every method, it might be worth broadening the scope.
Ryan Brunner
+1  A: 

I would create a function whose only job was to print the board, like this (untested):

void board_print(const char b[3][3]) }
   int i = 1;
   printf(        "     A   B   C\n");     // NOTE: Letters on top, like a spreadsheet
   while (1) {
      printf(      "%i  %c | %c | %c\n", i, b[i][0], b[i][1], b[i][2]);
      if (++i <=3) {
          printf(  "  ---+---+---\n");
      } else {
         break;
      }
   }
}

And then create a board like this:

int main(void) {
    char board[3][3] =
        {{ ' ', ' ', ' ' },
         { ' ', ' ', ' ' },
         { ' ', ' ', ' ' }};

    while (1) {
       board_print(board);
       printf("Place X at : ");

Then I would create another function whose entire job is to attempt to place an X or an O in a position:

int board_place(char board[3][3], char marker, char row, char column);

marker here would either be an 'x' or an 'o'.

board_place could return a value which you can use to determine the general state of play. For instance if board_place could not make the move because there was already a marker in that position then it should return a distinct error code from if the row was out of range. This could also be where you determine if there is a winner (because the current move would be the winning move {easy since you only have to test for lines made including the current square}) or if the board is full with no winner and return distinct things for each of these.

Then your main code just decides what to do based on the return value of board_place (issue an error message to the user and prompt for another position, try to make a move for O, congratulate the user on victory, tell the user that the cat won that one, ...).

As far as reading in the position, that's where user interface meets text processing. A simple scanf call could be enough, or maybe just a few getchar calls. I do suggest that you index the rows and columns differently (I used letters and numbers) because that would probably be easier for most people. Then you can either adjust before board_place or just handle adjusting the indexes within board_place.

nategoose