summaryrefslogtreecommitdiff
path: root/noncore/games/go/amigo.c
Unidiff
Diffstat (limited to 'noncore/games/go/amigo.c') (more/less context) (show whitespace changes)
-rw-r--r--noncore/games/go/amigo.c656
1 files changed, 656 insertions, 0 deletions
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 @@
1/* Go started 4/17/88 by Todd R. Johnson */
2/* 8/8/89 cleaned up for first release */
3/* Public Domain */
4
5#include "go.h"
6#include "goplayutils.h"
7#include "amigo.h"
8
9
10 extern char*playReason;
11 extern shortplayLevel, showTrees;
12
13 struct bRec goboard[19][19]; /*-- The main go board --*/
14
15 struct Group GroupList[MAXGROUPS]; /*-- The list of Groups --*/
16 short DeletedGroups[4]; /*-- Codes of deleted groups--*/
17
18 short GroupCount = 0; /*-- The total number of groups--*/
19 short DeletedGroupCount; /*-- The total number of groups--*/
20 /*-- deleted on a move --*/
21 short ko, koX, koY;
22 short blackTerritory,whiteTerritory;
23 short blackPrisoners, whitePrisoners;
24 short showMoveReason= FALSE,
25 groupInfo= FALSE,
26 whitePassed= FALSE,
27 blackPassed= FALSE;
28
29
30/* Arrays for use when checking around a point */
31 short xVec[4] = {0, 1, 0, -1};
32 short yVec[4] = {-1, 0, 1, 0};
33
34short
35member(group, grouplist, cnt)
36 short group;
37 short grouplist[4];
38 short cnt;
39{
40 unsigned shorti;
41
42
43 for (i = 0; i < cnt; i++)
44 if (grouplist[i] == group)
45 return TRUE;
46 return FALSE;
47}
48
49/* Does a stone at x, y connect to any groups of color? */
50short
51Connect( color, x, y, fGroups, fCnt, eGroups, eCnt)
52 enum bValcolor;
53 short x, y;
54 short fGroups[4], eGroups[4];
55 short *fCnt, *eCnt;
56{
57 unsigned shortpoint = 0;
58 short tx, ty, total = 0;
59 enum bValopcolor = WHITE;
60
61
62 *fCnt = 0;
63 *eCnt = 0;
64 if (color == WHITE)
65 opcolor = BLACK;
66 for (point = 0; point <= 3; point++ )
67 {
68 tx = x + xVec[point];
69 ty = y + yVec[point];
70 if (!LegalPoint(tx,ty))
71 continue;
72 if (goboard[tx][ty].Val == color)
73 {
74 total++;
75 if (!member(goboard[tx][ty].GroupNum, fGroups, *fCnt))
76 fGroups[(*fCnt)++] = goboard[tx][ty].GroupNum;
77 }
78 else if (goboard[tx][ty].Val == opcolor)
79 {
80 total++;
81 if (!member(goboard[tx][ty].GroupNum, eGroups, *eCnt))
82 eGroups[(*eCnt)++] = goboard[tx][ty].GroupNum;
83 }
84 }
85 return total;
86}
87
88/* Returns the maximum number of liberties for a given intersection */
89short
90Maxlibs(x, y)
91 shortx, y;
92{
93 shortcnt = 4;
94
95
96 if (x == 0 || x == 18)
97 cnt--;
98 if (y == 0 || y == 18)
99 cnt--;
100 return cnt;
101}
102
103DeleteGroupFromStone(x,y)
104 shortx,y;
105{
106 if (goboard[x][y].Val != EMPTY)
107 GroupCapture(goboard[x][y].GroupNum);
108}
109
110/* Determine whether x, y is suicide for color */
111short
112Suicide(color, x, y)
113 enum bValcolor;
114 short x, y;
115{
116 enum bValopcolor = BLACK;
117 short friendlycnt, friendlygroups[4],
118 enemycnt, enemygroups[4],
119 total;
120 short maxlibs, i, libcnt = 0;
121
122
123 if (color == BLACK)
124 opcolor = WHITE;
125 maxlibs = Maxlibs( x, y);
126 total = Connect(color, x, y, friendlygroups, &friendlycnt,
127 enemygroups, &enemycnt);
128
129 if (total < maxlibs)
130 return FALSE;
131
132 /* Check for a capture */
133 for (i = 0; i < enemycnt; i++)
134 if (GroupList[enemygroups[i]].liberties == 1)
135 return FALSE;
136 for (i = 0; i < friendlycnt; i++)
137 libcnt += (GroupList[friendlygroups[i]].liberties - 1);
138 if (libcnt != 0)
139 return FALSE;
140 return TRUE;
141}
142
143/* Returns the number of liberties for x, y */
144short
145StoneLibs(x, y)
146 short x, y;
147{
148 short cnt = 0, tx, ty;
149 unsigned shortpoint;
150
151
152 for (point = 0; point <= 3; point++)
153 {
154 tx = x + xVec[point];
155 ty = y + yVec[point];
156 if (LegalPoint(tx,ty) && goboard[tx][ty].Val == EMPTY)
157 cnt++;
158 }
159 return cnt;
160}
161
162void
163EraseMarks()
164{
165 register short i;
166 register struct bRec *gpt= &goboard[0][0];
167
168
169 for (i=0; i<361; gpt++,i++)
170 gpt->marked = FALSE;
171}
172
173/* Place a stone of color at x, y */
174short
175GoPlaceStone(color, x, y)
176 enum bValcolor;
177 short x, y;
178{
179 short fgroups[4], egroups[4];/* group codes surrounding stone */
180 shortfcnt, ecnt, i;
181 shortlowest = GroupCount + 1;
182
183
184 DeletedGroupCount = 0;
185 if (goboard[x][y].Val != EMPTY || Suicide(color,x,y))
186 return FALSE;
187
188 if (ko && koX == x && koY == y)
189 return FALSE;
190
191 ko = FALSE;
192 placestone(color, x, y);
193 goboard[x][y].Val = color;
194 /* Does the new stone connect to any friendly stone(s)? */
195 Connect(color, x, y, fgroups, &fcnt, egroups, &ecnt);
196 if (fcnt)
197 {
198 /* Find the connecting friendly group with the lowest code */
199 for (i = 0; i < fcnt; i++)
200 if (fgroups[i] <= lowest)
201 lowest = fgroups[i];
202 /*-- Renumber resulting group --*/
203 /*-- Raise the stone count of the lowest by one to account --*/
204 /*-- for new stone --*/
205 goboard[x][y].GroupNum = lowest;
206 GroupList[lowest].count++;
207 for (i = 0; i < fcnt; i++)
208 if (fgroups[i] != lowest)
209 MergeGroups(lowest, fgroups[i]);
210 /* Fix the liberties of the resulting group */
211 CountLiberties(lowest);
212 }
213 else
214 {
215 /* Isolated stone. Create new group. */
216 GroupCount++;
217 lowest = GroupCount;
218 GroupList[lowest].color = color;
219 GroupList[lowest].count = 1;
220 GroupList[lowest].internal = 0;
221 GroupList[lowest].external = StoneLibs( x, y);
222 GroupList[lowest].liberties = GroupList[lowest].external;
223 GroupList[lowest].eyes = 0;
224 GroupList[lowest].alive = 0;
225 GroupList[lowest].territory = 0;
226 goboard[x][y].GroupNum = lowest;
227 }
228 /* Now fix the liberties of enemy groups adjacent to played stone */
229 FixLibs(color, x, y, PLACED); /* Fix the liberties of opcolor */
230 ReEvalGroups(color, x, y, lowest);
231 RelabelGroups();
232 return TRUE;
233}
234
235/* Remove a stone from the board */
236void
237GoRemoveStone(x, y)
238 shortx, y;
239{
240 goboard[x][y].Val = EMPTY;
241 goboard[x][y].GroupNum = 0;
242 removestone( x, y);
243}
244
245/* Merges two groups -- Renumbers stones and deletes second group from
246list. Fixes stone count of groups. This does not fix anything else.
247FixLibs must be called to fix liberties, etc. */
248void
249MergeGroups(g1, g2)
250 shortg1, g2;
251{
252 shortx, y;
253
254
255 ForeachPoint(y,x)
256 if (goboard[x][y].GroupNum == g2)
257 goboard[x][y].GroupNum = g1;
258 GroupList[g1].count += GroupList[g2].count;
259 DeleteGroup( g2 ); /* Removes group from GroupList */
260}
261
262/* Stores a group code to be deleted */
263void
264DeleteGroup(code)
265 shortcode;
266{
267 DeletedGroups[DeletedGroupCount++] = code;
268}
269
270/* Re-evaluate the groups given the last move. This assumes that the
271last move has been merged into adjoining groups and all liberty counts
272are correct. Handles capture. Checks for Ko. Keeps track of captured
273stones. code is the group number of the stone just played. */
274void
275ReEvalGroups(color, x, y, code)
276 enum bValcolor;
277 short x, y, code;
278{
279 short fgroups[4], egroups[4],
280 fcnt, ecnt, i, killcnt = 0, count = 0;
281 enum bValopcolor = BLACK;
282
283 if (color == BLACK)
284 opcolor = WHITE;
285 /* Check for capture */
286 Connect( color, x, y, fgroups, &fcnt, egroups, &ecnt);
287 if (ecnt)
288 {
289 /* See if any of the groups have no liberties */
290 for (i = 0; i < ecnt; i++)
291 if (GroupList[egroups[i]].liberties == 0)
292 {
293 killcnt++;
294 count = GroupList[egroups[i]].count;
295 GroupCapture( egroups[i]);
296 }
297 }
298 /* Check for ko. koX and koY are set in GroupCapture above. */
299 if (killcnt == 1 && count == 1 && GroupList[ code ].count == 1
300 && GroupList[ code ].liberties == 1)
301 {
302 ko = TRUE;
303 }
304 if (killcnt)
305 intrPrisonerReport( blackPrisoners, whitePrisoners);
306 /* Set eye count for groups */
307 CountEyes();
308}
309
310/* Remove a captured group from the board and fix the liberties of any
311 adjacent groups. Fixes prisoner count. Sets KoX and KoY */
312/*-- update display of captured stones -neilb --*/
313void
314GroupCapture(code)
315 shortcode;
316{
317 shortx, y;
318
319 if (GroupList[code].color == BLACK)
320 blackPrisoners += GroupList[code].count;
321 else
322 whitePrisoners += GroupList[code].count;
323 intrPrisonerReport(blackPrisoners, whitePrisoners);
324 ForeachPoint(y,x)
325 if (goboard[x][y].GroupNum == code)
326 {
327 FixLibs(GroupList[code].color,x,y,REMOVED);
328 GoRemoveStone(x, y);
329 koX = x;
330 koY = y;
331 }
332 DeleteGroup( code);
333}
334
335/* Fix the liberties of groups adjacent to x, y. move indicates
336 whether a stone of color was placed or removed at x, y
337 This does not change liberty counts of friendly groups when a stone
338 is placed. Does not do captures. */
339void
340FixLibs( color, x, y, move)
341 enumbVal color;
342 shortx, y, move;
343{
344 shortfgroups[4], fcnt, egroups[4], ecnt, i;
345 enumbVal opcolor = BLACK;
346
347 if (color == BLACK)
348 opcolor = WHITE;
349 Connect( color, x, y, fgroups, &fcnt, egroups, &ecnt);
350 if (move == PLACED)
351 for (i = 0; i < ecnt; i++)
352 GroupList[egroups[i]].liberties--;
353 else /* Stone removed so increment opcolor */
354 for (i = 0; i < ecnt; i++)
355 GroupList[egroups[i]].liberties++;
356}
357
358void
359goSetHandicap(handicap)
360 int handicap;
361{
362 if (handicap < 2)
363 return;
364
365 GoPlaceStone(BLACK,3,3);
366 GoPlaceStone(BLACK,15,15);
367
368 if (handicap >= 3)
369 GoPlaceStone(BLACK,15,3);
370 if (handicap >= 4)
371 GoPlaceStone(BLACK,3,15);
372 if (handicap == 5 || handicap == 7 || handicap == 9)
373 GoPlaceStone(BLACK,9,9);
374 if (handicap >= 6)
375 {
376 GoPlaceStone(BLACK,15,9);
377 GoPlaceStone(BLACK,3,9);
378 }
379 if (handicap >= 8)
380 {
381 GoPlaceStone(BLACK,9,15);
382 GoPlaceStone(BLACK,9,3);
383 }
384}
385
386void
387goRestart(handicap)
388 inthandicap;
389{
390 register short i;
391 register struct bRec *gpt= &goboard[0][0];
392
393
394 GroupCount = 0;
395 ko = FALSE;
396 blackPrisoners = whitePrisoners = 0;
397 intrPrisonerReport(0, 0);
398 for (i=0; i<361; gpt++,i++)
399 {
400 gpt->Val = EMPTY;
401 gpt->GroupNum = 0;
402 }
403 goSetHandicap(handicap);
404}
405
406
407/* if any groups have been deleted as a result of the last move, this
408 routine will delete the old group numbers from GroupList and
409 reassign group numbers. */
410void
411RelabelGroups()
412{
413 unsignedshort i, j, x, y;
414
415 for (i = 0; i < DeletedGroupCount; i++)
416 {
417 /* Relabel all higher groups */
418 ForeachPoint(y,x)
419 if (goboard[x][y].GroupNum > DeletedGroups[i])
420 goboard[x][y].GroupNum--;
421 /* Move the groups down */
422 for (y = DeletedGroups[i]; y < GroupCount; y++)
423 GroupList[y] = GroupList[y+1];
424 /* fix the group numbers stored in the deleted list */
425 for (j = i+1; j < DeletedGroupCount; j++)
426 if (DeletedGroups[j] > DeletedGroups[i])
427 DeletedGroups[j]--;
428 GroupCount--;
429 }
430}
431
432/* Returns liberty count for x, y intersection. Sets marked to true
433 for each liberty */
434short
435CountAndMarkLibs( x, y)
436 shortx, y;
437{
438 shorttx,ty,i;
439 shortcnt = 0;
440
441
442 for (i=0;i<4;i++)
443 {
444 tx = x + xVec[i];
445 ty = y + yVec[i];
446 if (LegalPoint(tx,ty) && goboard[tx][ty].Val == EMPTY
447 && goboard[tx][ty].marked == FALSE)
448 {
449 cnt++;
450 goboard[tx][ty].marked = TRUE;
451 }
452 }
453 return cnt;
454}
455
456/* Determine the number of liberties for a group given the group code
457 num */
458void
459CountLiberties( code)
460 shortcode;
461{
462 shortx, y, libcnt = 0;
463
464 ForeachPoint(y,x)
465 if (goboard[x][y].GroupNum == code)
466 libcnt += CountAndMarkLibs( x, y);
467 EraseMarks();
468 GroupList[code].liberties = libcnt;
469}
470
471void
472CheckForEye( x, y, groups, cnt, recheck)
473 shortx, y, groups[4], cnt, *recheck;
474{
475 shorti;
476
477 for (i = 0; i < (cnt-1); i++)
478 if (groups[i] != groups[i+1])
479 {
480 /* Mark liberty for false eye check */
481 goboard[x][y].marked = TRUE;
482 (*recheck)++;
483 return;
484 }
485 /* It is an eye */
486 GroupList[groups[i]].eyes += 1;
487}
488
489/* Set the eye count for the groups */
490void CountEyes()
491{
492 shorti, x, y,
493 wgroups[4], bgroups[4], wcnt, bcnt, max, cnt, recheck = 0, eye;
494
495 for (i = 1; i <= GroupCount; i++)
496 GroupList[i].eyes = 0;
497
498 ForeachPoint(y,x)
499 {
500 if (goboard[x][y].Val != EMPTY)
501 continue;
502 cnt = Connect(WHITE,x,y,wgroups,&wcnt,bgroups,&bcnt);
503 max = Maxlibs( x, y);
504 if (cnt == max && wcnt == 1 && bcnt == 0)
505 GroupList[wgroups[0]].eyes++;
506 else if (cnt == max && bcnt == 1 && wcnt == 0)
507 GroupList[bgroups[0]].eyes++;
508 else if (cnt == max && ( bcnt == 0 || wcnt == 0 ))
509 {
510 goboard[x][y].marked = TRUE;
511 recheck++;
512 }
513 }
514
515 /*-- Now recheck marked liberties to see if two or more one eye --*/
516 /*-- groups contribute to a false eye */
517 if (recheck == 0)
518 return;
519
520 ForeachPoint(y,x)
521 if (goboard[x][y].marked)
522 {
523 recheck--;
524 goboard[x][y].marked = FALSE;
525 Connect( WHITE, x, y, wgroups, &wcnt, bgroups, &bcnt);
526 /* If all the groups have at least one eye then all the
527 groups are safe from capture because of the common
528 liberty at x, y */
529 eye = TRUE;
530 for (i = 0; i < wcnt; i++)
531 if (GroupList[wgroups[i]].eyes == 0)
532 eye = FALSE;
533 if (eye)
534 for (i = 0; i < wcnt; i++)
535 GroupList[wgroups[i]].eyes++;
536 for (i = 0; i < bcnt; i++)
537 if (GroupList[bgroups[i]].eyes == 0)
538 eye = FALSE;
539 if (eye)
540 for (i = 0; i < bcnt; i++)
541 GroupList[bgroups[i]].eyes++;
542 if (recheck == 0)
543 return;
544 }
545}
546
547
548 shortfoo[19][19];
549
550/*----------------------------------------------------------------
551 -- CountUp() --
552 -- Count up final scores at the end of the game. --
553----------------------------------------------------------------*/
554CountUp( wtotal, btotal )
555 int *wtotal, *btotal;
556{
557 shortx,y;
558 shortCountFromPoint();
559 shortvv;
560 charbuff[512];
561
562
563 blackTerritory = whiteTerritory = 0;
564 ForeachPoint(y,x)
565 {
566 goboard[x][y].marked = FALSE;
567 foo[x][y] = CNT_UNDECIDED;
568 }
569 ForeachPoint(y,x)
570 if (goboard[x][y].Val==EMPTY && foo[x][y]==CNT_UNDECIDED)
571 {
572 FillPoints(x,y,CountFromPoint(x,y));
573 }
574
575 *wtotal = whiteTerritory + blackPrisoners;
576 *btotal = blackTerritory + whitePrisoners;
577 /*
578 sprintf(buff,"White : %3d territory + %3d prisoners = %d\n\
579Black : %3d territory + %3d prisoners = %d\n\n%s.\n",
580 whiteTerritory,blackPrisoners,*wtotal,
581 blackTerritory,whitePrisoners,*btotal,
582 (*btotal>*wtotal?"Black wins":(*wtotal>*btotal?"White wins":
583 "A draw")));
584
585
586
587 XtVaSetValues(message,XtNstring,buff,0);
588 printf( "CountUp() %s", buff );
589 */
590}
591
592FillPoints(x,y,val)
593 shortx,y,val;
594{
595 inti;
596 shorttx,ty;
597
598
599 if ((foo[x][y] = val) == CNT_BLACK_TERR)
600 blackTerritory++;
601 else if (val == CNT_WHITE_TERR)
602 whiteTerritory++;
603 for (i=0;i<4;i++)
604 {
605 tx = x + xVec[i];
606 ty = y + yVec[i];
607 if (!LegalPoint(tx,ty))
608 continue;
609 if (goboard[tx][ty].Val==EMPTY && foo[tx][ty]==CNT_UNDECIDED)
610 FillPoints(tx,ty,val);
611 }
612}
613
614short
615CountFromPoint(x,y)
616 shortx,y;
617{
618 inti;
619 shorttx,ty;
620 shortblkcnt=0,whtcnt=0;
621 shortbaz;
622
623
624 goboard[x][y].marked = TRUE;
625 for (i=0;i<4;i++)
626 {
627 tx = x + xVec[i];
628 ty = y + yVec[i];
629 if (!LegalPoint(tx,ty))
630 continue;
631 if (goboard[tx][ty].Val == BLACK)
632 blkcnt++;
633 else if (goboard[tx][ty].Val == WHITE)
634 whtcnt++;
635 else
636 {
637 if (goboard[tx][ty].marked)
638 continue;
639 baz = CountFromPoint(tx,ty);
640 if (baz == CNT_NOONE)
641 return CNT_NOONE;
642 else if (baz == CNT_BLACK_TERR)
643 blkcnt++;
644 else if (baz == CNT_WHITE_TERR)
645 whtcnt++;
646 }
647 if (blkcnt && whtcnt)
648 return CNT_NOONE;
649 }
650 if (blkcnt && !whtcnt)
651 return CNT_BLACK_TERR;
652 else if (whtcnt && !blkcnt)
653 return CNT_WHITE_TERR;
654 else
655 return CNT_UNDECIDED;
656}