summaryrefslogtreecommitdiff
path: root/pgm7
diff options
context:
space:
mode:
Diffstat (limited to 'pgm7')
-rw-r--r--pgm7/TTT.c282
-rw-r--r--pgm7/child.c75
-rw-r--r--pgm7/child.h11
-rw-r--r--pgm7/common.h68
-rw-r--r--pgm7/makefile21
-rw-r--r--pgm7/msg.c125
-rw-r--r--pgm7/ttt.c386
-rw-r--r--pgm7/ttt.tcl123
8 files changed, 1091 insertions, 0 deletions
diff --git a/pgm7/TTT.c b/pgm7/TTT.c
new file mode 100644
index 0000000..cec9023
--- /dev/null
+++ b/pgm7/TTT.c
@@ -0,0 +1,282 @@
+/************************************************************************
+ 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]);
+}
diff --git a/pgm7/child.c b/pgm7/child.c
new file mode 100644
index 0000000..f9263e8
--- /dev/null
+++ b/pgm7/child.c
@@ -0,0 +1,75 @@
+/*
+ * child.c
+ *
+ * Created by Matt Welsh, 1995
+ *
+ * Adapted by Adam Carpenter - acarpent - acarpenter@email.wm.edu
+ * April 2017
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <string.h>
+#include "child.h"
+
+/* Exec the named cmd as a child process, returning
+ * two pipes to communicate with the process, and
+ * the child's process ID */
+int start_child(char *cmd, FILE **readpipe, FILE **writepipe) {
+ int childpid, pipe1[2], pipe2[2];
+
+ if ((pipe(pipe1) < 0) || (pipe(pipe2) < 0) ) {
+ perror("pipe"); exit(-1);
+ }
+
+ if ((childpid = fork()) < 0) {
+ perror("fork"); exit(-1);
+ } else if (childpid > 0) { /* Parent. */
+ close(pipe1[0]); close(pipe2[1]);
+ /* Write to child on pipe1[1], read from child on pipe2[0]. */
+ *readpipe = fdopen(pipe2[0], "r");
+ *writepipe = fdopen(pipe1[1], "w");
+ setlinebuf(*writepipe);
+ return childpid;
+
+ } else { /* Child. */
+ close(pipe1[1]); close(pipe2[0]);
+ /* Read from parent on pipe1[0], write to parent on pipe2[1]. */
+ dup2(pipe1[0],0); dup2(pipe2[1],1);
+ close(pipe1[0]); close(pipe2[1]);
+
+ if (execlp(cmd, cmd, NULL) < 0)
+ perror("execlp");
+ /* Never returns */
+ }
+ return 0; // to keep the compiler happy
+}
+
+void i_am_the_master_commander(char *handle, char *opphandle, FILE **writeTo) {
+ /*
+ * Look, don't touch.
+ */
+
+ if (strcmp(handle, "Adam") == 0) {
+ fprintf(*writeTo, ".statusFrame.playerStatus configure -fg blue\n");
+ }
+ else if (strcmp(handle, "Dan") == 0) {
+ fprintf(*writeTo, ".statusFrame.playerStatus configure -fg red\n");
+ }
+ else if (strcmp(handle, "Amy") == 0) {
+ fprintf(*writeTo, ".statusFrame.playerStatus configure -fg \"light sea green\"\n");
+ }
+
+ if (strcmp(opphandle, "Adam") == 0) {
+ fprintf(*writeTo, ".statusFrame.opponentStatus configure -fg blue\n");
+ }
+ else if (strcmp(opphandle, "Dan") == 0) {
+ fprintf(*writeTo, ".statusFrame.opponentStatus configure -fg red\n");
+ }
+ else if (strcmp(opphandle, "Amy") == 0) {
+ fprintf(*writeTo, ".statusFrame.opponentStatus configure -fg \"light sea green\"\n");
+ }
+
+}
diff --git a/pgm7/child.h b/pgm7/child.h
new file mode 100644
index 0000000..786bf7c
--- /dev/null
+++ b/pgm7/child.h
@@ -0,0 +1,11 @@
+#ifndef _mdw_CHILD_H
+#define _mdw_CHILD_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+int start_child(char *cmd, FILE **readpipe, FILE **writepipe);
+void i_am_the_master_commander(char *handle, char *opphandle, FILE **writeTo);
+
+#endif
diff --git a/pgm7/common.h b/pgm7/common.h
new file mode 100644
index 0000000..6775ade
--- /dev/null
+++ b/pgm7/common.h
@@ -0,0 +1,68 @@
+#ifndef COMMON_H
+
+#define COMMON_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/************************************************************
+ All "messages" sent between server and clients in the
+ distributed tic-tac-toe system are in the format defined
+ by struct tttmsg. The structure of the message is determined
+ by the type field:
+
+ type=A WHO no other fields used
+ type=B HANDLE data is the string handle for ttt
+ sending this message
+ type=C MATCH data is string handle of opponent;
+ board[0] is 'X' or 'O' to denote
+ character this ttt is using
+ type=D WHATMOVE board[] contains X/O/space chars
+ to denote current state
+ type=E MOVE res (ascii) indicates square into
+ which client is moving
+ type=F RESULT board[] contains X/O/space chars
+ to denote current state;
+ res = W -> you win
+ L -> you lose
+ D -> draw
+************************************************************/
+
+#define WHO 'A'
+#define HANDLE 'B'
+#define MATCH 'C'
+#define WHATMOVE 'D'
+#define MOVE 'E'
+#define RESULT 'F'
+#define RESIGNED 'R'
+#define ABORT '*'
+
+struct tttmsg{
+ char type; /* Message type */
+ char board[9]; /* X/O */
+ char data[32]; /* null-terminated string */
+ char res; /* integer data */
+};
+
+#define SFILE "./serverloc"
+
+void putmsg(int, struct tttmsg *);
+void getmsg(int, struct tttmsg *);
+void protocol_error(char, struct tttmsg *);
+void dumpmsg(struct tttmsg *);
+void init_board();
+void dump_board(FILE *, char *);
+int check_board(int);
+
+#endif
diff --git a/pgm7/makefile b/pgm7/makefile
new file mode 100644
index 0000000..3a3a73c
--- /dev/null
+++ b/pgm7/makefile
@@ -0,0 +1,21 @@
+CC=gcc
+CFLAGS=-g -Wall
+
+all: TTT ttt
+
+TTT: TTT.o msg.o
+ gcc -o TTT TTT.o msg.o
+
+ttt: ttt.o msg.o child.o
+ gcc -o ttt ttt.o msg.o child.o
+
+msg.o: msg.c common.h
+
+TTT.o: TTT.c common.h
+
+ttt.o: ttt.c common.h
+
+child.o: child.c child.h
+
+clean:
+ rm -f *.o ttt TTT serverloc
diff --git a/pgm7/msg.c b/pgm7/msg.c
new file mode 100644
index 0000000..f6ae0a5
--- /dev/null
+++ b/pgm7/msg.c
@@ -0,0 +1,125 @@
+/************************************************************************
+
+ Functions for reading and writing "messages" over virtual circuits for
+ the tic-tac-toe system.
+
+ Phil Kearns
+ April 12, 1998
+
+*************************************************************************/
+
+#include "common.h"
+
+void
+putmsg(int s, struct tttmsg *m)
+// int s socket on which sending
+// struct tttmsg *m pointer to the message to be sent
+
+{
+ int bytes_sofar, to_go, num;
+ char *addr;
+
+ bytes_sofar = 0;
+ to_go = sizeof(struct tttmsg);
+
+ addr = (char *) m;
+
+ while (to_go > 0) {
+ num = write(s, &(addr[bytes_sofar]), to_go);
+ if (num < 0) {
+ perror("putmsg");
+ exit(1);
+ }
+ to_go -= num; bytes_sofar += num;
+ }
+}
+
+void
+getmsg(int s, struct tttmsg *m)
+// int s socket on which receiving
+// struct tttmsg *m container for the message
+
+{
+ int bytes_sofar, to_go, num;
+ char *addr;
+
+ bytes_sofar = 0;
+ to_go = sizeof(struct tttmsg);
+
+ addr = (char *) m;
+
+ while (to_go > 0) {
+ num = read(s, &(addr[bytes_sofar]), to_go);
+ if (num < 0) {
+ perror("putmsg");
+ exit(1);
+ }
+ if (num == 0) {
+ fprintf(stderr, "Unexpected EOF\n");
+ exit(1);
+ }
+ to_go -= num; bytes_sofar += num;
+ }
+}
+
+void
+protocol_error(char expected, struct tttmsg *offender)
+
+{
+ char *stype;
+
+ fprintf(stderr, "Protocol error: expected ");
+ switch (expected) {
+ case 'A':
+ stype = "WHO"; break;
+ case 'B':
+ stype = "HANDLE"; break;
+ case 'C':
+ stype = "MATCH"; break;
+ case 'D':
+ stype = "WHATMOVE"; break;
+ case 'E':
+ stype = "MOVE"; break;
+ case 'F':
+ stype = "RESULT"; break;
+ default:
+ stype = "UNKNOWN"; break;
+ }
+ fprintf(stderr, "%s message; got following message:\n", stype);
+ dumpmsg(offender);
+ exit(1);
+}
+
+void
+dumpmsg(struct tttmsg *m)
+
+{
+ char *stype, datastring[32];
+ int i;
+
+ switch (m->type) {
+ case 'A':
+ stype = "WHO"; break;
+ case 'B':
+ stype = "HANDLE"; break;
+ case 'C':
+ stype = "MATCH"; break;
+ case 'D':
+ stype = "WHATMOVE"; break;
+ case 'E':
+ stype = "MOVE"; break;
+ case 'F':
+ stype = "RESULT"; break;
+ default:
+ stype = "UNKNOWN"; break;
+ }
+ fprintf(stderr,"\tTYPE: %s\n",stype);
+ fprintf(stderr,"\tBOARD: [");
+ for (i=0; i<8; i++)
+ fprintf(stderr,"%c,",m->board[i]);
+ fprintf(stderr,"%c]\n",m->board[8]);
+ bcopy(datastring,&(m->data),31);
+ datastring[31]='\0';
+ fprintf(stderr,"\tDATA: %s\n", datastring);
+ fprintf(stderr,"\tRES: %c\n", m->res);
+}
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);
+}
diff --git a/pgm7/ttt.tcl b/pgm7/ttt.tcl
new file mode 100644
index 0000000..5c6fc0c
--- /dev/null
+++ b/pgm7/ttt.tcl
@@ -0,0 +1,123 @@
+#!/usr/bin/tclsh
+#
+# ttt.tcl
+#
+# Adam Carpenter - 2017 - acarpent - acarpenter@email.wm.edu
+# Utilizes code from P. Kearns
+
+# **** Initialize Variables ****
+global soundFlag; set soundFlag 1
+global playerSide; set playerSide -
+global playerHandle; set playerHandle (Player1)
+global opponentHandle; set opponentHandle (Player2)
+global myTurn; set myTurn 0
+
+
+# **** Initialize Procedures****
+proc resignMatch {} {
+ global myTurn
+ global playerSide
+
+ if {$myTurn == 1} {
+ set myTurn 0
+ puts stdout R
+ flush stdout
+ }
+}
+
+proc soundToggle {} {
+ global soundFlag
+ set soundFlag [expr $soundFlag * -1]
+
+ if {$soundFlag > 0} {
+ .buttonFrame.soundButton configure -text "Silent"
+ } else {
+ .buttonFrame.soundButton configure -text "Sound"
+ }
+
+}
+
+proc exitMatch {} {
+ exit 0
+}
+
+proc playerMove {tag} {
+ global myTurn
+ global playerSide
+ global array taken
+
+ if {$myTurn == 1} {
+ set myTurn 0
+ puts stdout $tag
+ flush stdout
+ }
+
+}
+
+proc beep {} {
+ global soundFlag
+
+ if {$soundFlag > 0} {
+ bell
+ bell -nice
+ }
+
+}
+
+# **** Main ****
+
+# Create canvas.
+canvas .gameCanvas -width 300 -height 300 -bg white
+
+# Create board spaces.
+.gameCanvas create rectangle 0 0 100 100 -fill white -outline white -tag 1
+.gameCanvas create rectangle 100 0 200 100 -fill white -outline white -tag 2
+.gameCanvas create rectangle 200 0 300 100 -fill white -outline white -tag 3
+.gameCanvas create rectangle 0 100 100 200 -fill white -outline white -tag 4
+.gameCanvas create rectangle 100 100 200 200 -fill white -outline white -tag 5
+.gameCanvas create rectangle 200 100 300 200 -fill white -outline white -tag 6
+.gameCanvas create rectangle 0 200 100 300 -fill white -outline white -tag 7
+.gameCanvas create rectangle 100 200 200 300 -fill white -outline white -tag 8
+.gameCanvas create rectangle 200 200 300 300 -fill white -outline white -tag 9
+
+# Bind board spaces with rectangles.
+.gameCanvas bind 1 <Button-1> {playerMove 1}
+.gameCanvas bind 2 <Button-1> {playerMove 2}
+.gameCanvas bind 3 <Button-1> {playerMove 3}
+.gameCanvas bind 4 <Button-1> {playerMove 4}
+.gameCanvas bind 5 <Button-1> {playerMove 5}
+.gameCanvas bind 6 <Button-1> {playerMove 6}
+.gameCanvas bind 7 <Button-1> {playerMove 7}
+.gameCanvas bind 8 <Button-1> {playerMove 8}
+.gameCanvas bind 9 <Button-1> {playerMove 9}
+
+# Draw board grid.
+.gameCanvas create line 100 0 100 300 -width 4
+.gameCanvas create line 200 0 200 300 -width 4
+.gameCanvas create line 0 100 300 100 -width 4
+.gameCanvas create line 0 200 300 200 -width 4
+
+pack .gameCanvas
+
+# Set up game status frame and labels.
+frame .statusFrame -width 300 -height 100 -bg grey
+pack .statusFrame -expand 1 -fill x
+label .statusFrame.playerStatus -text "?" -bg grey -fg white
+label .statusFrame.vs -text "VS" -bg grey -fg white
+label .statusFrame.opponentStatus -text "?" -bg grey -fg white
+label .statusFrame.gameStatus -text "\nAwaiting match..." -bg grey -fg white
+pack .statusFrame.gameStatus -expand 1 -fill x -side bottom
+pack .statusFrame.playerStatus -expand 1 -fill x -side left
+pack .statusFrame.vs -expand 1 -fill x -side left
+pack .statusFrame.opponentStatus -expand 1 -fill x -side left
+
+
+# Set up button frame and buttons.
+frame .buttonFrame
+pack .buttonFrame -expand 1 -fill x
+button .buttonFrame.soundButton -text "Silent" -command soundToggle
+button .buttonFrame.resignButton -text "Resign" -command resignMatch -state disabled
+button .buttonFrame.exitButton -text "Exit" -command exitMatch -state disabled
+pack .buttonFrame.soundButton .buttonFrame.resignButton .buttonFrame.exitButton -expand 1 -fill x -side left
+
+bell