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.

esote
3,8002 gold badges24 silver badges44 bronze badges
asked Mar 24, 2019 at 4:20
\$\endgroup\$
1
  • 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\$ Commented Mar 24, 2019 at 4:33

1 Answer 1

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.

answered Mar 24, 2019 at 8:48
\$\endgroup\$
1
  • \$\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\$ Commented Mar 25, 2019 at 2:11

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.