Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Homework -2017 Spring T x prp2.v2-pp2.v2.pdf rbdav/pid-29812865-dt content rid 1

ID: 3840736 • Letter: H

Question

Homework -2017 Spring T x prp2.v2-pp2.v2.pdf rbdav/pid-29812865-dt content rid 131060592ucourses/IC01 Automatic Zoom Programming assignment #2 Due by 11:59pm, Wednesday, May. 31th, 2016 In this project, you are required to build a simple two-player game called Tic-Tac-Toe Tic-tac-toe (also known as noughts and crosses or Xs and Os) is a paper-and-pencil game for two players, X and O, who take turns marking the spaces in a 3x3grid. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row wins the game. (via Wikipedia.) Two players should be able to play with each other on two computers. Your program shoule be able to connect with another instance of your program and then start to play. Each player place a mark on the grid, and the play should be displayed on both side. When it reaches the final stage, both side should display the result, win, lose or draw. After a game finished, player can choose to play another round, if both sides agree to play, a new set will start, otherwise connection will be terminated.

Explanation / Answer

The below Tic-Tac-Toe game (Multiplayer) is written in C program using sockets concept.

This source code is developed on linux environment.

To compile, cd to this directory and run:

Player-1 (server) will need to set up a game and should be executed first as given below command:

The Player-2(client) should type in the below command on terminal:

for instance tic_client can be compiled on with 192.0.2.80 IP address of the server with port 1024.

all: tic_client tic_server

tic_client: tic_client.c
   gcc tic_client.c -o tic_client

tic_server: tic_server.c
   gcc -pthread tic_server.c -o tic_server

clean:
   rm -rf tic_client tic_server

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

void log_error(const char *err_msg)
{
printf("Either the server shut down or the other player disconnected. Game over. ");

exit(0);
}

/*
* Socket Read Functions
*/

/* Reads a message from the server socket. */
void recv_msg(int socket_fd, char * msg)
{
/* All messages are 3 bytes. */
memset(msg, 0, 4);
int n = read(socket_fd, msg, 3);
  
if (n < 0 || n != 3) /* Not what we were expecting. Server got killed or the other client disconnected. */
log_error("ERROR reading message from server socket.");

}

/* Reads an int from the server socket. */
int recv_int(int socket_fd)
{
int msg = 0;
int n = read(socket_fd, &msg, sizeof(int));
  
if (n < 0 || n != sizeof(int))
log_error("ERROR reading int from server socket");
  
return msg;
}

/*
* Socket Write Functions
*/

/* Writes an int to the server socket. */
void write_server_int(int socket_fd, int msg)
{
int n = write(socket_fd, &msg, sizeof(int));
if (n < 0)
log_error("ERROR writing int to server socket");
  
}

/*
* Connect Functions
*/

/* Sets up the connection to the server. */
int connect_to_server(char * hostname, int portno)
{
struct sockaddr_in serv_address;
struct hostent *server;

/* Get a socket. */
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  
if (socket_fd < 0)
log_error("ERROR opening socket for server.");
  
/* Get the address of the server. */
server = gethostbyname(hostname);
  
if (server == NULL) {
fprintf(stderr,"ERROR, no such host ");
exit(0);
}
  
/* Zero out memory for server info. */
memset(&serv_address, 0, sizeof(serv_address));

/* Set up the server info. */
serv_address.sin_family = AF_INET;
memmove(server->h_addr, &serv_address.sin_addr.s_addr, server->h_length);
serv_address.sin_port = htons(portno);

/* Make the connection. */
if (connect(socket_fd, (struct sockaddr *) &serv_address, sizeof(serv_address)) < 0)
log_error("ERROR connecting to server");


return socket_fd;
}

/*
* Below Functions implement the actual game
*/

/* Draw the board on screen. */
void draw_board(char my_board[][3])
{
printf(" %c | %c | %c ", my_board[0][0], my_board[0][1], my_board[0][2]);
printf("----------- ");
printf(" %c | %c | %c ", my_board[1][0], my_board[1][1], my_board[1][2]);
printf("----------- ");
printf(" %c | %c | %c ", my_board[2][0], my_board[2][1], my_board[2][2]);
}

