/************************************************************************ 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]); }