/*

   To Compile: cc -o xtic Xtic-Tac-Toe.c -lXext -lX11 -lm
   You may have to use options -I and -L if need be
   
   To Run: xtic hostname
   Example: xtic ftp.x.org 
   Will use Display 0:0 on ftp.x.org - ftp.x.org should
   give permission via xhost for the client's machine.

   Please mail in suggestions and bugs to
    solai: solaiapp@ucunix.san.uc.edu

*/

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/poll.h>

#define WIN  " YOU WON - Press button to continue   "
#define LOSS " YOU LOST- Press button to continue   "
#define WAIT "  W A I T - Press any key to exit     "
#define PLAY "  P L A Y - Press any key to exit     "
#define DRAW "   DRAW - Press any key to continue   "

Display *D[2];
Window W[2];
GC G[6];
int S[2];
int I,J,s[3][3],IS;
int IW,IL,TN,IS1;
Font Fo;
int IEVENT;
struct pollfd  PFD[2]; 

main(argc,argv)
int argc;
char **argv;
{            
 
        XEvent EV;
        XSizeHints Hi;
        char text[10];
        char *b[8];
        char hostbuf[80];
        int done,done1;     
        int i,j,x,y;
        int POLL;

        if(argc != 2) {
           printf("Usage: %s hostname\n",argv[0]);
           exit(0);
               }
        b[0] = " TIC-TAC-TOE (HOST) - O ";
        b[1] = " TIC-TAC-TOE (GUEST) - X ";
        b[3] = PLAY;
        b[4] = WAIT;
        b[5] = LOSS;
        b[6] = WIN;
        b[7] = DRAW; 

        printf("\nxtic (Tic-Tac-Toe) 1993\n");
        printf("developed by Solaiappan, O @ Comp.Sc/U.C\n");
        strcpy(hostbuf,argv[1]);
	strcat(hostbuf,":0.0");
        hostbuf[strlen(hostbuf)] = '\0';
        for(i=0;i<=1;++i) {

           if(i == 0) D[i] = XOpenDisplay("");
           if(i == 1) {D[i] = XOpenDisplay(hostbuf);
                  if(D[i] == NULL) {printf("\nUnable to open %s \n",hostbuf);
                                    exit(0);  }
                       }

           PFD[i].fd = ConnectionNumber(D[i]);
           PFD[i].events = POLLOUT;

           S[i] = DefaultScreen(D[i]);
   
 
	Hi.x=200;
	Hi.y=300;
	Hi.width=440;
	Hi.height=440;
	Hi.flags = PPosition | PSize;


	W[i] = XCreateSimpleWindow(D[i],DefaultRootWindow(D[i]),
			200,300,440,480,5,
			NULL,NULL);
	XSetStandardProperties(D[i],W[i],b[i],"ttt",None,NULL,
		0,&Hi);

	G[i] = XCreateGC(D[i],W[i],0,0);
        XSetLineAttributes(D[i],G[i],15,LineSolid,CapButt,JoinRound);
        G[i+2] = XCreateGC(D[i],W[i],0,0);
        XSetLineAttributes(D[i],G[i+2],20,LineSolid,CapButt,JoinMiter); 
        XSetForeground(D[i],G[i],BlackPixel(D[i],S[i]));
        XSetBackground(D[i],G[i],WhitePixel(D[i],S[i]));
        XSetForeground(D[i],G[i+2],BlackPixel(D[i],S[i]));
	XSelectInput(D[i],W[i], ButtonPressMask | ExposureMask | KeyPressMask);

	XMapRaised(D[i],W[i]);
        Fo = XLoadFont(D[i],"rk24");
        XSetFont(D[i],G[i],Fo);
                     }
        for(i=0;i<=2;++i) for(j=0;j<=2;++j) s[i][j] = -1; 
	done = 0;
        TN = 0;
        PFD[0].revents = 0;
        POLL = poll(PFD,2,-1);
        if(POLL == 1) { if(PFD[0].revents == POLLOUT) IEVENT = 0;
                        else IEVENT = 1;  }
        XCheckMaskEvent(D[IEVENT],ExposureMask,&EV);
        IEVENT = (IEVENT+1)%2;
        XCheckMaskEvent(D[IEVENT],ExposureMask,&EV);
        IS = rand() % 2;
        do_set_up();
        PFD[0].events = POLLIN;
        PFD[1].events = POLLIN;
        

	while(1)
	{
          PFD[0].revents = 0;
          POLL  = poll(PFD,2,-1);
     if(POLL == 1) { if(PFD[0].revents == POLLIN) IEVENT = 0;
                       else IEVENT = 1;
                     }
 XCheckMaskEvent(D[IEVENT],ExposureMask | ButtonPressMask | KeyPressMask, &EV); 
		switch(EV.type)
		{
      
			case Expose:  
                    	      do_set_up(); 
                              break; 
     
                        /* Process Mouse Button Presses */
			case ButtonPress:
                        if(done == 1) {
                             done = 0;
                             for(i=0;i<=1;++i) {XClearWindow(D[i],W[i]);
                                                XFlush(D[i]);  }
                             for(i=0;i<=2;++i)for(j=0;j<=2;++j) s[i][j] = -1;
                             IS = rand() % 2; 
                             do_set_up();
                             TN = 0;
                             break;
                                       } 
                        if(IEVENT != IS) break;
                        x = EV.xbutton.x;
                        y = EV.xbutton.y;
                        I = -1;
                        J = -1;
                        if(x >= 20 && x <= 140) I = 0;
                        if(x >=160 && x <= 280) I = 1;
                        if(x >= 300 && x <= 420) I = 2;
                        if(y >= 20 && y <= 140) J = 0;
                        if(y >= 160 && y <= 280) J = 1;
                        if(y >= 300 && y <= 420) J = 2; 
                        if(I >= 0 && J >= 0 && s[I][J] == -1) symbol(); 
                        check();  
     if(TN < 9 && IW < 0 ) {
       XDrawImageString(D[IS],W[IS],G[IS],5,470,PLAY,strlen(PLAY));
       XFlush(D[IS]);
       IS1  = (IS + 1) % 2;
       XDrawImageString(D[IS1],W[IS1],G[IS1],5,470,WAIT,strlen(WAIT));
       XFlush(D[IS1]);
                            }
                        if(IW >= 0)  { done = 1;
                       XDrawImageString(D[IW],W[IW],G[IW],5,470,b[6],38);
                       XFlush(D[IW]);
                       IL = (IW + 1) % 2;
                       XDrawImageString(D[IL],W[IL],G[IL],5,470,b[5],38); 
                       XFlush(D[IL]);
                                     }
  if(TN == 9 && IW < 0){ 
             for(i=0;i<=1;++i) XDrawImageString(D[i],W[i],G[i],5,470,b[7],38);
                          done = 1;  
                          XFlush(D[0]);
                          XFlush(D[1]);
                               }
                        break; 
                  case KeyPress : exit(1); 
                     }
              }
      }

