1
\$\begingroup\$

This is a tic-tac-toe game that I made in C. It works the way that I want it to but I feel like I could have done it better or shorter. Any input as to how I did would be appreciated.

Include Statements and Prototypes

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

//Creating the prototypes
int init(char ttt1[3][3]);
int display_board(char ttt2[3][3]);
int turn(int *player_turns);
int get_move(char ttt3[3][3], int player_turns2, int *move, char player1[], char player2[]);
int validate_move(int move);
int check_win(char ttt[3][3], int turns);
int update_board(char ttt[3][3], const int * move, int turn);
int menu();

Main Function

int main(void) {
    int play_again = 1; //set up the loop
    if(menu() == 1){ //calling the menu
        while(play_again == 1) { //as long as the player wants to play again, loop
            int player_turn = 1;
            int move = 0;
            int turns = 1;
            char player1[20];
            char player2[20];
            char ttt[3][3]; //create the array
            init(ttt); //initialize the board
            printf("Enter Player 1 name(without using spaces): ");
            scanf(" %s", player1);
            printf("%s, you are 'X'\n", player1);
            printf("Enter Player 2 name(without using spaces): ");
            scanf(" %s", player2);
            printf("%s, you are 'O'\n", player2);
            while (check_win(ttt, turns) == 0) {
                get_move(ttt, player_turn, &move, player1, player2); //receive the moves from the player
                validate_move(move); //call the function to validate the moves
                update_board(ttt, &move, player_turn); //call the function which updates the board based on the players move
                display_board(ttt); //redisplay the board
                turn(&player_turn); //call the function to change whose turn it is
                turns++; //increment turns
            }
            printf("Would you like to play again?(1 for yes, 2 for no) ");
            scanf(" %d", &play_again);
        }
    }
    return 0;
}

Board Initializer

//set up the board for use in the game
int init(char ttt1[3][3]){
    ttt1[0][0] = '1';
    ttt1[0][1] = '2';
    ttt1[0][2] = '3';
    ttt1[1][0] = '4';
    ttt1[1][1] = '5';
    ttt1[1][2] = '6';
    ttt1[2][0] = '7';
    ttt1[2][1] = '8';
    ttt1[2][2] = '9';
    return 0;
}

Board Display

This does display the board the way it should but I need a way to clear the screen. I have tried a few ways that I found online but since I am on Mac OS none of it worked. What is a good way to clear the screen that is portable?

//showing the board on the screen
int display_board(char ttt2[3][3]){
    printf("%c | %c | %c\n", ttt2[0][0], ttt2[0][1], ttt2[0][2]); //displays the top row
    printf("----------\n");
    printf("%c | %c | %c\n", ttt2[1][0], ttt2[1][1], ttt2[1][2]); //displays the middle row
    printf("----------\n");
    printf("%c | %c | %c\n", ttt2[2][0], ttt2[2][1], ttt2[2][2]); //displays the bottom row
    return 0;
}

Which Turn

int turn(int *player_turns1){
    if(*player_turns1 == 1){ //if it is player one's turn
        *player_turns1 = 2; //change it to player two's turn
    }
    else if(*player_turns1 == 2){ //if it is player two's turn
        *player_turns1 = 1; // change it to player one's turn
    }
    return 0;
}

Move Retrieval

//get the move from the player depending on whose turn it is
int get_move(char ttt3[3][3], int player_turns2, int *move, char player1_1[], char player2_1[]){
    if(player_turns2 == 1){ //if it is player one's turn
        display_board(ttt3); //display the board
        printf("%s, please enter where you would like to move: ", player1_1); //ask for the move
        scanf(" %d", move);//get the move from the player
    }
    else if(player_turns2 == 2){ //if it is player two's turn
        display_board(ttt3); //display the board
        printf("%s, please enter where you would like to move: ", player2_1); //ask for the move
        scanf(" %d", move); //get the move from the player
    }
    return *move;
}

Move Validator

int validate_move(int move1){
    if (move1 < 1 || move1 > 9) { //if the move is on the board
        return 0;
    }
    else //if the move does not fall on the board
        return 1;
}

Update the Board

 //function that updates the board with the user's move
