summaryrefslogtreecommitdiff
path: root/pgm7/ttt.c
diff options
context:
space:
mode:
Diffstat (limited to 'pgm7/ttt.c')
-rw-r--r--pgm7/ttt.c386
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);
+}