; /* 'execute connect5.c' to make!
lc -j73 -v -b -r -O -M connect5
blink LIB:c.o,connect5.o TO connect5 LIB LIB:lc.lib,LIB:amiga.lib SC SD ND
quit
*/

/*	Connect5	by Martin Round	6-Nov-90
	Hacked from 'FiveInLine' by Njål Fisketjøn.
	If I'd done it, I'd have killed those globals and gotos !!
	
	His was a nice(ish) intuition version - this is much messier, but can
	be used as an on-line game on Bulletin Boards
	(Well that was the idea anyway.... we shall see...)
*/

#include <stdio.h>

/*  GS is the gridsize e.g. 8 for a chessboard  */
#define GS 19

#define ATTACKFACTOR 4

void Human(),AddUp(),UpdateValue(),MakeMove(),FindMove();
void init_newgame(),Draw_Whole_Screen(),Draw_Line(short);

const unsigned char letters[] = "  |A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|   ";
const unsigned char top[] = "/===========\\\n";
const unsigned char bottom[] = "\\===========/";

unsigned char	gamewon;
short			d,i,j,k,l,x,y,start,moves;
short			lx,ly,pla,opp,x1,y1,max,value;
short			Board[GS+1][GS+1],Aline[4][GS+1][GS+1][2],Value[GS+1][GS+1][2];
int 			myscore,yourscore;
short			Weight[]={0,0,4,20,100,500,0};

short cursor_y;

void cursor_to(short x,short y)
	{
		
	if (cursor_y > y)
		printf("\x1b[%dF",cursor_y-y);
	else if (cursor_y < y)
		printf("\x1b[%dE",y-cursor_y);
	else 
		printf("\n\x1b[F");
	
	cursor_y = y;
	
	if (x > 1)
		printf("\x1b[%dC",x-1);
	}

void face()
	{
	cursor_to(46,4);
	printf("   0   0   ");
	cursor_to(46,5);
	printf("     ^     ");
	cursor_to(46,6);
	printf("  _______  ");
	cursor_to(46,7);
	printf("           ");
	}

void await_enter()
	{
	int letter;
	
	cursor_to(46,13);
	printf("Press Enter");
	cursor_y++;

	while ((letter = getchar()) != '\n')
		{
		cursor_to(57,13);
		if (toupper(letter) == 'X')
			{
			cursor_to(1,24);
			exit (0L);
			}
		} 
	}
	
void main()
	{
	start=0;	/*	computer will play first in first game	*/
	
	printf("\fCONNECT FIVE   by Martin Round.\n");
	printf("============\n\n");
	
	printf("This game is similar to 'Noughts and Crosses', but you need\n");
	printf("5 in a line rather than 3.  Based on a game by Njål Fisketjøn.\n");

	printf("\nMakes use of cursor movement ANSI sequences, which all comms\n");
	printf("programs do not emulate.  ACCESS! and JRCOMM V1.0 are O.K.\n");
	printf("JRCOMM V0.94, and other comms programs may not work.\n\n");
	printf("If the screen goes funny, press X and then ENTER to quit.\n\n");
	printf("Press ENTER to continue....");
	
	while (getchar() != '\n')
		;

NewGame:

	init_newgame();
	if(start == 0) goto Human_first;

loop:
	if (moves >= (GS*GS))
		{
		await_enter();
		goto NewGame;
		}
	pla=1;
	opp=0;
	FindMove();
	MakeMove();
	cursor_to(53,19);
	printf("%c%d",x +('A'-1),y);
	if (y<10) printf(" ");
	Board[x][y]=2;  /*  2:computer,  1:Human,  0: empty */
	moves++;
	cursor_to(1,(short)(3+y));
	Draw_Line(y);

	if (gamewon)
		{
		myscore++;
		face();
		cursor_to(46,6);
		printf(" \\_______/ ");
		cursor_to (48,10);
		printf("I WON!!");
		await_enter();
		goto NewGame;
		}

Human_first:

	pla=0;
	opp=1;
	Human();
	Board[x][y]=1;
	moves++;
	cursor_to(1,(short)(3+y));
	Draw_Line(y);
	MakeMove();

	if (gamewon)
		{
		yourscore++;
		face();
		cursor_to(47,7);
		printf("/       \\");
		cursor_to (47,10);
		printf("YOU WON!!");
		await_enter();
		goto NewGame;
		}

	goto loop;
	}

void Human()
	{
	char buffer[256];
	char letter;
	int number;
	do
		{
		cursor_to(53,22);
		printf ("    |");
		cursor_to(53,22);
		if (gets(buffer) == NULL)
			continue;
		cursor_y++;
		
		if (toupper(buffer[0]) == 'X')
			{
			cursor_to(1,24);
			exit (0L);
			}
		if (buffer[0] == '+')
			{
			Draw_Whole_Screen();
			continue;
			}
		
		letter = toupper(buffer[0]);
		number = atoi(&(buffer[1]));
		
		if ((letter < 'A') || (letter > 'S'))
			continue;
		if ((number < 1) || (number > 19))
			continue;
		y = number;
		x = letter - ('A'-1);
		} while (Board[x][y]);	/*	occupied square	*/
		
	}

