Plan 9 from Bell Labs’s /usr/web/sources/contrib/paurea/goban/rules.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <igo.h>


int verbose;


Move *moves;

/* in igo coordinates... */
Point hcap[Hcapsz]={
	{4,4},{16,16},{4,16},{16,4},{10,10},
	{10,4},{10,16},{16,10},
	{4,10},
};

Point hcapord[Hcapsz][Hcapsz]={
	{{4,4},{16,16},},
	{{4,4},{16,16},{4,16},},
	{{4,4},{16,16},{4,16},{16,4},},
	{{4,4},{16,16},{4,16},{16,4},{10,10},},
	{{4,4},{16,16},{4,16},{16,4},{16,10},{4,10},},
	{{4,4},{16,16},{4,16},{16,4},{10,10},{16,10},{4,10},},
	{{4,4},{16,16},{4,16},{16,4},{10,4},{10,16},{16,10},{4,10},},
	{{4,4},{16,16},{4,16},{16,4},{10,10},{10,16},{16,10},{4,10},{10,4},},
};

/* this file works on goban */
char goban[Bansz+1][Bansz+1];	// 0,0 left without anything in order to use go coordinates.
Move lstone;			// last move
Move lkou;			//last kou

extern char *emptytype = "ewbkc";
//{Emptystone, Wmarked, Bmarked, Kou, Cntstone};

enum{
	Nt,
	St,
	Et,
	Wt,
	Ncoord,
};
static Point to[]={
	[Nt]	{1,0},
	[St]	{-1,0},
	[Et]	{0,1},
	[Wt]	{0,-1}
};


static Move*
_getgrp(Move **lg, Move *m, char *neightype, int xgoban[Bansz+1][Bansz+1], char origtype);

static int 
isempty(Move *mv)
{
	char type;

	type=goban[mv->x][mv->y];
	return strchr(emptytype, type)!=nil;
}

void 
cleangoban(void)
{
	int i,j;

	for (i=0; i<Bansz+1; i++)
			for (j=0; j<Bansz+1; j++)
				goban[i][j] = Emptystone;
}



static void
opcount(Move *m, char){
//dprint("opcount, %P %c\n",m->Point, m->type);
	if(goban[m->x][m->y] == Emptystone)
		opplace(m,Cntstone);
	
}


void
opplace(Move *m, char type)
{	
	char lt;
	if(type!=0)
		lt=type;
	else
		lt=m->type;
	goban[m->x][m->y]=lt;
	//print("opplace, %d %d %c\n",m->Point.x, m->Point.y, lt);
}



int
isvalidpos(Point pos)
{
	if(pos.x<=Bansz && pos.y<=Bansz && pos.y>=1 && pos.x>=1)
		return 1;
	return 0;
}

/*Given a goban point returns malloc'ed Move*/
Move*
getmove(Point pos)
{
	Move *m;
	m=malloc(sizeof(Move));
	if(!m)
		threadexitsall("Malloc");
	fillmov(m, pos, goban[pos.x][pos.y]);
	return m;
}

static Move*
getneigh(Move m, int crd)
{
	Point pos;
	Move *n;

	assert(crd<Ncoord);

	pos = m.Point;
	pos = addpt(pos, to[crd]);
	if(isvalidpos(pos)){
		n = malloc(sizeof(Move));
		assert(n);
		fillmov(n, pos, goban[pos.x][pos.y]);
		return n;
	}
	else{
		return nil;
	}
}

static void
clearxgoban(int xgoban[Bansz+1][Bansz+1])
{
	int i,j;
	
	for(i=0;i<Bansz+1;i++)
		for(j=0;j<Bansz+1;j++)
			xgoban[i][j]=0;
}


static int
canbeneigh(char *type, Move *neigh)
{
	int can;
	

	if(!type)
		return 0;
	
	can = strchr(type, goban[neigh->x][neigh->y])!=nil;
	can = can || strchr(type, '*')!=nil;
	if(verbose)
	dprint("Canbeneigh %s, %c, %d, %P\n", type, neigh->type, can, neigh->Point); 
	return  can;
}

static Move*
_getgrp(Move **lg, Move *m, char *neightype, int xgoban[Bansz+1][Bansz+1], char origtype)
{
	Move *neigh;
	int i, addedm, isempty;

	isempty = strchr(emptytype, origtype)!=nil;
	addedm = 0;
	if(verbose)
	dprint("Getgrp %P\n",m->Point);
	xgoban[m->x][m->y]=1;

	if(!neightype && origtype==m->type){
		if(*lg!=m)		//move parameter implicitly added
			*lg=addlast(*lg,m);
		addedm++;
	}

	for(i=0; i<Ncoord;i++){
		if((neigh=getneigh(*m,i)) && !xgoban[neigh->x][neigh->y])
		{
			xgoban[neigh->x][neigh->y]=1;
			if(origtype==neigh->type || (isempty && strchr(emptytype, neigh->type)))
				_getgrp(lg, neigh, neightype, xgoban, origtype);
			else if(canbeneigh(neightype, neigh)){
				*lg=addlast(*lg,neigh);
				addedm++;
			}
			else
				free(neigh);
		}
			
	}
	if(!addedm)
		free(m);
	return(*lg);
}

/* if neightype == nil returns a group of contiguos stones to m
   of the same neightype
   if neightype != nil and point->neightype is in neightype
   returns a group of neightype in neightype neighbouring stones to m
   if neightype contains * returns neighbouring stones in general
   else undefined
   m itself is not used.

*/