/* Get's the players turn and sends it to the server. */
void my_turn(int socket_fd)
{
char temp[10];
  
while (1) { /* Ask until we receive. */
printf("Enter 0-8 to make a move, or 9 for number of active players: ");
fgets(temp, 10, stdin);
int move = temp[0] - '0';
if (move <= 9 && move >= 0){
printf(" ");
/* Send players move to the server. */
write_server_int(socket_fd, move);   
break;
}
else
printf(" Invalid input. Try again. ");
}
}

/* Gets a board update from the server. */
void get_serv_update(int socket_fd, char my_board[][3])
{
/* Get the update. */
int player_id = recv_int(socket_fd);
int move = recv_int(socket_fd);

/* Update the game board. */
my_board[move/3][move%3] = player_id ? 'X' : 'O';
}

/*
* Main Program
*/

int main(int argc, char *argv[])
{
/* Make sure host and port are specified. */
if (argc < 3) {
fprintf(stderr,"usage %s hostname port ", argv[0]);
exit(0);
}

/* Connect to the server. */
int socket_fd = connect_to_server(argv[1], atoi(argv[2]));

/* The client ID is the first thing we receive after connecting. */
int id = recv_int(socket_fd);

char msg[4];
char my_board[3][3] = { {' ', ' ', ' '}, /* Game board */
{' ', ' ', ' '},
{' ', ' ', ' '} };

printf("Tic-Tac-Toe ------------ ");

/* Wait for the game to start. */
do {
recv_msg(socket_fd, msg);
if (!strcmp(msg, "HLD"))
printf("Waiting for a second player... ");
} while ( strcmp(msg, "SRT") );

/* The game has begun. */
printf("Game on! ");
printf("Your are %c's ", id ? 'X' : 'O');

draw_board(my_board);

while(1) {
recv_msg(socket_fd, msg);

if (!strcmp(msg, "TRN")) { /* Take a turn. */
printf("Your move... ");
my_turn(socket_fd);
}
else if (!strcmp(msg, "INV")) { /* Move was invalid. Note that a "TRN" message will always follow an "INV" message, so we will end up at the above case in the next iteration. */
printf("That position has already been played. Try again. ");
}
else if (!strcmp(msg, "CNT")) { /* Server is sending the number of active players. Note that a "TRN" message will always follow a "CNT" message. */
int num_players = recv_int(socket_fd);
printf("There are currently %d active players. ", num_players);
}
else if (!strcmp(msg, "UPD")) { /* Server is sending a game board update. */
get_serv_update(socket_fd, my_board);
draw_board(my_board);
}
else if (!strcmp(msg, "WAT")) { /* Wait for other player to take a turn. */
printf("Waiting for other players move... ");
}
else if (!strcmp(msg, "WIN")) { /* Winner. */
printf("You win! ");
break;
}
else if (!strcmp(msg, "LSE")) { /* Loser. */
printf("You lost. ");
break;
}
else if (!strcmp(msg, "DRW")) { /* Game is a draw. */
printf("Draw. ");
break;
}
else /* Weird... */
log_error("Unknown message.");
}
  
printf("Game over. ");

/* Close server socket and exit. */
close(socket_fd);
return 0;
}

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int player_count = 0;
pthread_mutex_t mutex_count;

void log_error(const char *msg)
{
perror(msg);
pthread_exit(NULL);
}

/*
* Socket Functions for reading
*/

/* Reads an integer from a client socket. */
int recv_client(int client_sockfd)
{
int msg = 0;
int n = read(client_sockfd, &msg, sizeof(int));
  
if (n < 0 || n != sizeof(int)) /* Not what we were expecting. Client likely disconnected. */
return -1;

return msg;
}

/*
* Socket Write Functions
*/

/* Writes a message to a client socket. */
void write_client_msg(int client_sockfd, char * msg)
{
int n = write(client_sockfd, msg, strlen(msg));
if (n < 0)
log_error("ERROR writing msg to client socket");
}

/* Writes an int to a client socket. */
void write_client_int(int client_sockfd, int msg)
{
int n = write(client_sockfd, &msg, sizeof(int));
if (n < 0)
log_error("ERROR writing int to client socket");
}

/* Writes a message to both client sockets. */
void write_clients_msg(int * client_sockfd, char * msg)
{
write_client_msg(client_sockfd[0], msg);
write_client_msg(client_sockfd[1], msg);
}

/* Writes an int to both client sockets. */
void write_clients_int(int * client_sockfd, int msg)
{
write_client_int(client_sockfd[0], msg);
write_client_int(client_sockfd[1], msg);
}