do_set_up()
{
	int i,j,k;
        int x,y;

        for(i=0;i<=2;++i) for(j=0;j<=2;++j) {
                            x = 10 +140*i;
                            y = 10 +140*j;
             for(k=0;k<=1;++k) {XDrawRectangle(D[k],W[k],G[k+2],x,y,140,140);
                                XFlush(D[k]); }
                                            }
           for(i=0;i<=2;++i) for(j=0;j<=2;++j)Symbol(i,j,s[i][j]);
           XDrawImageString(D[IS],W[IS],G[IS],5,470,PLAY,strlen(PLAY));
           IS1 = (IS + 1) % 2;
           XDrawImageString(D[IS1],W[IS1],G[IS1],5,470,WAIT,strlen(WAIT));
           XFlush(D[0]);
           XFlush(D[1]);

}
 
blink() 
{
  IS1 = (IS + 1) % 2;
  XBell(D[IS1],100);
  XFlush(D[IS1]);
}

 

symbol()
{
     int x,y;

     TN = TN + 1; 
     s[I][J] = IS;
     Symbol(I,J,IS); 
     IS = IS + 1;
     IS = IS % 2;   
}

Symbol(II,JJ,V)
int II,JJ,V;

{
  int x,y,j;

 for(j=0;j<=1;++j) {

  x = 20 + 140*II;
  y = 20 + 140*JJ;

  if(V == 0) 
                XDrawArc(D[j],W[j],G[j],x+27,y+27,66,66,0,360*64);
                  
   if (V == 1) { 
                XDrawLine(D[j],W[j],G[j],x+27,y+27,x+93,y+93);  
                XDrawLine(D[j],W[j],G[j],x+93,y+27,x+27,y+93);
                }
        XFlush(D[j]);
                  }
 }
check()
{
  int i,j,k;
  IW = -1;
  for(k=0;k<=1;++k) {    
      for(i=0;i<=2;++i){
            j = 0;
            while(j<=2) { if(k != s[i][j]) break;
                             j = j + 1; }  
                    j = j - 1;  
                  if(j == 2 && k == s[i][j])  IW = k;
              j = 0; 
            while(j<=2) {if(k != s[j][i]) break;
                             j = j + 1;  }  
                   j = j - 1;  
                  if(j == 2 && k == s[j][i])  IW = k;

                           }
          if(s[0][0] == k && s[1][1] == k && s[2][2] == k) IW = k; 
          if(s[0][2] == k && s[1][1] == k && s[2][0] == k) IW = k;  
                } 
}    
