summaryrefslogblamecommitdiff
path: root/pgm7/TTT.c
blob: cec9023cc398c86fe12eae3bc9b6a6ee47098617 (plain) (tree)

























































































































































































































































































                                                                                      
/************************************************************************
 			     TTT.c
 Castrated TTT server. No datagram queries, no timeouts. Assumes
 completely well-behaved clients. Uses deprecated network address
 translation.

 Phil Kearns
 April 12, 1998
 Modified March, 2014

 Adapted with GUI by Adam Carpenter - acarpent - acarpenter@email.wm.edu
 Modified April 2017
*************************************************************************/

#include "common.h"

char board[9]; /* The tic-tac-toe board */

int main(int argc, char **argv)

{
  int listener;  /* fd for socket on which we get connection requests */
  int Xfd, Ofd;  /* fds for sockets onto VCs to clients */

  struct sockaddr_in s1, Xaddr, Oaddr;
  int length,  sfile, i, moveto, result, Xresult, Oresult;
  unsigned short lport;
  int currentmove;  /* 0->X, 1->O */
  char hostid[128], Xhandle[32], Ohandle[32];
  struct tttmsg outmsg, inmsg;

  if (argc != 1) {
    fprintf(stderr,"TTT:usage is TTT\n");
    exit(1);
  }

  if ( (sfile = open(SFILE, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
    perror("TTT:sfile");
    exit(1);
  }

  if (gethostname(hostid,128) < 0){
    perror("TTT:gethostname");
        exit(1);
  }

  i=0;
  while (hostid[i] != '\0')
    write(sfile,&hostid[i++], 1);
  write(sfile,"\0", 1);

  if ( (listener = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
    perror("TTT:socket");
    exit(1);
  }

  bzero((char *) &s1, sizeof(s1));
  s1.sin_family = AF_INET;
  s1.sin_addr.s_addr = INADDR_ANY;  /* Any of this host's interfaces is OK. */
  s1.sin_port = 0;                  /* bind() will gimme unique port. */
  if (bind(listener, (struct sockaddr *)&s1, sizeof(s1)) < 0) {
    perror("TTT:bind");
    exit(1);
  }

  length = sizeof(s1);
  if (getsockname(listener, (struct sockaddr *)&s1, (socklen_t *)&length) < 0) {
    perror("TTT:getsockname");
    exit(1);
  }
  lport = s1.sin_port;
  write(sfile, &lport, sizeof(unsigned short));
  close(sfile);

  listen(listener,5);

  length = sizeof(Xaddr);
  if ((Xfd = accept(listener, (struct sockaddr *)&Xaddr, (socklen_t *)&length)) < 0) {
    perror("TTT:accept X");
    exit(1);
  }

  /* Send WHO to X */

  bzero((char *)&outmsg, sizeof(outmsg));
  outmsg.type = WHO;
  putmsg(Xfd, &outmsg);

  /* Await HANDLE from X */

  bzero((char *)&inmsg, sizeof(inmsg));
  getmsg(Xfd, &inmsg);
  if (inmsg.type != HANDLE) protocol_error(HANDLE, &inmsg);
  strncpy(Xhandle, inmsg.data, 31);
  Xhandle[31] = '\0';

  length = sizeof(Oaddr);
  if ((Ofd = accept(listener, (struct sockaddr *)&Oaddr, (socklen_t *)&length)) < 0) {
    perror("TTT:accept O");
    exit(1);
  }

  /* Send WHO to O */

  bzero((char *)&outmsg, sizeof(outmsg));
  outmsg.type = WHO;
  putmsg(Ofd, &outmsg);

  /* Await HANDLE from O */

  bzero((char *)&inmsg, sizeof(inmsg));
  getmsg(Ofd, &inmsg);
  if (inmsg.type != HANDLE) protocol_error(HANDLE, &inmsg);
  strncpy(Ohandle, inmsg.data, 31);
  Ohandle[31] = '\0';

  /* WE HAVE A MATCH */

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

  /* Send MATCH to X */

  bzero((char *)&outmsg, sizeof(outmsg));
  outmsg.type=MATCH;
  strncpy(outmsg.data, Ohandle, 31);
  outmsg.data[31] = '\0';
  outmsg.board[0] = 'X';
  putmsg(Xfd, &outmsg);

  /* Send MATCH to O */

  bzero((char *)&outmsg, sizeof(outmsg));
  outmsg.type=MATCH;
  strncpy(outmsg.data, Xhandle, 31);
  outmsg.data[31] = '\0';
  outmsg.board[0] = 'O';
  putmsg(Ofd, &outmsg);

  while(1) {

    /* Send  WHATMOVE to X */

    bzero((char *)&outmsg, sizeof(outmsg));
    outmsg.type=WHATMOVE;
    for(i=0; i<9; i++) outmsg.board[i]=board[i];
    putmsg(Xfd, &outmsg);

    /* Await MOVE from X */

    bzero((char *)&inmsg, sizeof(inmsg));
    getmsg(Xfd, &inmsg);

    // End the match if player X resigned.
    if (inmsg.type == RESIGNED) {
        bzero((char *)&outmsg, sizeof(outmsg));
        outmsg.type=ABORT;
        putmsg(Ofd, &outmsg);
        exit(0);
    }
    else if (inmsg.type != MOVE) {
        protocol_error(MOVE, &inmsg);
    }

    currentmove = 0; /* X's move being reported*/
    moveto = inmsg.res & 0xF;
    if (board[moveto] != ' ') {
      fprintf(stderr, "TTT: invalid move\n");
      exit(1);
    }
    board[moveto] = 'X';
    if ((result = check_board(currentmove)) != 0) break;

    /* Send  WHATMOVE to O */

    bzero((char *)&outmsg, sizeof(outmsg));
    outmsg.type=WHATMOVE;
    for(i=0; i<9; i++) outmsg.board[i]=board[i];
    putmsg(Ofd, &outmsg);

    /* Await MOVE from O */

    bzero((char *)&inmsg, sizeof(inmsg));
    getmsg(Ofd, &inmsg);

    // End the match if player O resigned.
    if (inmsg.type == RESIGNED) {
        bzero((char *)&outmsg, sizeof(outmsg));
        outmsg.type=ABORT;
        putmsg(Xfd, &outmsg);
        exit(0);
    }
    else if (inmsg.type != MOVE) {
        protocol_error(MOVE, &inmsg);
    }

    if (inmsg.type != MOVE) protocol_error(MOVE, &inmsg);
    currentmove = 1; /* O's move being reported*/
    moveto = inmsg.res & 0xF;
    if (board[moveto] != ' ') {
      fprintf(stderr, "TTT: invalid move\n");
      exit(1);
    }
    board[moveto] = 'O';
    if ((result = check_board(currentmove)) != 0) break;
  } /* while */

  /* Match is over, report the result to both clients */

  if (result == 2) {
    Xresult = Oresult = 'D';
  }
  else { /* result must be 1, we have a winner */
    if (currentmove == 0) { Xresult = 'W'; Oresult = 'L';}
    else  { Xresult = 'L'; Oresult = 'W';}
  }

  /* Send RESULT to X */

  bzero((char *)&outmsg, sizeof(outmsg));
  outmsg.type = RESULT;
  outmsg.res = Xresult;
  for(i=0; i<9; i++) outmsg.board[i]=board[i];
  putmsg(Xfd, &outmsg);

  /* Send RESULT to O */

  bzero((char *)&outmsg, sizeof(outmsg));
  outmsg.type = RESULT;
  outmsg.res = Oresult;
  for(i=0; i<9; i++) outmsg.board[i]=board[i];
  putmsg(Ofd, &outmsg);

  /* The game is finished */

  return(0);
}


/************************************************************************
   check_board() returns 0 if no winner
                         1 if winner
                         2 if draw
   Brute force.
************************************************************************/
int
check_board(player)
int player; /* X is 0, O is 1 */
{
  char match;
  int i,spaces;

  match = (player?'O':'X');

  if (((board[0] == match) && (board[1] == match) && (board[2] == match)) ||
      ((board[3] == match) && (board[4] == match) && (board[5] == match)) ||
      ((board[6] == match) && (board[7] == match) && (board[8] == match)) ||
      ((board[0] == match) && (board[3] == match) && (board[6] == match)) ||
      ((board[1] == match) && (board[4] == match) && (board[7] == match)) ||
      ((board[2] == match) && (board[5] == match) && (board[8] == match)) ||
      ((board[0] == match) && (board[4] == match) && (board[8] == match)) ||
      ((board[2] == match) && (board[4] == match) && (board[6] == match))) return 1;
  spaces = 0;
  for(i=0; i<9; i++)
    if (board[i] == ' ') {
      spaces++;
      break;
    }
  if (!spaces) return 2;
  return 0;
}

void
dump_board(s,board)
FILE *s;
char board[];
{
  fprintf(s,"%c | %c | %c\n", board[0], board[1], board[2]);
  fprintf(s,"----------\n");
  fprintf(s,"%c | %c | %c\n", board[3], board[4], board[5]);
  fprintf(s,"----------\n");
  fprintf(s,"%c | %c | %c\n", board[6], board[7], board[8]);
}