#include #include #include #include #include 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; iPoint, 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(crdx][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; ix][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; itype!=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; i0){ 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; }