[gameprogrammer] networked tic tac toe server

  • From: Chris Nystrom <cnystrom@xxxxxxxxx>
  • To: gameprogrammer@xxxxxxxxxxxxx
  • Date: Fri, 21 May 2010 21:37:26 -0500

I wrote this to test some networking routines. Experienced programmers
may want to critique. Comments welcome. Beginning programmers might
find something useful.

Thanks,
Chris

--
/* tic_tac_toe.c
 *
 * (c) 2010 Chris Nystrom
 *
 * Public Domain
 *
 * Use this for whatever you want
 *
 * compiles with no errors on linux
 *
 * Start this server then telnet to the server using port 32662
("telnet localhost 32662") to play. You must have 2 players.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#ifndef FALSE
#define FALSE (0)
#endif

#ifndef TRUE
#define TRUE !FALSE
#endif

/* the port users will be connecting to */
#define MYPORT 32662

/* how many pending connections queue will hold */
#define BACKLOG 10

/* listener socket */
int sockfd;

void init_server(void)
{
    /* my address information */
    struct sockaddr_in my_addr;

    int yes = 1;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket() error");
        exit(1);
    } else
        printf("socket() sockfd (listener) is: %d\n", sockfd);

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))
        == -1) {
        perror("setsockopt() error");
        exit(1);
    } else
        printf("setsockopt() is OK...\n");

    /* host byte order */
    my_addr.sin_family = AF_INET;

    /* short, network byte order */
    my_addr.sin_port = htons(MYPORT);

    /* automatically fill with my IP */
    my_addr.sin_addr.s_addr = INADDR_ANY;

    printf("Using %s and port %d...\n", inet_ntoa(my_addr.sin_addr),
           MYPORT);

    /* zero the rest of the struct */
    memset(&(my_addr.sin_zero), '\0', 8);

    if (bind
        (sockfd, (struct sockaddr *) &my_addr,
         sizeof(struct sockaddr)) == -1) {
        perror("bind() error");
        exit(1);
    } else
        printf("bind() is OK...\n");

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen() error");
        exit(1);
    }

    printf("listen() is OK...\n");
    printf("Listening...\n");
}

int new_connection(void)
{
    int new_fd;
    socklen_t sin_size;

    /* connector’s address information */
    struct sockaddr_in their_addr;

    sin_size = sizeof(struct sockaddr_in);

    if ((new_fd =
         accept(sockfd, (struct sockaddr *) &their_addr,
                &sin_size)) == -1) {
        perror("accept() error");
        exit(1);
    } else
        printf("accept() is OK...\n");

    printf("socket %d: Connection from %s\n", new_fd,
           inet_ntoa(their_addr.sin_addr));

    return (new_fd);
}

void write_to_socket(int fd, char *s)
{
    if (send(fd, s, strlen(s), 0) == -1)
        perror("send() error");
//  else
//    printf ("send is OK...!\n");
}

#define BUF_SIZE (1024)
void printf_to_socket(int fd, const char *format, ...)
{
    char s[BUF_SIZE];
    va_list ap;

    va_start(ap, format);
    vsnprintf(s, BUF_SIZE, format, ap);
    va_end(ap);

    write_to_socket(fd, s);
}

int read_from_socket(int fd, char *buf)
{
    int nbytes;

    if ((nbytes = recv(fd, buf, sizeof(buf), 0)) <= 0) {
        if (nbytes == 0)
            /* connection closed */
            printf("socket %d hung up\n", fd);
        else
            perror("recv() error");
    }

    return (nbytes);
}

void close_socket(int fd)
{
    close(fd);
    printf("socket %d: closed...\n", fd);
}

#define NUM_OF_PLAYERS (2)

int fd[NUM_OF_PLAYERS];
int num_players = NUM_OF_PLAYERS;

void read_from_player(int player, char *s)
{
    read_from_socket(fd[player - 1], s);
}

void write_to_player(int player, char *s)
{
    write_to_socket(fd[player - 1], s);
}

void write_to_other_player(int player, char *s)
{
    /* switch player */
    if (1 == player) {
        player = 2;
    } else {
        player = 1;
    }

    write_to_player(player, s);
}

void write_to_all_players(char *s)
{
    int i;

    for (i = 0; i < num_players; i++) {
        write_to_socket(fd[i], s);
    }
}

void printf_to_player(int player, const char *format, ...)
{
    char s[BUF_SIZE];
    va_list ap;

    va_start(ap, format);
    vsnprintf(s, BUF_SIZE, format, ap);
    va_end(ap);

    write_to_player(player, s);
}

void printf_to_other_player(int player, const char *format, ...)
{
    char s[BUF_SIZE];
    va_list ap;

    va_start(ap, format);
    vsnprintf(s, BUF_SIZE, format, ap);
    va_end(ap);

    write_to_other_player(player, s);
}

