Home > Software engineering >  Weird output on TicTacToe game written in C
Weird output on TicTacToe game written in C

Time:11-26

I am a beginner C programmer and while writing a tictactoe game in C, I encountered a strange output. I mainly used if statements to check if the "squares" are either 'X' or 'O'

#include <stdio.h>

int main(){
    int p1,p2;
    char arr[] = {'1','2','3','4','5','6','7','8','9'};
    void drawboard(){
        printf("%c|%c|%c\n",arr[0],arr[1],arr[2]);
        printf("-----\n");
        printf("%c|%c|%c\n",arr[3],arr[4],arr[5]);
        printf("-----\n");
        printf("%c|%c|%c\n",arr[6],arr[7],arr[8]);
    }
    while(1>0){
        drawboard();
        printf("Player 1, enter your choice:\n");
        scanf("%d",&p1);
        printf("Player 2, enter your choice:\n");
        scanf("%d",&p2);
        arr[p1-1] = 'X';
        arr[p2-1] = 'O';
        if(arr[0]&&arr[1]&&arr[2]=='X'){
            printf("Player 1 won.\n");
            return 1;

        }
        if(arr[3]&&arr[4]&&arr[5]=='X'){
            printf("Player 1 won.\n");
            return 1;
        }
        if(arr[6]&&arr[7]&&arr[8]=='X'){
            printf("Player 1 won.\n");
            return 1;
        }
        if(arr[0]&&arr[3]&&arr[6]=='X'){
            printf("Player 1 won.\n");
            return 1;
        }
        if(arr[1]&&arr[4]&&arr[7]=='X'){
            printf("Player 1 won.\n");
            return 1;
        }
        if(arr[2]&&arr[5]&&arr[8]=='X'){
            printf("Player 1 won.\n");
            return 1;
        }
        if(arr[0]&&arr[4]&&arr[8]=='X'){
            printf("Player 1 won.\n");
            return 1;
        }
        if(arr[2]&&arr[4]&&arr[6]=='X'){
            printf("Player 1 won.\n");
            return 1;
        }
        else if(arr[0]&&arr[1]&&arr[2]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else if(arr[3]&&arr[4]&&arr[5]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else if(arr[6]&&arr[7]&&arr[8]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else if(arr[0]&&arr[3]&&arr[6]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else if(arr[1]&&arr[4]&&arr[7]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else if(arr[2]&&arr[5]&&arr[8]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else if(arr[0]&&arr[4]&&arr[8]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else if(arr[2]&&arr[4]&&arr[6]=='O'){
            printf("Player 2 won.\n");
            return 1;
        }
        else{
            continue;
        }

    }
    return 0;
}

After the first and the second player's input, if the input is '8' or '6', it says he won, even if only one space was occupied.

CodePudding user response:

You wrote:

arr[6]&&arr[7]&&arr[8]=='X'

which means:

if arr[6] is true and arr[7] is true and arr[8]=='X' is true.

True means any character except '\0', so all the squares are true and this condition is true as soon as arr[8] is an X.

You meant:

arr[6]=='X' && arr[7]=='X' && arr[8]=='X'

(spaces are optional) which checks that all 3 of them are X. And you have to fix all the if statements this way.

CodePudding user response:

Prefaced by my top comments. A few issues ...

  1. Don't use nested functions
  2. Put arr at global scope.
  3. if syntax is incorrect. (e.g.) if(arr[0]&&arr[1]&&arr[2]=='X') should be if ((arr[0] == 'X') && (arr[1] == 'X') && (arr[2] == 'X'))
  4. No check for illegal moves or out of range moves.
  5. Not all possible win positions checked (e.g. missing a diagonal).
  6. No need for separate win check for each player. A win [for either player] is all three in a given direction match.
  7. The program can be greatly simplified with breakup into smaller functions.

Here is the corrected code. It is annotated.

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

char arr[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

void
drawboard(void)
{
    printf("%c|%c|%c\n", arr[0], arr[1], arr[2]);
    printf("-----\n");
    printf("%c|%c|%c\n", arr[3], arr[4], arr[5]);
    printf("-----\n");
    printf("%c|%c|%c\n", arr[6], arr[7], arr[8]);
}

// match3 -- decide if win
// RETURNS: winning char or zero
int
match3(int a,int b,int c)
{
    int x;

    --a;
    --b;
    --c;

    x = arr[a];

    return ((arr[b] == x) && (arr[c] == x)) ? x : 0;
}

// check -- check for win
int
check(void)
{
    int win;

    do {
        // top row
        win = match3(1,2,3);
        if (win)
            break;

        // middle row
        win = match3(4,5,6);
        if (win)
            break;

        // bottom row
        win = match3(7,8,9);
        if (win)
            break;

        // left column
        win = match3(1,4,7);
        if (win)
            break;

        // middle column
        win = match3(2,5,8);
        if (win)
            break;

        // right column
        win = match3(3,6,9);
        if (win)
            break;

        // left to right diagonal
        win = match3(1,5,9);
        if (win)
            break;

        // right to left diagonal
        win = match3(3,5,7);
        if (win)
            break;
    } while (0);

    switch (win) {
    case 'X':
        printf("Player 1 won.\n");
        break;
    case 'O':
        printf("Player 2 won.\n");
        break;
    }

    if (win)
        drawboard();

    return win;
}

// legal -- check for remaining legal moves
void
legal(void)
{
    int more;

    // look for remaining legal moves
    more = 0;
    for (int idx = 0;  idx < 9;    idx) {
        more = (arr[idx] != 'X') && (arr[idx] != 'O');
        if (more)
            break;
    }

    if (! more) {
        printf("No more legal moves -- no winner\n");
        drawboard();
        exit(0);
    }
}

// ask -- ask player for moves
int
ask(int playno,int x)
{
    char buf[100];
    char *cp;
    int move;

    printf("\n");
    legal();

    while (1) {
        drawboard();

        printf("Player %d, enter your choice:\n",playno);
        if (fgets(buf,sizeof(buf),stdin) == NULL) {
            printf("EOF\n");
            exit(0);
        }

        // echo for debug input from file
        do {
            struct termios tio;
            if (tcgetattr(fileno(stdin),&tio) < 0)
                fputs(buf,stdout);
        } while (0);

        // get the move
        move = strtol(buf,&cp,10);

        if (*cp != '\n') {
            printf("syntax error\n");
            continue;
        }

        // move is within bounds
        if ((move >= 1) && (move <= 9)) {
            --move;

            // check for move to an already occupied space
            if ((arr[move] == 'X') || (arr[move] == 'O')) {
                printf("already has an '%c'\n",arr[move]);
                continue;
            }

            // make the move
            arr[move] = x;
            break;
        }

        printf("move out of range\n");
    }

    return check();
}

int
main(void)
{
    int more;

    while (1) {
        if (ask(1,'X'))
            break;
        if (ask(2,'O'))
            break;
    }

    return 0;
}

Below are some sample games I used to test the program ...



1|2|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
1

X|2|3
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
4

X|2|3
-----
O|5|6
-----
7|8|9
Player 1, enter your choice:
2

X|X|3
-----
O|5|6
-----
7|8|9
Player 2, enter your choice:
5

X|X|3
-----
O|O|6
-----
7|8|9
Player 1, enter your choice:
3
Player 1 won.
X|X|X
-----
O|O|6
-----
7|8|9


1|2|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
1

X|2|3
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
4

X|2|3
-----
O|5|6
-----
7|8|9
Player 1, enter your choice:
2

X|X|3
-----
O|5|6
-----
7|8|9
Player 2, enter your choice:
5

X|X|3
-----
O|O|6
-----
7|8|9
Player 1, enter your choice:
3
Player 1 won.
X|X|X
-----
O|O|6
-----
7|8|9


1|2|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
1

X|2|3
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
2

X|O|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
3

X|O|X
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
4

X|O|X
-----
O|5|6
-----
7|8|9
Player 1, enter your choice:
5

X|O|X
-----
O|X|6
-----
7|8|9
Player 2, enter your choice:
9

X|O|X
-----
O|X|6
-----
7|8|O
Player 1, enter your choice:
8

X|O|X
-----
O|X|6
-----
7|X|O
Player 2, enter your choice:
7

X|O|X
-----
O|X|6
-----
O|X|O
Player 1, enter your choice:
6

No more legal moves -- no winner
X|O|X
-----
O|X|X
-----
O|X|O
  •  Tags:  
  • c
  • Related