/* -	-	Tic Tac Toe -	-	*/
#define xedvars 0

#include "stdio.h"
#include "types.h"
#include "math.h"
#include "intuition/intuition.h"    
#include "graphics/gfxbase.h"
#include "graphics/text.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "exec/memory.h"

#include "devices/timer.h"

struct timerequest tr;
struct MsgPort *tport;

struct IntuitionBase *IntuitionBase;
struct IntuiMessage *txmsg;
struct GfxBase *GfxBase;
struct Window *txwin;
struct Process *mproc;
struct RastPort *txrp;
struct MsgPort *xport;
struct IOStdReq *iport;
struct Device *ConsoleDevice;

struct NewWindow frame =
{
/* Left Top		*/ 0,0,
/* Width			*/ 240, /* (N*8) + 24 */
/* Height		*/ 78, /* (N*8) + 14 */
/* DetailPen	*/ 0,
/* BlockPen		*/ 1,
/* IDCMPFlag	*/ RAWKEY,
/* Flags			*/ WINDOWDRAG| WINDOWSIZING| WINDOWDEPTH| SMART_REFRESH| ACTIVATE,
/* FirstGadget */ NULL,
/* Check_mark	*/ NULL,
/* Title       */ "X's and O's",
/* Screen		*/ NULL,
/* BitMap		*/ NULL,
/* MinWidth MinHeight */ 24,18,
/* MaxWidth MaxHeight */ -1,-1,
/* Type			*/ WBENCHSCREEN
};

struct InputEvent ievent = /*raw key input event*/
{
	NULL,					/*next event*/
	IECLASS_RAWKEY,	/*class*/
	0,0,0
};

int MaxStLen = 256;
#define MaxSt1 256  /*maxstlen */

/* Variables */

int TOP = 1; /*Cls*/
int BOT = 9;
int PW = 77;
int LLen;
int GX, GY;
ulong COLOR, BCOLOR; /* 0 brn 1 ylo 2 bk 3 grn*/
ulong Tstyle;
int func; /*kbd*/
char buff[10];
char Nstr[82];

#include "SCREEN.P";

/* - -  - - */
#ifndef BRN
#define BRN 0
#define YLO 1
#define BLK 2
#define GRN 3
#endif

char GetKey() /* keys convert to WS control codes. del = ^G */
{
	int C = 0, class, len;
	do {
		if((txmsg = (struct IntuiMessage *)GetMsg(txwin->UserPort)) == 0L)
		{
			Wait(1 << txwin->UserPort->mp_SigBit); continue; /* re-do */
		}
		class = txmsg->Class;
		if(class == RAWKEY)
		{ /* convert arrow keys et al to char code */
			if(txmsg->Code & IECODE_UP_PREFIX) {;}
			else
			{
				buff[0] = 0; buff[1] = 0; buff[2] = 0;
				ievent.ie_Code = txmsg->Code;
				ievent.ie_Qualifier = txmsg->Qualifier;
				ievent.ie_position.ie_addr = * (APTR *)txmsg->IAddress;
				len = (RawKeyConvert(&ievent,buff,10,NULL));
				if(len > 0) {
					if(len == 1) { C = buff[0]; if(C == 0x7f) C = 7; }
					else										/*DEL .. ^code*/
					{
						C = buff[1];
						if(buff[2] == '~') { /* help & function keys */
							func = '?';
							if((C >= '0') && (C <= '9')) func = C + 1;
							C = 31;
						}
						switch(C) /* arrow keys */
						{
						case 'A': C = 5;	break; /*^E ^*/
						case 'B': C = 24; break; /*^X v*/
						case 'C': C = 4;	break; /*^D >*/
						case 'D': C = 19; break; /*^S <*/
						case 'T': C = 18; break; /*^R ^^*/
						case 'S': C = 3;	break; /*^C vv*/
						case ' ':
						{
							if(buff[2] == 'A') C = 1; /*^A <<*/
							if(buff[2] == '@') C = 6; /*^F >>*/ break;
						}
						}
					}
				}
			}
		}
		ReplyMsg((struct Message *)txmsg);
	} while(C == 0);
	return(C);
}

