1
\$\begingroup\$

I developed this hash game in C for my college, but i need to optimize this code, can you help me?

it works well, but I need it to be a little more organized and faster, the rand function is the only one used in the code, it uses random to randomize the pc turn, i.e. the pc is completely inefficient. Maybe using more of these functions will help to compress the code, but how?

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

int main()
{

    int board[3][3] = { {0, 0, 0},
                            {0, 0, 0},
                            {0, 0, 0} }, i, j, lineUser, colunUser, linePC, colunPc, endGame = 0, turnPc, turnUser;
    srand( (unsigned)time(NULL) );

    do {
        turnPc = 0;
        turnUser = 0;
        for (i=0; i<3; i++){
            for (j=0; j<3; j++){
                printf("%d  ", board[i][j]);
            }
            printf("\n");
        }
        while (turnUser == 0){
            printf("Select your position:  \n");
            scanf("%d  %d", &lineUser, &colunUser);

            if (board[lineUser-1][colunUser-1] != 0){
                printf("this position has been selected \n");
            } else {
                board[lineUser-1][colunUser-1] = 1;
                turnUser = 1;
            }
                
        }
        if (board[0][0] != 0 && board[0][1] != 0 && board[0][2] != 0 && 
            board[1][0] != 0 && board[1][1] != 0 && board[1][2] != 0 && 
            board[2][0] != 0 && board[2][1] != 0 && board[2][2] != 0){
                printf("draw \n");
                break;
            }
        while (turnPc == 0){
        linePC = rand() %  3;
        colunPc = rand() % 3;

        if (board[linePC][colunPc]==0){
            board[linePC][colunPc] = -1;
            turnPc = 1;
        } 
        }
        if (board[0][0] + board[0][1] + board[0][2] ==3 ||
        board[1][0] + board[1][1] + board[1][2] == 3||
        board[2][0] + board[2][1] + board[2][2] == 3){
            printf("You win \n");
            endGame = 1;
        }
        if (board[0][0] + board[1][0] + board[2][0] ==3 ||
        board[0][1] + board[1][1] + board[2][1] == 3||
        board[0][2] + board[1][2] + board[2][2] == 3){
            printf("You win \n");
            endGame = 1; 
        }
         if (board[0][0] + board[1][1] + board[2][2] ==3 ||
        board[2][0] + board[1][1] + board[0][2] == 3){
            printf("You win \n");
            endGame = 1;
        }
        if (board[0][0] + board[0][1] + board[0][2] == -3 ||
        board[1][0] + board[1][1] + board[1][2] == -3||
        board[2][0] + board[2][1] + board[2][2] == -3){
            printf("You lose\n");
            endGame = 1;
        }
        if (board[0][0] + board[1][0] + board[2][0] == -3 ||
        board[0][1] + board[1][1] + board[2][1] == -3||
        board[0][2] + board[1][2] + board[2][2] == -3){
            printf("You lose \n");
            endGame = 1; 
        }
         if (board[0][0] + board[1][1] + board[2][2] == -3 ||
        board[2][0] + board[1][1] + board[0][2] == -3){
            printf("You lose \n");
            endGame = 1;
        }
        

    } while (endGame == 0);
    for (i=0; i<3; i++){
            for (j=0; j<3; j++){
                printf("%d  ", board[i][j]);
            }
            printf("\n");
        }
    return 0;
}

\$\endgroup\$
1
  • \$\begingroup\$ What would be the performance angle, how would one measure faster? \$\endgroup\$
    – greybeard
    Commented May 23, 2022 at 22:10

2 Answers 2

1
\$\begingroup\$

Use a function - this will improve readability: D Think about the separation of functions for the player and pc.

board[0][0] != 0 && board[0][1] != 0 && board[0][2] != 0 && 
            board[1][0] != 0 && board[1][1] != 0 && board[1][2] != 0 && 
            board[2][0] != 0 && board[2][1] != 0 && board[2][2] != 0

