[comp.sources.games] v09i033: tttt - tic-tac-toc-toe with wraparound edges, Part01/01

billr@saab.CNA.TEK.COM (Bill Randle) (03/07/90)

Submitted-by: Eric Lechner <lechner@ucscb.ucsc.edu>
Posting-number: Volume 9, Issue 33
Archive-name: tttt/Part01


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  README Makefile tttt.6 tttt.c
# Wrapped by billr@saab on Tue Mar  6 17:20:43 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(482 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is a 4 by 4 version of tic-tac-toe with "wraparound
Xedges" (so you can have off-center diagonal wins).
X
XI've compiled it under 4.3 BSD Unix, but it should compile
Xok just about everywhere that has a curses package.
X
XEdit the Makefile as necessary, then make.
X
XIf you improve the code, please let me know.  I'd be interested
Xin seeing any changes to it.
X
XThis program is public domain.
X
X-Eric Lechner,  6 March 1990
Xlechner@ucscb.ucsc.edu         ...!ucbvax!ucscc!ucscb!lechner
END_OF_FILE
if test 482 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(566 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# makefile for tic-tac-toc-toe
X#
X# edit as necessary, then make
X
X# where the executable will go
XBINDIR = /usr/games
X
X# where the formatted manpage will go
XMANDIR = /usr/games/Doc
X
X# options for the c compiler (-g, -O, etc.)
XCFLAGS = -O
X
X# compiler libraries (-ltermcap, etc.)
XLIBS = -lcurses -ltermcap
X
Xtttt: tttt.c
X	cc $(CFLAGS) -o tttt tttt.c $(LIBS)
X
Xinstall: tttt tttt.man
X	cp tttt $(BINDIR)/tttt
X	chmod 711 $(BINDIR)/tttt
X	cp tttt.man $(MANDIR)/tttt.6
X	chmod 644 $(MANDIR)/tttt.6
X
Xtttt.man: tttt.6
X	nroff -man tttt.6 > tttt.man
X
Xclean:
X	rm -f tttt *.o tttt.man
END_OF_FILE
if test 566 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'tttt.6' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tttt.6'\"
else
echo shar: Extracting \"'tttt.6'\" \(1013 characters\)
sed "s/^X//" >'tttt.6' <<'END_OF_FILE'
X.TH TTTT 6 "6 March 1990"
X.SH NAME
Xtttt
X\- tic-tac-toc-toe with wraparound edges
X.SH SYNOPSIS
X.B /usr/games/tttt
X.SH DESCRIPTION
XTic-Tac-Toc-Toe is a 4 by 4 version of Tic-Tac-Toe
Xwith wraparound edges.  The goal of the game is to
Xconnect 4 of your pieces in a row, either horizontally,
Xvertically, or diagonally.  Note that diagonal wins can
Xbe off-center, due to the wraparound edges (and hence, there
Xare no corners in the board).
X.PP
XTo play, simply press the letter and number corresponding
Xto select the appropriate square, and the computer will then
Xtake its turn.
X.PP
XThe first player to connect four squares in a row wins.  If
Xthe board becomes filled without a winner, it is a tie game.
X.SH HISTORY
XThis program was originally written for an Advanced Logic
XDesign class, as a high level version of the program to
Xlater be implemented in hardware.  It was converted to run
Xwith curses in an attempt to procrastinate working on the
Xhardware implementation.
X.SH AUTHOR
XEric Lechner, lechner@ucscb.ucsc.edu
END_OF_FILE
if test 1013 -ne `wc -c <'tttt.6'`; then
    echo shar: \"'tttt.6'\" unpacked with wrong size!
fi
# end of 'tttt.6'
fi
if test -f 'tttt.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tttt.c'\"
else
echo shar: Extracting \"'tttt.c'\" \(6961 characters\)
sed "s/^X//" >'tttt.c' <<'END_OF_FILE'
X/*
X	Eric Lechner				Feb. 27, 1990
X
X	revised for curses output: march 6, 1990
X
X		CE 126 Final Project Development
X
X	a high level simulation of tic-tac-toc-toe, a 4x4
X	version of tic-tac-toe with "wraparound edges"
X
X	this takes user input for one player, and has a
X	computer player for the other.
X*/
X
X#include <stdio.h>
X#include <curses.h>
X
X#define EMPTY	0
X#define X	1
X#define O	2
X
X#define TIE	-1		/* for ending when the board is full */
X#define QUIT	-2
X
X#define WIN	100		/* for position rank scoring */
X
X#ifndef TRUE
X#define TRUE	1		/* cause they aren't included elsewhere */
X#define FALSE	0
X#endif
X
Xchar board [4][4];		/* this is the playing board */
Xint pieces;
X
Xvoid	initboard(),
X	printboard();
X
Xint	check_win(),
X	getrank(),
X	x_move(),		/* "our" move */
X	o_move();		/* the computer player's move */
X
Xmain()
X{
X	int done = FALSE;
X	int xmove = TRUE;
X
X	pieces = 0;
X
X	initscr();
X	savetty();
X	cbreak();
X	noecho();
X
X	initboard();
X
X	clear();
X	printboard();
X	while (!done) {
X		if (xmove)
X			done = x_move();
X		else {
X			done = o_move();
X		}
X		if ((++pieces == 16) && !done) done = TIE;
X
X		xmove = !xmove;
X	}
X
X	switch (done) {
X		case TIE :
X			move(17,23);
X			printw("The board is full, and nobody won.\n");
X			break;
X		case QUIT :
X			move(17,23);
X			printw("Hope to beat you again someday!\n");
X			break;
X		default :
X			move(17,33);
X			printw("Player `%c' Wins!\n",(done == X) ? 'X' : 'O');
X	}
X	move(21,0);
X	refresh();
X	sleep(2);
X	resetty();
X	endwin();
X}
X
X/*
X	initialize the board to all empty
X*/
Xvoid initboard()
X{
X	int i,j;
X
X	for (i=0; i<4; i++)
X		for (j=0; j<4; j++)
X			board [i][j] = EMPTY;
X}
X
X/*
X	print the current board
X*/
Xvoid printboard()
X{
X	int i;
X
X	move(2,24);
X	printw("Tic-Tac-Toc-Toe - by Eric Lechner");
X
X	move(5,30);
X	printw("    A   B   C   D \n");
X	move(6,30);
X	printw("   --- --- --- ---\n");
X	for (i=0; i<4; i++) {
X		move(7 + (i * 2), 30);
X		printw("%d | %c | %c | %c | %c |\n", i,
X			(!board[i][0]) ? ' ' : (board[i][0] == X) ? 'X' : 'O',
X			(!board[i][1]) ? ' ' : (board[i][1] == X) ? 'X' : 'O',
X			(!board[i][2]) ? ' ' : (board[i][2] == X) ? 'X' : 'O',
X			(!board[i][3]) ? ' ' : (board[i][3] == X) ? 'X' : 'O');
X		move(8 + (i * 2), 30);
X		printw("   --- --- --- ---\n");
X	}
X	refresh();
X}
X
X/*
X	player "x", the human player
X*/
Xint x_move()
X{
X	int row, col, tmp, mess = 0;
XGetX:	row = col = -1;
X
X	move(15,33);
X	printw("Your move : ");
X	clrtoeol();
X	refresh();
X	while ((row == -1) || (col == -1)) {
X		tmp = getch();
X		switch (tmp) {
X			case 'A' :
X			case 'a' :
X			case 'B' :
X			case 'b' :
X			case 'C' :
X			case 'c' :
X			case 'D' :
X			case 'd' :
X				move(15,45);
X				printw("%c ",tmp);
X				if ((tmp >= 'a') && (tmp <= 'd'))
X					col = tmp - 'a';
X				else
X					col = tmp - 'A';
X				break;
X			case '0' :
X			case '1' :
X			case '2' :
X			case '3' :
X				move(15,47);
X				printw("%c",tmp);
X				row = tmp - '0';
X				break;
X			case 'q' :
X			case 'Q' :
X				return(QUIT);
X				break;
X			case 0x12 :
X			case 0x0c :
X				clear();
X				printboard();
X				goto GetX;
X			default:
X				break;
X		}
X		refresh();
X	}
X	if (board[row][col] == EMPTY) board[row][col] = X;
X	else {
X		move(17,34);
X		printw("Illegal move!\n");
X		mess = 1;	/* whether an error message has been printed */
X		refresh();
X		goto GetX;
X	}
X	
X	if (mess) {		/* if there was an error message, clear it */
X		move(17,1);
X		clrtoeol();
X	}
X
X	move(7 + (row * 2), 34 + (col * 4));	/* print the move */
X	printw("X");
X
X	refresh();
X
X	return (check_win (X,row,col));
X}
X
X/*
X	player "o", the computer player
X*/
Xint o_move()
X{
X	int bestrank = 0, bestrow = 0, bestcol = 0, i, j, rank;
X
X	for (i=0; i<4; i++) {
X		for (j=0; j<4; j++) {
X			rank = getrank(O,i,j);
X			if (rank > bestrank) {
X				bestrow = i;
X				bestcol = j;
X				bestrank = rank;
X			}
X		}
X	}
X
X	board [bestrow][bestcol] = O;
X
X	move(7 + (bestrow * 2), 34 + (bestcol * 4));
X	printw("O");
X	refresh();
X
X	return (check_win (O,bestrow,bestcol));
X}
X
X/*
X	this ranks a move location in order of "preference".
X
X	the strategy is to not let the opponent get lots in a row.
X	ever.
X
X
X	rows, columns, and diagonals get treated independently, and
X	the "best" rank of them all is considered.
X*/
Xint getrank(type,row,col)
Xint type,row,col;
X{
X	int i, j, rank = 0, countx = 0, counto = 0;
X
X	/* if already taken, this isn't a good spot */
X	if (board[row][col]) return (rank);
X
X	/* check across */
X	countx = counto = 0;
X	for (i=0; i<4; i++) {
X		if (board[row][i] == X) countx++;
X		else if (board[row][i] == O) counto++;
X	}
X	if (type == X) {
X		if (countx >= 3) return (WIN);
X		if (!countx && (counto > rank)) rank = counto;
X	} else {
X		if (counto >= 3) return (WIN);
X		if (!counto && (countx > rank)) rank = countx;
X	}
X
X	/* check vertically */
X	countx = counto = 0;
X	for (i=0; i<4; i++) {
X		if (board[i][col] == X) countx++;
X		else if (board[i][col] == O) counto++;
X	}
X	if (type == X) {
X		if (countx >= 3) return (WIN);
X		if (!countx && (counto > rank)) rank = counto;
X	} else {
X		if (counto >= 3) return (WIN);
X		if (!counto && (countx > rank)) rank = countx;
X	}
X
X	/* check \ diagonal */
X	countx = counto = 0;
X	for (i=0; i<4; i++) {
X		if (board[(row + i) % 4][(col + i) % 4] == X) countx++;
X		else if (board[(row + i) % 4][(col + i) % 4] == O) counto++;
X	}
X	if (type == X) {
X		if (countx >= 3) return (WIN);
X		if (!countx && (counto > rank)) rank = counto;
X	} else {
X		if (counto >= 3) return (WIN);
X		if (!counto && (countx > rank)) rank = countx;
X	}
X
X	/* check / diagonal */
X	countx = counto = 0;
X	for (i=0; i<4; i++) {
X		if (board[(row + 4 - i) % 4][(col + i) % 4] == X) countx++;
X		else if (board[(row + 4 - i) % 4][(col + i) % 4] == O) counto++;
X	}
X	if (type == X) {
X		if (countx >= 3) return (WIN);
X		if (!countx && (counto > rank)) rank = counto;
X	} else {
X		if (counto >= 3) return (WIN);
X		if (!counto && (countx > rank)) rank = countx;
X	}
X
X	/* add one, so that even no blocks still shows as a valid move	*/
X	/* and return the rank for this move				*/
X	return (++rank);
X}
X
X/*
X	checks for a win at a specific location, and returns the
X	type of win, or 0, if there wasn't a win.
X*/
Xint check_win(type,row,col)
Xint type, row, col;
X{
X	int r[4],c[4], i;	/* temp row, col, and counter vars */
X
X	/* check across */
X	if ((board [row][0] == type) && (board [row][1] == type) &&
X		(board [row][2] == type) && (board [row][3] == type))
X		return (type);
X
X	/* check vertically */
X	if ((board [0][col] == type) && (board [1][col] == type) &&
X		(board [2][col] == type) && (board [3][col] == type))
X		return (type);
X
X	/* check \ diagonal */
X	for (i=0; i<4; i++) {
X		r[i] = (row + i) % 4;
X		c[i] = (col + i) % 4;
X	}
X	if ((board [r[0]][c[0]] == type) && (board [r[1]][c[1]] == type) &&
X		(board [r[2]][c[2]] == type) && (board [r[3]][c[3]] == type))
X		return (type);
X
X	/* check / diagonal */
X	for (i=0; i<4; i++) {
X		r[i] = (row + i) % 4;
X		c[i] = (col + (4 - i)) % 4;
X	}
X	if ((board [r[0]][c[0]] == type) && (board [r[1]][c[1]] == type) &&
X		(board [r[2]][c[2]] == type) && (board [r[3]][c[3]] == type))
X		return (type);
X
X	/* if it got here, there aren't any wins at that spot */
X	return (0);
X}
X
END_OF_FILE
if test 6961 -ne `wc -c <'tttt.c'`; then
    echo shar: \"'tttt.c'\" unpacked with wrong size!
fi
# end of 'tttt.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0