SetAttr(S) /* Normal = 0 Uline = 1/2 Bold = 3/4 italic = 5/6 */
int S;
{
	ulong en;
	switch(S)
	{
	case 0: Tstyle = 0; break;
	case 1: Tstyle = Tstyle | 1; break;
	case 2: Tstyle = Tstyle & 6; break;
	case 3: Tstyle = Tstyle | 2; break;
	case 4: Tstyle = Tstyle & 5; break;
	case 5: Tstyle = Tstyle | 4; break;
	case 6: Tstyle = Tstyle & 3; break;
	}
	en = AskSoftStyle(txrp); SetSoftStyle(txrp,Tstyle,en);
}

/* 0 brn 1 ylo 2 bk 3 grn*/
SetCols() { SetAPen(txrp,COLOR); SetBPen(txrp,BCOLOR); }
YR() { COLOR = YLO; BCOLOR = BRN; SetCols(); SetAttr(0); }
KR() { COLOR = BLK; BCOLOR = BRN; SetCols(); SetAttr(0); }
KG() { COLOR = BLK; BCOLOR = GRN; SetCols(); SetAttr(0); }

int SetStLen(str)
char *str;
{
	char C; int E = 0, L = -1;
	do { ++L; C = str[L]; if((C == 0) || (C == 10) || (L >= MaxSt1)) E = 1; } while(E == 0);
	str[L] = 0;
	if(L >= MaxSt1)
	{
		E = 0; do { --L; C = str[L]; if((C > 32) || (L < 0)) E = 1; } while(E == 0);
		++L; str[L] = 0;
	}
	return(L);
}

WriteStr(str) char *str; { long L; Move(txrp,(long)GX,(long)GY); L = (long)SetStLen(str); Text(txrp,str,(ulong)L); GX +=(L << 3); }

WriteStN(str,L) char *str; int L; { Move(txrp,(long)GX,(long)GY); Text(txrp,str,(ulong)L); GX +=(L << 3); }

/* due to the extra Moves it's faster to compose a str */
WriteCh(C) char C; { Move(txrp,(long)GX,(long)GY); Nstr[0] = C; Text(txrp,Nstr,(ulong)1); GX += 8; }

WriteCN(C,N) char C; int N; { int L; for(L = 0; L < N; L++) Nstr[L] = C; WriteStN(Nstr,N); }

WriteLong(W)
long W;
{
	int L = 79, S = 0;
	Nstr[L--] = 0;
	if(W < 0) { W = -W; S = 1; }
	do { Nstr[L--] = ((W % 10) + 48); W /= 10; } while((W > 0) && (L > 1));
	if(S == 1) Nstr[L--] = '-';
	WriteStr(&Nstr[(L + 1)]);
}
WriteInt(N) int N; { WriteLong((long)N); }

GotoY(L) int L; /*origin 1,1*/ { GX = 4; GY = (L << 3) + 10; }
GotoXY(N,L) int N,L; { GX = (N << 3) - 4; GY = (L << 3) + 10; }

Cll(L) int L; { GotoY(L); WriteCN(' ',PW); GX = 4; }
Cls()
{
	int L;
	YR(); Tstyle = 0; SetAttr(3); SetAttr(5); /*Bold ital wide cls*/
	for(L = TOP; L <= BOT; L++) Cll(L);
	SetAttr(0);
}

char UPcase(C) char C; { if((C < 97) || (C > 122)) {;} else C -= 32; return(C); }

StJoin(str,str2) /*str(LLen) + str2*/
char *str; char *str2;
{
	char C; int E = 0, L, P = 0;
	L = --LLen;
	do { C = str2[P++]; str[++L] = C; if((C == 0) || (L >= MaxStLen)) E = 1; } while(E == 0);
	str[L] = 0; LLen = L;
}
/* - -  - - */

/* - - TIC TAC TOE - - */
TTT() {;}
 int count, key, tac, win;
 int dbg;
 int game[4], row[10], where[9];
 int data[9][3] = {{1,5,9},{3,5,7},{2,5,8},{4,5,6},{1,2,3},{7,8,9},{1,4,7},{3,6,9}};
 int datb[9][3] = {{2,5,8},{1,5,9},{3,5,7},{4,5,6},{1,2,3},{7,8,9},{1,4,7},{3,6,9}};

