/* 
 * nttt.c - TCP/IP TIC TAC TOE by r4lph
 *          You guessed it. Tic tac toe, taken to the next level. Play your
 *          friends, play your mom, even play so1o! Works on *BSD* and Linux
 *          as far as I know. Mail r4lph@b4b0.org if it works on your non 
 *          *BSD*\Linux system. If you don't like something in the code, 
 *          for christs sake, don't tell me, just change it. Don't distribute
 *          modified versions, blah blah blah. The connector will always be
 *          X and the connected to will be O. 
 * compile: cc -O2 -o nttt nttt.c
 * Have fun.
 * Oct. 18/1998
 * r4lph <r4lph@b4b0.org>
*/

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

/* defines */
#define X 1
#define O 0
#define PORT 9876

/* color defines */
#define END		""
#define RED		""
#define GREEN		""
#define BLUE		""
#define BOLDWHITE	""
#define BGRED		""

/* function prototypes */
int main(int argc, char *argv[]);     /* duh */
unsigned long getip(char *hostname);  /* resolve hostname */
void initiate(unsigned long ip);      /* initiate a connection */
void wait_for_connection(void);       /* listen for a connection */
void usage(char *name);               /* -h */
void play_ttt(void);                  /* main ttt function */
void draw(void);                      /* draw the grid on the screen */
void x_input(void);                   /* input X value */
void o_input(void);                   /* input O value */
void x_plot(int x_coord);             /* update the grid */
void o_plot(int o_coord);
void sync_players(void);              /* synchronize players */
int continue_ttt(void);               
int check(char xoro);                 /* check for winner */
void color_fix(int sig);                 /* signal handler */
void reset_ttt(void);                 /* reset the ttt grid */

/* global socket descriptors BADBADBAD! */
int sockfd, newsockfd, sfd;

/* two dimensional array for ttt grid */
char ttt[3][3] = {{'1','2','3'},{'4','5','6'},{'7','8','9'}};

/* player info struct */
struct players {
   char remote[10]; /* usernames */
   char local[10];
   int x_or_o; /* are we X or O? */
}player;

/* duh */
int main(int argc, char *argv[])
{
   int arg;
   int cont = 1;
   
   signal(SIGKILL, color_fix);
   signal(SIGINT, color_fix);
	  
   if(argc < 2)
     usage(argv[0]);
   
   while((arg=getopt(argc, argv, "i:lh")) != EOF)
     {
	switch(arg)
	  {
	   case 'i':  /* initiate */
	       {
		  printf("%splayername>%s%s ",BOLDWHITE,END,RED);
		  scanf("%9s", player.local);
		  initiate(getip(optarg));
		  while(cont == 1)
		    {
		       reset_ttt();
		       sync_players();
		       play_ttt();
		       cont = continue_ttt();
		    }
		  close(sockfd);
		  printf("%s", END);
		  exit(0);
	       }
	   case 'l':  /* listen */
	       {
		  printf("%splayername>%s%s ",BOLDWHITE,END,RED);
		  scanf("%9s", player.local);
		  wait_for_connection();
		  while(cont == 1)
		    {
		       reset_ttt();
		       sync_players();
		       play_ttt();
		       cont = continue_ttt();
		    }
		  close(sockfd);
		  printf("%s", END);
		  exit(0);
	       }
	   case 'h':
	       {
		  usage(argv[0]);
	       }
	   default:
	       {
		  usage(argv[0]);
	       }
	  }
     }   
   return(0);
}

unsigned long getip(char *hostname)
{
   struct hostent *he;
   if((he=gethostbyname(hostname)) == NULL) /* get that smaq */
     {
	herror("gethostbyname");
	printf("%s", END);
	exit(1);
     }
   return(inet_addr(inet_ntoa(*((struct in_addr *)he->h_addr)))); /* yuck. */
}