Move*
getgrp(Move *m, char *neightype)
{
	Move *grp, *lm;
	grp = nil;

	int xgoban[Bansz+1][Bansz+1];

	clearxgoban(xgoban);

	if(neightype && strchr(neightype, m->type))
		return nil;

	lm = malloc(sizeof(Move));
	fillmov(lm, m->Point, m->type);
	grp = _getgrp(&grp, lm, neightype, xgoban, m->type);
	return grp;
}



int
nlibert(Move *m)
{
	Move *grp;
	int nlib;

	assert(strchr(emptytype, m->type)==nil);

	grp = getgrp(m, emptytype);
	nlib = opgrp(grp, '\0', opnop);
dprint("nliberties: %d\n", nlib);
	freegrp(grp);
	return nlib;
}


/* returns number of eaten or -1 if not possible */
int
move(Move *m, Move **mdead)
{
	int nl, neighl, i, neaten, msz;
	Move *neigh, neigheat, *grp, *mgrp;

	neaten = 0;
	if(goban[m->x][m->y]!=Emptystone){
		if(verbose)
		dprint("Move: cannot place, not empty\n");
		return -1;
	} else
		opplace(&lkou, Emptystone);

	if(verbose)
	dprint("Move %P %c\n", m->Point, m->type);
	assert(strchr(emptytype, m->type)==nil);
	nl = nlibert(m);

	/* look at the neighbours, kill them */
	for(i=0; i<Ncoord; i++){
		if(neigh = getneigh(*m,i)){
			if(isempty(neigh)){
				free(neigh);
				continue;
			}
			neighl = nlibert(neigh);
			neighl--; /*the stone takes away a liberty*/
			if(!neighl && (neigh->type!=m->type) && (!isempty(neigh))){
				neigheat = *neigh;
				grp = getgrp(neigh, nil);
				neaten += opgrp(grp, Emptystone, opplace);
				*mdead = addlast(*mdead, grp);
				//opgrp(grp, Emptystone, opprint);
			}
			else
				free(neigh);
		}
	}

	/*suicide is forbidden*/
	if(!nl && !neaten){
		if(verbose)
		dprint("Move: cannot place, suicide\n");
		return -1;
	}
	
	/* kou, eat 1, no liberties before eating, group of one*/
	
	if(neaten==1 && !nl){
		mgrp = getgrp(m, nil);
		msz = opgrp(mgrp, '\0', opnop);
		if(msz == 1){
			fillmov(&lkou, neigheat, Kou);
			opplace(&lkou, 0);
		}
	}
	opplace(m, m->type);
dprint("Neaten %d\n", neaten);
	if(!neaten)
		*mdead = nil;
	lstone = *m;
	moves = addlast(moves, clonegrp(m));
	
	return neaten;
}

int
markdead(Move *m,Move **mdead)
{
	Move *grp,*mov;
	int neaten,type;

dprint("Mk dead %d %d\n",m->Point.x, m->Point.y);
	type=goban[m->x][m->y];
	if(type!=Bstone && type!=Wstone)  //killing nogroup.
		return(-1);
	mov = getmove(m->Point);
	grp = getgrp(mov, nil);
	neaten = opgrp(grp, tolower(type), opplace);
	*mdead = grp;
	//opgrp(grp, 0, opprint);
	free(mov);
	return neaten;
}



/* if it returns -1 it is not a territory 
*type returns what the group it is though to be
type has to be user malloc'ed memory
If *type=0, territory can't be decided (empty board, border of diff colours)*/

int
countpos(Move *m, Move **terr, char *type)
{
	Move *grp, *neighgrp, *p;
	char ltype;
	int nterr;

	if(!isempty(m))
		return 0;
	grp = getgrp(m, nil);
	neighgrp = getgrp(m, "*");
	if(!grp || !neighgrp){
		fprint(2, "countpos: weird counting\n");
		return 0;
	}

	ltype = neighgrp->type;
	for(p=neighgrp; p!=nil; p=p->next){	
		if(ltype != p->type){
			if(p->type == Bmarked || p->type == Wmarked)
				continue;
			freegrp(grp);
			freegrp(neighgrp);	
			//fprint(2, "differ\n");
			return 0;
		}
	}
	//fprint(2, "same: g: %d n: %d\n", opgrp(grp,0,opcount), opgrp(neighgrp,0,opcount));
	freegrp(neighgrp);
	*type = ltype;


	nterr = opgrp(grp, '\0', opnop);
	*terr = grp;
	return nterr;
}

/* tries counting, if success returns 1, if not returns 0, the (newly) counted
	are returned in *nw and *nb, 
	return can be 0 and some can be counted anyway */
int
trycount(int *nw, int *nb)
{
	int i,j, npoints, wascounted;
	Point pos;
	Move *mv, *grp;
	char typeterr;
	int lnw, lnb;

	lnw = 0;
	lnb = 0;
	wascounted = 1;

	lstone.type = '\0'; //no last stone, we are counting
	for (i=1; i<Bansz+1; i++){
		for (j=1; j<Bansz+1; j++){
			grp = nil;
			pos = Pt(i,j);
			mv = getmove(pos);
			if(isempty(mv) && goban[i][j]!=Cntstone){
				npoints = countpos(mv,&grp,&typeterr);
				if(npoints>0){
					if(grp && grp->type!=Wmarked && grp->type!=Bmarked) /* if groups alive*/
						opgrp(grp,0,opcount);		
					switch(typeterr){	
						case Bstone:
							lnb += npoints;
						break;
						case Wstone:
							lnw += npoints;
						break;
					}
					freegrp(grp);
				}
				else
					wascounted = 0;
			}
			free(mv);
		}
	}
	*nb = lnb;
	*nw = lnw;
	return wascounted;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.