int update_board(char ttt[3][3], const int *move, int turn){
    if(*move == 1 && turn == 1) //top left is chosen by player one
        ttt[0][0] = 'X'; //set the square to x
    else if(*move == 1 && turn == 2) //top left is chosen by player two
        ttt[0][0] = 'O'; //set the square to o
    else if(*move == 2 && turn == 1) //top middle is chosen by player one
        ttt[0][1] = 'X'; //set the square to x
    else if(*move == 2 && turn == 2) //top middle is chosen by player two
        ttt[0][1] = 'O'; //set the square to o
    else if(*move == 3 && turn == 1) //top right is chosen by player one
        ttt[0][2] = 'X'; //set the square to x
    else if(*move == 3 && turn == 2) //top right is chosen by player two
        ttt[0][2] = 'O'; //set the square to o
    else if(*move == 4 && turn == 1) //middle left is chosen by player one
        ttt[1][0] = 'X'; //set the square to x
    else if(*move == 4 && turn == 2) //middle left is chosen by player two
        ttt[1][0] = 'O'; //set the square to o
    else if(*move == 5 && turn == 1) //middle is chosen by player one
        ttt[1][1] = 'X'; //set the square to x
    else if(*move == 5 && turn == 2) //middle is chosen by player two
        ttt[1][1] = 'O'; //set the square to o
    else if(*move == 6 && turn == 1) //middle right is chosen by player one
        ttt[1][2] = 'X'; //set the square to x
    else if(*move == 6 && turn == 2) //middle right is chosen by player two
        ttt[1][2] = 'O'; //set the square to o
    else if(*move == 7 && turn == 1) //bottom right is chosen by player one
        ttt[2][0] = 'X'; //set the square to x
    else if(*move == 7 && turn == 2) //bottom right is chosen by player two
        ttt[2][0] = 'O'; //set the square to o
    else if(*move == 8 && turn == 1) //bottom middle is chosen by player one
        ttt[2][1] = 'X'; //set the square to x
    else if(*move == 8 && turn == 2) //bottom middle is chosen by player two
        ttt[2][1] = 'O';//set the square to o
    else if(*move == 9 && turn == 1) //bottom right is chosen by player one
        ttt[2][2] = 'X'; //set the square to x
    else if(*move == 9 && turn == 2) //bottom right is chosen by player two
        ttt[2][2] = 'O'; //set the square to o
    return 0;
}

Victory/Tie Check

//check the board to see if there is a winner
int check_win(char ttt[3][3], int turns1){
    if(ttt[0][0] == ttt[0][1] && ttt[0][1] == ttt[0][2]) { //top row horizontal check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(ttt[1][0] == ttt[1][1] && ttt[1][1] == ttt[1][2]) { //middle row horizontal check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(ttt[2][0] == ttt[2][1] && ttt[2][1] == ttt[2][2]) { //bottom row horizontal check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(ttt[0][0] == ttt[1][0] && ttt[1][0] == ttt[2][0]) { //left column vertical check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(ttt[0][1] == ttt[1][1] && ttt[1][1] == ttt[2][1]) { //middle column vertical check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(ttt[0][2] == ttt[1][2] && ttt[1][2] == ttt[2][2]) { //right column vertical check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(ttt[0][0] == ttt[1][1] && ttt[1][1] == ttt[2][2]) { //top left to bottom right diagonal check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(ttt[2][0] == ttt[1][1] && ttt[1][1] == ttt[0][2]) { //top right to bottom left diagonal check
        printf("Congratulations, You Won!\n");
        return 1;
    }
    else if(turns1 >= 10) //checks to see if the game ends in a tie
        printf("The game ends in a draw, no one wins.\n");
    else
        return 0;
}

Menu Function

Switch/Case seemed to be the best way that I could think of to do a menu. Options 2-4 are my next projects to be working on.

//the function that controls the menu
int menu(){
    int state = 0; //establish the state variable
    printf("Welcome to my Tic Tac Toe Game!\n");
    printf("How would you like to play?\n");
    printf("1. 2D Player vs. Player\n");
    printf("2. 2D Player vs. Computer(Not ready yet)\n");
    printf("3. 3D Player vs. Player(Not ready yet)\n");
    printf("3. 3D Player vs. Computer(Not ready yet)\n");
    printf("Enter your choice: ");
    scanf(" %d", &state); //get the user's choice for the menu
    switch(state){
        case 1: //option 1 in the menu
            return 1;
        case 2: //option 2 in the menu
            return 2;
        case 3: //option 3 in the menu
            return 3;
        case 4: //option 4 in the menu
            return 4;
        default: //if an invalid option is chosen
            printf("There was an error. Please try again.");
    }
}

I know that this code works as I want it to but I feel like it's too long or that there are easier ways to achieve some of the tasks. Again, any help or input is much appreciated.

\$\endgroup\$
  • 1
    \$\begingroup\$ This would be easier to review if all the code was in one block, enabling reviewers to copy and paste the code into their own environments if desired. \$\endgroup\$ – 1201ProgramAlarm Mar 24 at 4:33
1
\$\begingroup\$

1.

In the function int menu()
you can reduce the switch with this statement

return ((state>0 && state<5)?state:printf("There was an error. Please try again."),0);  

With this your menu() will return 0 whenever illegal input is received and hence you can put the menu() call inside main in a loop and handle wrong input better way.

This piece of code

int main(void) {
    int play_again = 1; //set up the loop
    if(menu() == 1){ //calling the menu  

can be written like this

int main(void) {
    int choice;
    while(!(choice = menu()));
    int play_again = 1; //set up the loop
    if(choice == 1){ //calling the menu  

2.

in the function int update_board(char ttt[3][3], const int *move, int turn)

move variable provides with enough information to find out the coordinate of the character in the 2D-array ttt which needs to be changed

int update_board(char ttt[3][3], const int *move, int turn){
    char ch = (turn==1)?'X':'O';
    int x = (*move-1)/3, y=(*move-1)-(x*3);
    ttt[x][y]=ch;
    return 0; // return statement does not make any sense right now
}  

The overall code can become slightly simpler and shorter if you treat turn variable as a bool and use 0 and 1 to know which players are having turns.

\$\endgroup\$
  • \$\begingroup\$ @grabbailoutrun, you can show appreciation by putting an upvote. Also remember to avoid saying hi,hello,thank you like statements here (statements which are not constructive). Also check out the rules one should follow while posting here. \$\endgroup\$ – Mukul Kumar Mar 25 at 2:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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