#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;
}
|