This may be a function - like a checkFieldInBoard. All if's can be a function's, but give them a correct name, When someone wants reads this code - function names must make sense. The code should be read like a book

   for (i=0; i<3; i++){
            for (j=0; j<3; j++){
                printf("%d  ", board[i][j]);
            }
            printf("\n");
        }

What does this function print the boards? If yes - that may be a function

\$\endgroup\$
1
\$\begingroup\$

I'm just going to put this here, mostly to illustrate that there are different approaches to solving the problem. The OP asked to 'compress' the code, which perhaps means to make it more succinct, or just to use standard library routines to provide some of the solution.

A little modularisation helps, and certainly adding some semantics to the variable types and names, I think, helps to clarify what the code is doing.

It's not LESS lines of code. But it does make the code less rigidly implemented around the idea of a 3 x 3 grid (even if that's well beyond the scope of the question).

We shouldn't always be concerned about reducing the line count, its a somewhat artificial metric in most cases, nor should we be concerned with the number of CPU cycles or memory consumed, unless through benchmarking we can prove that there is a benefit from doing so.

I'm not saying that this is the most succinct implementation, nor do I claim it to be correct in every possible case. I think the sub-routines could easily take the bounds as arguments to make them function independently of the defines.

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

typedef enum {
    User = 'X',
    Computer = 'O',
    None = '_'
} Player;

#define ROWS    3
#define COLS    3

void printBoard(Player board[ROWS][COLS]) {
    int row, col;
    for (row=0; row<ROWS; row++){
        for (col=0; col<COLS; col++){
            printf("%c  ", board[row][col]);
        }
        printf("\n");
    }
}

Player checkWinner(Player board[ROWS][COLS]) {
    int row, col;
    Player last = None;

    // row    
    for (row=0; row<ROWS; row++){
        for (col=0, last=board[row][col]; col<COLS; col++){
            if (board[row][col] != last) {
                last = None;
                break;
            }
        }
        if (last != None) {
            return last;
        }
    }

    // col
    for (col=0; col<COLS; col++){
        for (row=0, last=board[row][col]; row<ROWS; row++){
            if (board[row][col] != last) {
                last = None;
                break;
            }
        }
        if (last != None) {
            return last;
        }
    }

    // diag forward
    for (row=0, col=0, last=board[row][col]; row<ROWS && col<COLS; row++, col++){
        if (board[row][col] != last) {
            last = None;
            break;
        }
    }
    if (last != None) {
        return last;
    }

    // diag backward
    for (row=0, col=COLS-1, last=board[row][col]; col>=0 && row < ROWS; row++, col--){
        if (board[row][col] != last) {
            last = None;
            break;
        }
    }
    if (last != None) {
        return last;
    }

    return None;
}

int main()
{

    Player board[ROWS][COLS] = { 
        { None, None, None },
        { None, None, None },
        { None, None, None }
    };

    Player player = User;
    Player winner = None;
    int turn = 0;
    
    srand( (unsigned)time(NULL) );

    while (turn < (ROWS * COLS)) {
        
        int row = 0, col = 0;
        
        if (player == User) {
        
            printBoard(board);
            
            printf("Select your position:  \n");
            scanf("%d %d", &row, &col);

            if (row < 1 || col < 1) {
                printf("Row/Column must be greater than 1\n");
                continue;
            }
            
            if (row >= ROWS || col >= COLS) {
                printf("Row/Column must be greater than 1\n");
                continue;
            }
            
            row--;
            col--;
            
        }
        
        if (player == Computer) {
            
            row = rand() % ROWS;
            col = rand() % COLS;
            
        }

        if (board[row][col] != None) {
            if (player == User) {
                printf("Position already played, try again\n");
            }
            continue;
        }
        
        board[row][col] = player;
        turn++;
        
        winner = checkWinner(board);
        
        if (winner != None) {
            printf("The %s is the Winner!\n", winner == User ? "User" : "Computer");
            break;
        }
        
        player = player == User ? Computer : User;
        
    }
    
    printBoard(board);
    if (turn >= (ROWS*COLS) && winner == None) {
        printf("Game over, its a draw!\n");
    }
    
    return 0;
}
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.