Search code examples
carrayswhile-loopconsoletic-tac-toe

Struggling with TicTacToe in C


I tried to program a simple TicTacToe in C. The program itselfs compiles and show no errors. So the program draws the field, reads the names and let a player put his symbol in a specific field. All this happens in a while loop, the should be run until its a draw or someone wins. But the program just run the loop one time so there is only one turn then the program stops.

So here is my code:

main.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "game.h"


#define NAMELENGTH 20

 int main(void) {
char names[2][NAMELENGTH];
// field positions
char field[9];
int winner = -1;
getnames(names);
printf("\n\n");
initField(field);
// set field positions to 'empty'
char actualPlayer = (char)(get_random_number()*10.0) % 2;

while (1) {
    drawField(field);
    turn(actualPlayer, names, field);
    winner = isWinner(actualPlayer, field);
    drawField(field);
    if (winner >= 1) {
        printwinner(winner, names);
        return 0;
    }
    else if (winner == 0) {
        printDrawGame(names);
        return 0;
    }
    actualPlayer = (actualPlayer + 1) % 2;

}

return 0;

}

game.h Headerfile:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define NAMELENGTH 20
#pragma warning(disable:4996)

extern void drawField(char *field);
extern void getnames(char nameField[][NAMELENGTH]);
extern void initField(char *field);
extern void turn(char actualPlayer, char names[][NAMELENGTH], char *field);
extern char isWinner(char actualPlayer, char *field);
extern void printwinner(char winnerNumber, char names[][NAMELENGTH]);
extern void printDrawGame(char names[][NAMELENGTH]);
extern double get_random_number();

and then my game.c where I defined my functions:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "game.h"
#define NAMELENGTH 20
#pragma warning(disable:4996)

void drawField(char *field) {

printf("________________________\n");
printf("|       |       |      |\n");
printf("|   %c   |   %c   |   %c  |\n", field[0], field[1], field[2]);
printf("|_______|_______|______|\n");
printf("|       |       |      |\n");
printf("|   %c   |   %c   |   %c  |\n", field[3], field[4], field[5]);
printf("|_______|_______|______|\n");
printf("|       |       |      |\n");
printf("|   %c   |   %c   |   %c  |\n", field[6], field[7], field[8]);
printf("|_______|_______|______|\n");

}

void getnames(char nameField[][NAMELENGTH]) {

printf("Name of the first player: ");
scanf("%s", nameField[0]);
printf("Name of the second player: ");
scanf("%s", nameField[1]);

}

void initField(char *field) {

for (int i = 0; i <= 8; i++)
{
    field[i] = i + '1';
}

}

void turn(char actualPlayer, char names[][NAMELENGTH], char *field) {

char symbol = ' ';
int p1fieldnumber;
int p2fieldnumber;


if (actualPlayer == 0)
{
    do {

        printf("\nIts Player %s's turn.", names[0]);
        char symbol = 'X';
        printf("\nNumber of the field which you want to put your symbol in: ");
        scanf("%d", &p1fieldnumber);
        if (field[p1fieldnumber] == 'X' || field[p1fieldnumber] == 'O')
        {
            printf("\nField is already occupied!");
            p1fieldnumber = 10;
        }
    } while (p1fieldnumber < 1 || p1fieldnumber > 9);

    field[p1fieldnumber-1] = 'X';

}
else {

    do {
        printf("\nIts Player %s's turn.", names[1]);
        char symbol = 'O';
        printf("\nNumber of the field which you want to put your symbol in: ");
        scanf("%d", &p2fieldnumber);
        if (field[p2fieldnumber] == 'X' || field[p2fieldnumber] == 'O')
        {
            printf("\nField is already occupied!");
            p2fieldnumber = 10;
        }
    } while (p2fieldnumber < 1 || p2fieldnumber > 9);

    field[p2fieldnumber-1] = 'O';

}

}

