diff options
Diffstat (limited to 'pgm7/ttt.c')
-rw-r--r-- | pgm7/ttt.c | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/pgm7/ttt.c b/pgm7/ttt.c new file mode 100644 index 0000000..da728b3 --- /dev/null +++ b/pgm7/ttt.c @@ -0,0 +1,386 @@ +/************************************************************************ + ttt.c + Simple ttt client. No queries, no timeouts. + Uses deprecated address translation functions. + + 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" +#include "child.h" + + +void dump_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]); +} + + +void drawWin(FILE **writeTo, char *board) { + + // Check rows for win. + if (board[0] + board[1] + board[2] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 0 50 300 50 -width 5 -fill red\n"); + else if (board[0] + board[1] + board[2] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 0 50 300 50 -width 5 -fill red\n"); + if (board[3] + board[4] + board[5] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 0 150 300 150 -width 5 -fill red\n"); + else if (board[3] + board[4] + board[5] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 0 150 300 150 -width 5 -fill red\n"); + if (board[6] + board[7] + board[8] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 0 250 300 250 -width 5 -fill red\n"); + else if (board[6] + board[7] + board[8] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 0 250 300 250 -width 5 -fill red\n"); + + // Check columns for win. + if (board[0] + board[3] + board[6] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 50 0 50 300 -width 5 -fill red\n"); + else if (board[0] + board[3] + board[6] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 50 0 50 300 -width 5 -fill red\n"); + if (board[1] + board[4] + board[7] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 150 0 150 300 -width 5 -fill red\n"); + else if (board[1] + board[4] + board[7] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 150 0 150 300 -width 5 -fill red\n"); + if (board[2] + board[5] + board[8] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 250 0 250 300 -width 5 -fill red\n"); + else if (board[2] + board[5] + board[8] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 250 0 250 300 -width 5 -fill red\n"); + + // Check diagonals for win. + if (board[0] + board[4] + board[8] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 0 0 300 300 -width 5 -fill red\n"); + else if (board[0] + board[4] + board[8] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 0 0 300 300 -width 5 -fill red\n"); + if (board[2] + board[4] + board[6] == 'X' + 'X' + 'X') fprintf(*writeTo, ".gameCanvas create line 0 300 300 0 -width 5 -fill red\n"); + else if (board[2] + board[4] + board[6] == 'O' + 'O' + 'O') fprintf(*writeTo, ".gameCanvas create line 0 300 300 0 -width 5 -fill red\n"); + +} + + +void drawBoard(FILE **writeTo, int space, char symbol) { + switch (space + 1) { + case 1: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 0 0 100 100 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 0 100 100 0 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 0 0 100 100 -width 5\n"); + } + break; + + case 2: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 100 0 200 100 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 100 100 200 0 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 100 0 200 100 -width 5\n"); + } + break; + + case 3: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 200 0 300 100 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 200 100 300 0 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 200 0 300 100 -width 5\n"); + } + break; + + case 4: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 0 100 100 200 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 0 200 100 100 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 0 100 100 200 -width 5\n"); + } + break; + + case 5: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 100 100 200 200 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 100 200 200 100 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 100 100 200 200 -width 5\n"); + } + break; + + case 6: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 200 100 300 200 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 200 200 300 100 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 200 100 300 200 -width 5\n"); + } + break; + + case 7: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 0 200 100 300 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 0 300 100 200 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 0 200 100 300 -width 5\n"); + } + break; + + case 8: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 100 200 200 300 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 100 300 200 200 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 100 200 200 300 -width 5\n"); + } + break; + + case 9: + if (symbol == 'X') { + fprintf(*writeTo, ".gameCanvas create line 200 200 300 300 -width 5\n"); + fprintf(*writeTo, ".gameCanvas create line 200 300 300 200 -width 5\n"); + } + else { + fprintf(*writeTo, ".gameCanvas create oval 200 200 300 300 -width 5\n"); + } + break; + } +} + + +int main(int argc, char **argv) { + char hostid[128], handle[32], opphandle[32]; + char my_symbol; /* X or O ... specified by server in MATCH message */ + char board[9]; + char prevBoard[9]; + unsigned short xrport; + int sock, sfile; + struct sockaddr_in remote; + struct hostent *h; + int num, i, move, valid, finished; + struct tttmsg inmsg, outmsg; + + if (argc != 1) { + fprintf(stderr,"ttt:usage is ttt\n"); + exit(1); + } + + /* Get host,port of server from file. */ + if ( (sfile = open(SFILE, O_RDONLY)) < 0) { + perror("TTT:sfile"); + exit(1); + } + i=0; + while (1) { + num = read(sfile, &hostid[i], 1); + if (num == 1) { + if (hostid[i] == '\0') break; + else i++; + } + else { + fprintf(stderr, "ttt:error reading hostname\n"); + exit(1); + } + } + if (read(sfile, &xrport, sizeof(int)) != sizeof(unsigned short)) { + fprintf(stderr, "ttt:error reading port\n"); + exit(1); + } + close(sfile); + + + /* Got the info. Connect. */ + if ( (sock = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) { + perror("ttt:socket"); + exit(1); + } + + bzero((char *) &remote, sizeof(remote)); + remote.sin_family = AF_INET; + if ((h = gethostbyname(hostid)) == NULL) { + perror("ttt:gethostbyname"); + exit(1); + } + bcopy((char *)h->h_addr, (char *)&remote.sin_addr, h->h_length); + remote.sin_port = xrport; + if ( connect(sock, (struct sockaddr *)&remote, sizeof(remote)) < 0) { + perror("ttt:connect"); + exit(1); + } + + /* We're connected to the server. Engage in the prescribed dialog */ + + /* Await WHO */ + bzero((char *)&inmsg, sizeof(inmsg)); + getmsg(sock, &inmsg); + if (inmsg.type != WHO) protocol_error(WHO, &inmsg); + + /* Send HANDLE */ + printf("Enter handle (31 char max):"); + fgets(handle, 31, stdin); + bzero((char *)&outmsg, sizeof(outmsg)); + outmsg.type = HANDLE; + strncpy(outmsg.data, handle, 31); outmsg.data[31] = '\0'; + putmsg(sock, &outmsg); + + // Set up ttt.tcl GUI. + FILE *readFrom; + FILE *writeTo; + char result[80]; + int childpid; + + // Fork off child process and use it to run wish with the ttt.tcl script. + if ((childpid = start_child("wish", &readFrom, &writeTo)) <= 0) { + fprintf(stderr, "ttt: couldn't start child GUI.\n"); + exit(1); + } + + fprintf(writeTo, "source ttt.tcl\n"); + sscanf(handle, "%s[^\n]", handle); + fprintf(writeTo, ".statusFrame.playerStatus configure -text %s\n", handle); + + /* Await MATCH */ + bzero((char *)&inmsg, sizeof(inmsg)); + getmsg(sock, &inmsg); + if (inmsg.type != MATCH) protocol_error(MATCH, &inmsg); + my_symbol = inmsg.board[0]; + strncpy(opphandle, inmsg.data, 31); opphandle[31] = '\0'; + sscanf(opphandle, "%s[^\n]", opphandle); + + i_am_the_master_commander(handle, opphandle, &writeTo); + + if (my_symbol == 'X') { + strcat(handle, "(X)"); + strcat(opphandle, "(O)"); + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"Your move.\"\n"); + } + else { + strcat(handle, "(O)"); + strcat(opphandle, "(X)"); + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"Awaiting opponent move...\"\n"); + } + + fprintf(writeTo, ".statusFrame.playerStatus configure -text %s\n", handle); + fprintf(writeTo, ".statusFrame.opponentStatus configure -text %s\n", opphandle); + + /* In the match */ + for(i = 0; i < 9; i++) { + board[i]=' '; + prevBoard[i] = ' '; + } + + finished = 0; + + while(!finished){ + /* Await WHATMOVE/RESULT from server */ + bzero((char *)&inmsg, sizeof(inmsg)); + getmsg(sock, &inmsg); + switch (inmsg.type) { + + case WHATMOVE: + fprintf(writeTo, "beep\n"); + fprintf(writeTo, ".buttonFrame.resignButton configure -state normal\n"); + + for (i = 0; i < 9; i++) { + board[i] = inmsg.board[i]; + } + + // Draw the new board. + for (i = 0; i < 9; i++) { + if (board[i] != prevBoard[i]) { + // Remove taken spaces from game board canvas and draw board. + drawBoard(&writeTo, i, board[i]); + } + } + strcpy(prevBoard, board); + + do { + valid = 0; + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"Your move.\"\n"); + fprintf(writeTo, "global myTurn; set myTurn 1\n"); + + if (fgets(result, 80, readFrom) <= 0) { + fprintf(stderr, "ttt: GUI terminated.\n"); + exit(0); + } + + move = atoi(result); + + // If player resigned, alert the server and end the client. + if (result[0] == 'R') { + bzero((char *)&outmsg, sizeof(outmsg)); + outmsg.type = RESIGNED; + putmsg(sock, &outmsg); + fprintf(writeTo, "global myTurn; set myTurn 0\n"); + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"You lose. (You resigned)\"\n"); + fprintf(writeTo, ".buttonFrame.exitButton configure -state normal\n"); + fprintf(writeTo, ".buttonFrame.resignButton configure -state disabled\n"); + exit(0); + } + + if ((move >= 1) && (move <= 9)) valid = 1; + if ((valid) && (board[move-1] != ' '))valid=0; + if (valid == 0) fprintf(writeTo, "beep\n"); + + } while (!valid); + + /* Send MOVE to server */ + bzero((char *)&outmsg, sizeof(outmsg)); + outmsg.type = MOVE; + sprintf(&outmsg.res, "%c", move-1); + putmsg(sock, &outmsg); + fprintf(writeTo, "global myTurn; set myTurn 0\n"); + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"Awaiting opponent move...\"\n"); + fprintf(writeTo, ".buttonFrame.resignButton configure -state disabled\n"); + drawBoard(&writeTo, move - 1, my_symbol); + break; + + case RESULT: + for(i=0; i<9; i++) board[i]=inmsg.board[i]; + + // Draw the new board. + for (i = 0; i < 9; i++) { + if (board[i] != prevBoard[i]) { + drawBoard(&writeTo, i, board[i]); + } + } + + switch (inmsg.res) { + case 'W': + // printf("You win\n"); + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"You Win!\"\n"); + break; + + case 'L': + // printf("You lose\n"); + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"You Lose!\"\n"); + break; + + case 'D': + // printf("Draw\n"); + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"Draw\"\n"); + break; + + default: + fprintf(stderr,"Invalid result code\n"); + exit(1); + } + + finished = 1; + fprintf(writeTo, ".buttonFrame.exitButton configure -state normal\n"); + drawWin(&writeTo, board); + break; + + case ABORT: + fprintf(writeTo, ".statusFrame.gameStatus configure -text \"You won! (Opponent resigned)\"\n"); + fprintf(writeTo, ".buttonFrame.exitButton configure -state normal\n"); + fprintf(writeTo, ".buttonFrame.resignButton configure -state disabled\n"); + fprintf(stderr, "Opponent resigned match.\n"); + exit(0); + + default: + protocol_error(MOVE, &inmsg); + } + + } + return(0); +} |