setzero()
{
	int a;
	for(a = 0; a < 10; a++) row[a] = 0;
	count = tac = win = 0;
}

 ulong R_N_D; int R_N_;
unsigned RndInt(K) /* 0..K-1 */
unsigned K;
{
	ulong N;
	N = R_N_D; N++;
	R_N_++; if(R_N_ > 6) R_N_ = 0;
	switch (R_N_)
	{
	case	0: N *= 75; break;
	case	1: N *= 47; break;
	case	2: N *= 41; break;
	case	3: N *= 66; break;
	case	4: N *= 76; break;
	case	5: N *= 25; break;
	default: N *= 7; break;
	}
	R_N_D = N >> 1;
	return((N >> 2) % K);
}

Randomise()
{
	ulong micro;
	if(OpenDevice(TIMERNAME,UNIT_MICROHZ,(struct IORequest *) &tr,0) == 0L)
	{
		if((tport = (struct MsgPort *)CreatePort(0,0)) != 0)
		{
			tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
			tr.tr_node.io_Message.mn_Node.ln_Pri  = 0;
			tr.tr_node.io_Message.mn_Node.ln_Name = 0L;
			tr.tr_node.io_Message.mn_ReplyPort	  = tport;
			tr.tr_node.io_Command					  = TR_GETSYSTIME;
			DoIO((struct IORequest *) &tr);
			micro=tr.tr_time.tv_micro;
			DeletePort(tport);
		}
		CloseDevice((struct IORequest *) &tr);
	}
	R_N_D = micro; R_N_ = micro & 7;
}

tstrnd()
{
	int X,Y,C;
	do {
		X = 1 + RndInt(PW); Y = 1 + RndInt(30); GotoXY(X,Y);
		COLOR = 1 + RndInt(3); SetAPen(txrp,(ulong)COLOR);
		C = 65 + RndInt(25); WriteCh(C);
	} while(RndInt(32768) != 12345);
}

prt(ip)
int ip;
{
	int x,y;
	YR(); y = (ip - 1) / 3; x = ip - (3 * y);
	GotoXY((4 * x),2 + (2 * y));
	if(row[ip] ==	1) WriteCh('X');
	if(row[ip] ==	0) WriteCh(' ');
	if(row[ip] == -1) WriteCh('O');
}

printrows()
{
	int x,y,n;
	KR();
   GotoXY(2,1); WriteStr("ME "); WriteInt(game[1]);
   GotoXY(10,1); WriteStr("YOU "); WriteInt(game[2]);
	for(y = 0; y < 3; y++) {
		for(x = 1; x < 4; x++) {
			n = (x + (y * 3));
			prt(n);
         KR(); if(x < 3) WriteStr(" |");
			YR(); GotoXY(14 + (4 * x),6 - (2 * y)); WriteInt(n);
         KR(); if(x < 3) WriteStr(" |");
		}
		if(y < 2) {
         GotoXY(3,(y * 2) + 3); WriteStr("---+---+---   ---+---+---");
		}
	}
}

int getip()
{
	int a, ok = 0;
	while(ok == 0) {
		GotoXY(8,7); KG(); WriteCh('?'); fflush(stdout);
		a = UPcase(GetKey());
		if(a == 27) a = 'Q'; /* ESC quit */
		if(a < 32) a = 32;
		/*if(a == 'D') dbg += 1; if(dbg > 1) dbg = 0;*/ dbg = 1;
		if(a == 'T') { YR(); tstrnd(); Cls(); printrows(); prt(5); }
		if( (a == 'Q') || ((a > '0') && (a < ('9' + 1))) ) { ok = 1;}
	}
	return(a);
}

prchk()
{
	int a,b;
	if(dbg == 1) {
		for(a = 1; a < 9; a++) {
			KR();	 GotoXY(60,a);
         WriteInt(a); WriteStr(" ="); WriteInt(where[a]); WriteCh(' ');
			for(b = 0; b < 3; b++) {
				KG(); GotoXY(66 + (4 * b), a);
				if(tac == 0) WriteInt(data[a-1][b]); else WriteInt(datb[a-1][b]);
			}
		}
	}
}

