// longminigo.c version 1.06; by Mathijs Romans
// shorter version on http://www.romansland.nl/minigo

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define LEVEL 1000
#define FALSE 0
#define TRUE 1
#define SIZE 9
#define VOID 0
#define BEYE 2
#define WEYE 3
#define ILLEGAL 8
#define BEYEILLEGAL 10
#define WEYEILLEGAL 11
#define BLACK 4
#define WHITE 5
#define FIELD for(x=0;x<SIZE;x++) for(y=0;y<SIZE;y++)
#define IFOR4 for (i=0;i<4;i++)
#define infield(x,y) (x>=0 && x<SIZE && y>=0 && y<SIZE)
		
int xq,yq,x,y,lib[SIZE][SIZE],b[SIZE][SIZE],turn,pturn,p[SIZE][SIZE],ko,kox,koy,pas,tpas,dx[]={1,0,-1,0,1,1,-1,-1}, dy[]={0,1,0,-1,1,-1,1,-1};

int liberties(int x, int y, int color)
{
	int i;
	if (!infield(x,y))
		return FALSE;
	if (b[x][y] != BLACK && b[x][y] != WHITE) //empty
		return TRUE;
 	if (b[x][y] != color || lib[x][y])
		return FALSE;
	lib[x][y] = TRUE;
	IFOR4
		if (liberties(x+dx[i],y+dy[i],color)) 
			return TRUE;
	return FALSE;
}

void take(int x, int y)
{
	int i;
	if (!infield(x,y) || b[x][y]!=(turn+1)%2+4)
		return;
	b[x][y] = 0;
	kox = x;
	koy = y;
	ko++;
	IFOR4
		take(x+dx[i],y+dy[i]);
}

void draw()
{
		for (x=0;x<SIZE;x++)
			printf("  %c   ",'a'+x);
	printf("\n");
	for(y=0;y<SIZE;y++) {
			for(x=0;x<SIZE;x++) {
				switch (b[x][y])
				{
					case BLACK:
						printf(" _|_  ");
					break;
					default:
						printf("  |   ");
				}
			}
			printf("\n");
			for(x=0;x<SIZE;x++) {
				switch (b[x][y])
				{
					case BLACK:
						printf("/   \\_");
					break;
					case WHITE:
							printf("_XXX__");
					break;
					case BEYE:
						printf("__B___");
					break;
					case WEYE:
						printf("__W___");
					break;
					case BEYEILLEGAL:
						printf("__Bx__");
					break;
					case WEYEILLEGAL:
						printf("__Wx__");
					break;
					case ILLEGAL:
						printf("__x___");
					break;
					case 0:
						printf("__|___");
					break;
					default:
						printf("__%i___",b[x][y]);
					
				}
			}
			printf(" %i\n",y+1);
			for(x=0;x<SIZE;x++) {
				switch (b[x][y])
				{
					case BLACK:
						printf("\\___/ ");
					break;
					case WHITE:
							printf(" XXX  ");
					break;
					
					default:
						printf("  |   ");
				}
			}
			printf("\n");
		}
	printf("\n");
}

void findeyes(int color)
{
	int changed,eyeness,i;
	FIELD
	{
		if (b[x][y] > 7)	//remove old illegal moves
			b[x][y] -= 8;
		if (b[x][y] == 0)
			b[x][y] = 2+color;
	}
	do
	{
		changed=FALSE;
		FIELD
			if (b[x][y] == 2+color)
			{
				IFOR4
					if (infield(x+dx[i],y+dy[i]) && b[x+dx[i]][y+dy[i]] != 4+color)
						goto notaneye;
				eyeness = 0;
				IFOR4					
					if (infield(x+dx[i+4],y+dy[i+4]) && (b[x+dx[i+4]][y+dy[i+4]] == 4+color || b[x+dx[i+4]][y+dy[i+4]] == 2+color))
						eyeness++;
				if (x == 0 || x == SIZE-1)
					eyeness++;
				if (y == 0 || y == SIZE-1)
					eyeness++;			
				if (eyeness < 3)
				{
					notaneye:
					changed = TRUE;
					b[x][y] = 0;
				}
			}
	}
	while (changed);
}