void printf_to_all_players(const char *format, ...)
{
    char s[BUF_SIZE];
    va_list ap;

    va_start(ap, format);
    vsnprintf(s, BUF_SIZE, format, ap);
    va_end(ap);

    write_to_all_players(s);
}

void init_game(void)
{
    char sTitle[] = "\nTic Tac Toe Server v1.0\n\n";

    init_server();

    fd[0] = new_connection();

    printf("Player 1 has joined.\n");

    fd[1] = new_connection();

    printf("Player 2 has joined.\n");

    write_to_all_players(sTitle);
}

void print_guide(void)
{
    write_to_all_players("Select moves from this grid:\n\n");
    write_to_all_players(" 1 | 2 | 3\n");
    write_to_all_players("----------\n");
    write_to_all_players(" 4 | 5 | 6\n");
    write_to_all_players("----------\n");
    write_to_all_players(" 7 | 8 | 9\n");
}

int board[9] = { 0 };

void reset_game(void)
{
    int i;

    for (i = 0; i < 9; i++) {
        board[i] = 0;
    }
}

void print_board(void)
{
    int i;
    int count = 0;

    write_to_all_players("\n");

    for (i = 0; i < 9; i++) {
        if (1 == board[i]) {
            write_to_all_players(" X ");
        } else if (2 == board[i]) {
            write_to_all_players(" O ");
        } else {
            write_to_all_players(" . ");
        }

        count++;
        if (3 == count) {
            write_to_all_players("\n");
            if (i < 8) {
                write_to_all_players("-----------\n");
            }
            count = 0;
        } else {
            write_to_all_players("|");
        }
    }

    write_to_all_players("\n");
}

int get_move(int player)
{
    int move = 0;
    char buf[1024];

    printf_to_other_player(player, "Waiting on player %d...\n", player);

    while (move < 1 || move > 9) {
        printf_to_player(player, "Player %d move: ", player);

        read_from_player(player, buf);
        move = atoi(buf);

        if (board[move - 1] != 0) {
            write_to_player(player, "That spot already taken!\n");
            move = 0;
        }
    }

    printf_to_other_player(player, "Player %d move: %d\n", player, move);

    return (move);
}

void process_move(int player, int move)
{
    board[move - 1] = player;
}

int check_for_winner(void)
{
    int winner = FALSE;

    /* across */

    if ((board[0] != 0) && (board[0] == board[1])
        && (board[1] == board[2])) {
        winner = board[0];
    }
    if ((board[3] != 0) && (board[3] == board[4])
        && (board[4] == board[5])) {
        winner = board[3];
    }
    if ((board[6] != 0) && (board[6] == board[7])
        && (board[7] == board[8])) {
        winner = board[6];
    }

    /* down */

    if ((board[0] != 0) && (board[0] == board[3])
        && (board[3] == board[6])) {
        winner = board[0];
    }
    if ((board[1] != 0) && (board[1] == board[4])
        && (board[4] == board[7])) {
        winner = board[1];
    }
    if ((board[2] != 0) && (board[2] == board[5])
        && (board[5] == board[8])) {
        winner = board[2];
    }

    /* diagonal */

    if ((board[0] != 0) && (board[0] == board[4])
        && (board[4] == board[8])) {
        winner = board[4];
    }
    if ((board[2] != 0) && (board[2] == board[4])
        && (board[4] == board[6])) {
        winner = board[4];
    }

    return (winner);
}

void close_all_sockets(void)
{
    int i;

    for (i = 0; i < num_players; i++) {
        close_socket(fd[i]);
    }
}

void play_game(void)
{
    int player = 1;
    int winner = FALSE;
    int draw = FALSE;
    int move;
    int count = 0;

    reset_game();
    print_guide();
    print_board();
    while (!winner && !draw) {
        move = get_move(player);
        printf_to_other_player(player, "%d\n", move);
        process_move(player, move);
        print_board();
        winner = check_for_winner();
        count++;
        if (!winner && 9 == count) {
            draw = TRUE;
        }
        /* switch player */
        if (1 == player) {
            player = 2;
        } else {
            player = 1;
        }
    }

    write_to_all_players("\nGame over!\n\n");

    if (winner) {
        printf_to_all_players("The winner is player %d!\n\n", winner);
    }

    if (draw) {
        write_to_all_players("The game was a draw! No winner!\n\n");
    }
}

int main(int argc, char *argv[])
{
    init_game();
    play_game();
    close_all_sockets();
    exit(0);
}


-- 
E-Mail: Chris Nystrom <cnystrom@xxxxxxxxx>
Saving the world from web programming.
http://www.newio.org - G-Talk: cnystrom

---------------------
To unsubscribe go to http://gameprogrammer.com/mailinglist.html


Other related posts:

  • » [gameprogrammer] networked tic tac toe server - Chris Nystrom