void usage(char *name)
{
   fprintf(stderr, "%s%sTCP/IP TIC TAC TOE by r4lph%s\n",BGRED,BLUE,END);
   fprintf(stderr, "%susage: %s -l                 [ listen for a connection ]\n",BLUE, name);
   fprintf(stderr, "       %s -i < remote host > [ initiate a connection ]\n", name);
   fprintf(stderr, "       %s -h                 [ help ]%s\n", name, END);
   exit(0);
}

void draw(void)
{
   (void)system("clear");
   printf("\n\n\n\n\n\n\n\n\n\n");
   printf("\t\t\t    %s%c%s º %s %c %s º %s%c\n",BLUE,ttt[0][0],RED,BLUE,ttt[0][1],RED,BLUE,ttt[0][2]);
   printf("\t\t\t   %sÍÍÍÎÍÍÍÍÍÎÍÍÍ%s\n",RED,END);
   printf("\t\t\t    %s%c%s º %s %c %s º %s%c\n",BLUE,ttt[1][0],RED,BLUE,ttt[1][1],RED,BLUE,ttt[1][2]);
   printf("\t\t\t   %sÍÍÍÎÍÍÍÍÍÎÍÍÍ%s\n", RED, END);
   printf("\t\t\t    %s%c%s º %s %c %s º %s%c\n",BLUE,ttt[2][0],RED,BLUE,ttt[2][1],RED,BLUE,ttt[2][2]);
}

int continue_ttt(void)
{
   char c;
   printf("\n%s\t\t   Play another game? (y)es/(n)o:%s%s ",BOLDWHITE,END,RED);
   scanf("%1s", &c); /* PLEEZE SEY YES !@# */
   if(c == 'y' || c == 'Y')
     return(1);
   else
     return(0);
}

void reset_ttt(void)
{
   ttt[0][0] = '1'; /* OINK */
   ttt[0][1] = '2';
   ttt[0][2] = '3';
   ttt[1][0] = '4';
   ttt[1][1] = '5';
   ttt[1][2] = '6';
   ttt[2][0] = '7';
   ttt[2][1] = '8';
   ttt[2][2] = '9';
}

