ctic-tac-toe

getch() replacement in C


I want and searching for an alternative that could replace the getch() function of C language. I want help if any any function which can replace the getch() function from the code below or an appropriate alternative. The conio.h header file is unavailable because I used the GNU GCC compiler but I don't want to change compilers because it will be super long to wait.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h> // No such file or directory

char square[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
int choice, player;

int checkForWin();
void displayBoard();
void markBoard(char mark);

int checkForWin() {
    int returnValue = 0;

    if (square[1] == square[2] && square[2] == square[3]) {
        returnValue = 1;
    } else if (square[4] == square[5] && square[5] == square[6]) {
        returnValue = 1;
    } else if (square[7] == square[8] && square[8] == square[9]) {
        returnValue = 1;
    } else if (square[1] == square[4] && square[4] == square[7]) {
        returnValue = 1;
    } else if (square[2] == square[5] && square[5] == square[8]) {
        returnValue = 1;
    } else if (square[3] == square[6] && square[6] == square[9]) {
        returnValue = 1;
    } else if (square[1] == square[5] && square[5] == square[9]) {
        returnValue = 1;
    } else if (square[3] == square[5] && square[5] == square[7]) {
        returnValue = 1;
    } else if (square[1] != '1' && square[2] != '2' && square[3] != '3' && square[4] != '4' && square[5] != '5'&& square[6] != '6' && square[7] != '7' && square[8] != '8' && square[9] != '9') {
        returnValue = 0;
    } else {
        returnValue = -1;
    }
    return returnValue;
}

void displayBoard() {
    system("cls");

    printf("\n\n\tTic Tac Toe\n\n");

    printf("Player 1 (X) - Player (O)\n\n\n");

    printf("   |   |   \n");
    printf(" %c | %c | %c \n", square[1], square[2], square[3]);

    printf("___|___|___\n");
    printf("   |   |   \n");

    printf(" %c | %c | %c \n", square[4], square[5], square[6]);

    printf("___|___|___\n");
    printf("   |   |   \n");

    printf(" %c | %c | %c \n", square[7], square[8], square[9]);

    printf("   |   |   \n\n");
}

void markBoard(char mark) {
    if (choice == 1 && square[1] == '1') {
        square[1] = mark;
    } else if (choice == 2 && square[2] == '2') {
        square[2] = mark;
    } else if (choice == 3 && square[3] == '3') {
        square[3] = mark;
    } else if (choice == 4 && square[4] == '4') {
        square[4] = mark;
    } else if (choice == 5 && square[5] == '5') {
        square[5] = mark;
    } else if (choice == 6 && square[6] == '6') {
        square[6] = mark;
    } else if (choice == 7 && square[7] == '7') {
        square[7] = mark;
    } else if (choice == 8 && square[8] == '8') {
        square[8] = mark;
    } else if (choice == 9 && square[9] == '9') {
        square[9] = mark;
    } else {
        printf("Invalid move ");

        player--;
        getch(); // error
    }
}

int main()
{
    int gameStatus;

    char mark;

    player = 1;

    do {
        displayBoard();

        player = (player % 2) ? 1 : 2;

        printf("Player %d, enter a number: ", player);
        scanf("%d", &choice);

        mark = (player == 1) ? 'X' : 'O';

        markBoard(mark);

        gameStatus = checkForWin;

        player++;
    } while (gameStatus == -1);

    if (gameStatus == 1) {
        printf("==>\aPlayer %d wins! ", --player);
    } else {
        printf("==>\aGame draw!");
    }
}

I'm just simply creating a Tic-Tac-Toe game, you need to write a number from 1 to 9 for each squares, if any of the players wins, it will print "==>Player __ wins!", if the game is a tie, it will print out "==>Game draw!"

I tried the getchar() function but it keeps on printing "==>Game draw!" and "sh: line 1: cls: command not found" I tried the getche() and putch() function also but it also alerts an error


Solution

  • conio.h will not be available if you moved to a different OS. See also Why the use of "conio.h" is not good habit of programming? and Why must we refrain from using conio.h? Is it obsolete?

    But in your actual case you should not need to use getch. In your code you call it at a moment that the user enters an invalid move, but in that case you don't really have to wait for a key. The user anyway needs a new opportunity to enter a valid move, so just go ahead and ask for their move again without further delay.

    There are some other problems in your code:

    Not a real problem, but:

    Here is your code adapted with these remarks:

    #include <stdio.h>
    #include <stdlib.h>
    
    int checkForWin(char square[]);
    void displayBoard(char square[]);
    int markBoard(char square[], char mark, int choice);
    
    // Avoid globals: moved to main.
    
    int checkForWin(char square[]) {
        // Avoid code repetition
        static int wins[8][3] = {
            { 1, 2, 3 },
            { 4, 5, 6 },
            { 7, 8, 9 },
            { 1, 4, 7 },
            { 2, 5, 8 },
            { 3, 6, 9 },
            { 1, 5, 9 },
            { 3, 5, 7 }
        };
        for (int i = 0; i < 8; i++) {
            if (square[wins[i][0]] == square[wins[i][1]] && square[wins[i][0]] == square[wins[i][2]]) {
                return 1; // A win detected
            }
        }
        for (int i = 1; i <= 9; i++) {
            if (square[i] == '0' + i) return -1; // Still a square available for a move
        }
        return 0; // A draw
    }
    
    void displayBoard(char square[]) {
        // Don't use system("cls"). It makes your code OS dependent. Use a VT100 escape sequence:
        puts("\033[2J\033[H"); // clear and home
        printf("\n\n\tTic Tac Toe\n\n");
    
        printf("Player 1 (X) - Player 2 (O)\n\n\n");
    
        printf("   |   |   \n");
        printf(" %c | %c | %c \n", square[1], square[2], square[3]);
    
        printf("___|___|___\n");
        printf("   |   |   \n");
    
        printf(" %c | %c | %c \n", square[4], square[5], square[6]);
    
        printf("___|___|___\n");
        printf("   |   |   \n");
    
        printf(" %c | %c | %c \n", square[7], square[8], square[9]);
    
        printf("   |   |   \n\n");
    }
    
    // Have the function return a boolean to indicate whether the move was performed
    int markBoard(char square[], char mark, int choice) {
        // Use dynamic indexing
        if (choice < 1 || choice > 9 || square[choice] != '0' + choice) return 0;
        square[choice] = mark;
        // Don't alter player here, nor display a message. This should be done by main.
        return 1;
    }
    
    int main()
    {
        // Avoid globals, define your variables in main, and pass them as arguments where relevant
        char square[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        int choice;
        int gameStatus;
        char mark;
        int player = 2; // This will switch to 1 in the first iteration
        int wasValid = 1; // False when previously entered move was not valid
    
        do {
            displayBoard(square);
            if (wasValid) {
                player = 3 - player; // This is a way to toggle between 1 and 2.
            } else {
                printf("Invalid Move! "); // Don't wait for a key
            }
            mark = player == 1 ? 'X' : 'O';
            printf("Player %d, enter a number: ", player);
            scanf("%d", &choice);
            wasValid = markBoard(square, mark, choice); // Get the result
            gameStatus = checkForWin(square); // Must call the function!
        } while (gameStatus == -1);
    
        displayBoard(square); // Also display the board at the end
        if (gameStatus == 1) {
            printf("==> Player %d wins!", player);
        } else {
            printf("==> It's a draw!");
        }
    }