/*
* Connect Functions
*/

/* Sets up the listener socket. */
int setup_listener(int portno)
{
int sockfd;
struct sockaddr_in serv_addr;

/* Get a socket to listen on */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
log_error("ERROR opening listener socket.");
  
/* Zero out the memory for the server information */
memset(&serv_addr, 0, sizeof(serv_addr));
  
   /* set up the server info */
serv_addr.sin_family = AF_INET;  
serv_addr.sin_addr.s_addr = INADDR_ANY;  
serv_addr.sin_port = htons(portno);      

/* Bind the server info to the listener socket. */
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
log_error("ERROR binding listener socket.");

/* Return the socket number. */
return sockfd;
}

/* Sets up the client sockets and client connections. */
void get_clients(int lis_sockfd, int * client_sockfd)
{
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
  

/* Listen for two clients. */
int num_conn = 0;
while(num_conn < 2)
{
/* Listen for clients. */
   listen(lis_sockfd, 253 - player_count);
  
/* Zero out memory for the client information. */
memset(&cli_addr, 0, sizeof(cli_addr));

clilen = sizeof(cli_addr);
  
   /* Accept the connection from the client. */
client_sockfd[num_conn] = accept(lis_sockfd, (struct sockaddr *) &cli_addr, &clilen);
  
if (client_sockfd[num_conn] < 0)
/* Horrible things have happened. */
log_error("ERROR accepting a connection from a client.");


/* Send the client it's ID. */
write(client_sockfd[num_conn], &num_conn, sizeof(int));
  

/* Increment the player count. */
pthread_mutex_lock(&mutex_count);
player_count++;
printf("Number of players is now %d. ", player_count);
pthread_mutex_unlock(&mutex_count);

if (num_conn == 0) {
/* Send "HLD" to first client to let the user know the server is waiting on a second client. */
write_client_msg(client_sockfd[0],"HLD");
  
}

num_conn++;
}
}

/*
* Game Functions
*/

/* Gets a move from a client. */
int get_player_move(int client_sockfd)
{

/* Tell player to make a move. */
write_client_msg(client_sockfd, "TRN");

/* Get players move. */
return recv_client(client_sockfd);
}

/* Checks that a players move is valid. */
int check_move(char board[][3], int move, int player_id)
{
if ((move == 9) || (board[move/3][move%3] == ' ')) { /* Move is valid. */
  
return 1;
}
else { /* Move is invalid. */
return 0;
}
}

/* Updates the board with a new move. */
void update_board(char board[][3], int move, int player_id)
{
board[move/3][move%3] = player_id ? 'X' : 'O';
}

/* Draws the game board to stdout. */
void draw_board(char board[][3])
{
printf(" %c | %c | %c ", board[0][0], board[0][1], board[0][2]);
printf("----------- ");
printf(" %c | %c | %c ", board[1][0], board[1][1], board[1][2]);
printf("----------- ");
printf(" %c | %c | %c ", board[2][0], board[2][1], board[2][2]);
}

/* Sends a board update to both clients. */
void send_update(int * client_sockfd, int move, int player_id)
{

/* Signal an update */
write_clients_msg(client_sockfd, "UPD");

/* Send the id of the player that made the move. */
write_clients_int(client_sockfd, player_id);
  
/* Send the move. */
write_clients_int(client_sockfd, move);
  
}

/* Sends the number of active players to a client. */
void send_player_count(int client_sockfd)
{
write_client_msg(client_sockfd, "CNT");
write_client_int(client_sockfd, player_count);

}

/* Checks the board to determine if there is a winner. */
int check_board(char board[][3], int last_move)
{
  
int row = last_move/3;
int col = last_move%3;

if ( board[row][0] == board[row][1] && board[row][1] == board[row][2] ) { /* Check the row for a win. */

return 1;
}
else if ( board[0][col] == board[1][col] && board[1][col] == board[2][col] ) { /* Check the column for a win. */

return 1;
}
else if (!(last_move % 2)) { /* If the last move was at an even numbered position we have to check the diagonal(s) as well. */
if ( (last_move == 0 || last_move == 4 || last_move == 8) && (board[1][1] == board[0][0] && board[1][1] == board[2][2]) ) { /* Check backslash diagonal. */

return 1;
}
if ( (last_move == 2 || last_move == 4 || last_move == 6) && (board[1][1] == board[0][2] && board[1][1] == board[2][0]) ) { /* Check frontslash diagonal. */

return 1;
}
}
  
/* No winner, yet. */
return 0;
}