void initiate(unsigned long ip)
{
   struct sockaddr_in remote;
   
   player.x_or_o = X;  /* we are X */
   bzero(&remote, sizeof(struct sockaddr_in));
   remote.sin_family = AF_INET;
   remote.sin_port = htons(PORT);
   remote.sin_addr.s_addr = ip;
   
   if((sfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
     {
	perror("socket");
	printf("%s", END);
	exit(1);
     }
   printf("%s%sWaiting for player...%s\n",END,BOLDWHITE,END);
   if(connect(sfd, (struct sockaddr *)&remote, sizeof(struct sockaddr)) == -1)
     {
	perror("connect");
	printf("%s", END);
	close(sfd);
	exit(1);
     }
   send(sfd, player.local, sizeof(player.local), 0);
   recv(sfd, player.remote, sizeof(player.remote), 0);
   printf("%s%sConnection established with%s%s %s [ %s ]%s\n",END,BOLDWHITE,END,RED,player.remote
	                                ,inet_ntoa(remote.sin_addr.s_addr),END);
   sleep(2);
}

void wait_for_connection(void)
{
   struct sockaddr_in remote;
   struct sockaddr_in local;
   int addrlen;
      
   player.x_or_o = O;  /* we are O */
   addrlen = sizeof(struct sockaddr_in);
   
   bzero(&remote, sizeof(struct sockaddr_in));
   bzero(&local, sizeof(struct sockaddr_in));
   local.sin_family = AF_INET;
   local.sin_port = htons(PORT);
   local.sin_addr.s_addr = INADDR_ANY;
   
   if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
     {
	perror("socket");
	printf("%s", END);
	exit(1);
     }
   if(bind(sockfd, (struct sockaddr *)&local, sizeof(struct sockaddr)) == -1)
     {
	perror("bind");
	printf("%s", END);
	close(sockfd);
	exit(1);
     }
   if(listen(sockfd, 1) == -1)
     {
	perror("listen");
	printf("%s", END);

	close(sockfd);
	exit(1);
     }
   printf("%s%sWaiting for player...\n%s",END,BOLDWHITE,END);
   if((newsockfd=accept(sockfd, (struct sockaddr *)&remote, &addrlen)) == -1)
     {
	perror("accept");
	printf("%s", END);
	close(sockfd);
	exit(1);
     }
   sfd = newsockfd;
   recv(sfd, player.remote, sizeof(player.remote), 0);
   send(sfd, player.local, sizeof(player.local), 0);
   printf("%s%sConnection established with %s%s%s [ %s ]%s\n",END,BOLDWHITE,END,RED, player.remote
	                                          , inet_ntoa(remote.sin_addr.s_addr), END);
   sleep(2);
}

void x_input(void)
{
   int coord;
   if(player.x_or_o == O)
     {
	recv(sfd, &coord, sizeof(coord), 0);
	x_plot(coord);
	draw();
	return;
     }
   printf("\n");
   printf("\t\t\t    %s%sX>%s%s ",END,BOLDWHITE,END,RED);
   scanf("%d", &coord);   /* d0nt LOSE !@#$ */
   send(sfd, &coord, sizeof(coord), 0);
   x_plot(coord);
   draw();
   return;
}

void o_input(void)
{
   int coord;
   if(player.x_or_o == X)
     {
	recv(sfd, &coord, sizeof(coord), 0);
	o_plot(coord);
	draw();
	return;
     }
   printf("\n");
   
   printf("\t\t\t    %s%sO>%s%s ",END,BOLDWHITE,END,RED);
   scanf("%d", &coord);
   send(sfd, &coord, sizeof(coord), 0);
   o_plot(coord);
   draw();
   return;
}

void x_plot(int x_coord)
{
   switch(x_coord)
     {
      case 1:
        if(ttt[0][0] == 'o' || ttt[0][0] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[0][0] = 'x'; break;
      case 2:
        if(ttt[0][1] == 'o' || ttt[0][1] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[0][1] = 'x'; break;
      case 3:
        if(ttt[0][2] == 'o' || ttt[0][2] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[0][2] = 'x'; break;
      case 4:
        if(ttt[1][0] == 'o' || ttt[1][0] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[1][0] = 'x'; break;
      case 5:
        if(ttt[1][1] == 'o' || ttt[1][1] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[1][1] = 'x'; break;
      case 6:
        if(ttt[1][2] == 'o' || ttt[1][2] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[1][2] = 'x'; break;
      case 7:
        if(ttt[2][0] == 'o' || ttt[2][0] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[2][0] = 'x'; break;
      case 8:
        if(ttt[2][1] == 'o' || ttt[2][1] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
             else
          ttt[2][1] = 'x'; break;
      case 9:
        if(ttt[2][2] == 'o' || ttt[2][2] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, x_coord, END);
             x_input();
          }
        else
          ttt[2][2] = 'x'; break;
     }
}

void o_plot(int o_coord)
{
   switch(o_coord)
     {
      case 1:
        if(ttt[0][0] == 'o' || ttt[0][0] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[0][0] = 'o'; break;
      case 2:
        if(ttt[0][1] == 'o' || ttt[0][1] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[0][1] = 'o'; break;
      case 3:
        if(ttt[0][2] == 'o' || ttt[0][2] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[0][2] = 'o'; break;
      case 4:
        if(ttt[1][0] == 'o' || ttt[1][0] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[1][0] = 'o'; break;
      case 5:
        if(ttt[1][1] == 'o' || ttt[1][1] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[1][1] = 'o'; break;
      case 6:
        if(ttt[1][2] == 'o' || ttt[1][2] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[1][2] = 'o'; break;
      case 7:
        if(ttt[2][0] == 'o' || ttt[2][0] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[2][0] = 'o'; break;
      case 8:
        if(ttt[2][1] == 'o' || ttt[2][1] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[2][1] = 'o'; break;
      case 9:
        if(ttt[2][2] == 'o' || ttt[2][2] == 'x')
          {
             printf("%s\t\t\tLocation %d is occupied%s",BOLDWHITE, o_coord, END);
             o_input();
          }
        else
          ttt[2][2] = 'o'; break;
     }
}
   
void sync_players(void)
{
char buf[7];
   
if(player.x_or_o == X)
  {
     send(sfd, "sync", 5, 0);
     recv(sfd, buf, sizeof(buf), 0);
     if(strcmp("synced", buf) != 0)
       {
	  fprintf(stderr, "%sCouldn't sync!%s\n", BOLDWHITE, END);
	  close(sfd);
	  exit(1);
       }
  }  
if(player.x_or_o == O)
  {
     recv(sfd, buf, sizeof(buf), 0);
     if(strcmp("sync", buf) != 0)
       {
	  fprintf(stderr, "%sCouldn't sync!%s\n", BOLDWHITE, END);
	  close(sfd);
	  exit(1);
       }
     send(sfd, "synced", 7, 0);
  }
}

void play_ttt(void)
{
int c = 0;
   
draw();
for(;;)
  {  
     x_input();
     if(check('x'))
       return;
     c++; /* heh */
     if(c==9)
       { 
	  return;
       }
     o_input();
     if(check('o'))
       return;
     c++; /* heh? */
     if(c==9)
       {
	  return;
       }
  }
}

int check(char xoro)  /* sorta sounds like porno */
{
   int blah;
   
   if(xoro=='x')
     blah = X;
   if(xoro=='o')
     blah = O;
   
   if(ttt[0][0]==xoro && ttt[0][1]==xoro && ttt[0][2]==xoro)
     {
	if(player.x_or_o==blah)
	  {
	     printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
	     return(1);  /* bewm */
	  }
	printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
	return(1);
     }
   if(ttt[1][0]==xoro && ttt[1][1]==xoro && ttt[1][2]==xoro)
     {
        if(player.x_or_o==blah)
          {
             printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
             return(1);
          }
        printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
        return(1);
     }
   if(ttt[2][0]==xoro && ttt[2][1]==xoro && ttt[2][2]==xoro)
     {
        if(player.x_or_o==blah)
          {
             printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
             return(1);
          }
        printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
        return(1);
     }
   if(ttt[0][0]==xoro && ttt[1][0]==xoro && ttt[2][0]==xoro)
     {
        if(player.x_or_o==blah)
          {
             printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
             return(1);
          }
        printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
        return(1);
     }
   if(ttt[0][1]==xoro && ttt[1][1]==xoro && ttt[2][1]==xoro)
     {
        if(player.x_or_o==blah)
          {
             printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
             return(1);
          }
        printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
        return(1);
     }
   if(ttt[0][2]==xoro && ttt[1][2]==xoro && ttt[2][2]==xoro)
     {
        if(player.x_or_o==blah)
          {
             printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
             return(1);
          }
        printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
        return(1);
     }
   if(ttt[0][0]==xoro && ttt[1][1]==xoro && ttt[2][2]==xoro)
     {
        if(player.x_or_o==blah)
          {
             printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
             return(1);
          }
        printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
        return(1);
     }
   if(ttt[2][0]==xoro && ttt[1][1]==xoro && ttt[0][2]==xoro)
     {
        if(player.x_or_o==blah)
          {
             printf("\n%s\t\t\t   YOU WIN %s%s\n",GREEN, player.local, END);
             return(1);
          }
        printf("\n%s\t\t\t   YOU LOSE %s%s\n",GREEN, player.local, END);
        return(1);
     }
   return(0);
}

void color_fix(int sig)
{
   printf("%s\n", END);
   close(sfd);
   exit(0);
}


syntax highlighted by Code2HTML, v. 0.9.1