int move(int xloc, int yloc)
{
	int i,prev;
	prev = b[xloc][yloc];
	b[xloc][yloc] = turn%2+4; //try move
	ko = 0;
	IFOR4
	{
		if (infield(xloc+dx[i],yloc+dy[i]) && !lib[xloc+dx[i]][yloc+dy[i]] && b[xloc+dx[i]][yloc+dy[i]] == (turn+1)%2+4 && !liberties(xloc+dx[i],yloc+dy[i],(turn+1)%2+4))
			take(xloc+dx[i],yloc+dy[i]);
		FIELD lib[x][y]=0;
	}
	i=liberties(xloc,yloc,b[xloc][yloc]);
	FIELD lib[x][y]=0;
	if (i)	// proper move
	{
		pas = FALSE;
		findeyes(turn%2);		
		if (ko==1)
		{
			b[kox][koy] += 8;	//new ko
			IFOR4
				if (infield(xloc+dx[i],yloc+dy[i]) && b[xloc+dx[i]][yloc+dy[i]] == 4+turn%2)
				{
					b[kox][koy] -= 8; //not a ko
					break;
				}
		}
		return TRUE;
	}
	b[xloc][yloc] = prev+8; //illegal move, do not play here
	return FALSE;
}

int game()
{
	int count;
	for(;turn<10*SIZE*SIZE;turn++)
	{
		count=0;
		FIELD if (!b[x][y] || b[x][y] == 2+(turn+1)%2)
			count++;	//count available moves
		do
		{
			if (!count)
			{
				findeyes(turn%2);
				if (pas)
				{
					xq=0;
					FIELD
						if (b[x][y] == BLACK || b[x][y]== BEYE)
							xq++;
					return 2*xq-81;			//end of game
				}
				pas = TRUE;
				break;
			}
			do
			{
				xq=rand()%SIZE;
				yq=rand()%SIZE;
			}
			while (!(!b[xq][yq] || b[xq][yq] == 2+(turn+1)%2));
			if (move(xq,yq))
				break;
			count--;
		}
		while (1);
	}
	return 0;	//triple ko
}
int main()
{
	int tx,ty,tot,i,hx,hy,h;
	char input[20];
	srand(time(0));
	ko = 0;
	FIELD
	{
		p[x][y] = 0;
		lib[x][y] = 0;
	}
	for (pturn=0;TRUE;pturn++)
	{
		if (pturn%2)
		do		//human move
			{
				turn = pturn;
				hx = -1;
				printf("YOUR MOVE!\n");
				scanf ("%s",input);
				if(input[0] == 'p')
					break;
				hx = input[0] - 'a';
				hy = input[1] - '1';
				if (hx >= 0 && hx <SIZE && hy >= 0 && hy < SIZE && b[hx][hy]<4 && move(hx,hy))
					break;
			}
			while(1);
		else
		{					//computer move
   		hx = -1;
			for (tx=0;tx<SIZE;tx++)
				for (ty=0;ty<SIZE;ty++)
				if ((!p[tx][ty] || p[tx][ty] == 3)) //play on empty space or opponents eye
				{
					turn = pturn;
					FIELD b[x][y] = p[x][y];
					if (move(tx,ty))	// is move possible?
					{
						tot = 0;
						for (i=0;i<LEVEL;i++)	// loop games
						{
							FIELD b[x][y] = p[x][y];	// restore original b
							move(tx,ty);
							turn++;
							tot += game();
							turn = pturn;	//set for next game
						}
						if (hx == -1 || tot > h)
						{
							hx = tx;	//
							hy = ty;	// remember best move
							h = tot;	//
						}
					}
				}
		}
		FIELD b[x][y] = p[x][y];
		if (hx != -1)
		{
			tpas=FALSE;
			move(hx,hy);
		}
		else
		{
			findeyes(turn%2);
			printf("PASS!\n");
			if (tpas)  //end of game
			{
				turn++;
				xq=game();
				if (xq>0)
					printf("BLACK");
				else
					printf("WHITE");
				printf(" WINS WITH %i POINTS!\n",xq>0?xq:-xq);
				return 0;
			}
			tpas = TRUE;
		}	
		FIELD p[x][y] = b[x][y];
		draw();
	}
	return 0;
}