void MakeMove()
	{
	gamewon=0;

	d=0;
	for(k=0;k<=4;k++)
		{
		x1=x-k;
		y1=y;
		if(x1>=1 && x1<=GS-4)
			{
			AddUp();
			for(l=0;l<=4;l++)
				UpdateValue();
			}
		}	

	d=1;
	for(k=0;k<=4;k++)
		{
		x1=x-k;
		y1=y-k;
		if((x1>=1 && x1<=GS-4) && (y1>=1 && y1<=GS-4))
			{
			AddUp();
			for(l=0;l<=4;l++)
				UpdateValue();
			}
		}

	d=3;
	for(k=0;k<=4;k++)
		{
		x1=x+k;
		y1=y-k;
		if((x1>=5 && x1 <= GS) && (y1>=1 && y1<=GS-4))
			{
			AddUp();
			for(l=0;l<=4;l++)
				UpdateValue();
			}
		}

	d=2;
	for(k=0;k<=4;k++)
		{
		x1=x;
		y1=y-k;
		if(y1>=1 && y1<=GS-4)
			{
			AddUp();
			for(l=0;l<=4;l++)
				UpdateValue();
			}
		}
	}

void AddUp()
	{
	Aline[d][x1][y1][pla] = Aline[d][x1][y1][pla] + 1;

	if(Aline[d][x1][y1][pla] == 5) gamewon=1;
	}

void UpdateValue()

	{
	if(d==0)
		{
		lx=l;
		ly=0;
		}
	else if(d==1)
		{
		lx=l;
		ly=l;
		}
	else if(d==2)
		{
		lx=0;
		ly=l;
		}
	else
		{
		lx=-l;
		ly=l;
		}

	if(Aline[d][x1][y1][opp] == 0)
		Value[x1+lx][y1+ly][pla] =  Value[x1+lx][y1+ly][pla] 
									+ Weight[Aline[d][x1][y1][pla]+1] 
									- Weight[Aline[d][x1][y1][pla]];
									
	else if(Aline[d][x1][y1][pla] == 1)
		Value[x1+lx][y1+ly][opp] =  Value[x1+lx][y1+ly][opp] 
									- Weight[Aline[d][x1][y1][opp]+1];
	}

void FindMove()

	{
	max=-32767;
	x=(GS+1)/2;
	y=(GS+1)/2;
	if(Board[x][y] == 0) max=4;

	for(i=1;i<=GS;i++)
		{
		for(j=1;j<=GS;j++)
			{
			if(Board[i][j] == 0)
				{
				value=  Value[i][j][pla] * (16 + ATTACKFACTOR) / 16
						+ Value[i][j][opp];
				if(value == max)
					if (rand()%7)
						{
						x=i;
						y=j;
						}
				if(value > max)
					{
					x=i;
					y=j;
					max=value;
					}
				}
			}
		}
	}

void init_newgame()
	{
	start=1-start;  			  /* toggle between computer and human */
	moves = 0;

	for(x=1;x<=GS;x++)
		{
		for(y=1;y<=GS;y++)
			Board[x][y]=0;
		}

	for(d=0;d<=3;d++)
		{
		for(x=1;x<=GS;x++)
			{
			for(y=1;y<=GS;y++)
				{	
				for(pla=0;pla<=1;pla++)
					Aline[d][x][y][pla]=0;
				}
			}
		}

	for(x=1;x<=GS;x++)
		{
		for(y=1;y<=GS;y++)
			{
			for(pla=0;pla<=1;pla++)
				Value[x][y][pla]=0;
			}
		}

	Draw_Whole_Screen();
	}

void Draw_Line(short line)
	{
	unsigned char symbol[3] = {'-','*','O'};
	int i;
	
	printf("%2d",line);
	
	for (i=1;i<=GS;i++)
		printf("|%c",symbol[Board[i][line]]);

	printf("|%d",line);
	}

void Draw_Whole_Screen()
	{
	short i;
	
	printf("\f");	/*	clear creen	*/
	
	printf("\n============== CONNECT FIVE =============================\n\n");
	printf("%s%s",letters,top);
	
	for (i=1;i<=GS;i++)
		{
		Draw_Line(i);
		switch(i)
			{
			case 1:
				printf("  |   SCORE   |\n");
				break;
			case 3:
				printf("  |O  (Me)| %2d|\n",myscore);
				break;
			case 4:
				printf("  |* (You)| %2d|\n",yourscore);
				break;
			case 5:
				printf("  %s\n",bottom);
				break;
			case 10:
				printf("  + to Redraw\n");
				break;
			case 12:
				printf("   X to Exit\n");
				break;
			case 14:
				printf(" %s",top);
				break;
			case 15:
				printf(" |  MY       |\n");
				break;
			case 16:
			case 19:
				printf(" | MOVE:     |\n");
				break;
			case 2:
				printf(" ");
			case 17:
				printf(" |===========|\n");
				break;
			case 18:
				printf(" | YOUR      |\n");
			    break;
			default:
				printf("\n");
				break;
			}
		}
	printf("%s%s",letters,bottom);
	
	cursor_y = 23;	/*	if GS == 19	*/
	}
