
/*
	BD Software presents:

	Tic Tac Toe  (by exhaustive search)

	written by Leor Zolman
		   September 1979

	This program was written for use as the crux
	of an article in BYTE (as yet to be published)
	on BDS C, structured programming and gaming.

	It is also intended to get you addicted to C so
	you'll go out and buy the 

		BD Software C Compiler

		only $110 on CP/M disk from:

		tiny c associates
		post office box 269
		holmdel, new jersey 07733

	The package includes the compiler, linking loader,
	library manager, standard library of functions, many
	interesting sample programs (such as "TELNET.C" for
	using your computer as a terminal and allowing I/O
	directly from modem to disk and vice-versa.) Also
	included is a copy of the best reference book available
	on the C language, written by the original implementors
	at Bell Labs (the package may be purchased without
	the book for $100.)

*/

#include <stdio.h> // gss
#include <stdlib.h> // gss

#define X 1				/* The pieces on the board */
#define O 5
#define EMPTY 0

char board[9];				/* the playing board */
char BEST;				/* move returned by "ttteval" */
//int wins[8][3];				/* table of  winning positions */
int wins[8][3] = { 0,1,2, 3,4,5, 6,7,8, 0,3,6, 1,4,7, 2,5,8, 0,4,8, 2,4,6 };


int toupper(int c) { return ('a'<=c && c<='z') ? c+'A'-'a' : c; }
int getchoice(void) {
    int c;
    while ((c=getchar())<' ') ; // ignore ctl chars like CR LF
    return c;
}

/*
	This function returns true (non-zero) if player p
	has three in a row on the board:
*/

int win(int p)
{
	char i;
	for (i=0; i<8; ++i)
		if (board[wins[i][0]] == p &&
		    board[wins[i][1]] == p &&
		    board[wins[i][2]] == p) return 1;
	return 0;
}


/*
	This function returns true if all nine squares are
	taken (usually called after checking for a win, so
	that all spaces filled indicates a cat's game)
*/

int cats(void)
{
	char i;
	for (i=0; i<9; ++i)
		if (!board[i]) return 0;
	return 1;
}

/*
	Function to clear the game board
*/

void clear(void)
{
	char i;
	for (i=0; i<9; ++i)
		board[i] = EMPTY;
}

/*
	This one returns true if the player responds
	positively to the prompt string, else returns false
	(a good general-purpose yes/no asking function!)
*/

int ask(char *s)
{
	char *gets(), c;
	printf(s);
	c = toupper(getchoice());
	return (c == 'Y');
}

/*
	Display the playing board with pieces if flag is 0,
	or else with each square numbered from 1-9.
*/

void display(int flag)
{
	int i,j;
	printf("\n\n");
	for (i=0; i<9; i+=3) {
		for (j=i; j< i+3; ++j) {
			putchar(' ');
			if (!flag)
			  switch(board[j]) {
			    case EMPTY: putchar(' ');
					break;
			    case X:	putchar('x');
					break;
			    case O:	putchar('o');
			   }
			else printf("%1d",j+1);
			putchar(' ');
			if (j != i+2) putchar('|');
		 }
		putchar('\n');
		if (i != 6) printf("---+---+---\n");
	 }
	putchar('\n');
}

/*
	The function $"ttteval" returns an evaluation of
	player x's position on the tic-tac-toe board. If he's
	in a winning position, 1 is returned. If the best he
	can hope for is a cat's game, 0 is returned. And, if
	he's sure to lose if player y plays correctly, -1 is
	returned. In any case, the best move available to 
	player x is left in external variable BEST upon return
	from ttteval.

	Note that a value of -1 is often returned while
	recursive searching branches down into all possible
	wins and losses, but with the program in the shape
	it appears here, the outermost-level call to ttteval
	(from the main program) will never produce a return
	value of -1, since the computer has decided not to be
	able to lose (the obviously logical choice of any
	self-respecting problem-solver.)
	In any case, the main program still bothers to 
	consider the possibility of losing, so that if you
	want to try inserting your own "ttteval" routine
	in place of the one given, it dosn't have to be
	perfect in order to work with the main program.
	Tic-tac-toe is, of course, just about the only game
	in which it is feasable to do an exhaustive search;
	most game evaluation algorithms only go so deep and
	then make a "static" evaluation, or estimate of the
	player's status at the terminal position. That is how
	all decent chess playing programs today work.
*/

