290 lines · 4.8 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include "game.h" int sgoban;int turn;int npass;int nblackcaptured;int nwhitecaptured;int ko;int isgameover;int goban[Maxgobansize * Maxgobansize];int group[Maxgobansize * Maxgobansize];int liberty[Maxgobansize * Maxgobansize]; static void listnbr(int, int*);static void push(int, int*, int);static int newgroup(void);static void mergegroup(int, int);static void updatelib(int); voidinitgoban(int sg){	int i; 	sgoban = sg;	turn = Black;	npass = 0;	nblackcaptured = 0;	nwhitecaptured = 0;	ko = -1;	isgameover = 0;	for(i = 0; i < sgoban * sgoban; i++){		goban[i] = 0;		group[i] = -1;		liberty[i] = -1;	}} intplaymove(int move){	int i;	int mlib, nnbr, ncap, cap, newgrp;	int nbr[4], oppogrp[4]; 	if(move == Pass){		turn *= -1;		npass++;		if(ko != -1){			goban[ko] = Empty;			ko = -1;		}		if(npass == 2)			isgameover = 1;		return 0;	}	if(npass > 0)		npass--; 	if(move< 0 || move > sgoban * sgoban){		werrstr("Move is out of bounds.");		return -1;	}	switch(goban[move]){	case Black:	case White:		werrstr("There is already a stone here.");		return -1;	case Ko:		werrstr("Cannot retake ko.");		return -1;	} 	mlib = 0;	ncap = 0;	cap = 0;	nnbr = 0;	listnbr(move, nbr);	for(i = 0; i < 4; i++)		oppogrp[i] = -1;	for(i = 0; i < 4; i++){		if(nbr[i] != -1 && goban[nbr[i]] == Empty			|| goban[nbr[i]] == Ko)		{			mlib++;		}else if(nbr[i] != -1 && goban[nbr[i]] == turn){			nnbr += liberty[group[nbr[i]]] - 1;		}else if(nbr[i] != -1 && liberty[group[nbr[i]]] == 1){			mlib++;			cap = nbr[i];			ncap += capture(group[nbr[i]]);		}else if(nbr[i] != -1){			push(group[nbr[i]], oppogrp, 4);		}	}	if(mlib == 0 && nnbr == 0){		werrstr("Suicidal moves are illegal.");		return -1;	} 	goban[move] = turn;	newgrp = newgroup();	if(newgrp < 0){		print("How???: %r\n");		exits("Error");	}	group[move] = newgrp;	liberty[newgrp] = mlib; 	/* Apply the liberty changes to neighbouring groups. */	for(i = 0; i < 4 && oppogrp[i] != -1; i++)		liberty[oppogrp[i]]--;	for(i = 0; i < 4; i++){		if(nbr[i] != -1 && goban[nbr[i]] == turn)			mergegroup(newgrp, group[nbr[i]]);	} 	if(ko != -1){		goban[ko] = Empty;		ko = -1;	}	if(mlib == 1 && ncap == 1){		goban[cap] = Ko;		ko = cap;	}	turn *= -1;	return 0;} static voidlistnbr(int move, int nbr[4]){	int i; 	for(i = 0; i < 4; i++)		nbr[i] = -1;	if(move % sgoban != 0)		nbr[0] = move - 1;	if(move % sgoban != sgoban - 1)		nbr[1] = move + 1;	if(move / sgoban != 0)		nbr[2] = move - sgoban;	if(move / sgoban != sgoban - 1)		nbr[3] = move + sgoban;} intcapture(int grp){	int i, j;	int ncap, lsize;	int nbr[4], oppogrp[Maxgobansize * Maxgobansize / 2]; 	ncap = 0;	lsize = Maxgobansize * Maxgobansize / 2;	for(i = 0; i < lsize; i++)		oppogrp[i] = -1; 	liberty[grp] = -1;	for(i = 0; i < sgoban * sgoban; i++){		if(group[i] == grp){			ncap++;			switch(goban[i]){			case Black:				nblackcaptured++;				break;			case White:				nwhitecaptured++;			}			/* List opponent neighbouring groups. */			listnbr(i, nbr);			for(j = 0; j < 4; j++){				if(nbr[j] != -1 && goban[nbr[j]] == -goban[i])					push(group[nbr[j]], oppogrp, lsize);			}			goban[i] = Empty;			group[i] = -1;		}	}	for(i = 0; i < lsize && oppogrp[i] != -1; i++)		liberty[oppogrp[i]]++; 	return ncap;} /* Push val in a list l implemented with an array of size lsize. * Note that the array has to be initialized to -1. */static voidpush(int val, int *l, int lsize){	int i; 	for(i = 0; i < lsize; i++){		if(l[i] == -1){			l[i] = val;			return;		}else if(l[i] == val){			return;		}	}	exits("List full.");} static intnewgroup(){	int i; 	for(i = 0; i < sgoban * sgoban; i++){		if(liberty[i] == -1)			return i;	}	werrstr("Could not make a new group.");	return -1;} /* Merge h in g. */static voidmergegroup(int g, int h){	int i; 	if(g == h)		return; 	liberty[h] = -1;	for(i = 0; i < sgoban * sgoban; i++) {		if(group[i] == h)			group[i] = g;	}	updatelib(g);}	 /* Update liberties of group g. */static voidupdatelib(int g){	int i, j;	int nbr[4], nlib; 	for(i = 0; i < sgoban * sgoban; i++) {		/* Mark liberties. */		if(group[i] == g){			listnbr(i, nbr);			for(j = 0; j < 4; j++){				switch(goban[nbr[j]]){				case Empty:				case Ko:					goban[nbr[j]] += Marked;				}			}		}	}	/* Count and delete marks. */	nlib = 0;	for(i = 0; i < sgoban * sgoban; i++) {		switch(goban[i]){		case Marked:		case Ko + Marked:			nlib++;			goban[i] -= Marked;		}	}	liberty[g] = nlib;} intundomove(int move){	int i;	int nbr[4], nbrgrp[4]; 	for(i = 0; i < 4; i++)		nbrgrp[i] = -1; 	goban[move] = Empty;	group[move] = -1;	listnbr(move, nbr);	for(i = 0; i < 4; i++)		push(group[nbr[i]], nbrgrp, 4); 	for(i = 0; i < 4 && nbrgrp[i] != -1; i++)		updatelib(nbrgrp[i]); 	return 0;}