From 15318cad33835e4e2dc620d033e43cd930676cdd Mon Sep 17 00:00:00 2001 From: kergoth Date: Fri, 25 Jan 2002 22:14:26 +0000 Subject: Initial revision --- (limited to 'noncore/games/go') diff --git a/noncore/games/go/.cvsignore b/noncore/games/go/.cvsignore new file mode 100644 index 0000000..6fe2396 --- a/dev/null +++ b/noncore/games/go/.cvsignore @@ -0,0 +1,2 @@ +moc_* +Makefile diff --git a/noncore/games/go/Makefile.in b/noncore/games/go/Makefile.in new file mode 100644 index 0000000..27304f1 --- a/dev/null +++ b/noncore/games/go/Makefile.in @@ -0,0 +1,158 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = ../bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = go +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = amigo.h \ + go.h \ + goplayutils.h \ + gowidget.h +SOURCES = amigo.c \ + goplayer.c \ + goplayutils.c \ + killable.c \ + gowidget.cpp \ + main.cpp +OBJECTS = amigo.o \ + goplayer.o \ + goplayutils.o \ + killable.o \ + gowidget.o \ + main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_gowidget.cpp +OBJMOC = moc_gowidget.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake go.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +amigo.o: amigo.c \ + go.h \ + goplayutils.h \ + amigo.h + +goplayer.o: goplayer.c \ + go.h \ + goplayutils.h \ + amigo.h + +goplayutils.o: goplayutils.c \ + goplayutils.h \ + amigo.h \ + go.h + +killable.o: killable.c \ + go.h \ + goplayutils.h \ + amigo.h + +gowidget.o: gowidget.cpp \ + gowidget.h \ + amigo.h \ + go.h \ + goplayutils.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h \ + $(QPEDIR)/include/qpe/qpemenubar.h + +main.o: main.cpp \ + gowidget.h \ + amigo.h \ + go.h \ + goplayutils.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +moc_gowidget.o: moc_gowidget.cpp \ + gowidget.h \ + amigo.h \ + go.h \ + goplayutils.h + +moc_gowidget.cpp: gowidget.h + $(MOC) gowidget.h -o moc_gowidget.cpp + + diff --git a/noncore/games/go/README b/noncore/games/go/README new file mode 100644 index 0000000..c6fa1f5 --- a/dev/null +++ b/noncore/games/go/README @@ -0,0 +1,3 @@ +This Go player For Qtopia is based on Xamigo, which in turn was +based on Amigo. The original README files are included as README.XAMIGO +and README.AMIGO. diff --git a/noncore/games/go/README.AMIGO b/noncore/games/go/README.AMIGO new file mode 100644 index 0000000..03978e7 --- a/dev/null +++ b/noncore/games/go/README.AMIGO @@ -0,0 +1,42 @@ + This is version 1.0 of AmiGo --- a Go board and player for the Amiga. +The Amiga interface and board manager were written by Todd R. Johnson. +The player is a C port of a Pascal player written by Stoney Ballard. +The interface allows you to play human vs. human, human vs. Amiga, or +Amiga vs. Amiga. + + The board manager and player could both use some work. Currently, +you cannot save/load games, take back a move, or automatically score a +game. It is also limited to a 19 by 19 board. I'm releasing AmiGo +now because 1) I'm in the final phases of my dissertation and probably +won't have much time to do any further work on AmiGo, and 2) a lot of +people have been asking for an Amiga Go player. I am also releasing +all of the source code so that others can add to and modify AmiGo. +Note that all of my code in this release is public domain, while the +ported go player retains the original copyright. + + If you distribute AmiGo, I urge you to include the source +code. If anyone makes changes, I would appreciate a copy. In fact, I +am willing to act as a clearinghouse for AmiGo changes. + +Todd R. Johnson +tj@cis.ohio-state.edu +8/8/89 + +Here is the message attached to the original USENET posting of Stoney +Ballard's Pascal code. Note that the board manager mentioned here is +not included in this distribution. + +This go board manager and rudimentary go player was written by +Stoney Ballard at Perq Systems in 1983-1984. It is written in +Perq Pascal and utilizes some Perq libraries for I/O. The code +is offered here if someone is interested to convert it to Unix. + +The wonderful part about it is that a game is recorded as a tree +and can be played forward or backward, branching at any point +where there were alternate moves. + +For some time, this program was also used to generate the go +boards displayed in the American Go Journal. For this it used +some large font digits which are now lost. + +Fred Hansen diff --git a/noncore/games/go/README.XAMIGO b/noncore/games/go/README.XAMIGO new file mode 100644 index 0000000..219b25f --- a/dev/null +++ b/noncore/games/go/README.XAMIGO @@ -0,0 +1,26 @@ + + Xamigo 1.1 + +This is an alpha release of xamigo --- a port (read: quick hack) of the +Amiga Go program AmiGo. I don't have time to get it real nice now, +but will spend some more time on it when my thesis is out of the way. +Sadly this is the second time I've said that :-) + +The `readme' from the original distribution is included as README.AMIGO + +An Imakefile is included, so you should be able to type + xmkmf + make +to build xamigo. Let me know if you have problems with the Imakefile, +preferably with fixes :-) + +You *have* to install the app-defaults file (Xamigo.ad) before you use +xamigo. This should either go in /usr/lib/X11/app-defaults, +or in your own app-defaults directory, as file Xamigo (ie lose the '.ad') +If you do the latter, you have to: + setenv XAPPLRESDIR + +Feel free to mail me any comments and suggestions for improvements. + +Neil +neilb@scs.leeds.ac.uk diff --git a/noncore/games/go/amigo.c b/noncore/games/go/amigo.c new file mode 100644 index 0000000..cd61013 --- a/dev/null +++ b/noncore/games/go/amigo.c @@ -0,0 +1,656 @@ +/* Go started 4/17/88 by Todd R. Johnson */ +/* 8/8/89 cleaned up for first release */ +/* Public Domain */ + +#include "go.h" +#include "goplayutils.h" +#include "amigo.h" + + +extern char *playReason; +extern short playLevel, showTrees; + +struct bRec goboard[19][19]; /*-- The main go board --*/ + +struct Group GroupList[MAXGROUPS]; /*-- The list of Groups --*/ +short DeletedGroups[4]; /*-- Codes of deleted groups --*/ + +short GroupCount = 0; /*-- The total number of groups --*/ +short DeletedGroupCount; /*-- The total number of groups --*/ + /*-- deleted on a move --*/ +short ko, koX, koY; +short blackTerritory,whiteTerritory; +short blackPrisoners, whitePrisoners; +short showMoveReason = FALSE, + groupInfo = FALSE, + whitePassed = FALSE, + blackPassed = FALSE; + + +/* Arrays for use when checking around a point */ +short xVec[4] = {0, 1, 0, -1}; +short yVec[4] = {-1, 0, 1, 0}; + +short +member(group, grouplist, cnt) + short group; + short grouplist[4]; + short cnt; +{ + unsigned short i; + + + for (i = 0; i < cnt; i++) + if (grouplist[i] == group) + return TRUE; + return FALSE; +} + +/* Does a stone at x, y connect to any groups of color? */ +short +Connect( color, x, y, fGroups, fCnt, eGroups, eCnt) + enum bVal color; + short x, y; + short fGroups[4], eGroups[4]; + short *fCnt, *eCnt; +{ + unsigned short point = 0; + short tx, ty, total = 0; + enum bVal opcolor = WHITE; + + + *fCnt = 0; + *eCnt = 0; + if (color == WHITE) + opcolor = BLACK; + for (point = 0; point <= 3; point++ ) + { + tx = x + xVec[point]; + ty = y + yVec[point]; + if (!LegalPoint(tx,ty)) + continue; + if (goboard[tx][ty].Val == color) + { + total++; + if (!member(goboard[tx][ty].GroupNum, fGroups, *fCnt)) + fGroups[(*fCnt)++] = goboard[tx][ty].GroupNum; + } + else if (goboard[tx][ty].Val == opcolor) + { + total++; + if (!member(goboard[tx][ty].GroupNum, eGroups, *eCnt)) + eGroups[(*eCnt)++] = goboard[tx][ty].GroupNum; + } + } + return total; +} + +/* Returns the maximum number of liberties for a given intersection */ +short +Maxlibs(x, y) + short x, y; +{ + short cnt = 4; + + + if (x == 0 || x == 18) + cnt--; + if (y == 0 || y == 18) + cnt--; + return cnt; +} + +DeleteGroupFromStone(x,y) + short x,y; +{ + if (goboard[x][y].Val != EMPTY) + GroupCapture(goboard[x][y].GroupNum); +} + +/* Determine whether x, y is suicide for color */ +short +Suicide(color, x, y) + enum bVal color; + short x, y; +{ + enum bVal opcolor = BLACK; + short friendlycnt, friendlygroups[4], + enemycnt, enemygroups[4], + total; + short maxlibs, i, libcnt = 0; + + + if (color == BLACK) + opcolor = WHITE; + maxlibs = Maxlibs( x, y); + total = Connect(color, x, y, friendlygroups, &friendlycnt, + enemygroups, &enemycnt); + + if (total < maxlibs) + return FALSE; + + /* Check for a capture */ + for (i = 0; i < enemycnt; i++) + if (GroupList[enemygroups[i]].liberties == 1) + return FALSE; + for (i = 0; i < friendlycnt; i++) + libcnt += (GroupList[friendlygroups[i]].liberties - 1); + if (libcnt != 0) + return FALSE; + return TRUE; +} + +/* Returns the number of liberties for x, y */ +short +StoneLibs(x, y) + short x, y; +{ + short cnt = 0, tx, ty; + unsigned short point; + + + for (point = 0; point <= 3; point++) + { + tx = x + xVec[point]; + ty = y + yVec[point]; + if (LegalPoint(tx,ty) && goboard[tx][ty].Val == EMPTY) + cnt++; + } + return cnt; +} + +void +EraseMarks() +{ + register short i; + register struct bRec *gpt = &goboard[0][0]; + + + for (i=0; i<361; gpt++,i++) + gpt->marked = FALSE; +} + +/* Place a stone of color at x, y */ +short +GoPlaceStone(color, x, y) + enum bVal color; + short x, y; +{ + short fgroups[4], egroups[4]; /* group codes surrounding stone */ + short fcnt, ecnt, i; + short lowest = GroupCount + 1; + + + DeletedGroupCount = 0; + if (goboard[x][y].Val != EMPTY || Suicide(color,x,y)) + return FALSE; + + if (ko && koX == x && koY == y) + return FALSE; + + ko = FALSE; + placestone(color, x, y); + goboard[x][y].Val = color; + /* Does the new stone connect to any friendly stone(s)? */ + Connect(color, x, y, fgroups, &fcnt, egroups, &ecnt); + if (fcnt) + { + /* Find the connecting friendly group with the lowest code */ + for (i = 0; i < fcnt; i++) + if (fgroups[i] <= lowest) + lowest = fgroups[i]; + /*-- Renumber resulting group --*/ + /*-- Raise the stone count of the lowest by one to account --*/ + /*-- for new stone --*/ + goboard[x][y].GroupNum = lowest; + GroupList[lowest].count++; + for (i = 0; i < fcnt; i++) + if (fgroups[i] != lowest) + MergeGroups(lowest, fgroups[i]); + /* Fix the liberties of the resulting group */ + CountLiberties(lowest); + } + else + { + /* Isolated stone. Create new group. */ + GroupCount++; + lowest = GroupCount; + GroupList[lowest].color = color; + GroupList[lowest].count = 1; + GroupList[lowest].internal = 0; + GroupList[lowest].external = StoneLibs( x, y); + GroupList[lowest].liberties = GroupList[lowest].external; + GroupList[lowest].eyes = 0; + GroupList[lowest].alive = 0; + GroupList[lowest].territory = 0; + goboard[x][y].GroupNum = lowest; + } + /* Now fix the liberties of enemy groups adjacent to played stone */ + FixLibs(color, x, y, PLACED); /* Fix the liberties of opcolor */ + ReEvalGroups(color, x, y, lowest); + RelabelGroups(); + return TRUE; +} + +/* Remove a stone from the board */ +void +GoRemoveStone(x, y) + short x, y; +{ + goboard[x][y].Val = EMPTY; + goboard[x][y].GroupNum = 0; + removestone( x, y); +} + +/* Merges two groups -- Renumbers stones and deletes second group from +list. Fixes stone count of groups. This does not fix anything else. +FixLibs must be called to fix liberties, etc. */ +void +MergeGroups(g1, g2) + short g1, g2; +{ + short x, y; + + + ForeachPoint(y,x) + if (goboard[x][y].GroupNum == g2) + goboard[x][y].GroupNum = g1; + GroupList[g1].count += GroupList[g2].count; + DeleteGroup( g2 ); /* Removes group from GroupList */ +} + +/* Stores a group code to be deleted */ +void +DeleteGroup(code) + short code; +{ + DeletedGroups[DeletedGroupCount++] = code; +} + +/* Re-evaluate the groups given the last move. This assumes that the +last move has been merged into adjoining groups and all liberty counts +are correct. Handles capture. Checks for Ko. Keeps track of captured +stones. code is the group number of the stone just played. */ +void +ReEvalGroups(color, x, y, code) + enum bVal color; + short x, y, code; +{ + short fgroups[4], egroups[4], + fcnt, ecnt, i, killcnt = 0, count = 0; + enum bVal opcolor = BLACK; + + if (color == BLACK) + opcolor = WHITE; + /* Check for capture */ + Connect( color, x, y, fgroups, &fcnt, egroups, &ecnt); + if (ecnt) + { + /* See if any of the groups have no liberties */ + for (i = 0; i < ecnt; i++) + if (GroupList[egroups[i]].liberties == 0) + { + killcnt++; + count = GroupList[egroups[i]].count; + GroupCapture( egroups[i]); + } + } + /* Check for ko. koX and koY are set in GroupCapture above. */ + if (killcnt == 1 && count == 1 && GroupList[ code ].count == 1 + && GroupList[ code ].liberties == 1) + { + ko = TRUE; + } + if (killcnt) + intrPrisonerReport( blackPrisoners, whitePrisoners); + /* Set eye count for groups */ + CountEyes(); +} + +/* Remove a captured group from the board and fix the liberties of any + adjacent groups. Fixes prisoner count. Sets KoX and KoY */ +/*-- update display of captured stones -neilb --*/ +void +GroupCapture(code) + short code; +{ + short x, y; + + if (GroupList[code].color == BLACK) + blackPrisoners += GroupList[code].count; + else + whitePrisoners += GroupList[code].count; + intrPrisonerReport(blackPrisoners, whitePrisoners); + ForeachPoint(y,x) + if (goboard[x][y].GroupNum == code) + { + FixLibs(GroupList[code].color,x,y,REMOVED); + GoRemoveStone(x, y); + koX = x; + koY = y; + } + DeleteGroup( code); +} + +/* Fix the liberties of groups adjacent to x, y. move indicates + whether a stone of color was placed or removed at x, y + This does not change liberty counts of friendly groups when a stone + is placed. Does not do captures. */ +void +FixLibs( color, x, y, move) + enum bVal color; + short x, y, move; +{ + short fgroups[4], fcnt, egroups[4], ecnt, i; + enum bVal opcolor = BLACK; + + if (color == BLACK) + opcolor = WHITE; + Connect( color, x, y, fgroups, &fcnt, egroups, &ecnt); + if (move == PLACED) + for (i = 0; i < ecnt; i++) + GroupList[egroups[i]].liberties--; + else /* Stone removed so increment opcolor */ + for (i = 0; i < ecnt; i++) + GroupList[egroups[i]].liberties++; +} + +void +goSetHandicap(handicap) + int handicap; +{ + if (handicap < 2) + return; + + GoPlaceStone(BLACK,3,3); + GoPlaceStone(BLACK,15,15); + + if (handicap >= 3) + GoPlaceStone(BLACK,15,3); + if (handicap >= 4) + GoPlaceStone(BLACK,3,15); + if (handicap == 5 || handicap == 7 || handicap == 9) + GoPlaceStone(BLACK,9,9); + if (handicap >= 6) + { + GoPlaceStone(BLACK,15,9); + GoPlaceStone(BLACK,3,9); + } + if (handicap >= 8) + { + GoPlaceStone(BLACK,9,15); + GoPlaceStone(BLACK,9,3); + } +} + +void +goRestart(handicap) + int handicap; +{ + register short i; + register struct bRec *gpt = &goboard[0][0]; + + + GroupCount = 0; + ko = FALSE; + blackPrisoners = whitePrisoners = 0; + intrPrisonerReport(0, 0); + for (i=0; i<361; gpt++,i++) + { + gpt->Val = EMPTY; + gpt->GroupNum = 0; + } + goSetHandicap(handicap); +} + + +/* if any groups have been deleted as a result of the last move, this + routine will delete the old group numbers from GroupList and + reassign group numbers. */ +void +RelabelGroups() +{ + unsigned short i, j, x, y; + + for (i = 0; i < DeletedGroupCount; i++) + { + /* Relabel all higher groups */ + ForeachPoint(y,x) + if (goboard[x][y].GroupNum > DeletedGroups[i]) + goboard[x][y].GroupNum--; + /* Move the groups down */ + for (y = DeletedGroups[i]; y < GroupCount; y++) + GroupList[y] = GroupList[y+1]; + /* fix the group numbers stored in the deleted list */ + for (j = i+1; j < DeletedGroupCount; j++) + if (DeletedGroups[j] > DeletedGroups[i]) + DeletedGroups[j]--; + GroupCount--; + } +} + +/* Returns liberty count for x, y intersection. Sets marked to true + for each liberty */ +short +CountAndMarkLibs( x, y) + short x, y; +{ + short tx,ty,i; + short cnt = 0; + + + for (i=0;i<4;i++) + { + tx = x + xVec[i]; + ty = y + yVec[i]; + if (LegalPoint(tx,ty) && goboard[tx][ty].Val == EMPTY + && goboard[tx][ty].marked == FALSE) + { + cnt++; + goboard[tx][ty].marked = TRUE; + } + } + return cnt; +} + +/* Determine the number of liberties for a group given the group code + num */ +void +CountLiberties( code) + short code; +{ + short x, y, libcnt = 0; + + ForeachPoint(y,x) + if (goboard[x][y].GroupNum == code) + libcnt += CountAndMarkLibs( x, y); + EraseMarks(); + GroupList[code].liberties = libcnt; +} + +void +CheckForEye( x, y, groups, cnt, recheck) + short x, y, groups[4], cnt, *recheck; +{ + short i; + + for (i = 0; i < (cnt-1); i++) + if (groups[i] != groups[i+1]) + { + /* Mark liberty for false eye check */ + goboard[x][y].marked = TRUE; + (*recheck)++; + return; + } + /* It is an eye */ + GroupList[groups[i]].eyes += 1; +} + +/* Set the eye count for the groups */ +void CountEyes() +{ + short i, x, y, + wgroups[4], bgroups[4], wcnt, bcnt, max, cnt, recheck = 0, eye; + + for (i = 1; i <= GroupCount; i++) + GroupList[i].eyes = 0; + + ForeachPoint(y,x) + { + if (goboard[x][y].Val != EMPTY) + continue; + cnt = Connect(WHITE,x,y,wgroups,&wcnt,bgroups,&bcnt); + max = Maxlibs( x, y); + if (cnt == max && wcnt == 1 && bcnt == 0) + GroupList[wgroups[0]].eyes++; + else if (cnt == max && bcnt == 1 && wcnt == 0) + GroupList[bgroups[0]].eyes++; + else if (cnt == max && ( bcnt == 0 || wcnt == 0 )) + { + goboard[x][y].marked = TRUE; + recheck++; + } + } + + /*-- Now recheck marked liberties to see if two or more one eye --*/ + /*-- groups contribute to a false eye */ + if (recheck == 0) + return; + + ForeachPoint(y,x) + if (goboard[x][y].marked) + { + recheck--; + goboard[x][y].marked = FALSE; + Connect( WHITE, x, y, wgroups, &wcnt, bgroups, &bcnt); + /* If all the groups have at least one eye then all the + groups are safe from capture because of the common + liberty at x, y */ + eye = TRUE; + for (i = 0; i < wcnt; i++) + if (GroupList[wgroups[i]].eyes == 0) + eye = FALSE; + if (eye) + for (i = 0; i < wcnt; i++) + GroupList[wgroups[i]].eyes++; + for (i = 0; i < bcnt; i++) + if (GroupList[bgroups[i]].eyes == 0) + eye = FALSE; + if (eye) + for (i = 0; i < bcnt; i++) + GroupList[bgroups[i]].eyes++; + if (recheck == 0) + return; + } +} + + +short foo[19][19]; + +/*---------------------------------------------------------------- +-- CountUp() -- +-- Count up final scores at the end of the game. -- +----------------------------------------------------------------*/ +CountUp( wtotal, btotal ) + int *wtotal, *btotal; +{ + short x,y; + short CountFromPoint(); + short vv; + char buff[512]; + + + blackTerritory = whiteTerritory = 0; + ForeachPoint(y,x) + { + goboard[x][y].marked = FALSE; + foo[x][y] = CNT_UNDECIDED; + } + ForeachPoint(y,x) + if (goboard[x][y].Val==EMPTY && foo[x][y]==CNT_UNDECIDED) + { + FillPoints(x,y,CountFromPoint(x,y)); + } + + *wtotal = whiteTerritory + blackPrisoners; + *btotal = blackTerritory + whitePrisoners; + /* + sprintf(buff,"White : %3d territory + %3d prisoners = %d\n\ +Black : %3d territory + %3d prisoners = %d\n\n%s.\n", + whiteTerritory,blackPrisoners,*wtotal, + blackTerritory,whitePrisoners,*btotal, + (*btotal>*wtotal?"Black wins":(*wtotal>*btotal?"White wins": + "A draw"))); + + + + XtVaSetValues(message,XtNstring,buff,0); + printf( "CountUp() %s", buff ); + */ +} + +FillPoints(x,y,val) + short x,y,val; +{ + int i; + short tx,ty; + + + if ((foo[x][y] = val) == CNT_BLACK_TERR) + blackTerritory++; + else if (val == CNT_WHITE_TERR) + whiteTerritory++; + for (i=0;i<4;i++) + { + tx = x + xVec[i]; + ty = y + yVec[i]; + if (!LegalPoint(tx,ty)) + continue; + if (goboard[tx][ty].Val==EMPTY && foo[tx][ty]==CNT_UNDECIDED) + FillPoints(tx,ty,val); + } +} + +short +CountFromPoint(x,y) + short x,y; +{ + int i; + short tx,ty; + short blkcnt=0,whtcnt=0; + short baz; + + + goboard[x][y].marked = TRUE; + for (i=0;i<4;i++) + { + tx = x + xVec[i]; + ty = y + yVec[i]; + if (!LegalPoint(tx,ty)) + continue; + if (goboard[tx][ty].Val == BLACK) + blkcnt++; + else if (goboard[tx][ty].Val == WHITE) + whtcnt++; + else + { + if (goboard[tx][ty].marked) + continue; + baz = CountFromPoint(tx,ty); + if (baz == CNT_NOONE) + return CNT_NOONE; + else if (baz == CNT_BLACK_TERR) + blkcnt++; + else if (baz == CNT_WHITE_TERR) + whtcnt++; + } + if (blkcnt && whtcnt) + return CNT_NOONE; + } + if (blkcnt && !whtcnt) + return CNT_BLACK_TERR; + else if (whtcnt && !blkcnt) + return CNT_WHITE_TERR; + else + return CNT_UNDECIDED; +} diff --git a/noncore/games/go/amigo.h b/noncore/games/go/amigo.h new file mode 100644 index 0000000..5150ac0 --- a/dev/null +++ b/noncore/games/go/amigo.h @@ -0,0 +1,146 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +/*========================================================================= +=== === +=== FILE amigo.h === +=== === +=== CONTENTS prototypes for the various AmiGo routines. === +=== added by neilb === +=== === +=========================================================================*/ + +#ifndef __amigo_h +#define __amigo_h + +#include "go.h" +#include "goplayutils.h" + +#ifdef __STDC__ +#define PROTO(fp) fp +#else +#define PROTO(fp) () +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* From goplayer.c */ + + + +/* Procedures from amigo.c */ + +short Connect PROTO((enum bVal, short, short, short[4], short[4], short *, short * )); +short Maxlibs PROTO((short, short)); +short Suicide PROTO((enum bVal, short, short)); +short StoneLibs PROTO((short, short)); +void EraseMarks PROTO(()); +short GoPlaceStone PROTO((enum bVal, short, short)); +void GoRemoveStone PROTO((short, short)); +void MergeGroups PROTO((short, short)); +void DeleteGroup PROTO((short)); +void ReEvalGroups PROTO((enum bVal, short, short, short)); +void GroupCapture PROTO((short)); +void FixLibs PROTO((enum bVal, short, short, short)); +int CountUp PROTO((int*, int*)); +/*void main PROTO(());*/ +void goRestart PROTO((int)); +void RelabelGroups PROTO(()); +short CountAndMarkLibs PROTO((short, short)); +void CountLiberties PROTO((short)); +void CheckForEye PROTO((short, short, short[4], short, short *)); +void CountEyes PROTO(()); +void printGroupReport PROTO((short, short)); + + +/* killable.c */ + +int tryPlay PROTO(( short, short, short )); +int sSpanGroup PROTO(( short, short, sPointList * )); +int spanGroup PROTO(( short, short, pointList *)); +int pause PROTO(()); + +int genState PROTO(()); +int initGPUtils PROTO(()); +int genBord PROTO((enum bVal)); + +short genMove PROTO(( enum bVal, short *, short * )); +short checkPos PROTO(( short, short, short )); +short takeCorner PROTO(( short *, short * )); +short extend PROTO(( short *, short * )); +short noNbrs PROTO(( short, short )); +short extend2 PROTO(( short *, short * )); +short lookForSave PROTO(( short *, short * )); +short lookForSaveN PROTO(( short *, short * )); +short lookForKill PROTO(( short *, short * )); +short doubleAtari PROTO(( short *, short * )); +short lookForAttack PROTO(( short *, short * )); +short threaten PROTO(( short *, short * )); +short connectCut PROTO(( short *, short * )); +short heCanCut PROTO(( short, short )); +short safeMove PROTO(( short, short )); +short extendWall PROTO(( short *, short * )); +short findAttack2 PROTO(( short *, short * )); +short blockCut PROTO(( short *, short * )); +short cutHim PROTO(( short *, short * )); +short atariAnyway PROTO(( short *, short * )); +short underCut PROTO(( short *, short * )); +short dropToEdge PROTO(( short *, short * )); +short pushWall PROTO(( short *, short * )); +short reduceHisLiberties PROTO(( short *, short * )); +short dropToEdge2 PROTO(( short *, short * )); + + +/* goplayutils.c */ + +short saveable PROTO((short, short, short *, short *)); +short killable PROTO((short, short, short *, short *)); +int initBoolBoard PROTO((boolBoard)); +int intersectPlist PROTO((pointList *, pointList *, pointList *)); +int initArray PROTO((intBoard)); +int initState PROTO(()); +int copyArray PROTO((intBoard, intBoard)); +int stake PROTO(()); +int spread PROTO(()); +int respreicen PROTO(()); +int tryPlay PROTO((short, short, short)); +int saveState PROTO(()); +int restoreState PROTO(()); +short tencen PROTO((short, short)); +int genConnects PROTO(()); +int sortLibs PROTO(()); + + +/*-- from xinterface.c --*/ +void removestone PROTO((short, short)); +void placestone PROTO((enum bVal, short, short)); + +void intrMoveReport PROTO((enum bVal,char *,char *)); +void intrPrisonerReport PROTO(( short, short )); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/noncore/games/go/go.h b/noncore/games/go/go.h new file mode 100644 index 0000000..9aa644b --- a/dev/null +++ b/noncore/games/go/go.h @@ -0,0 +1,81 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +/* AmiGo Include */ +/* MSG types for getinput() */ + +#ifndef __go_h +#define __go_h + + +#define INTERSECTIONMSG 1 /* User buttoned an intersection */ +#define QUITMSG 2 /* User buttoned QUIT icon */ +#define PLAYMSG 3 +#define RESTARTMSG 4 +#define PASSMSG 5 + +#define TRUE 1 +#define FALSE 0 + +#define MAXGROUPS 100 + +#define PLACED 0 +#define REMOVED 1 + +#define numPoints 19 +#define maxPoint numPoints - 1 + +/*-- definitions used when counting up --*/ + +#define CNT_UNDECIDED 0 +#define CNT_BLACK_TERR 1 +#define CNT_WHITE_TERR 2 +#define CNT_NOONE 3 + +/*-- macro functions --*/ + +#define LegalPoint(x,y) (x>=0 && x<=18 && y>=0 && y<=18) +#define ForeachPoint(a,b) for(a=0;a<19;a++) for (b=0;b<19;b++) + +enum bVal {BLACK, WHITE, EMPTY}; +typedef enum bVal sType; +struct Group +{ + enum bVal color; /* The color of the group */ + short code, /* The code used to mark stones in the group */ + count, /* The number of stones in the group */ + internal, /* The number of internal liberties */ + external, /* The number of external liberties */ + liberties, /* The total number of liberties */ + eyes, /* The number of eyes */ + alive, /* A judgement of how alive this group is */ + territory; /* The territory this group controls */ +}; + +struct bRec +{ + enum bVal Val; /* What is at this intersection */ + short xOfs, + yOfs; + short mNum; + short GroupNum; /* What group the stone belongs to */ + short marked; /* TRUE or FALSE */ +}; + +#endif diff --git a/noncore/games/go/go.pro b/noncore/games/go/go.pro new file mode 100644 index 0000000..deb90c5 --- a/dev/null +++ b/noncore/games/go/go.pro @@ -0,0 +1,19 @@ +DESTDIR = ../bin +TEMPLATE = app +CONFIG = qt warn_on release +HEADERS = amigo.h \ + go.h \ + goplayutils.h \ + gowidget.h +SOURCES = amigo.c \ + goplayer.c \ + goplayutils.c \ + killable.c \ + gowidget.cpp \ + main.cpp +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe +TARGET = go + +TRANSLATIONS = ../i18n/de/go.ts \ No newline at end of file diff --git a/noncore/games/go/goplayer.c b/noncore/games/go/goplayer.c new file mode 100644 index 0000000..88c0f61 --- a/dev/null +++ b/noncore/games/go/goplayer.c @@ -0,0 +1,1499 @@ +/* The go player */ +/* Ported from Pascal to C by Todd R. Johnson 4/17/88 */ +/* From the original pascal file: +Go Move Generator +Copyright (c) 1983 by Three Rivers Computer Corp. + +Written: January 17, 1983 by Stoney Ballard +Edit History: +*/ + +#include "go.h" +#include "goplayutils.h" +#include "amigo.h" + +#define BIGGEST 32767 /* maximum value for short */ + +/* From go.c */ +extern struct bRec goboard[19][19]; +extern short ko, koX, koY; + +/* From goplayutils.c */ +extern intBoard bord; +extern intBoard ndbord; +extern intBoard claim; +extern intBoard legal; +extern intBoard connectMap; +extern intBoard threatBord; +extern short maxGroupID; +extern short treeLibLim; +extern short killFlag; +extern short depthLimit; +extern short showTrees; +extern short utilPlayLevel; +extern groupRec gList[maxGroup]; +extern short sGlist[maxGroup + 1]; +extern pointList pList; +extern pointList pList1; +extern pointList plist2; +extern pointList plist3; +extern intBoard groupIDs; +extern intBoard protPoints; +extern sType mySType; + + +short saveNLibs; +pointList dapList1, dapList2, dapList3; +char *playReason; +short maxPlayLevel = 7; +short playLevel = 7; + +genBord(color) + enum bVal color; +{ + short x, y, nomoves = TRUE; + char mv[8]; + + maxPlayLevel = 7; + utilPlayLevel = playLevel; + mySType = color; + if (playLevel < 2) + treeLibLim = 2; + else + treeLibLim = 3; + depthLimit = 100; + for (y = 0; y <= 18; y++) + for (x = 0; x <= 18; x++) + if (goboard[x][y].Val == color) + { + bord[x][y] = 1; + legal[x][y] = FALSE; + nomoves = FALSE; + } + else if (goboard[x][y].Val == EMPTY) + { + bord[x][y] = 0; + legal[x][y] = TRUE; + } + else + { + bord[x][y] = -1; + legal[x][y] = FALSE; + nomoves = FALSE; + } + if (ko) + { + legal[koX][koY] = FALSE; + } + + if (! nomoves) + genState(); + else + initGPUtils(); +} + + +short getMove( x, y ) +short *x, *y; +{ + if (takeCorner(x, y)) return TRUE; + if (lookForSave(x, y)) return TRUE; + if (lookForSaveN(x, y)) return TRUE; + if (extend(x, y)) return TRUE; + if (lookForKill(x, y)) return TRUE; + if (doubleAtari(x, y)) return TRUE; + if (lookForAttack(x, y)) return TRUE; + if (threaten(x, y)) return TRUE; + if (extend2(x, y)) return TRUE; + if (connectCut(x, y)) return TRUE; + if (blockCut(x, y)) return TRUE; + if (cutHim(x, y)) return TRUE; + if (extendWall(x, y)) return TRUE; + if (findAttack2(x, y)) return TRUE; + if (atariAnyway(x, y)) return TRUE; + if (underCut(x, y)) return TRUE; + if (dropToEdge(x, y)) return TRUE; + if (pushWall(x, y)) return TRUE; + if (reduceHisLiberties(x, y)) return TRUE; + if (dropToEdge2(x, y)) return TRUE; + return FALSE; +} + +short genMove( color, x, y ) +enum bVal color; +short *x, *y; +{ + if (playLevel > 2) + saveNLibs = TRUE; + else + saveNLibs = FALSE; + genBord(color); + if (getMove(x, y)) + return TRUE; + return FALSE; +} + +short checkPos(x, y, field) +short x, y, field; +{ + short ok; + ok = (((field == 0) && (claim[x][y] == 0)) || + ((field > 0) && + (claim[x][y] >= 0) && (claim[x][y] <= field)) || + ((field < 0) && + (claim[x][y] <= 0) && (claim[x][y] >= field))) && + (bord[x-1][y] == 0) && + (bord[x+1][y] == 0) && + (bord[x][y-1] == 0) && + (bord[x][y+1] == 0); + if (ok) return TRUE; else return FALSE; +} + +short takeCorner( x, y ) +short *x, *y; +{ + short field = -1, i; + i = 18 - 3; + playReason = "takeCorner"; + while (field != -4) + { + if (field == -1) field = 0; + else if (field == 0) field = 4; + else field = -4; + if (checkPos(2, 3, field)) { *x = 2; *y = 3; return TRUE; } + if (checkPos(3, 2, field)) { *x = 3; *y = 2; return TRUE; } + if (checkPos(2, i, field)) { *x = 2; *y = i; return TRUE; } + if (checkPos(3, i + 1, field)) { *x = 3; *y = i+1; return TRUE; } + if (checkPos(i, i + 1, field)) { *x = i; *y = i+1; return TRUE; } + if (checkPos(i + 1, i, field)) { *x = i+1; *y = i; return TRUE; } + if (checkPos(i, 2, field)) { *x = i; *y = 2; return TRUE; } + if (checkPos(i + 1, 3, field)) { *x = i+1; *y = 3; return TRUE; } + if (checkPos(2, 4, field)) { *x = 2; *y = 4; return TRUE; } + if (checkPos(4, 2, field)) { *x = 4; *y = 2; return TRUE; } + if (checkPos(2, i - 1, field)) { *x = 2; *y = i-1; return TRUE; } + if (checkPos(4, i + 1, field)) { *x = 4; *y = i+1; return TRUE; } + if (checkPos(i - 1, i + 1, field)) { *x = i-1; *y = i+1; return TRUE; } + if (checkPos(i + 1, i - 1, field)) { *x = i+1; *y = i-1; return TRUE; } + if (checkPos(i + 1, 4, field)) { *x = i+1; *y = 4; return TRUE; } + if (checkPos(i - 1, 2, field)) { *x = i-1; *y = 2; return TRUE; } + } + return FALSE; +} + +printBoard(brd, name) +intBoard brd; +char *name; +{ + short x, y; + printf( "%s\n", name ); + for (y = 0; y <= 18; y++) + { + for (x = 0; x <= 18; x++) + printf("%d ", brd[x][y]); + printf("\n"); + } +} + +short noNbrs( x, y ) +short x, y; +{ + if (x > 0 && bord[x-1][y] != 0) return FALSE; + if (x < 18 && bord[x+1][y] != 0) return FALSE; + if (y > 0 && bord[x][y-1] != 0) return FALSE; + if (y < 18 && bord[x][y+1] != 0) return FALSE; + return TRUE; +} + +short extend(x, y) +short *x, *y; +{ + short i; + playReason = "extend"; + for (i = 2; i <= 18-2; i++) + if (claim[2][i] == 0 && noNbrs( 2, i )) + { + *x = 2; + *y = i; + return TRUE; + } + for (i = 2; i <= 18-2; i++) + if (claim[i][18-2] == 0 && noNbrs( 2, i )) + { + *x = i; + *y = 18-2; + return TRUE; + } + for (i = 18-2; i >= 2; i--) + if (claim[18-2][i] == 0 && noNbrs( 18-2, i )) + { + *x = 18-2; + *y = i; + return TRUE; + } + for (i = 18-2; i >= 2; i--) + if (claim[i][2] == 0 && noNbrs( i, 2 )) + { + *x = i; + *y = 2; + return TRUE; + } + return FALSE; +} + +short extend2( x, y ) +short *x, *y; +{ + short i, lowest = BIGGEST, value; + playReason = "extend2"; + for (i = 3; i <= 18-3; i++) + if (legal[2][i]) /* if there is nobody there */ + { + value = claim[2][i]; /* get influence */ + if ((value < 7) && /* a reasonable hole in my wall */ + (value > -5) && /* or a reasonable gap in his */ + (bord[2][i + 1] == 0) && /* not in contact with any stones */ + (bord[2][i - 1] == 0)) + if (value < lowest) + { + lowest = value; /* lowest gets the smallest value */ + *x = 2; /* that was seen along all the 3-lines */ + *y = i; /* x and y save that location */ + } + } + for (i = 3; i <= 18-3; i++) + if (legal[i][2]) + { + value = claim[i][2]; + if ((value < 7) && + (value > -5) && + (bord[i + 1][2] == 0) && + (bord[i - 1][2] == 0)) + if (value < lowest) + { + lowest = value; + *x = i; + *y = 2; + } + } + for (i = 18-3; i >= 3; i--) + if (legal[18 - 2][i]) + { + value = claim[18 - 2][i]; + if ((value < 7) && + (value > -5) && + (bord[18 - 2][i + 1] == 0) && + (bord[18 - 2][i - 1] == 0)) + if (value < lowest) + { + lowest = value; + *x = 18 - 2; + *y = i; + } + } + for (i = 3; i <= 18-3; i++) + if (legal[i][18 - 2]) + { + value = claim[i][18 - 2]; + if ((value < 7) && + (value > -5) && + (bord[i + 1][18 - 2] == 0) && + (bord[i - 1][18 - 2] == 0)) + if (value < lowest) + { + lowest = value; + *x = i; + *y = 18 - 2; + } + } + if (lowest == BIGGEST) return FALSE; + return TRUE; +} + + /* + check to see if I can save anything in atari + */ +short lookForSave(x, y) +short *x, *y; + { /* lookForSave */ + short i; + playReason = "lookForSave"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC == 1) && + (ndbord[gList[i].lx][gList[i].ly] == 1)) + if (saveable(gList[i].lx, gList[i].ly, x, y)) /* see if I can save it */ + return TRUE; + return FALSE; + } /* lookForSave */ + + /* + check to see if I can save anything with n libs + */ +short lookForSaveN(x, y) +short *x, *y; + { /* lookForSaveN */ + short i; + if (saveNLibs) + { + playReason = "lookForSaveN"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC > 1) && + (gList[i].libC <= treeLibLim) && + (ndbord[gList[i].lx][gList[i].ly] == 1)) + { + if (killable(gList[i].lx, gList[i].ly, x, y)) + if (saveable(gList[i].lx, gList[i].ly, x, y)) /* see if I can save it */ + return TRUE; + } + } + return FALSE; + } /* lookForSaveN */ + + +/*---------------------------------------------------------------- +-- lookForKill() -- +-- check to see if I can kill anything. -- +----------------------------------------------------------------*/ +short +lookForKill(x, y) + short *x, *y; +{ + short i; + char mv[8]; + + playReason = "lookForKill"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC == 1) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { /* we found a live enemy group with one liberty */ + /* find the liberty */ + spanGroup(gList[i].lx, gList[i].ly, &pList); + *x = pList.p[1].px; + *y = pList.p[1].py; + if (legal[*x][*y]) + { + return TRUE; + } + } + return FALSE; +} + +short doubleAtari(x, y) +short *x, *y; + { /* doubleAtari */ + short i, j; + playReason = "doubleAtari"; + for (i = 1; i <= maxGroupID - 1; i++) + if ((gList[i].libC == 2) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) /* found an atariable group of his */ + { + spanGroup(gList[i].lx, gList[i].ly, &dapList1); + for (j = i + 1; j <= maxGroupID; j++) + if ((gList[j].libC == 2) && + (ndbord[gList[j].lx][gList[j].ly] == -1)) + { + spanGroup(gList[j].lx, gList[j].ly, &dapList2); + intersectPlist(&dapList1, &dapList2, &dapList3); + if (dapList3.indx > 0) + if (legal[dapList3.p[1].px][dapList3.p[1].py]) + { + tryPlay(dapList3.p[1].px, dapList3.p[1].py, 1); + if (gList[groupIDs[dapList3.p[1].px][ + dapList3.p[1].py]].libC > 1) + { + *x = dapList3.p[1].px; + *y = dapList3.p[1].py; + restoreState(); + return TRUE; + } + restoreState(); + } + } + } + return FALSE; + } /* doubleAtari */ + +short lookForAttack(x, y) +short *x, *y; + { /* lookForAttack */ + short tx, ty, i; + playReason = "lookForAttack"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((! gList[i].isLive) && + (gList[i].libC > 1) && + (gList[i].libC <= (treeLibLim + 1)) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { + if (killable(gList[i].lx, gList[i].ly, &tx, &ty)) /* can we kill it? */ + { + *x = tx; /* yep - do so */ + *y = ty; + return TRUE; + } + } + return FALSE; + } /* lookForAttack */ + + /* + Plays a move that requires a response on the opponent's part + */ +short threaten(x, y) +short *x, *y; + { /* threaten */ + short i, j, gx, gy, tNum; + playReason = "threaten"; + initArray(threatBord); + for (i = 1; i <= maxGroupID; i++) + if ((! gList[i].isLive) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { + spanGroup(gList[i].lx, gList[i].ly, &pList); + for (j = 1; j <= pList.indx; j++) + if (legal[pList.p[j].px][pList.p[j].py]) + { + tryPlay(pList.p[j].px, pList.p[j].py, 1); + if (gList[groupIDs[pList.p[j].px][pList.p[j].py]].libC > 1) + if (killable(gList[i].lx, gList[i].ly, &gx, &gy)) + threatBord[pList.p[j].px][pList.p[j].py] += 1; + restoreState(); + } + } + tNum = 0; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if ((threatBord[i][j] > tNum) && + ((threatBord[i][j] > 1) || + (connectMap[i][j] > 0))) + { + tNum = threatBord[i][j]; + *x = i; + *y = j; + } + if (tNum > 0) return TRUE; + else return FALSE; + } /* threaten */ + + /* + connects against enemy cuts + */ +short connectCut(x, y) +short *x, *y; + { /* connectCut */ + short i, j, nap, gid, infl; + playReason = "connectCut"; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j] && + (protPoints[i][j] == 0)) /* not a protected point */ + { + nap = 0; /* how many of my stones am I adjacent to? */ + if ((i > 0) && (bord[i - 1][j] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i - 1; + pList.p[nap].py = j; + } + if ((j > 0) && (bord[i][j - 1] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j - 1; + } + if ((i < maxPoint) && (bord[i + 1][j] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i + 1; + pList.p[nap].py = j; + } + if ((j < maxPoint) && (bord[i][j + 1] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j + 1; + } + if (nap == 1) /* possible knight's || 2-point extention */ + { + gid = groupIDs[pList.p[1].px][pList.p[1].py]; + if ((i > 0) && (i < maxPoint) && + (ndbord[i - 1][j] == 1) && + (ndbord[i + 1][j] == 0)) /* contact on left */ + { + if (((j > 0) && (ndbord[i][j - 1] == -1) && + (ndbord[i + 1][j - 1] == 1) && + (gid != groupIDs[i + 1][j - 1])) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1) && + (ndbord[i + 1][j + 1] == 1) && + (gid != groupIDs[i + 1][j + 1])) || + ((((j > 0) && (ndbord[i][j - 1] == -1)) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1))) && + (i < (maxPoint - 1)) && + (ndbord[i + 2][j] == 1) && + (gid != groupIDs[i + 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((i < maxPoint) && (i > 0) && + (ndbord[i + 1][j] == 1) && + (ndbord[i - 1][j] == 0)) /* r */ + { + if (((j > 0) && (ndbord[i][j - 1] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (gid != groupIDs[i - 1][j - 1])) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1) && + (ndbord[i - 1][j + 1] == 1) && + (gid != groupIDs[i - 1][j + 1])) || + ((((j > 0) && (ndbord[i][j - 1] == -1)) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1))) && + (i > 1) && + (ndbord[i - 2][j] == 1) && + (gid != groupIDs[i - 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j - 1] == 1) && + (ndbord[i][j + 1] == 0)) /* top */ + { + if (((i > 0) && (ndbord[i - 1][j] == -1) && + (ndbord[i - 1][j + 1] == 1) && + (gid != groupIDs[i - 1][j + 1])) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1) && + (ndbord[i + 1][j + 1] == 1) && + (gid != groupIDs[i + 1][j + 1])) || + ((((i > 0) && (ndbord[i - 1][j] == -1)) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1))) && + (j < (maxPoint - 1)) && + (ndbord[i][j + 2] == 1) && + (gid != groupIDs[i][j + 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j + 1] == 1) && + (ndbord[i][j - 1] == 0)) /* bottom */ + { + if (((i > 0) && (ndbord[i - 1][j] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (gid != groupIDs[i - 1][j - 1])) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1) && + (ndbord[i + 1][j - 1] == 1) && + (gid != groupIDs[i + 1][j - 1])) || + ((((i > 0) && (ndbord[i - 1][j] == -1)) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1))) && + (j > 1) && + (ndbord[i][j - 2] == 1) && + (gid != groupIDs[i][j - 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + else if (nap == 2) /* diagonal or 1-point extention */ + { + if (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) + { + if ((pList.p[1].px != pList.p[2].px) && + (pList.p[1].py != pList.p[2].py)) /* diag */ + { + spanGroup(pList.p[1].px, + pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, + pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + if (plist3.indx == 1) + if ((i > 0) && (ndbord[i - 1][j] == -1) || + (i < maxPoint) && (ndbord[i + 1][j] == -1) || + (j > 0) && (ndbord[i][j - 1] == -1) || + (j < maxPoint) && (ndbord[i][j + 1] == -1)) + { /* must make direct connection */ + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + else if (heCanCut(i, j)) + { /* protect point if possible */ + infl = 1000; + if ((i > 0) && legal[i - 1][j] && + ((i == 1) || (ndbord[i - 2][j] == 0)) && + ((j == 0) || (ndbord[i - 1][j - 1] == 0)) && + ((j == maxPoint) || + (ndbord[i - 1][j + 1] == 0))) + if (safeMove(i - 1, j)) + if (claim[i - 1][j] < infl) + { + *x = i - 1; + *y = j; + infl = claim[i - 1][j]; + } + if ((j > 0) && legal[i][j - 1] && + ((j == 1) || (ndbord[i][j - 2] == 0)) && + ((i == 0) || (ndbord[i - 1][j - 1] == 0)) && + ((i == maxPoint) || + (ndbord[i + 1][j - 1] == 0))) + if (safeMove(i, j - 1)) + if (claim[i][j - 1] < infl) + { + *x = i; + *y = j - 1; + infl = claim[i][j - 1]; + } + if ((i < maxPoint) && legal[i + 1][j] && + ((i == (maxPoint - 1)) || + (ndbord[i + 2][j] == 0)) && + ((j == 0) || (ndbord[i + 1][j - 1] == 0)) && + ((j == maxPoint) || + (ndbord[i + 1][j + 1] == 0))) + if (safeMove(i + 1, j)) + if (claim[i + 1][j] < infl) + { + *x = i + 1; + *y = j; + infl = claim[i + 1][j]; + } + if ((j < maxPoint) && legal[i][j + 1] && + ((j == (maxPoint - 1)) || + (ndbord[i][j + 2] == 0)) && + ((i == 0) || (ndbord[i - 1][j + 1] == 0)) && + ((i == maxPoint) || + (ndbord[i + 1][j + 1] == 0))) + if (safeMove(i, j + 1)) + if (claim[i][j + 1] < infl) + { + *x = i; + *y = j + 1; + infl = claim[i][j + 1]; + } + if (infl < 1000) + return TRUE; + *x = i; /* direct connection */ + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else /* 1-point extension, only protect if threatened */ + { + if ((i > 0) && (ndbord[i - 1][j] == -1) || + (j > 0) && (ndbord[i][j - 1] == -1) || + (i < maxPoint) && (ndbord[i + 1][j] == -1) || + (j < maxPoint) && (ndbord[i][j + 1] == -1)) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + } + } + else if (nap == 3) /* unprotected, but me on 3 sides */ + { + if ((groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) || + (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[3].px][pList.p[3].py]) || + (groupIDs[pList.p[3].px][pList.p[3].py] != + groupIDs[pList.p[2].px][pList.p[2].py])) + { + spanGroup(pList.p[1].px, pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + spanGroup(pList.p[3].px, pList.p[3].py, &plist2); + intersectPlist(&plist2, &plist3, &pList1); + if (pList1.indx == 1) /* a common connect point */ + if (heCanCut(i, j)) + if (safeMove(i, j)) + { + *x = i; + *y = j; + return TRUE; + } + } + } + } + return FALSE; + } /* connectCut */ + +short heCanCut(x, y) +short x, y; + { /* heCanCut */ + short gx, gy, result; + if (playLevel > 3) + { + tryPlay(x, y, -1); /* try his cut */ + result = ! killable(x, y, &gx, &gy); + restoreState(); + return result; + } + else + return FALSE; + } /* heCanCut */ + + /* + Checks out a move. + If my stone is not killable then true. + */ +short safeMove(x, y) +short x, y; + { /* safeMove */ + short gbx, gby, result; + tryPlay(x, y, 1); /* try playing at point */ + if (killFlag) /* I shouldn't kill if lookForKill didn't */ + result = FALSE; + else if (gList[groupIDs[x][y]].libC < 2) + { /* if it is in atari or dead */ + result = FALSE; /* reject it */ + } + else if (gList[groupIDs[x][y]].libC <= treeLibLim) /* see if killable */ + if (playLevel > 0) + result = ! killable(x, y, &gbx, &gby); + else + result = TRUE; + else + result = TRUE; + restoreState(); + return result; + } /* safeMove */ + + /* + Extends walls in a connected fashion. + Finds the lowest influence (mine) point that is connected to one + of my groups. + Only looks in the center of the board. + */ +short extendWall(x, y) +short *x, *y; + { /* extendWall */ + short infl, i, j; + playReason = "extendWall"; + *x = iNil; + *y = iNil; + infl = 11; + for (i = 2; i <= maxPoint - 2; i++) + for (j = 2; j <= maxPoint - 2; j++) + if (legal[i][j]) + if (connectMap[i][j] > 0) + if ((claim[i][j] < infl) && + (ndbord[i - 1][j] < 1) && + (ndbord[i + 1][j] < 1) && + (ndbord[i][j - 1] < 1) && + (ndbord[i][j + 1] < 1) && + ((claim[i - 1][j] < 0) || + (claim[i + 1][j] < 0) || + (claim[i][j - 1] < 0) || + (claim[i][j + 1] < 0))) + if (safeMove(i, j)) + { + infl = claim[i][j]; + *x = i; + *y = j; + } + if (*x != iNil) return TRUE; + return FALSE; + } /* extendWall */ + + + /* + check to see if I can attack one of his groups + uses limited depth search so that it can work on larger lib counts + */ +short findAttack2(x, y) +short *x, *y; + { /* findAttack2 */ + short tx, ty, i, otll; + if (playLevel < 7) + return FALSE; + playReason = "findAttack2"; + depthLimit = 8; + otll = treeLibLim; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((! gList[i].isLive) && + (ndbord[gList[i].lx][gList[i].ly] == -1) && + (gList[i].libC > 1)) + { + treeLibLim = 6; + if (killable(gList[i].lx, gList[i].ly, &tx, &ty)) /* can we kill it? */ + { + *x = tx; /* yep - do so */ + *y = ty; + return TRUE; + } + treeLibLim = otll; + } + depthLimit = 100; + return FALSE; + } /* findAttack2 */ + + + /* + blocks enemy cuts thru 1-point extensions + */ +short blockCut(x, y) +short *x, *y; + { /* blockCut */ + short i, j; + playReason = "blockCut"; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j]) + { + if ((i > 0) && (j > 0) && (j < maxPoint)) + { + if ((ndbord[i - 1][j] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (ndbord[i - 1][j + 1] == 1) && + (groupIDs[i - 1][j - 1] != groupIDs[i - 1][j + 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + if ((i < maxPoint) && (j > 0) && (j < maxPoint)) + { + if ((ndbord[i + 1][j] == -1) && + (ndbord[i + 1][j - 1] == 1) && + (ndbord[i + 1][j + 1] == 1) && + (groupIDs[i + 1][j - 1] != groupIDs[i + 1][j + 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + if ((j > 0) && (i > 0) && (i < maxPoint)) + { + if ((ndbord[i][j - 1] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (ndbord[i + 1][j - 1] == 1) && + (groupIDs[i - 1][j - 1] != groupIDs[i + 1][j - 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + if ((j < maxPoint) && (i > 0) && (i < maxPoint)) + { + if ((ndbord[i][j + 1] == -1) && + (ndbord[i - 1][j + 1] == 1) && + (ndbord[i + 1][j + 1] == 1) && + (groupIDs[i - 1][j + 1] != groupIDs[i + 1][j + 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + } + return FALSE; + } /* blockCut */ + + + /* + cuts the enemy + */ +short cutHim(x, y) +short *x, *y; + { /* cutHim */ + short i, j, nap, gid; + playReason = "cutHim"; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j]) + { + nap = 0; /* how many of his stones am I adjacent to? */ + if ((i > 0) && (ndbord[i - 1][j] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i - 1; + pList.p[nap].py = j; + } + if ((j > 0) && (ndbord[i][j - 1] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j - 1; + } + if ((i < maxPoint) && (ndbord[i + 1][j] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i + 1; + pList.p[nap].py = j; + } + if ((j < maxPoint) && (ndbord[i][j + 1] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j + 1; + } + if (nap == 1) /* possible knight's or 2-point extention */ + { + gid = groupIDs[pList.p[1].px][pList.p[1].py]; + if ((i > 0) && (i < maxPoint) && + (ndbord[i - 1][j] == -1) && + (connectMap[i][j] > 0)) /* contact on left */ + { + if (((j > 0) && + (ndbord[i + 1][j - 1] == -1) && + (gid != groupIDs[i + 1][j - 1])) || + ((j < maxPoint) && + (ndbord[i + 1][j + 1] == -1) && + (gid != groupIDs[i + 1][j + 1])) || + ((i < (maxPoint - 1)) && + (ndbord[i + 1][j] == 0) && + (ndbord[i + 2][j] == -1) && + (gid != groupIDs[i + 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((i < maxPoint) && (i > 0) && + (ndbord[i + 1][j] == -1) && + (connectMap[i][j] > 0)) /* r */ + { + if (((j > 0) && + (ndbord[i - 1][j - 1] == -1) && + (gid != groupIDs[i - 1][j - 1])) || + ((j < maxPoint) && + (ndbord[i - 1][j + 1] == -1) && + (gid != groupIDs[i - 1][j + 1])) || + ((i > 1) && + (ndbord[i - 1][j] == 0) && + (ndbord[i - 2][j] == -1) && + (gid != groupIDs[i - 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j - 1] == -1) && + (connectMap[i][j] > 0)) /* top */ + { + if (((i > 0) && + (ndbord[i - 1][j + 1] == -1) && + (gid != groupIDs[i - 1][j + 1])) || + ((i < maxPoint) && + (ndbord[i + 1][j + 1] == -1) && + (gid != groupIDs[i + 1][j + 1])) || + ((j < (maxPoint - 1)) && + (ndbord[i][j + 1] == 0) && + (ndbord[i][j + 2] == -1) && + (gid != groupIDs[i][j + 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j + 1] == -1) && + (connectMap[i][j] > 0)) /* bottom */ + { + if (((i > 0) && + (ndbord[i - 1][j - 1] == -1) && + (gid != groupIDs[i - 1][j - 1])) || + ((i < maxPoint) && + (ndbord[i + 1][j - 1] == -1) && + (gid != groupIDs[i + 1][j - 1])) || + ((j > 1) && + (ndbord[i][j - 1] == 0) && + (ndbord[i][j - 2] == -1) && + (gid != groupIDs[i][j - 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + else if (nap == 2) /* diagonal or 1-point extention */ + { + if (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) + { + if ((pList.p[1].px != pList.p[2].px) && + (pList.p[1].py != pList.p[2].py)) /* diag */ + { + spanGroup(pList.p[1].px, + pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, + pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + if (plist3.indx == 1) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else /* 1-point extension, only cut if connected */ + { + if (connectMap[i][j] > 0) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + } + else if (nap == 3) /* unprotected, but him on 3 sides */ + { + if ((groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) || + (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[3].px][pList.p[3].py]) || + (groupIDs[pList.p[3].px][pList.p[3].py] != + groupIDs[pList.p[2].px][pList.p[2].py])) + { + spanGroup(pList.p[1].px, pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + spanGroup(pList.p[3].px, pList.p[3].py, &plist2); + intersectPlist(&plist2, &plist3, &pList1); + if (pList1.indx == 1) /* a common connect point */ + if (safeMove(i, j)) + { + *x = i; + *y = j; + return TRUE; + } + } + } + } + return FALSE; + } /* cutHim */ + + + /* + ataris a group just for the hell of it + */ +short atariAnyway(x, y) +short *x, *y; + { /* atariAnyway */ + short i; + playReason = "atariAnyway"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC == 2) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { + spanGroup(gList[i].lx, gList[i].ly, &pList); + if (legal[pList.p[1].px][pList.p[1].py] && + ((connectMap[pList.p[1].px][pList.p[1].py] > 0) || + ((pList.p[1].px > 0) && + (connectMap[pList.p[1].px - 1][pList.p[1].py] > 0)) || + ((pList.p[1].px < maxPoint) && + (connectMap[pList.p[1].px + 1][pList.p[1].py] > 0)) || + ((pList.p[1].py > 0) && + (connectMap[pList.p[1].px][pList.p[1].py - 1] > 0)) || + ((pList.p[1].py < maxPoint) && + (connectMap[pList.p[1].px][pList.p[1].py + 1] > 0)))) + if (safeMove(pList.p[1].px, pList.p[1].py)) + { + *x = pList.p[1].px; + *y = pList.p[1].py; + return TRUE; + } + if (legal[pList.p[2].px][pList.p[2].py] && + ((connectMap[pList.p[2].px][pList.p[2].py] > 0) || + ((pList.p[2].px > 0) && + (connectMap[pList.p[2].px - 1][pList.p[2].py] > 0)) || + ((pList.p[2].px < maxPoint) && + (connectMap[pList.p[2].px + 1][pList.p[2].py] > 0)) || + ((pList.p[2].py > 0) && + (connectMap[pList.p[2].px][pList.p[2].py - 1] > 0)) || + ((pList.p[2].py < maxPoint) && + (connectMap[pList.p[2].px][pList.p[2].py + 1] > 0)))) + if (safeMove(pList.p[2].px, pList.p[2].py)) + { + *x = pList.p[2].px; + *y = pList.p[2].py; + return TRUE; + } + } + return FALSE; + } /* atariAnyway */ + + + /* + undercuts his groups + */ +short underCut(x, y) +short *x, *y; + { /* underCut */ + short i, j; + playReason = "underCut"; + for (i = 1; i <= maxPoint - 1; i++) + { + if (legal[0][i]) + { + if (ndbord[1][i] == -1) + if (safeMove(0, i)) + { + *x = 0; + *y = i; + return TRUE; + } + } + if (legal[maxPoint][i]) + { + if (ndbord[maxPoint - 1][i] == -1) + if (safeMove(maxPoint, i)) + { + *x = maxPoint; + *y = i; + return TRUE; + } + } + if (legal[i][0]) + { + if (ndbord[i][1] == -1) + if (safeMove(i, 0)) + { + *x = i; + *y = 0; + return TRUE; + } + } + if (legal[i][maxPoint]) + { + if (ndbord[i][maxPoint - 1] == -1) + if (safeMove(i, maxPoint)) + { + *x = i; + *y = maxPoint; + return TRUE; + } + } + } + return FALSE; + } /* underCut */ + + /* + drops to the edge of the board if threatened + */ +short dropToEdge(x, y) +short *x, *y; + { /* dropToEdge */ + short i; + playReason = "dropToEdge"; + for (i = 1; i <= maxPoint - 1; i++) + { + if (legal[1][i]) + if ((ndbord[2][i] == 1) && + (ndbord[0][i] == 0) && + (ndbord[1][i - 1] < 1) && + (ndbord[1][i + 1] < 1) && + ((ndbord[2][i - 1] == -1) || + (ndbord[2][i + 1] == -1) || + (ndbord[1][i - 1] == -1) || + (ndbord[1][i + 1] == -1))) + { + *x = 1; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[maxPoint - 1][i]) + if ((ndbord[maxPoint - 2][i] == 1) && + (ndbord[maxPoint][i] == 0) && + (ndbord[maxPoint - 1][i - 1] < 1) && + (ndbord[maxPoint - 1][i + 1] < 1) && + ((ndbord[maxPoint - 2][i - 1] == -1) || + (ndbord[maxPoint - 2][i + 1] == -1) || + (ndbord[maxPoint - 1][i - 1] == -1) || + (ndbord[maxPoint - 1][i + 1] == -1))) + { + *x = maxPoint - 1; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][1]) + if ((ndbord[i][2] == 1) && + (ndbord[i][0] == 0) && + (ndbord[i - 1][1] < 1) && + (ndbord[i + 1][1] < 1) && + ((ndbord[i - 1][2] == -1) || + (ndbord[i + 1][2] == -1) || + (ndbord[i - 1][1] == -1) || + (ndbord[i + 1][1] == -1))) + { + *x = i; + *y = 1; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][maxPoint - 1]) + if ((ndbord[i][maxPoint - 2] == 1) && + (ndbord[i][maxPoint] == 0) && + (ndbord[i - 1][maxPoint - 1] < 1) && + (ndbord[i + 1][maxPoint - 1] < 1) && + ((ndbord[i - 1][maxPoint - 2] == -1) || + (ndbord[i + 1][maxPoint - 2] == -1) || + (ndbord[i - 1][maxPoint - 1] == -1) || + (ndbord[i + 1][maxPoint - 1] == -1))) + { + *x = i; + *y = maxPoint - 1; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[0][i]) + if ((ndbord[1][i] == 1) && + (ndbord[0][i - 1] < 1) && + (ndbord[0][i + 1] < 1) && + (((ndbord[1][i - 1] == -1) && + (ndbord[1][i + 1] == -1)) || + (ndbord[0][i - 1] == -1) || + (ndbord[0][i + 1] == -1))) + { + *x = 0; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[maxPoint][i]) + if ((ndbord[maxPoint - 1][i] == 1) && + (ndbord[maxPoint][i - 1] < 1) && + (ndbord[maxPoint][i + 1] < 1) && + (((ndbord[maxPoint - 1][i - 1] == -1) && + (ndbord[maxPoint - 1][i + 1] == -1)) || + (ndbord[maxPoint][i - 1] == -1) || + (ndbord[maxPoint][i + 1] == -1))) + { + *x = maxPoint; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][0]) + if ((ndbord[i][1] == 1) && + (ndbord[i - 1][0] < 1) && + (ndbord[i + 1][0] < 1) && + (((ndbord[i - 1][1] == -1) && + (ndbord[i + 1][1] == -1)) || + (ndbord[i - 1][0] == -1) || + (ndbord[i + 1][0] == -1))) + { + *x = i; + *y = 0; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][maxPoint]) + if ((ndbord[i][maxPoint - 1] == 1) && + (ndbord[i - 1][maxPoint] < 1) && + (ndbord[i + 1][maxPoint] < 1) && + (((ndbord[i - 1][maxPoint - 1] == -1) && + (ndbord[i + 1][maxPoint - 1] == -1)) || + (ndbord[i - 1][maxPoint] == -1) || + (ndbord[i + 1][maxPoint] == -1))) + { + *x = i; + *y = maxPoint; + if (safeMove(*x, *y)) + return TRUE; + } + } + return FALSE; + } /* dropToEdge */ + + /* + Pushes walls in a tightly connected fashion. + Finds the lowest influence (mine) point that is connected to one + of my groups. + */ +short pushWall(x, y) +short *x, *y; + { /* pushWall */ + short infl, i, j, na; + playReason = "pushWall"; + *x = iNil; + *y = iNil; + infl = 11; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j]) + if (connectMap[i][j] > 0) + if ((claim[i][j] < infl) && + (((i > 0) && (ndbord[i - 1][j] == 1)) || + ((i < maxPoint) && (ndbord[i + 1][j] == 1)) || + ((j > 0) && (ndbord[i][j - 1] == 1)) || + ((j < maxPoint) && (ndbord[i][j + 1] == 1)) || + ((i > 0) && (j > 0) && (ndbord[i - 1][j - 1] == 1)) || + ((i < maxPoint) && (j > 0) && (ndbord[i + 1][j - 1] == 1)) || + ((i > 0) && (j < maxPoint) && (ndbord[i - 1][j + 1] == 1)) || + ((i < maxPoint) && (j < maxPoint) && + (ndbord[i + 1][j + 1] == 1))) && + (((i > 0) && (claim[i - 1][j] < 0)) || + ((i < maxPoint) && (claim[i + 1][j] < 0)) || + ((j > 0) && (claim[i][j - 1] < 0)) || + ((j < maxPoint) && (claim[i][j + 1] < 0)))) + { + na = 0; + if ((i > 0) && (ndbord[i - 1][j] != 0)) + na = na + 1; + if ((i < maxPoint) && (ndbord[i + 1][j] != 0)) + na = na + 1; + if ((j > 0) && (ndbord[i][j - 1] != 0)) + na = na + 1; + if ((j < maxPoint) && (ndbord[i][j + 1] != 0)) + na = na + 1; + if (na < 3) + if (safeMove(i, j)) + { + infl = claim[i][j]; + *x = i; + *y = j; + } + } + if (*x != iNil) return TRUE; + return FALSE; + } /* pushWall */ + + + /* + reduces the liberty count of one of his groups + */ +short reduceHisLiberties(x, y) +short *x, *y; + { /* reduceHisLiberties */ + short i, j; + playReason = "reduceHisLiberties"; + sortLibs(); + for (i = 1; i <= maxGroupID; i++) + if ((! gList[sGlist[i]].isLive) && + (gList[sGlist[i]].libC > 2) && + (ndbord[gList[sGlist[i]].lx][gList[sGlist[i]].ly] == -1)) + { + spanGroup(gList[sGlist[i]].lx, gList[sGlist[i]].ly, &pList); + for (j = 1; j <= pList.indx; j++) + if (legal[pList.p[j].px][pList.p[j].py] && + (connectMap[pList.p[j].px][pList.p[j].py] > 0)) + if (safeMove(pList.p[j].px, pList.p[j].py)) + { + *x = pList.p[j].px; + *y = pList.p[j].py; + return TRUE; + } + } + return FALSE; + } /* reduceHisLiberties */ + + + /* + connects a group to the edge + */ +short dropToEdge2(x, y) +short *x, *y; + { /* dropToEdge2 */ + short i; + playReason = "dropToEdge2"; + for (i = 1; i <= maxPoint - 1; i++) + { + if (legal[i][0]) + { + if ((ndbord[i][1] == 1) && + ((ndbord[i - 1][0] < 1) || + (groupIDs[i - 1][0] != groupIDs[i][1])) && + ((ndbord[i + 1][0] < 1) || + (groupIDs[i + 1][0] != groupIDs[i][1])) && + ((ndbord[i - 1][1] == -1) || + (ndbord[i + 1][1] == -1))) + { + *x = i; + *y = 0; + if (safeMove(*x, *y)) + return TRUE; + } + } + if (legal[0][i]) + { + if ((ndbord[1][i] == 1) && + ((ndbord[0][i - 1] < 1) || + (groupIDs[0][i - 1] != groupIDs[1][i])) && + ((ndbord[0][i + 1] < 1) || + (groupIDs[0][i + 1] != groupIDs[1][i])) && + ((ndbord[1][i - 1] == -1) || + (ndbord[1][i + 1] == -1))) + { + *x = 0; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + } + if (legal[i][maxPoint]) + { + if ((ndbord[i][maxPoint - 1] == 1) && + ((ndbord[i - 1][maxPoint] < 1) || + (groupIDs[i - 1][maxPoint] != groupIDs[i][maxPoint - 1])) && + ((ndbord[i + 1][maxPoint] < 1) || + (groupIDs[i + 1][maxPoint] != groupIDs[i][maxPoint - 1])) && + ((ndbord[i - 1][maxPoint - 1] == -1) || + (ndbord[i + 1][maxPoint - 1] == -1))) + { + *x = i; + *y = maxPoint; + if (safeMove(*x, *y)) + return TRUE; + } + } + if (legal[maxPoint][i]) + { + if ((ndbord[maxPoint - 1][i] == 1) && + ((ndbord[maxPoint][i - 1] < 1) || + (groupIDs[maxPoint][i - 1] != groupIDs[maxPoint - 1][i])) && + ((ndbord[maxPoint][i + 1] < 1) || + (groupIDs[maxPoint][i + 1] != groupIDs[maxPoint - 1][i])) && + ((ndbord[maxPoint - 1][i - 1] == -1) || + (ndbord[maxPoint - 1][i + 1] == -1))) + { + *x = maxPoint; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + return FALSE; + } /* dropToEdge2 */ + diff --git a/noncore/games/go/goplayutils.c b/noncore/games/go/goplayutils.c new file mode 100644 index 0000000..9e2ce4c --- a/dev/null +++ b/noncore/games/go/goplayutils.c @@ -0,0 +1,1317 @@ +/* The go player utilities */ +/* Ported from Pascal to C by Todd R. Johnson */ +/* From the original Pascal file: +Copyright (c) 1983 by Three Rivers Computer Corp. + +Written: January 17, 1983 by Stoney Ballard +*/ + +#include "goplayutils.h" +#include "amigo.h" +#include "go.h" + +extern struct bRec goboard[19][19]; + +intBoard claim, extra, bord, ndbord, sGroups, threatBord, + groupIDs, connectMap, protPoints; +boolBoard groupSeen, legal; +short maxGroupID; +pointList pList, pList1, plist2, plist3, pPlist; +intList nlcGroup, aList; +sgRec sList[401]; +groupRec gList[maxGroup]; +short killFlag, + numCapt, + utilPlayLevel, + treeLibLim; +sType mySType; +short showTrees; +short sGlist[maxGroup+1]; +short depthLimit; +intBoard markBoard; +short marker; + +short adjInAtari, adj2Libs, + intersectNum, spanNum, libMark; +playRec playStack[1025]; +short playMark, + newGID, + tryLevel, + grpMark, + gMap[maxGroup]; +short dbStop, inGenState; + + pause() +{ /* pause */ +/* if (dbStop and ! inGenState) + { + while ! tabswitch do; + repeat + if (tabYellow) + dbStop = false; + until ! tabswitch; + } */ +} /* pause */ + +sstone(w, x, y, numb) +short w, x, y, numb; +{ /* sstone */ + if (w == 1) + placestone(mySType, x, y); + else if (mySType == WHITE) + placestone(BLACK, x, y); + else + placestone(WHITE, x, y); +} /* sstone */ + +rstone(x, y) +short x, y; +{ /* rstone */ + removestone(x, y); +} /* rstone */ + +initBoolBoard(bb) +boolBoard bb; +{ /* initBoolBoard */ + short i, j; +#ifdef DEBUG + printf( "initBoolBoard\n" ); +#endif + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + bb[i][j] = FALSE; +} /* initBoolBoard */ + +sortLibs() +{ /* sortLibs */ + short i, j, t; +#ifdef DEBUG + printf( "sortLibs\n" ); +#endif + for (i = 1; i <= maxGroupID; i++) + sGlist[i] = i; + for (i = 1; i < maxGroupID; i++) + for (j = i + 1; j <= maxGroupID; j++) + if (gList[sGlist[i]].libC > gList[sGlist[j]].libC) + { + t = sGlist[i]; + sGlist[i] = sGlist[j]; + sGlist[j] = t; + } +} /* sortLibs */ + +spanGroupspan(x, y, libs, lookFor) +short x, y, lookFor; +pointList *libs; + { /* span */ + markBoard[x][y] = marker; + if (bord[x][y] == 0) + { + libs->indx = libs->indx + 1; + libs->p[libs->indx].px = x; + libs->p[libs->indx].py = y; + } + else if (bord[x][y] == lookFor) + { + groupSeen[x][y] = TRUE; + if ((x > 0) && (markBoard[x - 1][y] != marker)) + spanGroupspan(x - 1, y, libs, lookFor); + if ((y > 0) && (markBoard[x][y - 1] != marker)) + spanGroupspan(x, y - 1, libs, lookFor); + if ((x < maxPoint) && (markBoard[x + 1][y] != marker)) + spanGroupspan(x + 1, y, libs, lookFor); + if ((y < maxPoint) && (markBoard[x][y + 1] != marker)) + spanGroupspan(x, y + 1, libs, lookFor); + } + else if (gList[gMap[groupIDs[x][y]]].libC == 1) + adjInAtari = TRUE; + else if ((gList[gMap[groupIDs[x][y]]].libC == 2) && + (! gList[gMap[groupIDs[x][y]]].isLive)) + adj2Libs = TRUE; + } /* span */ + +spanGroup(x, y, libs) +short x, y; +pointList *libs; +{ /* spanGroup */ + short lookFor; +#ifdef DEBUG + printf( "spanGroup\n" ); +#endif + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + adjInAtari = FALSE; + adj2Libs = FALSE; + lookFor = bord[x][y]; + libs->indx = 0; + spanGroupspan(x, y, libs, lookFor); +} /* spanGroup */ + +sSpanGroupspan(x, y, libs, lookFor) +short x, y, lookFor; +sPointList *libs; + { /* span */ + markBoard[x][y] = marker; + if (bord[x][y] == 0) + { + libs->indx += 1; + if (libs->indx <= maxSPoint) + { + libs->p[libs->indx].px = x; + libs->p[libs->indx].py = y; + } + } + else if (bord[x][y] == lookFor) + { + groupSeen[x][y] = TRUE; + if ((x > 0) && (markBoard[x - 1][y] != marker)) + sSpanGroupspan(x - 1, y, libs, lookFor); + if ((y > 0) && (markBoard[x][y - 1] != marker)) + sSpanGroupspan(x, y - 1, libs, lookFor); + if ((x < maxPoint) && (markBoard[x + 1][y] != marker)) + sSpanGroupspan(x + 1, y, libs, lookFor); + if ((y < maxPoint) && (markBoard[x][y + 1] != marker)) + sSpanGroupspan(x, y + 1, libs, lookFor); + } + else if (gList[gMap[groupIDs[x][y]]].libC == 1) + adjInAtari = TRUE; + else if ((gList[gMap[groupIDs[x][y]]].libC == 2) && + (! gList[gMap[groupIDs[x][y]]].isLive)) + adj2Libs = TRUE; + } /* span */ + +sSpanGroup(x, y, libs) +short x, y; +sPointList *libs; +{ /* sSpanGroup */ + short lookFor; +#ifdef DEBUG + printf( "sSpanGroup\n" ); +#endif + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + adjInAtari = FALSE; + adj2Libs = FALSE; + lookFor = bord[x][y]; + libs->indx = 0; + sSpanGroupspan(x, y, libs, lookFor); +} /* sSpanGroup */ + +LAspan(x, y, me, him, iL) +short x, y, me, him; +intList *iL; + { /* span */ +#ifdef DEBUG + printf( "LAspan\n" ); +#endif + markBoard[x][y] = marker; + if (bord[x][y] == me) + { + if ((x > 0) && (markBoard[x - 1][y] != marker)) + LAspan(x - 1, y, me, him, iL); + if ((x < maxPoint) && (markBoard[x + 1][y] != marker)) + LAspan(x + 1, y, me, him, iL); + if ((y > 0) && (markBoard[x][y - 1] != marker)) + LAspan(x, y - 1, me, him, iL); + if ((y < maxPoint) && (markBoard[x][y + 1] != marker)) + LAspan(x, y + 1, me, him, iL); + } + else if (bord[x][y] == him) + if (gList[gMap[groupIDs[x][y]]].groupMark != grpMark) + { + gList[gMap[groupIDs[x][y]]].groupMark = grpMark; + iL->indx = iL->indx + 1; + iL->v[iL->indx] = gMap[groupIDs[x][y]]; + } + } /* span */ + +listAdjacents(x, y, iL) +short x, y; +intList *iL; +{ /* listAdjacents */ + short me, him; +#ifdef DEBUG + printf( "listAdjacents\n" ); +#endif + grpMark = grpMark + 1; + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + iL->indx = 0; + me = bord[x][y]; + him = -me; + LAspan(x, y, me , him, iL); +} /* listAdjacents */ + +LDspan(x, y, me, diags) +short x, y, me; +sPointList *diags; + { /* span */ +#ifdef DEBUG + printf( "LDspan\n" ); +#endif + markBoard[x][y] = marker; + if ((x > 0) && (y > 0) && + (bord[x - 1][y - 1] == 0) && + (bord[x][y - 1] != me) && + (bord[x - 1][y] != me) && + (markBoard[x - 1][y - 1] != marker)) + { + markBoard[x - 1][y - 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x - 1; + diags->p[diags->indx].py = y - 1; + } + } + if ((x < maxPoint) && (y > 0) && + (bord[x + 1][y - 1] == 0) && + (bord[x][y - 1] != me) && + (bord[x + 1][y] != me) && + (markBoard[x + 1][y - 1] != marker)) + { + markBoard[x + 1][y - 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x + 1; + diags->p[diags->indx].py = y - 1; + } + } + if ((x > 0) && (y < maxPoint) && + (bord[x - 1][y + 1] == 0) && + (bord[x][y + 1] != me) && + (bord[x - 1][y] != me) && + (markBoard[x - 1][y + 1] != marker)) + { + markBoard[x - 1][y + 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x - 1; + diags->p[diags->indx].py = y + 1; + } + } + if ((x < maxPoint) && (y < maxPoint) && + (bord[x + 1][y + 1] == 0) && + (bord[x][y + 1] != me) && + (bord[x + 1][y] != me) && + (markBoard[x + 1][y + 1] != marker)) + { + markBoard[x + 1][y + 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x + 1; + diags->p[diags->indx].py = y + 1; + } + } + if ((x > 0) && (bord[x - 1][y] == me) && + (markBoard[x - 1][y] != marker)) + LDspan(x - 1, y, me, diags); + if ((x < maxPoint) && (bord[x + 1][y] == me) && + (markBoard[x + 1][y] != marker)) + LDspan(x + 1, y, me, diags); + if ((y > 0) && (bord[x][y - 1] == me) && + (markBoard[x][y - 1] != marker)) + LDspan(x, y - 1, me, diags); + if ((y < maxPoint) && (bord[x][y + 1] == me) && + (markBoard[x][y + 1] != marker)) + LDspan(x, y + 1, me , diags); +} /* span */ + +listDiags(x, y, diags) +short x, y; +sPointList *diags; +{ /* listDiags */ + short me; +#ifdef DEBUG + printf( "listDiags\n" ); +#endif + me = bord[x][y]; + diags->indx = 0; + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + LDspan(x, y, me, diags); +} /* listDiags */ + +intersectPlist(p1, p2, pr) +pointList *p1, *p2, *pr; +{ /* intersectPlist */ + short i, j, k; +#ifdef DEBUG + printf( "intersectPlist\n" ); +#endif + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + pr->indx = 0; + for (i = 1; i <= p1->indx; i++) + markBoard[p1->p[i].px][p1->p[i].py] = marker; + j = 0; + for (i = 1; i <= p2->indx; i++) + if (markBoard[p2->p[i].px][p2->p[i].py] == marker) + { + j = j + 1; + pr->p[j] = p2->p[i]; + } + pr->indx = j; +} /* intersectPlist */ + +initArray(ary) +intBoard ary; +{ /* initArray */ + short i, j; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + ary[i][j] = 0; +} /* initArray */ + +initState() +{ /* initState */ + short i, j; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + { + extra[i][j] = 0; + claim[i][j] = 0; + groupIDs[i][j] = 0; + connectMap[i][j] = 0; + protPoints[i][j] = 0; + } +} /* initState */ + +copyArray( dest, src ) +intBoard dest, src; +{ + short x, y; + for (y = 0; y <= maxPoint; y++) + for (x = 0; x <= maxPoint; x++) + dest[x][y] = src[x][y]; +} + +/* + generates a one-point spread in the force field array (claim) + + the spread from a single point after four calls is: + + 1 + 2 2 2 + 2 4 6 4 2 + 2 4 8 10 8 4 2 + 1 2 6 10 62 10 6 2 1 + 2 4 8 10 8 4 2 + 2 4 6 4 2 + 2 2 2 + 1 + +*/ +stake() +{ + short x, y; + initArray( extra ); + for (y = 0; y <= maxPoint; y++) + for (x = 0; x <= maxPoint; x++) + { + extra[x][y] = extra[x][y] + claim[x][y]; + if (claim[x][y] > 0) + { + if (x > 0) extra[x-1][y] += 1; + if (y > 0) extra[x][y-1] += 1; + if (x < maxPoint) extra[x+1][y] += 1; + if (y < maxPoint) extra[x][y+1] += 1; + } + else if (claim[x][y] < 0) + { + if (x > 0) extra[x-1][y] -= 1; + if (y > 0) extra[x][y-1] -= 1; + if (x < maxPoint) extra[x+1][y] -= 1; + if (y < maxPoint) extra[x][y+1] -= 1; + } + } + copyArray( claim, extra ); +} /* stake */ + +/* + sets up claim from the current board position +*/ +spread() +{ + short x, y; + for (y = 0; y <= maxPoint; y++) + for (x = 0; x <= maxPoint; x++) + claim[x][y] = ndbord[x][y] * 50; + stake(); + stake(); + stake(); + stake(); +} /* spread */ + +/* + gList is initialized with the size, loc, and libCount of each group + groupIDs contains the serial numbers of the groups. +*/ +Resspan(x, y, gID, gSize, libCount, who) +short x, y, gID, *gSize, *libCount, who; + { /* span */ + if ((bord[x][y] == 0) && + (markBoard[x][y] != marker)) /* a liberty */ + { + markBoard[x][y] = marker; + *libCount = *libCount + 1; + } + else if ((bord[x][y] == who) && + (groupIDs[x][y] == 0)) + { + groupIDs[x][y] = gID; + *gSize = *gSize + 1; + if (x > 0) + Resspan(x - 1, y, gID, gSize, libCount, who); + if (x < maxPoint) + Resspan(x + 1, y, gID, gSize, libCount, who); + if (y > 0) + Resspan(x, y - 1, gID, gSize, libCount, who); + if (y < maxPoint) + Resspan(x, y + 1, gID, gSize, libCount, who); + } + } /* span */ + +respreicen() +{ /* respreicen */ + short i, j, gID, libCount, gSize, who; + gID = 0; +#ifdef DEBUG + printf( "respreicen\n" ); +#endif + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + groupIDs[i][j] = 0; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if ((bord[i][j] != 0) && /* a stone there */ + (groupIDs[i][j] == 0)) /* not seen yet */ + { + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + gID = gID + 1; + libCount = 0; + gSize = 0; + who = bord[i][j]; + Resspan(i, j, gID, &gSize, &libCount, who); /* span the group, collecting info */ + gList[gID].groupMark = 0; + gList[gID].atLevel = 0; + gList[gID].isLive = FALSE; /* we don't know yet */ + gList[gID].isDead = FALSE; + gList[gID].numEyes = -1; + gList[gID].size = gSize; + gList[gID].libC = libCount; + gList[gID].lx = i; + gList[gID].ly = j; + gMap[gID] = gID; /* set up identity map */ + } + maxGroupID = gID; + newGID = gID; + grpMark = 0; +} /* respreicen */ + +/* + play z at [x, y]. + killFlag is set true if anything is killed. +*/ +killGroup(x, y, me, him) +short x, y, me, him; + { /* killGroup */ +#ifdef DEBUG + printf( "killGroup\n" ); +#endif + playMark = playMark + 1; + /* record this kill */ + playStack[playMark].kind = rem; + playStack[playMark].uval.rem.who = him; + playStack[playMark].uval.rem.xl = x; + playStack[playMark].uval.rem.yl = y; + playStack[playMark].gID = groupIDs[x][y]; + playStack[playMark].uval.rem.sNumber = goboard[x][y].mNum; + if (showTrees) + rstone(x, y); + numCapt = numCapt + 1; + bord[x][y] = 0; + groupIDs[x][y] = 0; + if (x > 0) + { + if (bord[x - 1][y] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x - 1][y]]; + } + else if (bord[x - 1][y] == him) + killGroup(x - 1, y, me , him); + } + if (x < maxPoint) + { + if (bord[x + 1][y] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x + 1][y]]; + } + else if (bord[x + 1][y] == him) + killGroup(x + 1, y, me, him); + } + if (y > 0) + { + if (bord[x][y - 1] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y - 1]]; + } + else if (bord[x][y - 1] == him) + killGroup(x, y - 1, me, him); + } + if (y < maxPoint) + { + if (bord[x][y + 1] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y + 1]]; + } + else if (bord[x][y + 1] == him) + killGroup(x, y + 1, me, him); + } + } /* killGroup */ + +mergeGroup(sGID, myGID) +short sGID, myGID; + { /* mergeGroup */ + short i; +#ifdef DEBUG + printf( "mergeGroup\n" ); +#endif + for (i = 1; i <= newGID; i++) + if (gMap[i] == sGID) + { + playMark = playMark + 1; + playStack[playMark].kind = reMap; + playStack[playMark].gID = i; + playStack[playMark].uval.reMap.oldGID = sGID; + gMap[i] = myGID; + } + } /* mergeGroup */ + +tryPlay(x, y, z) +short x, y, z; +{ /* plei */ + short i, me, him, myGID; + short isNew; +#ifdef DEBUG + printf( "tryPlay\n" ); +#endif + me = z; + him = -me; + killFlag = FALSE; /* set true if something is killed */ + numCapt = 0; + tryLevel = tryLevel + 1; + isNew = FALSE; + bord[x][y] = z; /* play the stone */ + if ((x > 0) && (bord[x - 1][y] == me)) /* connect to adjacent group */ + myGID = gMap[groupIDs[x - 1][y]]; + else if ((x < maxPoint) && (bord[x + 1][y] == me)) + myGID = gMap[groupIDs[x + 1][y]]; + else if ((y > 0) && (bord[x][y - 1] == me)) + myGID = gMap[groupIDs[x][y - 1]]; + else if ((y < maxPoint) && (bord[x][y + 1] == me)) + myGID = gMap[groupIDs[x][y + 1]]; + else /* nobody to connect to */ + { + newGID = newGID + 1; + isNew = TRUE; + myGID = newGID; + gList[myGID].groupMark = 0; + gList[myGID].atLevel = tryLevel; + gList[myGID].isLive = FALSE; + gList[myGID].numEyes = -1; + gList[myGID].size = -1; + gList[myGID].lx = x; + gList[myGID].ly = y; + gMap[myGID] = myGID; + } + groupIDs[x][y] = myGID; + playMark = playMark + 1; + /* record this move */ + playStack[playMark].kind = add; + playStack[playMark].uval.add.who = me; + playStack[playMark].uval.add.xl = x; + playStack[playMark].uval.add.yl = y; + playStack[playMark].gID = myGID; + playStack[playMark].uval.add.sNumber = 0; + if (isNew) + playStack[playMark].uval.add.nextGID = newGID - 1; + else + playStack[playMark].uval.add.nextGID = newGID; + if (showTrees) + sstone(me, x, y, 0); + /* merge adjacent groups */ + if ((x > 0) && (bord[x - 1][y] == me) && + (gMap[groupIDs[x - 1][y]] != myGID)) + mergeGroup(gMap[groupIDs[x - 1][y]], myGID); + if ((x < maxPoint) && (bord[x + 1][y] == me) && + (gMap[groupIDs[x + 1][y]] != myGID)) + mergeGroup(gMap[groupIDs[x + 1][y]], myGID); + if ((y > 0) && (bord[x][y - 1] == me) && + (gMap[groupIDs[x][y - 1]] != myGID)) + mergeGroup(gMap[groupIDs[x][y - 1]], myGID); + if ((y < maxPoint) && (bord[x][y + 1] == me) && + (gMap[groupIDs[x][y + 1]] != myGID)) + mergeGroup(gMap[groupIDs[x][y + 1]], myGID); + /* kill opposing groups, listing affected groups */ + nlcGroup.indx = 1; + nlcGroup.v[1] = myGID; /* init list to include me */ + if ((x > 0) && (bord[x - 1][y] == him) && + (gList[gMap[groupIDs[x - 1][y]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x - 1, y, me, him); + } + if ((x < maxPoint) && (bord[x + 1][y] == him) && + (gList[gMap[groupIDs[x + 1][y]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x + 1, y, me, him); + } + if ((y > 0) && (bord[x][y - 1] == him) && + (gList[gMap[groupIDs[x][y - 1]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x, y - 1, me, him); + } + if ((y < maxPoint) && (bord[x][y + 1] == him) && + (gList[gMap[groupIDs[x][y + 1]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x, y + 1, me, him); + } + /* list groups adjacent to me */ + if ((x > 0) && (bord[x - 1][y] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x - 1][y]]; + } + if ((x < maxPoint) && (bord[x + 1][y] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x + 1][y]]; + } + if ((y > 0) && (bord[x][y - 1] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y - 1]]; + } + if ((y < maxPoint) && (bord[x][y + 1] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y + 1]]; + } + /* fix liberty count for affected groups */ + grpMark = grpMark + 1; + for (i = 1; i <= nlcGroup.indx; i++) + if (gList[nlcGroup.v[i]].groupMark != grpMark) + { + if (gList[nlcGroup.v[i]].atLevel != tryLevel) + { + playMark = playMark + 1; + playStack[playMark].kind = chLib; + playStack[playMark].gID = nlcGroup.v[i]; + playStack[playMark].uval.chLib.oldLevel = + gList[nlcGroup.v[i]].atLevel; + playStack[playMark].uval.chLib.oldLC = + gList[nlcGroup.v[i]].libC; + } + gList[nlcGroup.v[i]].groupMark = grpMark; + gList[nlcGroup.v[i]].atLevel = tryLevel; + spanGroup(gList[nlcGroup.v[i]].lx, gList[nlcGroup.v[i]].ly, &pPlist); + gList[nlcGroup.v[i]].libC = pPlist.indx; + } +} /* plei */ + +saveState() +{ /* saveState */ + playMark = 0; + tryLevel = 0; + newGID = maxGroupID; +} /* saveState */ + +/* + undoes a move sequence back to uMark +*/ +undoTo(uMark) +short uMark; +{ /* undoTo */ + short i, xl, yl; +#ifdef DEBUG + printf( "undoTo\n" ); +#endif + for (i = playMark; i >= uMark + 1; i--) + if (playStack[i].kind == rem) + { + xl = playStack[i].uval.rem.xl; + yl = playStack[i].uval.rem.yl; + bord[xl][yl] = playStack[i].uval.rem.who; + groupIDs[xl][yl] = playStack[i].gID; + if (showTrees) + sstone(playStack[i].uval.rem.who, xl, yl, + playStack[i].uval.rem.sNumber); + } + else if (playStack[i].kind == add) + { + xl = playStack[i].uval.add.xl; + yl = playStack[i].uval.add.yl; + bord[xl][yl] = 0; + groupIDs[xl][yl] = 0; + tryLevel = tryLevel - 1; + newGID = playStack[i].uval.add.nextGID; + if (showTrees) + rstone(xl, yl); + } + else if (playStack[i].kind == reMap) + gMap[playStack[i].gID] = playStack[i].uval.reMap.oldGID; + else /* change libs of group - gID is pre-mapped */ + { + gList[playStack[i].gID].libC = playStack[i].uval.chLib.oldLC; + gList[playStack[i].gID].atLevel = playStack[i].uval.chLib.oldLevel; + } + playMark = uMark; +} /* undoTo */ + +/* + restores the state of the world after trying a move sequence +*/ +restoreState() +{ /* restoreState */ +#ifdef DEBUG + printf( "restoreState\n" ); +#endif + if (playMark > 0) + { + undoTo(0); + playMark = 0; + tryLevel = 0; + } +} /* restoreState */ + +/* exception bpt; */ + + +/* + returns true if (the group (at gx, gy) is saveable. + if so, returns the point to play at in savex, savey +*/ +short saveable(gx, gy, savex, savey) +short gx, gy, *savex, *savey; +{ /* saveable */ + short me, him, gx1, gx2, i, j, smark, mark2, tl, result; + char sChar; + sPointList dList; + point tp; + short libList[maxSPoint+1]; +#ifdef DEBUG + printf( "saveable\n" ); +#endif + dbStop = TRUE; + me = bord[gx][gy]; + him = -me; + if (me == 1) + sChar = '|'; + else + sChar = '>'; +/* write(sChar); */ + spanGroup(gx, gy, &plist3); /* find my liberties */ + if (adjInAtari) /* one of my options is to kill */ + { + listAdjacents(gx, gy, &aList); + for (i = 1; i <= aList.indx; i++) + if (gList[aList.v[i]].libC == 1) + { + spanGroup(gList[aList.v[i]].lx, gList[aList.v[i]].ly, + &pList1); /* find it's liberty */ + plist3.indx = plist3.indx + 1; + plist3.p[plist3.indx].px = pList1.p[1].px; + plist3.p[plist3.indx].py = pList1.p[1].py; + } + } + for (i = 1; i <= maxSPoint; i++) + libList[i] = -1; + if ((utilPlayLevel > 4) && + (gList[gMap[groupIDs[gx][gy]]].libC > 1)) /* account for diags */ + { + listDiags(gx, gy, &dList); + j = 0; + i = plist3.indx; + while ((j < dList.indx) && + (i < maxSPoint)) + { + j = j + 1; + i = i + 1; + libList[i] = 100; + plist3.p[i].px = dList.p[j].px; + plist3.p[i].py = dList.p[j].py; + } + plist3.indx = i; + } + if (plist3.indx > 1) /* sort by decreasing lib count */ + { + for (i = 1; i <= plist3.indx; i++) + if (libList[i] != 100) + { + mark2 = playMark; + tryPlay(plist3.p[i].px, plist3.p[i].py, me); + libList[i] = gList[gMap[groupIDs[gx][gy]]].libC; + if (libList[i] > treeLibLim) /* i'm safe */ + { + *savex = plist3.p[i].px; + *savey = plist3.p[i].py; + result = TRUE; + goto one; + } + undoTo(mark2); + } + for (i = 1; i <= plist3.indx - 1; i++) + for (j = i + 1; j <= plist3.indx; j++) + if (libList[i] < libList[j]) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = plist3.p[i]; + plist3.p[i] = plist3.p[j]; + plist3.p[j] = tp; + } + } + for (i = 1; i <= plist3.indx; i++) + { + *savex = plist3.p[i].px; + *savey = plist3.p[i].py; + if (legal[*savex][*savey]) + { + smark = playMark; + tryPlay(*savex, *savey, me); + pause(); + if (gList[gMap[groupIDs[*savex][*savey]]].libC > 1) + if (gList[gMap[groupIDs[gx][gy]]].libC > treeLibLim) + { + restoreState(); +/* sClearChar(sChar, rXor); */ + return TRUE; + } + else if (gList[gMap[groupIDs[gx][gy]]].libC > 1) + if (! killable(gx, gy, &gx1, &gx2)) + { + restoreState(); +/* sClearChar(sChar, rXor); */ + return TRUE; + } + undoTo(smark); + } + } + result = FALSE; +one: + restoreState(); +/* sClearChar(sChar, rXor); */ + return result; +} /* saveable */ + +/* + marks unsavable groups as dead +*/ +markDead() +{ /* markDead */ + short i, j, gx, gy, result; +#ifdef DEBUG + printf( "markDead\n" ); +#endif + for (i = 1; i <= maxGroupID; i++) + if (killable(gList[i].lx, gList[i].ly, &gx, &gy)) + result = ! saveable(gList[i].lx, gList[i].ly, &gx, &gy); + else + result = FALSE; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (bord[i][j] == 0) + ndbord[i][j] = 0; + else if (gList[groupIDs[i][j]].isDead) + ndbord[i][j] = 0; + else + ndbord[i][j] = bord[i][j]; +} /* markDead */ + +/* + marks groups with two eyes as live +*/ +MLspan(x, y, saw1, sawm1, size, sMark) +short x, y, *saw1, *sawm1, *size, sMark; + { /* span */ + if (ndbord[x][y] == 1) + *saw1 = TRUE; + else if (ndbord[x][y] == -1) + *sawm1 = TRUE; + else if (sGroups[x][y] == 0) + { + sGroups[x][y] = sMark; + *size = *size + 1; + if (x > 0) + MLspan(x - 1, y, saw1, sawm1, size, sMark); + if (x < maxPoint) + MLspan(x + 1, y, saw1, sawm1, size, sMark); + if (y > 0) + MLspan(x, y - 1, saw1, sawm1, size, sMark); + if (y < maxPoint) + MLspan(x, y + 1, saw1, sawm1, size, sMark); + } + } /* span */ + +short CLspan(x, y, numEyes, who) +short x, y, *numEyes, who; + { /* span */ + markBoard[x][y] = marker; + if (ndbord[x][y] == 0) + { + if ((sList[sGroups[x][y]].sm != marker) && + (sList[sGroups[x][y]].w == who)) + { + sList[sGroups[x][y]].sm = marker; + if (sList[sGroups[x][y]].s > 6) + return TRUE; + *numEyes = *numEyes + 1; + if (*numEyes > 1) + return TRUE; + } + } + else if (bord[x][y] == who) + { + if ((x > 0) && + (markBoard[x - 1][y] != marker)) + if (CLspan(x - 1, y, numEyes, who)) return TRUE; + if ((x < maxPoint) && + (markBoard[x + 1][y] != marker)) + if (CLspan(x + 1, y, numEyes, who)) return TRUE; + if ((y > 0) && + (markBoard[x][y - 1] != marker)) + if (CLspan(x, y - 1, numEyes, who)) return TRUE; + if ((y < maxPoint) && + (markBoard[x][y + 1] != marker)) + if (CLspan(x, y + 1, numEyes, who)) return TRUE; + } + return FALSE; + } /* span */ + +short checkLive(x, y) +short x, y; + { /* checkLive */ + short numEyes, who; +#ifdef DEBUG + printf( "checkLive\n" ); +#endif + numEyes = 0; + who = bord[x][y]; + marker = marker + 1; + return CLspan(x, y, &numEyes, who); + } /* checkLive */ + +markLive() +{ /* markLive */ + short i, j, size, sMark = 0; + short saw1, sawm1; +#ifdef DEBUG + printf( "markLive\n" ); +#endif + initArray(sGroups); + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if ((sGroups[i][j] == 0) && + (ndbord[i][j] == 0)) + { + size = 0; + sMark = sMark + 1; + sawm1 = FALSE; + saw1 = FALSE; + MLspan(i, j, &saw1, &sawm1, &size, sMark); + sList[sMark].s = size; + sList[sMark].sm = 0; + if (sawm1) + if (saw1) + sList[sMark].w = 0; + else + sList[sMark].w = -1; + else if (saw1) + sList[sMark].w = 1; + else + sList[sMark].w = 0; + } + for (i = 1; i <= maxGroupID; i++) + if (! gList[i].isDead) + gList[i].isLive = checkLive(gList[i].lx, gList[i].ly); +} /* markLive */ + +/* + generates the connection map and the protected point map. +*/ +genConnects() +{ /* genConnects */ + short x, y, numStones; +#ifdef DEBUG + printf( "genConnects\n" ); +#endif + for (x = 0; x <= maxPoint; x++) + for (y = 0; y <= maxPoint; y++) + { + connectMap[x][y] = 0; + protPoints[x][y] = 0; + } + for (x = 0; x <= maxPoint; x++) + for (y = 0; y <= maxPoint; y++) + if (bord[x][y] == 1) /* map connections to this stone */ + { + if (x > 0) /* direct connection */ + connectMap[x - 1][y] += 1; + if (x < maxPoint) + connectMap[x + 1][y] += 1; + if (y > 0) + connectMap[x][y - 1] += 1; + if (y < maxPoint) + connectMap[x][y + 1] += 1; + if ((x > 0) && (y > 0) && /* diagonal connection */ + (bord[x - 1][y] == 0) && (bord[x][y - 1] == 0)) + connectMap[x - 1][y - 1] += 1; + if ((x < maxPoint) && (y > 0) && + (bord[x + 1][y] == 0) && (bord[x][y - 1] == 0)) + connectMap[x + 1][y - 1] += 1; + if ((x < maxPoint) && (y < maxPoint) && + (bord[x + 1][y] == 0) && (bord[x][y + 1] == 0)) + connectMap[x + 1][y + 1] += 1; + if ((x > 0) && (y < maxPoint) && + (bord[x - 1][y] == 0) && (bord[x][y + 1] == 0)) + connectMap[x - 1][y + 1] += 1; + if ((x > 1) && (claim[x - 1][y] > 3)) /* one point jump */ + connectMap[x - 2][y] += 1; + if ((x < (maxPoint - 1)) && (claim[x + 1][y] > 3)) + connectMap[x + 2][y] += 1; + if ((y > 1) && (claim[x][y - 1] > 3)) + connectMap[x][y - 2] += 1; + if ((y < (maxPoint - 1)) && (claim[x][y + 1] > 3)) + connectMap[x][y + 2] += 1; + if ((x > 1) && (y > 0) && /* knight's move */ + (claim[x - 1][y] > 3) && (claim[x - 1][y - 1] > 3)) + connectMap[x - 2][y - 1] += 1; + if ((x > 0) && (y > 1) && + (claim[x][y - 1] > 3) && (claim[x - 1][y - 1] > 3)) + connectMap[x - 1][y - 2] += 1; + if ((x < (maxPoint - 1)) && (y > 0) && + (claim[x + 1][y] > 3) && (claim[x + 1][y - 1] > 3)) + connectMap[x + 2][y - 1] += 1; + if ((x < maxPoint) && (y > 1) && + (claim[x][y - 1] > 3) && (claim[x + 1][y - 1] > 3)) + connectMap[x + 1][y - 2] += 1; + if ((x > 1) && (y < maxPoint) && + (claim[x - 1][y] > 3) && (claim[x - 1][y + 1] > 3)) + connectMap[x - 2][y + 1] += 1; + if ((x > 0) && (y < (maxPoint - 1)) && + (claim[x][y + 1] > 3) && (claim[x - 1][y + 1] > 3)) + connectMap[x - 1][y + 2] += 1; + if ((x < (maxPoint - 1)) && (y < maxPoint) && + (claim[x + 1][y] > 3) && (claim[x + 1][y + 1] > 3)) + connectMap[x + 2][y + 1] += 1; + if ((x < maxPoint) && (y < (maxPoint - 1)) && + (claim[x][y + 1] > 3) && (claim[x + 1][y + 1] > 3)) + connectMap[x + 1][y + 2] += 1; + } + else if (bord[x][y] == 0) /* see if protected point */ + { + numStones = 0; + if (x == 0) + numStones = numStones + 1; + if (y == 0) + numStones = numStones + 1; + if (x == maxPoint) + numStones = numStones + 1; + if (y == maxPoint) + numStones = numStones + 1; + if ((x > 0) && (bord[x - 1][y] == 1)) + numStones = numStones + 1; + if ((y > 0) && (bord[x][y - 1] == 1)) + numStones = numStones + 1; + if ((x < maxPoint) && (bord[x + 1][y] == 1)) + numStones = numStones + 1; + if ((y < maxPoint) && (bord[x][y + 1] == 1)) + numStones = numStones + 1; + if (numStones == 4) + protPoints[x][y] = 1; + else if (numStones == 3) + { + if ((x > 0) && + ((bord[x - 1][y] == 0) || + ((bord[x - 1][y] == -1) && + (gList[groupIDs[x - 1][y]].libC == 1)))) + protPoints[x][y] = 1; + else if ((x < maxPoint) && + ((bord[x + 1][y] == 0) || + ((bord[x + 1][y] == -1) && + (gList[groupIDs[x + 1][y]].libC == 1)))) + protPoints[x][y] = 1; + else if ((y > 0) && + ((bord[x][y - 1] == 0) || + ((bord[x][y - 1] == -1) && + (gList[groupIDs[x][y - 1]].libC == 1)))) + protPoints[x][y] = 1; + else if ((y < maxPoint) && + ((bord[x][y + 1] == 0) || + ((bord[x][y + 1] == -1) && + (gList[groupIDs[x][y + 1]].libC == 1)))) + protPoints[x][y] = 1; + } + } + for (x = 0; x <= maxPoint; x++) + for (y = 0; y <= maxPoint; y++) + if (bord[x][y] != 0) + { + connectMap[x][y] = 0; + protPoints[x][y] = 0; + } +} /* genConnects */ + +/* + generates the whole state of the game. +*/ +genState() +{ /* genState */ +#ifdef DEBUG + printf( "genState\n" ); +#endif + inGenState = TRUE; + respreicen(); + markDead(); + markLive(); + spread(); + genConnects(); +#ifdef DEBUG +/* printBoard( claim, "claim" ); */ +/* printBoard( bord, "bord" ); */ +/* printBoard( ndbord, "ndbord" ); + printBoard( sGroups, "sGroups" ); + printBoard( groupIDs, "groupIDs" ); + printBoard( connectMap, "connectMap" ); + printBoard( protPoints, "protPoints" ); */ +#endif + inGenState = FALSE; +} /* genState */ + +/* + generates a value for the [x, y] location that appears to get larger + for points that are saddle points in the influence graph (klein) +*/ +short tencen(x, y) +short x, y; +{ /* tencen */ + short a, b, c, d, w, z; +#ifdef DEBUG + printf( "tencen\n" ); +#endif + if (claim[x][y] > -1) /* if (he does not influence this area, return 50 */ + { + return 50; + } + w = claim[x][y]; /* w <= -1 */ + a = iNil; + if (x > 0) + if (claim[x - 1][y] > -1) /* if (neighbor is not influenced by him */ + a = claim[x - 1][y] - w; /* score is sum of his influence on central */ + b = iNil; /* point and my influence on this neighbor */ + if (y > 0) + if (claim[x][y - 1] > -1) + b = claim[x][y - 1] - w; + c = iNil; + if (x < maxPoint) + if (claim[x + 1][y] > -1) + c = claim[x + 1][y] - w; + d = iNil; + if (y < maxPoint) + if (claim[x][y + 1] > -1) + d = claim[x][y + 1] - w; + z = a; /* z = max(a, b, c, d) */ + if (z != iNil) + { + if ((b != iNil) && + (b > z)) + z = b; + } + else + z = b; + if (z != iNil) + { + if ((c != iNil) && + (c > z)) + z = c; + } + else + z = c; + if (z != iNil) + { + if ((d != iNil) && + (d > z)) + z = d; + } + else + z = d; + if ((z != iNil) && + ((x == 0) || + (y == 0) || + (x == maxPoint) || + (y == maxPoint))) + z = z * 2; /* double z if (on the edge of the board ?? */ + if (z != iNil) + return z; + else + return 50; +} /* tencen */ + +initGPUtils() +{ /* initGPUtils */ +#ifdef DEBUG + printf( "initGPUtils\n" ); +#endif + initArray(markBoard); + initState(); + marker = 0; + playMark = 0; + gList[0].isLive = FALSE; + gList[0].isDead = FALSE; + gList[0].libC = 0; + gList[0].size = 0; + gList[0].numEyes = 0; + gList[0].lx = -1; + gList[0].ly = -1; + gMap[0] = 0; + dbStop = FALSE; + inGenState = FALSE; +} /* initGPUtils */ + diff --git a/noncore/games/go/goplayutils.h b/noncore/games/go/goplayutils.h new file mode 100644 index 0000000..11ab658 --- a/dev/null +++ b/noncore/games/go/goplayutils.h @@ -0,0 +1,85 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef __goplayutils_h +#define __goplayutils_h + +#define iNil 32767 /* a distinguished value like nil */ +#define maxGroup 512 +#define maxSPoint 16 +#define tryLimit 300 + +typedef short intBoard[19][19]; /* these were -2 to maxPoint + 2 */ + +typedef short boolBoard[19][19]; + +typedef struct +{ + short px, py; +} point; + +typedef struct +{ + point p[401]; + short indx; +} pointList; + +typedef struct +{ + point p[maxSPoint+1]; + short indx; +} sPointList; + +typedef struct +{ + short indx, + v[401]; +} intList; + +typedef struct { short w, s, sm; } sgRec; + +typedef struct +{ + short groupMark, + atLevel, + isLive, + isDead, + libC, + numEyes, + size, + lx, ly; +} groupRec; + +typedef enum {rem, add, chLib, reMap} playType; + +typedef struct { short who, xl, yl, nextGID, sNumber; } remAddRec; +typedef struct { short oldLC, oldLevel; } chLibRec; +typedef struct { short oldGID; } reMapRec; +typedef struct +{ + short gID; + playType kind; + union { + remAddRec rem, add; + chLibRec chLib; + reMapRec reMap; + } uval; +} playRec; + +#endif diff --git a/noncore/games/go/gowidget.cpp b/noncore/games/go/gowidget.cpp new file mode 100644 index 0000000..fca9797 --- a/dev/null +++ b/noncore/games/go/gowidget.cpp @@ -0,0 +1,449 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "gowidget.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include //processEvents() +#include + +//#include + +#include "amigo.h" +#include "goplayutils.h" + +static const enum bVal computer_color = BLACK; + +static int current_handicap = 1; + +static QBrush *goBrush; +//static QImage *newBlackStone; +//static QImage *blackStone; +//static QImage *whiteStone; +static QPixmap *newBlackStone; +static QPixmap *blackStone; +static QPixmap *whiteStone; + +GoMainWidget::GoMainWidget( QWidget *parent, const char* name) : + QMainWindow( parent, name ) +{ + setToolBarsMovable( FALSE ); + GoWidget *go = new GoWidget(this); + + setCentralWidget(go); + toolbar = new QPEToolBar(this); + toolbar->setHorizontalStretchable( TRUE ); + addToolBar(toolbar); + + QPEMenuBar *mb = new QPEMenuBar( toolbar ); + mb->setMargin(0); + QPopupMenu *file = new QPopupMenu( this ); + + QAction *a = new QAction( tr( "New Game" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), go, SLOT( newGame() ) ); + a->addTo( file ); + + a = new QAction( tr( "Pass" ), Resource::loadPixmap( "pass" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), go, SLOT( pass() ) ); + a->addTo( file ); + a->addTo( toolbar ); + + + a = new QAction( tr( "Resign" ), Resource::loadPixmap( "reset" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), go, SLOT( resign() ) ); + a->addTo( file ); + + a = new QAction( tr( "Two player option" ), QString::null, 0, this, 0 ); + a->setToggleAction( TRUE ); + connect( a, SIGNAL( toggled(bool) ), go, SLOT( setTwoplayer(bool) ) ); + a->addTo( file ); + + mb->insertItem( tr( "Game" ), file ); + + QLabel *turnLabel = new QLabel( toolbar ); + turnLabel->setBackgroundMode( PaletteButton ); + connect( go, SIGNAL(showTurn(const QPixmap&)), + turnLabel, SLOT(setPixmap(const QPixmap&)) ); + + + QLabel * scoreLabel = new QLabel( toolbar ); + scoreLabel->setBackgroundMode( PaletteButton ); + connect( go, SIGNAL(showScore(const QString&)), + scoreLabel, SLOT(setText(const QString&)) ); + + toolbar->setStretchableWidget( scoreLabel ); + + go->readConfig(); +} + +void GoMainWidget::resizeEvent( QResizeEvent * ) +{ + //### this won't work because of the text label... + /* + if ( width() > height() ) + moveToolBar( toolbar, Left ); + else + moveToolBar( toolbar, Top ); + */ +} + +GoWidget *GoWidget::self = 0; + +GoWidget::GoWidget( QWidget *parent, const char* name) : + QWidget( parent, name ) +{ + if ( self ) + fatal( "Only one Go widget allowed" ); + self = this; + twoplayer = FALSE; + + + d = bx = by = 1; + + QPixmap pix = Resource::loadPixmap( "pine" ); + goBrush = new QBrush( black, pix ); + /* + QString fn = Resource::findPixmap("Go-black"); + blackStone = new QImage( fn ); + fn = Resource::findPixmap("Go-black-highlight"); + newBlackStone = new QImage( fn ); + fn = Resource::findPixmap("Go-white"); + whiteStone = new QImage( fn ); + */ + blackStone = new QPixmap(Resource::loadPixmap( "Go-black" )); + whiteStone = new QPixmap(Resource::loadPixmap( "Go-white" )); + newBlackStone = new QPixmap(Resource::loadPixmap( "Go-black-highlight" )); + + init(); +} + +GoWidget::~GoWidget() +{ + writeConfig(); +} + +void GoWidget::writeConfig() +{ + Config cfg("Go"); + cfg.setGroup("Game"); + cfg.writeEntry("TwoPlayer", twoplayer); + cfg.writeEntry("CurrentPlayer", currentPlayer); + cfg.writeEntry("NPassed", nPassed); + QString b; + for (int i=0; i<19; i++) + for (int j=0; j<19; j++) + b += board[i][j] == BLACK ? 'B' : board[i][j] == WHITE ? 'W' : '.'; + cfg.writeEntry("Board", b); + cfg.writeEntry("LastX", lastX); + cfg.writeEntry("LastY", lastY); + extern int blackPrisoners, whitePrisoners; + cfg.writeEntry("BlackPrisoners", blackPrisoners); + cfg.writeEntry("WhitePrisoners", whitePrisoners); +} + +void GoWidget::readConfig() +{ + init(); + Config cfg("Go"); + cfg.setGroup("Game"); + twoplayer = cfg.readBoolEntry("TwoPlayer"); + currentPlayer = (bVal)cfg.readNumEntry("CurrentPlayer",1); + nPassed = cfg.readNumEntry("NPassed",0); + QString b = cfg.readEntry("Board"); + if ( b.length() == 19*19 ) + for (int i=0; i<19; i++) + for (int j=0; j<19; j++) { + QChar ch = b[j+19*i]; + if ( ch != '.' ) + GoPlaceStone( ch == 'B' ? BLACK : WHITE, i, j ); + } + lastX = cfg.readNumEntry("LastX"); + lastY = cfg.readNumEntry("LastY"); + extern int blackPrisoners, whitePrisoners; + blackPrisoners = cfg.readNumEntry("BlackPrisoners",0); + whitePrisoners = cfg.readNumEntry("WhitePrisoners",0); + reportPrisoners(blackPrisoners,whitePrisoners); + emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone ); +} + +void GoWidget::resizeEvent( QResizeEvent * ) +{ + d = QMIN(width(),height())/19; + // int r = (d/2-1); + bx = (width() - 18*d)/2 ; + by = (height() - 18*d)/2 ; +} + +void GoWidget::init() +{ + lastX = lastY = newX = newY = -1; + nPassed = 0; + for ( int i = 0; i < 19; i++ ) + for ( int j = 0; j < 19; j++ ) + board[i][j]=-1; + gameActive = TRUE; + goRestart(current_handicap); + + if ( twoplayer ) { + currentPlayer = BLACK; + } else { + doComputerMove(); + currentPlayer = WHITE; + } + emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone ); +} + +void GoWidget::paintEvent( QPaintEvent *e ) +{ + int i,j; + + int r = whiteStone->width()/2; + + QPainter p(this); + p.fillRect( bx - d/2, by - d/2, 19*d, 19*d, *goBrush ); + + int xMin = QMAX( x2board(e->rect().left()), 0 ); + int xMax = QMIN( x2board(e->rect().right()), 18 ); + int yMin = QMAX( y2board(e->rect().top()), 0 ); + int yMax = QMIN( y2board(e->rect().bottom()), 18 ); + + QColor pine( 255, 186, 89 ); + p.setPen( pine.dark() ); + + for ( i = xMin; i < xMax+1 ; i ++ ) { + p.drawLine( bx+i*d, by, bx+i*d, by+18*d ); + } + for ( j = yMin; j < yMax+1 ; j ++ ) { + p.drawLine( bx, by+j*d, bx+18*d, by+j*d); + } + + // dots are at (3,3), (3,9), (3,15) and so on + p.setBrush( black ); + for ( i = 3; i < xMax+1; i+=6 ) + for ( j = 3; j < yMax+1; j+=6 ) + p.drawEllipse( bx+i*d-2, by+j*d-2, 5, 5 ); + + + for ( i = xMin; i < xMax+1; i++ ) + for ( j = yMin; j < yMax+1; j++ ) { + if ( board[i][j] == WHITE || + currentPlayer==WHITE && newX == i && newY == j ) + p.drawPixmap( bx+i*d - r, by+j*d - r, *whiteStone ); + else if ( i == lastX && j == lastY ) + p.drawPixmap( bx+i*d - r, by+j*d - r, *newBlackStone ); + else if ( board[i][j] == BLACK || + currentPlayer==BLACK && newX == i && newY == j) + p.drawPixmap( bx+i*d - r, by+j*d - r, *blackStone ); + } +} + +void GoWidget::doMove( int x, int y ) +{ + + if ( !GoPlaceStone( currentPlayer, x, y ) ) { + //printf( "Illegal move (%d,%d)\n", x, y ); + return; + } + //printf( "you do (%d,%d)\n", x, y ); + nPassed = 0; + if ( twoplayer ) + currentPlayer = (currentPlayer==WHITE) ? BLACK : WHITE; + else + doComputerMove(); + + emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone ); + +} + +void GoWidget::pass() +{ + if ( !gameActive ) + return; + nPassed++; + if ( nPassed >= 2 ) + endGame(); + else if ( !twoplayer ) + doComputerMove(); +} + +void GoWidget::resign() +{ + if ( gameActive ) + endGame(); +} + + +void GoWidget::newGame() +{ + init(); + update(); +} + + +void GoWidget::endGame() +{ + gameActive = FALSE; + + int w,b; + CountUp( &w, &b); + QString s = tr("White %1, Black %2. ").arg(w).arg(b); + if ( w > b ) + s += tr("White wins."); + else if ( w < b ) + s += tr("Black wins."); + else + s += tr("A draw."); + emit showScore( s ); +} + +void GoWidget::doComputerMove() +{ + int ox = lastX; + int oy = lastY; + lastX = lastY = -1; + emit showTurn( *blackStone ); + refresh( ox, oy); + qApp->processEvents(); + short int x,y; + if ( genMove( computer_color, &x, &y ) ) { + lastX = x; + lastY = y; + //printf( "I do (%d,%d)\n", x, y ); + GoPlaceStone(computer_color,x,y); + nPassed = 0; + } else { + emit showScore( tr("I pass") ); + nPassed++; + if ( nPassed >= 2 ) + endGame(); + } +} + +void GoWidget::mousePressEvent( QMouseEvent *me ) +{ + if ( !gameActive ) + return; + int x = x2board(me->x()); + int y = y2board(me->y()); + showStone(x,y,currentPlayer); +} + +void GoWidget::mouseMoveEvent( QMouseEvent *me ) +{ + if ( !gameActive ) + return; + int x = x2board(me->x()); + int y = y2board(me->y()); + if ( x != newX || y != newY ) + showStone(x,y,currentPlayer); +} + +void GoWidget::showStone( int x, int y, enum bVal c ) +{ + + if ( newX > -1 ) { + refresh( newX, newY ); + newY = newX = -1; + } + if ( x < 0 || x > 18 || y < 0 || y > 18 ) { + newX = newY = -1; + return; + } + if ( board[x][y] == -1 && !Suicide( c, x, y ) ) { + newX = x; + newY = y; + refresh(x,y); + } + +} + +void GoWidget::mouseReleaseEvent( QMouseEvent * ) +{ + if ( gameActive && newX > -1 ) + doMove( newX, newY ); + newX = newY = -1; +} + +void GoWidget::refresh( int x, int y ) +{ + update( bx+d*x-d/2-1, by+d*y-d/2-1, d+2, d+2 ); +} + +void GoWidget::removeStone(short x, short y) +{ + board[x][y]=-1; + refresh( x, y ); +} + +void GoWidget::placeStone (enum bVal c, short x, short y ) +{ + board[x][y]=c; + refresh( x, y ); +} + +void GoWidget::reportPrisoners( int blackcnt, int whitecnt ) +{ + QString s = tr( "Prisoners: black %1, white %2" ).arg(blackcnt).arg(whitecnt); + emit showScore( s ); +} + +void GoWidget::setTwoplayer( bool b ) +{ + twoplayer = b; +} + +void GoWidget::setHandicap( int h ) +{ + current_handicap = h; +} + + +extern "C" { + +void removestone(short x, short y) +{ + GoWidget::self->removeStone(x,y); +} + +void placestone (enum bVal c, short x, short y ) +{ + GoWidget::self->placeStone(c,x,y); +} + +void intrMoveReport(enum bVal c ,char *coord ,char *reason ) +{ + qDebug( "intrMoveReport colour %d, %s %s", c, coord, reason ); +} + +void intrPrisonerReport( short blackcnt, short whitecnt ) +{ + GoWidget::self->reportPrisoners(blackcnt,whitecnt); +} + +} + diff --git a/noncore/games/go/gowidget.h b/noncore/games/go/gowidget.h new file mode 100644 index 0000000..94de2cc --- a/dev/null +++ b/noncore/games/go/gowidget.h @@ -0,0 +1,111 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef GOWIDGET_H +#define GOWIDGET_H + +#include +#include "amigo.h" + + +class QToolBar; + +class GoMainWidget : public QMainWindow +{ + Q_OBJECT +public: + GoMainWidget( QWidget *parent=0, const char* name=0); +protected: + void resizeEvent( QResizeEvent * ); +private: + QToolBar *toolbar; + +}; + + +class QLabel; +class GoWidget : public QWidget +{ + Q_OBJECT +public: + GoWidget( QWidget *parent=0, const char* name=0); + ~GoWidget(); + + void doMove( int x, int y ); + void doComputerMove(); + + void readConfig(); + void writeConfig(); + +public slots: + void pass(); + void resign(); + void newGame(); + void setTwoplayer( bool ); + void setHandicap( int ); +signals: + void showScore( const QString& ); + void showTurn( const QPixmap& ); + +protected: + void paintEvent( QPaintEvent * ); + void mousePressEvent( QMouseEvent * ); + void mouseMoveEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + void resizeEvent( QResizeEvent * ); +private: + void init(); + void removeStone(short x, short y); + void placeStone (enum bVal c, short x, short y ); + + void refresh( int x, int y ); + void showStone( int x, int y, enum bVal ); + void reportPrisoners(int,int); + + inline int x2board( int x ) { return (x-bx+d/2)/d; } + inline int y2board( int y ) { return (y-by+d/2)/d; } + + void endGame(); + + bool twoplayer; + enum bVal currentPlayer; + bool gameActive; + int nPassed; + signed char board[19][19]; + + int d; //distance between lines + int bx; //vertical baseline + int by; //horizontal baseline + + int lastX,lastY; + int newX,newY; + + static GoWidget *self; + + friend void removestone(short x, short y); + friend void intrPrisonerReport( short, short ); + friend void placestone(enum bVal c, short x, short y ); +}; + + + + + +#endif diff --git a/noncore/games/go/killable.c b/noncore/games/go/killable.c new file mode 100644 index 0000000..3ed2d2e --- a/dev/null +++ b/noncore/games/go/killable.c @@ -0,0 +1,373 @@ +/* By Stoney Ballard */ +/* Ported from Pascal to C by Todd R. Johnson */ + +#include "go.h" +#include "goplayutils.h" +#include "amigo.h" + +extern intBoard bord, groupIDs; +extern boolBoard legal; +extern groupRec gList[maxGroup]; +extern short gMap[maxGroup], adjInAtari, adj2Libs, playMark, treeLibLim, + utilPlayLevel, killFlag, depthLimit, dbStop, showTrees; +extern pointList plist2; + +/* + returns true if the group (at x, y) is killable. + if so, returns the point to play at in killx, killy. +*/ + + short me, him, depth, i, j, tryCount, tl, topMark, tkMark, mark2; + char sChar; + sPointList lList, dList; + point tp; + short libList[maxSPoint+1]; + short esc; + +short mtNbrs(x, y) +short x, y; + { /* mtNbrs */ + short n = 0; + if ((x > 0) && (bord[x - 1][y] == 0)) + n = n + 1; + if ((x < maxPoint) && (bord[x + 1][y] == 0)) + n = n + 1; + if ((y > 0) && (bord[x][y - 1] == 0)) + n = n + 1; + if ((y < maxPoint) && (bord[x][y + 1] == 0)) + n = n + 1; + return n; + } /* mtNbrs */ + +short killTree(tx, ty, gx, gy, escape, tkMark) +short tx, ty, gx, gy, *escape, tkMark; + { /* killTree */ + short curMark, mark2, mark3, i, j, k, tl, dStart, result; + sPointList lList1, lList2; + short libList[maxSPoint+1]; + point tp; + short esc = FALSE; + tryCount = tryCount + 1; + if (tryCount > tryLimit) + { + undoTo(tkMark); +/* for (i = 1; i <= depth - 1; i++) + { + sClearChar(sChar, rXor); + } */ + depth = 1; + return FALSE; + } +/* write(sChar); */ + depth = depth + 1; + curMark = playMark; + tryPlay(tx, ty, me); /* try my move */ + pause(); + if (gList[gMap[groupIDs[tx][ty]]].libC == 0) /* I'm dead */ + { + result = FALSE; + goto one; + } + else if (killFlag) /* I killed something of his */ + { + result = TRUE; + goto one; + } + else if (gList[gMap[groupIDs[gx][gy]]].libC > treeLibLim) /* safe */ + { + result = FALSE; + goto one; + } + else + { + sSpanGroup(gx, gy, &lList1); /* find his liberties */ + if (gList[gMap[groupIDs[tx][ty]]].libC == 1) /* he can kill me */ + { + if (lList1.indx < maxSPoint) /* add that option to his list */ + { + lList1.indx = lList1.indx + 1; + spanGroup(tx, ty, &plist2); /* find my liberty */ + lList1.p[lList1.indx].px = plist2.p[1].px; + lList1.p[lList1.indx].py = plist2.p[1].py; + } + else + { + result = FALSE; + goto one; + } + } + for (i = 1; i <= maxSPoint; i++) /* init liblist so diags can be marked */ + libList[i] = -1; + if ((utilPlayLevel > 4) && + (lList1.indx > 1) && + (gList[gMap[groupIDs[gx][gy]]].libC > 1)) /* try diags */ + { + listDiags(gx, gy, &dList); + j = 0; + i = lList1.indx; + while ((j < dList.indx) && + (i < maxSPoint)) + { + j = j + 1; + i = i + 1; + libList[i] = 0; /* mark this as a diag */ + lList1.p[i].px = dList.p[j].px; + lList1.p[i].py = dList.p[j].py; + } + lList1.indx = i; + } + if (lList1.indx > 1) /* sort by decreasing lib count */ + { + for (i = 1; i <= lList1.indx; i++) + if (libList[i] != 0) /* diags are tried last */ + { + mark2 = playMark; + tryPlay(lList1.p[i].px, lList1.p[i].py, him); + libList[i] = gList[gMap[groupIDs[gx][gy]]].libC; + if ((libList[i] > treeLibLim) || + ((libList[i] > (depthLimit - depth)) && + (libList[i] > 2))) + { + *escape = TRUE; + result = FALSE; + goto one; + } + undoTo(mark2); + } + for (i = 1; i <= lList1.indx - 1; i++) + for (j = i + 1; j <= lList1.indx; j++) + if (libList[i] < libList[j]) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = lList1.p[i]; + lList1.p[i] = lList1.p[j]; + lList1.p[j] = tp; + } + } + for (i = 1; i <= lList1.indx + 1; i++) /* try his responses */ + { + mark2 = playMark; + if (i <= lList1.indx) /* try his move */ + { + tryPlay(lList1.p[i].px, lList1.p[i].py, him); /* play his response */ + pause(); + if (gList[gMap[groupIDs[lList1.p[i].px] + [lList1.p[i].py]]].libC < 2) + goto two; /* a bogus move */ + } + else if (gList[gMap[groupIDs[gx][gy]]].libC <= 1) + { + result = TRUE; + goto one; + } + if (gList[gMap[groupIDs[gx][gy]]].libC > treeLibLim) + { + *escape = TRUE; + result = FALSE; + goto one; + } + if (gList[gMap[groupIDs[gx][gy]]].libC > 1) + { /* look at my responses */ + sSpanGroup(gx, gy, &lList2); /* list his liberties */ + dStart = lList2.indx + 1; + if (adjInAtari) /* he wins */ + { + result = FALSE; + goto one; + } + if ((lList2.indx > 2) && adj2Libs) /* he wins */ + { + result = FALSE; + goto one; + } + for (k = 1; k <= maxSPoint; k++) + libList[k] = -1; + if (utilPlayLevel > 4) /* account for diagonal moves */ + { + listDiags(gx, gy, &dList); + j = 0; + k = lList2.indx; + while ((j < dList.indx) && + (k < maxSPoint)) + { + j = j + 1; + k = k + 1; + libList[k] = 100; + lList2.p[k].px = dList.p[j].px; + lList2.p[k].py = dList.p[j].py; + } + lList2.indx = k; + } + if (lList2.indx > 1) /* sort by increasing lib count */ + { + for (k = 1; k <= lList2.indx; k++) + if (libList[k] != 100) /* diags go last */ + { + mark3 = playMark; + tryPlay(lList2.p[k].px, lList2.p[k].py, me); + libList[k] = gList[gMap[groupIDs[gx][gy]]].libC; + undoTo(mark3); + } + for (k = 1; k <= lList2.indx - 1; k++) + for (j = k + 1; j <= lList2.indx; j++) + if (libList[k] > libList[j]) + { + tl = libList[k]; + libList[k] = libList[j]; + libList[j] = tl; + tp = lList2.p[k]; + lList2.p[k] = lList2.p[j]; + lList2.p[j] = tp; + } + else if ((libList[k] == libList[j]) && + (libList[k] == 1)) + if (mtNbrs(lList2.p[k].px, lList2.p[k].py) < + mtNbrs(lList2.p[j].px, lList2.p[j].py)) + { + tl = libList[k]; + libList[k] = libList[j]; + libList[j] = tl; + tp = lList2.p[k]; + lList2.p[k] = lList2.p[j]; + lList2.p[j] = tp; + } + } + for (j = 1; j <= lList2.indx; j++) + { + if (killTree(lList2.p[j].px, lList2.p[j].py, gx, + gy, &esc, tkMark)) + goto two; /* this kills him */ + if (esc && (j >= dStart)) + { + result = FALSE; + goto one; /* don't bother with more diags if escapes */ + } + } + result = FALSE; /* none of my responses kills him */ + goto one; + } + two: + undoTo(mark2); + } + result = TRUE; /* none of his responses saves him */ + } + one: + undoTo(curMark); +/* sClearChar(sChar, rXor); */ + depth = depth - 1; + return result; + } /* killTree */ + +short tKillTree(tx, ty, gx, gy) +short tx, ty, gx, gy; + { /* tKillTree */ + short tkMark, escape; + tryCount = 0; + tkMark = playMark; + return killTree(tx, ty, gx, gy, &escape, tkMark); + } /* tKillTree */ + +short killable(gx, gy, killx, killy) +short gx, gy, *killx, *killy; +{ /* killable */ +#ifdef DEBUG + printf( "killable\n" ); + showTrees = TRUE; +#endif + dbStop = TRUE; + him = bord[gx][gy]; /* find out who I am */ + me = -him; +/* if (me == 1) + sChar = '>'; + else + sChar = '|'; */ +/* write(sChar); */ + depth = 1; + topMark = playMark; + sSpanGroup(gx, gy, &lList); /* find his liberties */ + if (lList.indx == 1) + { + *killx = lList.p[1].px; + *killy = lList.p[1].py; + return TRUE; + } + else if (lList.indx > treeLibLim) + return FALSE; + else if (adjInAtari) + return FALSE; + else if ((lList.indx > 2) && adj2Libs) + return FALSE; + else + { + for (i = 1; i <= maxSPoint; i++) + libList[i] = -1; + if (utilPlayLevel > 4) /* account for diagonal moves */ + { + listDiags(gx, gy, &dList); + j = 0; + i = lList.indx; + while ((j < dList.indx) && + (i < maxSPoint)) + { + j = j + 1; + i = i + 1; + libList[i] = 100; + lList.p[i].px = dList.p[j].px; + lList.p[i].py = dList.p[j].py; + } + lList.indx = i; + } + if (lList.indx > 1) /* sort by increasing lib count */ + { + for (i = 1; i <= lList.indx; i++) + if (libList[i] != 100) /* diags go last */ + { + mark2 = playMark; + tryPlay(lList.p[i].px, lList.p[i].py, me); + libList[i] = gList[gMap[groupIDs[gx][gy]]].libC; + undoTo(mark2); + } + for (i = 1; i <= lList.indx - 1; i++) + for (j = i + 1; j <= lList.indx; j++) + if (libList[i] > libList[j]) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = lList.p[i]; + lList.p[i] = lList.p[j]; + lList.p[j] = tp; + } + else if ((libList[i] == libList[j]) && + (libList[i] == 1)) + if (mtNbrs(lList.p[i].px, lList.p[i].py) < + mtNbrs(lList.p[j].px, lList.p[j].py)) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = lList.p[i]; + lList.p[i] = lList.p[j]; + lList.p[j] = tp; + } + } + for (i = 1; i <= lList.indx; i++) + { + if (legal[lList.p[i].px][lList.p[i].py]) + { + *killx = lList.p[i].px; + *killy = lList.p[i].py; + if (tKillTree(*killx, *killy, gx, gy)) + { +/* sClearChar(sChar, rXor); */ + return TRUE; + } + } + } + return FALSE; + } +/* sClearChar(sChar, rXor); */ +} /* killable */ + diff --git a/noncore/games/go/main.cpp b/noncore/games/go/main.cpp new file mode 100644 index 0000000..c7e2669 --- a/dev/null +++ b/noncore/games/go/main.cpp @@ -0,0 +1,35 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "gowidget.h" + +#include + +#include + +int main( int argc, char ** argv) +{ + QPEApplication app( argc, argv ); + + GoMainWidget m; + m.setCaption( GoWidget::tr("Go") ); + app.showMainWidget( &m ); + return app.exec(); +} diff --git a/noncore/games/go/qpe-go.control b/noncore/games/go/qpe-go.control new file mode 100644 index 0000000..edc106b --- a/dev/null +++ b/noncore/games/go/qpe-go.control @@ -0,0 +1,9 @@ +Files: bin/go apps/Games/go.desktop +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: The game of Go + A game for the Qtopia environment. -- cgit v0.9.0.2