87.7k views
5 votes
PROGRAM DESCRIPTION: In this assignment, you will write two complete C programs that will allow two players to play the game of network tic-tac-toe. It will include two programs, a server and a client. The server will allow two clients to connect and then will begin the game. The client programs accept input from the player and transmits the command to the server which will execute the commands and send a reply back to the client programs. The client and server programs are to communicate via the Internet (network) using TCP sockets. Your server should be able to handle commands from either client in any order. Your clients should be able to handle responses from the server or the player. (hint: use select) The game is for two players on a 3x3 grid. The player who moves first uses X marks. The second player uses O marks. Each player takes turns placing their mark (XJO) on an empty spot on the grid. The game ends when all spots have a mark or either player has 3 marks in a row. REQUIREMENTS: Your code should be well documented in terms of comments. For example, good comments in general consist of a header (with your name, course section, date, and brief description), comments for each variable, and commented blocks of code. Your server should be named "minor4server.c". without the quotes. Your client should be named "minor4client.c", without the quotes. Your programs will be graded based largely on whether it works correctly on the CSE machines (e.g., cse01, cse02, ..., cse06), so you should make sure that your scripts do not have any runtime errors and runs on a CSE machine. This is an individual programming assignment that must be the sole work of the individual student. Any instance of academic dishonesty will result in a grade of "F" for the course, along with a report filed into the Academic Integrity Database.

1 Answer

3 votes

Answer:

Step-by-step explanation:

minor4server.c:

#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 mutexcount;

void error(const char *msg)

{

perror(msg);

pthread_exit(NULL);

}

/* Reads an int from a client socket. */

int recv_int(int cli_sockfd)

n != sizeof(int)) /* Client likely disconnected. */

return -1;

#ifdef DEBUG

printf("[DEBUG] Received int: %d\\", msg);

#endif

return msg;

/* Writes a message to a client socket. */

void write_client_msg(int cli_sockfd, char * msg)

{

int n = write(cli_sockfd, msg, strlen(msg));

if (n < 0)

error("ERROR writing msg to client socket");

}

/* Writes an int to a client socket. */

void write_client_int(int cli_sockfd, int msg)

{

int n = write(cli_sockfd, &msg, sizeof(int));

if (n < 0)

error("ERROR writing int to client socket");

}

/* Writes a message to both client sockets. */

void write_clients_msg(int * cli_sockfd, char * msg)

{

write_client_msg(cli_sockfd[0], msg);

write_client_msg(cli_sockfd[1], msg);

}

/* Writes an int to both client sockets. */

void write_clients_int(int * cli_sockfd, int msg)

{

write_client_int(cli_sockfd[0], msg);

write_client_int(cli_sockfd[1], msg);

}

/* 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)

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)

error("ERROR binding listener socket.");

#ifdef DEBUG

printf("[DEBUG] Listener set.\\");

#endif

/* Return the socket number. */

return sockfd;

}

/* Sets up the client sockets and client connections. */

void get_clients(int lis_sockfd, int * cli_sockfd)

{

socklen_t clilen;

struct sockaddr_in serv_addr, cli_addr;

#ifdef DEBUG

printf("[DEBUG] Listening for clients...\\");

#endif

/* 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. */

cli_sockfd[num_conn] = accept(lis_sockfd, (struct sockaddr *) &cli_addr, &clilen);

if (cli_sockfd[num_conn] < 0)

/* Horrible things have happened. */

error("ERROR accepting a connection from a client.");

#ifdef DEBUG

printf("[DEBUG] Accepted connection from client %d\\", num_conn);

#endif

/* Send the client it's ID. */

write(cli_sockfd[num_conn], &num_conn, sizeof(int));

#ifdef DEBUG

printf("[DEBUG] Sent client %d it's ID.\\", num_conn);

#endif

/* Increment the player count. */

pthread_mutex_lock(&mutexcount);

player_count++;

printf("Number of players is now %d.\\", player_count);

pthread_mutex_unlock(&mutexcount);

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(cli_sockfd[0],"HLD");

#ifdef DEBUG

printf("[DEBUG] Told client 0 to hold.\\");

#endif

}

num_conn++;

}

}

/* Gets a move from a client. */

int get_player_move(int cli_sockfd)

{

#ifdef DEBUG

printf("[DEBUG] Getting player move...\\");

#endif

/* Tell player to make a move. */

write_client_msg(cli_sockfd, "TRN");

/* Get players move. */

return recv_int(cli_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. */

#ifdef DEBUG

printf("[DEBUG] Player %d's move was valid.\\", player_id);

#endif

return 1;

}

else { /* Move is invalid. */

#ifdef DEBUG

printf("[DEBUG] Player %d's move was invalid.\\", player_id);

#endif

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';

#ifdef DEBUG

printf("[DEBUG] Board updated.\\");

#endif

}

/* Draws the game board to stdout. */

void draw_board(char board[][3])

%c \\", board[0][0], board[0][1], board[0][2]);

printf("-----------\\");

printf(" %c

/* Sends a board update to both clients. */

void send_update(int * cli_sockfd, int move, int player_id)

{

#ifdef DEBUG

printf("[DEBUG] Sending update...\\");

#endif

/* Signal an update */

write_clients_msg(cli_sockfd, "UPD");

/* Send the id of the player that made the move. */

write_clients_int(cli_sockfd, player_id);

/* Send the move. */

write_clients_int(cli_sockfd, move);

#ifdef DEBUG

printf("[DEBUG] Update sent.\\");

#endif

User Mgigirey
by
4.3k points