char isWinner(char actualPlayer, char *field) {

char pwinner = '3';

if (((field[0] == 'O') && (field[1] == 'O') && (field[2] == 'O')) || 
    (field[3] == 'O') && (field[4] == 'O') && (field[5] == 'O') || 
    (field[6] == 'O') && (field[7] == 'O') && (field[8] == 'O') || 
    (field[0] == 'O') && (field[4] == 'O') && (field[8] == 'O') || 
    (field[2] == 'O') && (field[4] == 'O') && (field[6] == 'O') || 
    (field[0] == 'O') && (field[3] == 'O') && (field[6] == 'O') ||
    (field[1] == 'O') && (field[4] == 'O') && (field[7] == 'O') || 
    (field[2] == 'O') && (field[5] == 'O') && (field[8] == 'O'))

{
    pwinner = '2';
}

else if (((field[0] == 'X') && (field[1] == 'X') && (field[2] == 'X')) || 
    (field[3] == 'X') && (field[4] == 'X') && (field[5] == 'X') || 
    (field[6] == 'X') && (field[7] == 'X') && (field[8] == 'X') || 
    (field[0] == 'X') && (field[4] == 'X') && (field[8] == 'X') || 
    (field[2] == 'X') && (field[4] == 'X') && (field[6] == 'X') || 
    (field[0] == 'X') && (field[3] == 'X') && (field[6] == 'X') || 
    (field[1] == 'X') && (field[4] == 'X') && (field[7] == 'X') || 
    (field[2] == 'X') && (field[5] == 'X') && (field[8] == 'X'))

{
    pwinner = '1';
}

else if (((field[0] == 'X') || (field[0] == 'O')) && ((field[1] == 'X') || (field[1] == 'O')) && ((field[2] == 'X') || (field[2] == 'O')) ||
    ((field[3] == 'X') || (field[3] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[5] == 'X') || (field[5] == 'O')) ||
    ((field[6] == 'X') || (field[6] == 'O')) && ((field[7] == 'X') || (field[7] == 'O')) && ((field[8] == 'X') || (field[8] == 'O')) ||
    ((field[0] == 'X') || (field[0] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[8] == 'X') || (field[8] == 'O')) ||
    ((field[2] == 'X') || (field[2] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[6] == 'X') || (field[6] == 'O')) ||
    ((field[0] == 'X') || (field[0] == 'O')) && ((field[3] == 'X') || (field[3] == 'O')) && ((field[6] == 'X') || (field[6] == 'O')) ||
    ((field[1] == 'X') || (field[1] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[7] == 'X') || (field[7] == 'O')) ||
    ((field[2] == 'X') || (field[2] == 'O')) && ((field[5] == 'X') || (field[5] == 'O')) && ((field[8] == 'X') || (field[8] == 'O')))
{
    pwinner = '0';
}

return pwinner;
}

void printwinner(char winnerNumber, char names[][NAMELENGTH]) {

if (winnerNumber == '1') {
    printf("Player %s won!", names[0]);
}
else if (winnerNumber == '2') {
    printf("Player %s won!", names[1]);
}

}

void printDrawGame(char names[][NAMELENGTH]) {
printf("Draw!");
}

static int _initialized;

double get_random_number() {
if (!_initialized) {
    srand(time(NULL));
    _initialized = 1;
}
return (double)rand() / ((double)(RAND_MAX)+1);
}

Solution

  • There are multiple issues

    1. isWinner returns characters '0', '1', '2' and '3'. Replace them with numbers 0, 1, 2, 3, because your are comparing with numbers in main.

    2. In main instead of checking if (winner >= 1) {, which is true even if 3 is returned by isWinner, check for if (winner == 1 || winner == 2) {.

    3. Suggest to use parentheses in isWinner around each condition separated by ||.

    Parentheses as shown below for the first condition

    if (((field[0] == 'O') && (field[1] == 'O') && (field[2] == 'O')) ||
        ((field[3] == 'O') && (field[4] == 'O') && (field[5] == 'O')) ||
        ((field[6] == 'O') && (field[7] == 'O') && (field[8] == 'O')) ||
        ((field[0] == 'O') && (field[4] == 'O') && (field[8] == 'O')) ||
        ((field[2] == 'O') && (field[4] == 'O') && (field[6] == 'O')) ||
        ((field[0] == 'O') && (field[3] == 'O') && (field[6] == 'O')) ||
        ((field[1] == 'O') && (field[4] == 'O') && (field[7] == 'O')) ||
        ((field[2] == 'O') && (field[5] == 'O') && (field[8] == 'O')))