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.
-
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– 1201ProgramAlarm2019年03月24日 04:33:26 +00:00Commented Mar 24, 2019 at 4:33
1 Answer 1
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.
-
\$\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– Mukul Kumar2019年03月25日 02:11:11 +00:00Commented Mar 25, 2019 at 2:11