/* starts the game between two clients. */
void *start_game(void *thread_fd)
{
int *client_sockfd = (int*)thread_fd; /* Client sockets. */
char board[3][3] = { {' ', ' ', ' '}, /* Game Board */
{' ', ' ', ' '},
{' ', ' ', ' '} };

printf("Game on >>>>> Let's play..! ");
  
/* Send the start message. */
write_clients_msg(client_sockfd, "SRT");

draw_board(board);
  
int prev_player_turn = 1;
int player_turn = 0;
int game_over = 0;
int turn_count = 0;
while(!game_over) {
/* Tell other player to wait, if necessary. */
if (prev_player_turn != player_turn)
write_client_msg(client_sockfd[(player_turn + 1) % 2], "WAT");

int valid = 0;
int move = 0;
while(!valid) { /* We need to keep asking for a move until the player's move is valid. */
move = get_player_move(client_sockfd[player_turn]);
if (move == -1) break; /* Error reading client socket. */

printf("Player %d played position %d ", player_turn, move);
  
valid = check_move(board, move, player_turn);
if (!valid) { /* Move was invalid. */
printf("Move was invalid. Let's try this again... ");
write_client_msg(client_sockfd[player_turn], "INV");
}
}

   if (move == -1) { /* Error reading from client. */
printf("Player disconnected. ");
break;
}
else if (move == 9) { /* Send the client the number of active players. */
prev_player_turn = player_turn;
send_player_count(client_sockfd[player_turn]);
}
else {
/* Update the board and send the update. */
update_board(board, move, player_turn);
send_update( client_sockfd, move, player_turn );
  
/* Re-draw the board. */
draw_board(board);

/* Check for a winner/loser. */
game_over = check_board(board, move);
  
if (game_over == 1) { /* We have a winner. */
write_client_msg(client_sockfd[player_turn], "WIN");
write_client_msg(client_sockfd[(player_turn + 1) % 2], "LSE");
printf("Player %d won. ", player_turn);
}
else if (turn_count == 8) { /* There have been nine valid moves and no winner, game is a draw. */
printf("Draw. ");
write_clients_msg(client_sockfd, "DRW");
game_over = 1;
}

/* Move to next player. */
prev_player_turn = player_turn;
player_turn = (player_turn + 1) % 2;
turn_count++;
}
}

printf("Game over. ");

   /* Close client sockets and decrement player counter. */
close(client_sockfd[0]);
close(client_sockfd[1]);

pthread_mutex_lock(&mutex_count);
player_count--;
printf("Number of players is now %d.", player_count);
player_count--;
printf("Number of players is now %d.", player_count);
pthread_mutex_unlock(&mutex_count);
  
free(client_sockfd);

pthread_exit(NULL);
}

/*
* Main function
*/

int main(int argc, char *argv[])
{   
/* Make sure a port was specified. */
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided ");
exit(1);
}
  
int lis_sockfd = setup_listener(atoi(argv[1])); /* Listener socket. */
pthread_mutex_init(&mutex_count, NULL);

while (1) {
if (player_count <= 252) { /* Only launch a new game if we have room. Otherwise, just spin. */
int *client_sockfd = (int*)malloc(2*sizeof(int)); /* Client sockets */
memset(client_sockfd, 0, 2*sizeof(int));
  
/* Get two clients connected. */
get_clients(lis_sockfd, client_sockfd);

pthread_t my_thread; /* Pthread creation */
int ret = pthread_create(&my_thread, NULL, start_game, (void *)client_sockfd); /* Start a new thread for this game. */
if (ret){
printf("Thread creation failed with return code %d ", ret);
exit(-1);
}
}
}

close(lis_sockfd);

pthread_mutex_destroy(&mutex_count);
pthread_exit(NULL);
}

README

The below Tic-Tac-Toe game (Multiplayer) is written in C program using sockets concept.

This source code is developed on linux environment.

To compile, cd to this directory and run:

    make all  

Player-1 (server) will need to set up a game and should be executed first as given below command:

    ./tic_server [some port]  

The Player-2(client) should type in the below command on terminal:

    ./tic_client [server host] [some port]  

for instance tic_client can be compiled on with 192.0.2.80 IP address of the server with port 1024.

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Chat Now And Get Quote