int ttteval(int me, int him)
{
	char i,safemove;
	int v,loseflag;
		/* first check for the 3 simple terminal
		   conditions:				*/
	if (win(me)) return 1;
	if (win(him)) return -1;
	if (cats()) return 0;
		/* OK...now try all possible moves and see
		   our honorable opponent can do with each: */
	loseflag = 1;
	for (i=0; i<9; ++i) {
		if (board[i]) continue; /* ignore non-moves! */
		board[i] = me;		/* try the move...*/
		v = ttteval(him,me);
		board[i] = 0;		/* restore the empty space */
		if (v == -1) { 		/* if we force a loss, yey! */
			BEST = i;
			return 1;
		 }
		if (v) continue;   	/* uh oh! we shouldn't get beaten! */
		loseflag = 0;		/* cat's game guaranteed at least */
		safemove = i;
	 }
	BEST = safemove;
	return -loseflag;		/* if loseflag is true, this returns
					   -1 to indicate a loss; else zero
					   is returned (cat's game.)    */
}

int main(int argc, char *argv[])
{
	int i;
	int mefirst;			/* 1: computer goes first; 0: human */
	int turn;			/* counts number of moves played */
	int mypiece, hispiece;		/* who has x or o */
	int mywins, hiswins, catwins;	/* game count */
	int t;
	srand(0);			/* initialize random generator */
//	initw(wins,"0,1,2,3,4,5,6,7,8,0,3,6,1,4,7,2,5,8,0,4,8,2,4,6");
	mywins = hiswins = catwins = 0;
	mefirst = 1;			/* let human go first */
	printf("\n\nWelcome to BDS Tic Tac Toe!!\n");
	printf("(In this version, X always goes first.\n");
	printf("The board is arranged as follows:");
	do {
	  mefirst = !mefirst;		/* reverse who goes first */
	  turn = 0;
	  display(1);
	  printf(mefirst ? "I go first...\n":
			   "You go first...\n");
	  clear();			/* clear the game board */
     	  mypiece = mefirst ? X : O; 	/* set who has got what */
	  hispiece  = mefirst ? O : X;
	  if (!mefirst) goto hismove;

 mymove: if (turn == 0)    		/* Opening move may be random */
		BEST = rand() % 9;
	  else if (turn == 1) {  	/* Response to opener: */
		if (board[4])
			BEST = rand() % 2 * 6 +
			rand() % 2 * 2;
		else BEST = 4;
	   }
	  else {			/* OK, we're into the game... */
		t = ttteval(mypiece,hispiece);
		if (t == 1) printf("I've got ya!\n");
	    }
	   board[BEST] = mypiece;  	/* make the move */
	   ++turn;
	   display(0);
	   if (win(mypiece)) {
		++mywins;
		printf("\nI win!!!\n");
		continue;
	    }
	   if (cats()) {
		++catwins;
		printf("\nMeee-ow!\n");
		continue;
	    }

  hismove: printf("Your move (1-9) ? ");
	   i = getchoice() - 0x30;
	   if (i < 1 || i > 9 || board[i-1]) {
		printf("\nIllegal!\n");
		goto hismove;
	    }
	   board[i-1] = hispiece;
	   ++turn;
	   display(0);
	   if (win(hispiece)) {
		++hiswins;
		printf("\nYou beat me!!\n");
		continue;
	    }
	   if (cats()) {
		++catwins;
		printf("\nOne for Morris.\n");
		continue;
	    }
	   goto mymove;

	} while (ask("\nAnother game (y/n) ? "));

	printf("\n\nOK...Final score:\n");
	printf("You won %d game",hiswins);
	if (hiswins != 1) putchar('s');
	printf(";\nI won %d game",mywins);
	if (mywins != 1) putchar('s');
	printf(";\nThe Cat got %d game",catwins);
	if (catwins != 1) putchar('s');
	printf(".\nSee ya later!!\n");
}


	