check()
{
	int a,b,temp;
	int lo = 0, hi = 0;
	count++;
	for(a = 1; a < 9; a++) {
		temp = 0;
		if(a < 5) temp = row[a] + row[5] + row[10 - a];
		if((a == 5) || (a == 6)) {
			for(b = 1; b < 4; b++) temp += row[b + (6 * (a - 5))];
		}
		if(a > 6) {
			for(b = 1; b < 8; b +=3) temp += row[b + (2 * (a - 7))];
		}
		if(temp <= lo) {lo = temp; where[a] = temp; }
		if(temp >= hi) {hi = temp; where[a] = temp; }
	}
	if(tac == 0) { a = where[2]; where[2] = where[3]; where[3] = a;}
	else { a = where[2]; where[2] = where[1]; where[1] = a;}
	if(lo == -3) { game[1]++; win = 1; }
	if(hi == 3) { game[2]++; win = 1; }
}

iplay()
{
	int a,b,c,d,f,ok;
	ok = 0;
	if(row[5] == 0) {row[5] = -1; prt(5); ok = 1;}
	for(a = 0; a < 4; a++)
	{
		switch (a)
		{
		case 0: b = -2; break;
		case 1: b =	 2; break;
		case 2: b =	 1; break;
		case 3: b = -1; break;
		}
		if((tac) && (a > 1)) b = -b;
		for(c = 0; c < 8; c++)
		{
			if((where[c + 1] == b) && (ok == 0))
			{
				for(d = 0; d < 3; d++)
				{
					if(tac == 1) f = datb[c][d]; else f = data[c][d];
					if((row[f] == 0) && (ok == 0))
					  { row[f] = -1; prt(f); ok = 1; }
				}
			}
		}
	}
}

play()
{
	int ok = 0;
	while(ok == 0)
	{
		key = getip();
		if(key == 'Q') {ok = 1;}
		else
		{
			key -='0'; if(key < 4) key +=6; else if(key > 6) key -=6;
			if(row[key] == 0)
			{
				row[key] = 1;
				prt(key); ok = 1;
				if((count < 5) && ((key == 3) || (key == 7))) {tac = 1;}
				else {tac = 0;}
			}
		}
	}
}

Start()
{
	int pl;
	dbg = 0; game[1] = 0; game[2] = 0; key = 0;
	Randomise();
	while((key != 'Q') && (game[1] < 12) && (game[2] < 12))
	{
		setzero();
		printrows();
		pl = RndInt(2);
		while((win == 0) && (key != 'Q') && (count < 9))
		{
/*			if(pl = 1) {play(); check();} most compilers automatically */
			if(pl == 1) {play(); check();}  /* accept this error */
			prchk();
			pl = 1;
			if((win == 0) && (key != 'Q')) {iplay(); check();}
			prchk();
		}
	}
}
/* -	-	Tic Tac Toe -	-	*/

 int error;
main(argc,argv)
int argc;
char *argv[];
{
	long d;
   if((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L)) != 0L)
	{
      if((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)) != 0L)
		{
			if((txwin = (struct Window *)OpenWindow(&frame)) != 0L)
			{
				txrp = (struct RastPort *)txwin->RPort;
            if((xport = (struct MsgPort *)CreatePort("conread",0)) != 0L)
				{
					if((iport = (struct IOStdReq *)CreateStdIO(xport)) != 0L)
					{
                  if((d = OpenDevice("console.device",-1,iport,0)) == 0)
						{
							ConsoleDevice = iport->io_Device;

							/* At last the keyboard and WBscreen are accessible*/

								Start();

							if((d = CheckIO(iport)) == FALSE) AbortIO(iport);
						} else error = 32;
						DeleteStdIO(iport);
					} else error = 16;
					DeletePort(xport);
				} else error = 8;
				CloseWindow(txwin);
			} else error = 4;
			CloseLibrary(GfxBase);
		} else error = 2;
		CloseLibrary(IntuitionBase);
	} else error = 1;
	if(error)
	{
	switch(error)
	{
   case  1: fputs("intui",stderr);  break;
   case  2: fputs("gfx",stderr);    break;
   case  4: fputs("window",stderr); break;
   case  8: fputs("msgport",stderr);break;
   case 16: fputs("iport",stderr);  break;
   case 32: fputs("condev",stderr); break;
   case 64: fputs("ram",stderr);    break;
	}
   fputs(" error",stderr);
	}
}
/* -	-	Tic Tac Toe -	-	*/
