]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - gomoku/pickmove.c
1 /* $NetBSD: pickmove.c,v 1.17 2009/06/04 06:41:50 dholland Exp $ */
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
38 static char sccsid
[] = "@(#)pickmove.c 8.2 (Berkeley) 5/3/95";
40 __RCSID("$NetBSD: pickmove.c,v 1.17 2009/06/04 06:41:50 dholland Exp $");
51 #define BITS_PER_INT (sizeof(int) * CHAR_BIT)
52 #define MAPSZ (BAREA / BITS_PER_INT)
54 #define BIT_SET(a, b) ((a)[(b)/BITS_PER_INT] |= (1 << ((b) % BITS_PER_INT)))
55 #define BIT_CLR(a, b) ((a)[(b)/BITS_PER_INT] &= ~(1 << ((b) % BITS_PER_INT)))
56 #define BIT_TEST(a, b) ((a)[(b)/BITS_PER_INT] & (1 << ((b) % BITS_PER_INT)))
58 struct combostr
*hashcombos
[FAREA
]; /* hash list for finding duplicates */
59 struct combostr
*sortcombos
; /* combos at higher levels */
60 int combolen
; /* number of combos in sortcombos */
61 int nextcolor
; /* color of next move */
62 int elistcnt
; /* count of struct elist allocated */
63 int combocnt
; /* count of struct combostr allocated */
64 int forcemap
[MAPSZ
]; /* map for blocking <1,x> combos */
65 int tmpmap
[MAPSZ
]; /* map for blocking <1,x> combos */
66 int nforce
; /* count of opponent <1,x> combos */
71 struct spotstr
*sp
, *sp1
, *sp2
;
72 union comboval
*Ocp
, *Tcp
;
75 /* first move is easy */
79 /* initialize all the board values */
80 for (sp
= &board
[PT(T
,20)]; --sp
>= &board
[PT(A
,1)]; ) {
81 sp
->s_combo
[BLACK
].s
= MAXCOMBO
+ 1;
82 sp
->s_combo
[WHITE
].s
= MAXCOMBO
+ 1;
83 sp
->s_level
[BLACK
] = 255;
84 sp
->s_level
[WHITE
] = 255;
85 sp
->s_nforce
[BLACK
] = 0;
86 sp
->s_nforce
[WHITE
] = 0;
87 sp
->s_flags
&= ~(FFLAGALL
| MFLAGALL
);
90 memset(forcemap
, 0, sizeof(forcemap
));
92 /* compute new values */
97 /* find the spot with the highest value */
98 for (sp
= sp1
= sp2
= &board
[PT(T
,19)]; --sp
>= &board
[PT(A
,1)]; ) {
99 if (sp
->s_occ
!= EMPTY
)
101 if (debug
&& (sp
->s_combo
[BLACK
].c
.a
== 1 ||
102 sp
->s_combo
[WHITE
].c
.a
== 1)) {
103 debuglog("- %s %x/%d %d %x/%d %d %d", stoc(sp
- board
),
104 sp
->s_combo
[BLACK
].s
, sp
->s_level
[BLACK
],
106 sp
->s_combo
[WHITE
].s
, sp
->s_level
[WHITE
],
110 /* pick the best black move */
111 if (better(sp
, sp1
, BLACK
))
113 /* pick the best white move */
114 if (better(sp
, sp2
, WHITE
))
119 debuglog("B %s %x/%d %d %x/%d %d %d",
121 sp1
->s_combo
[BLACK
].s
, sp1
->s_level
[BLACK
],
122 sp1
->s_nforce
[BLACK
],
123 sp1
->s_combo
[WHITE
].s
, sp1
->s_level
[WHITE
],
124 sp1
->s_nforce
[WHITE
], sp1
->s_wval
);
125 debuglog("W %s %x/%d %d %x/%d %d %d",
127 sp2
->s_combo
[WHITE
].s
, sp2
->s_level
[WHITE
],
128 sp2
->s_nforce
[WHITE
],
129 sp2
->s_combo
[BLACK
].s
, sp2
->s_level
[BLACK
],
130 sp2
->s_nforce
[BLACK
], sp2
->s_wval
);
132 * Check for more than one force that can't
133 * all be blocked with one move.
135 sp
= (us
== BLACK
) ? sp2
: sp1
;
137 if (sp
->s_combo
[!us
].c
.a
== 1 && !BIT_TEST(forcemap
, m
))
138 debuglog("*** Can't be blocked");
141 Ocp
= &sp1
->s_combo
[BLACK
];
142 Tcp
= &sp2
->s_combo
[WHITE
];
144 Tcp
= &sp1
->s_combo
[BLACK
];
145 Ocp
= &sp2
->s_combo
[WHITE
];
151 * Block their combo only if we have to (i.e., if they are one move
152 * away from completing a force and we don't have a force that
153 * we can complete which takes fewer moves to win).
155 if (Tcp
->c
.a
<= 1 && (Ocp
->c
.a
> 1 ||
156 Tcp
->c
.a
+ Tcp
->c
.b
< Ocp
->c
.a
+ Ocp
->c
.b
))
157 return (sp2
- board
);
158 return (sp1
- board
);
162 * Return true if spot 'sp' is better than spot 'sp1' for color 'us'.
165 better(const struct spotstr
*sp
, const struct spotstr
*sp1
, int us
)
169 if (sp
->s_combo
[us
].s
< sp1
->s_combo
[us
].s
)
171 if (sp
->s_combo
[us
].s
!= sp1
->s_combo
[us
].s
)
173 if (sp
->s_level
[us
] < sp1
->s_level
[us
])
175 if (sp
->s_level
[us
] != sp1
->s_level
[us
])
177 if (sp
->s_nforce
[us
] > sp1
->s_nforce
[us
])
179 if (sp
->s_nforce
[us
] != sp1
->s_nforce
[us
])
185 if (BIT_TEST(forcemap
, s
) && !BIT_TEST(forcemap
, s1
))
187 if (!BIT_TEST(forcemap
, s
) && BIT_TEST(forcemap
, s1
))
189 if (sp
->s_combo
[them
].s
< sp1
->s_combo
[them
].s
)
191 if (sp
->s_combo
[them
].s
!= sp1
->s_combo
[them
].s
)
193 if (sp
->s_level
[them
] < sp1
->s_level
[them
])
195 if (sp
->s_level
[them
] != sp1
->s_level
[them
])
197 if (sp
->s_nforce
[them
] > sp1
->s_nforce
[them
])
199 if (sp
->s_nforce
[them
] != sp1
->s_nforce
[them
])
202 if (sp
->s_wval
> sp1
->s_wval
)
204 if (sp
->s_wval
!= sp1
->s_wval
)
210 return (random() & 1);
214 int curcolor
; /* implicit parameter to makecombo() */
215 int curlevel
; /* implicit parameter to makecombo() */
218 * Scan the sorted list of non-empty frames and
219 * update the minimum combo values for each empty spot.
220 * Also, try to combine frames to find more complex (chained) moves.
223 scanframes(int color
)
225 struct combostr
*cbp
, *ecbp
;
228 struct elist
*ep
, *nep
;
234 /* check for empty list of frames */
235 cbp
= sortframes
[color
];
236 if (cbp
== (struct combostr
*)0)
239 /* quick check for four in a row */
240 sp
= &board
[cbp
->c_vertex
];
241 cb
.s
= sp
->s_fval
[color
][d
= cbp
->c_dir
].s
;
244 for (i
= 5 + cb
.c
.b
; --i
>= 0; sp
+= d
) {
245 if (sp
->s_occ
!= EMPTY
)
247 sp
->s_combo
[color
].s
= cb
.s
;
248 sp
->s_level
[color
] = 1;
254 * Update the minimum combo value for each spot in the frame
255 * and try making all combinations of two frames intersecting at
261 sp
= &board
[cbp
->c_vertex
];
262 cp
= &sp
->s_fval
[color
][r
= cbp
->c_dir
];
266 * Since this is the first spot of an open ended
267 * frame, we treat it as a closed frame.
269 cb
.c
.a
= cp
->c
.a
+ 1;
271 if (cb
.s
< sp
->s_combo
[color
].s
) {
272 sp
->s_combo
[color
].s
= cb
.s
;
273 sp
->s_level
[color
] = 1;
276 * Try combining other frames that intersect
279 makecombo2(cbp
, sp
, 0, cb
.s
);
282 else if (color
!= nextcolor
)
283 memset(tmpmap
, 0, sizeof(tmpmap
));
290 for (; i
< 5; i
++, sp
+= d
) { /* for each spot */
291 if (sp
->s_occ
!= EMPTY
)
293 if (cp
->s
< sp
->s_combo
[color
].s
) {
294 sp
->s_combo
[color
].s
= cp
->s
;
295 sp
->s_level
[color
] = 1;
297 if (cp
->s
== 0x101) {
298 sp
->s_nforce
[color
]++;
299 if (color
!= nextcolor
) {
305 * Try combining other frames that intersect
308 makecombo2(cbp
, sp
, i
, cb
.s
);
310 if (cp
->s
== 0x101 && color
!= nextcolor
) {
312 memcpy(forcemap
, tmpmap
, sizeof(tmpmap
));
314 for (i
= 0; (unsigned int)i
< MAPSZ
; i
++)
315 forcemap
[i
] &= tmpmap
[i
];
318 /* mark frame as having been processed */
319 board
[cbp
->c_vertex
].s_flags
|= MFLAG
<< r
;
320 } while ((cbp
= cbp
->c_next
) != ecbp
);
323 * Try to make new 3rd level combos, 4th level, etc.
324 * Limit the search depth early in the game.
327 while (d
<= ((movenum
+ 1) >> 1) && combolen
> n
) {
329 debuglog("%cL%d %d %d %d", "BW"[color
],
330 d
, combolen
- n
, combocnt
, elistcnt
);
338 /* scan for combos at empty spots */
339 for (sp
= &board
[PT(T
,20)]; --sp
>= &board
[PT(A
,1)]; ) {
340 for (ep
= sp
->s_empty
; ep
; ep
= nep
) {
342 if (cbp
->c_combo
.s
<= sp
->s_combo
[color
].s
) {
343 if (cbp
->c_combo
.s
!= sp
->s_combo
[color
].s
) {
344 sp
->s_combo
[color
].s
= cbp
->c_combo
.s
;
345 sp
->s_level
[color
] = cbp
->c_nframes
;
346 } else if (cbp
->c_nframes
< sp
->s_level
[color
])
347 sp
->s_level
[color
] = cbp
->c_nframes
;
353 sp
->s_empty
= (struct elist
*)0;
354 for (ep
= sp
->s_nempty
; ep
; ep
= nep
) {
356 if (cbp
->c_combo
.s
<= sp
->s_combo
[color
].s
) {
357 if (cbp
->c_combo
.s
!= sp
->s_combo
[color
].s
) {
358 sp
->s_combo
[color
].s
= cbp
->c_combo
.s
;
359 sp
->s_level
[color
] = cbp
->c_nframes
;
360 } else if (cbp
->c_nframes
< sp
->s_level
[color
])
361 sp
->s_level
[color
] = cbp
->c_nframes
;
367 sp
->s_nempty
= (struct elist
*)0;
370 /* remove old combos */
371 if ((cbp
= sortcombos
) != (struct combostr
*)0) {
372 struct combostr
*ncbp
;
380 } while ((cbp
= ncbp
) != ecbp
);
381 sortcombos
= (struct combostr
*)0;
387 debuglog("scanframes: %c combocnt %d", "BW"[color
],
392 debuglog("scanframes: %c elistcnt %d", "BW"[color
],
400 * Compute all level 2 combos of frames intersecting spot 'osp'
401 * within the frame 'ocbp' and combo value 's'.
404 makecombo2(struct combostr
*ocbp
, struct spotstr
*osp
, int off
, int s
)
407 struct combostr
*ncbp
;
409 int baseB
, fcnt
, emask
, bmask
, n
;
410 union comboval ocb
, fcb
;
411 struct combostr
**scbpp
, *fcbp
;
414 /* try to combine a new frame with those found so far */
416 baseB
= ocb
.c
.a
+ ocb
.c
.b
- 1;
418 emask
= fcnt
? ((ocb
.c
.b
? 0x1E : 0x1F) & ~(1 << off
)) : 0;
419 for (r
= 4; --r
>= 0; ) { /* for each direction */
420 /* don't include frames that overlap in the same direction */
421 if (r
== ocbp
->c_dir
)
425 * Frame A combined with B is the same value as B combined with A
426 * so skip frames that have already been processed (MFLAG).
427 * Also skip blocked frames (BFLAG) and frames that are <1,x>
428 * since combining another frame with it isn't valid.
430 bmask
= (BFLAG
| FFLAG
| MFLAG
) << r
;
432 for (f
= 0; f
< 5; f
++, fsp
-= d
) { /* for each frame */
433 if (fsp
->s_occ
== BORDER
)
435 if (fsp
->s_flags
& bmask
)
438 /* don't include frames of the wrong color */
439 fcb
.s
= fsp
->s_fval
[curcolor
][r
].s
;
444 * Get the combo value for this frame.
445 * If this is the end point of the frame,
446 * use the closed ended value for the frame.
448 if ((f
== 0 && fcb
.c
.b
) || fcb
.s
== 0x101) {
453 /* compute combo value */
454 c
= fcb
.c
.a
+ ocb
.c
.a
- 3;
457 n
= fcb
.c
.a
+ fcb
.c
.b
- 1;
461 /* make a new combo! */
462 ncbp
= (struct combostr
*)malloc(sizeof(struct combostr
) +
463 2 * sizeof(struct combostr
*));
465 panic("Out of memory!");
466 scbpp
= (struct combostr
**)(ncbp
+ 1);
467 fcbp
= fsp
->s_frame
[r
];
475 ncbp
->c_combo
.c
.a
= c
;
476 ncbp
->c_combo
.c
.b
= n
;
477 ncbp
->c_link
[0] = ocbp
;
478 ncbp
->c_link
[1] = fcbp
;
479 ncbp
->c_linkv
[0].s
= ocb
.s
;
480 ncbp
->c_linkv
[1].s
= fcb
.s
;
481 ncbp
->c_voff
[0] = off
;
483 ncbp
->c_vertex
= osp
- board
;
486 ncbp
->c_frameindex
= 0;
487 ncbp
->c_flags
= (ocb
.c
.b
) ? C_OPEN_0
: 0;
489 ncbp
->c_flags
|= C_OPEN_1
;
490 ncbp
->c_framecnt
[0] = fcnt
;
491 ncbp
->c_emask
[0] = emask
;
492 ncbp
->c_framecnt
[1] = fcb
.c
.a
- 2;
493 ncbp
->c_emask
[1] = ncbp
->c_framecnt
[1] ?
494 ((fcb
.c
.b
? 0x1E : 0x1F) & ~(1 << f
)) : 0;
497 if ((c
== 1 && debug
> 1) || debug
> 3) {
498 debuglog("%c c %d %d m %x %x o %d %d",
500 ncbp
->c_framecnt
[0], ncbp
->c_framecnt
[1],
501 ncbp
->c_emask
[0], ncbp
->c_emask
[1],
502 ncbp
->c_voff
[0], ncbp
->c_voff
[1]);
503 printcombo(ncbp
, tmp
, sizeof(tmp
));
507 /* record the empty spots that will complete this combo */
510 /* add the new combo to the end of the list */
511 appendcombo(ncbp
, curcolor
);
513 updatecombo(ncbp
, curcolor
);
518 if (c
== 1 && debug
> 1 || debug
> 5) {
530 * Scan the sorted list of frames and try to add a frame to
531 * combinations of 'level' number of frames.
536 struct combostr
*cbp
, *ecbp
;
537 struct spotstr
*sp
, *fsp
;
538 struct elist
*ep
, *nep
;
540 struct combostr
**cbpp
, *pcbp
;
541 union comboval fcb
, cb
;
545 /* scan for combos at empty spots */
547 for (sp
= &board
[PT(T
,20)]; --sp
>= &board
[PT(A
,1)]; ) {
548 for (ep
= sp
->s_empty
; ep
; ep
= nep
) {
550 if (cbp
->c_combo
.s
<= sp
->s_combo
[i
].s
) {
551 if (cbp
->c_combo
.s
!= sp
->s_combo
[i
].s
) {
552 sp
->s_combo
[i
].s
= cbp
->c_combo
.s
;
553 sp
->s_level
[i
] = cbp
->c_nframes
;
554 } else if (cbp
->c_nframes
< sp
->s_level
[i
])
555 sp
->s_level
[i
] = cbp
->c_nframes
;
561 sp
->s_empty
= sp
->s_nempty
;
562 sp
->s_nempty
= (struct elist
*)0;
565 /* try to add frames to the uncompleted combos at level curlevel */
566 cbp
= ecbp
= sortframes
[curcolor
];
568 fsp
= &board
[cbp
->c_vertex
];
570 /* skip frames that are part of a <1,x> combo */
571 if (fsp
->s_flags
& (FFLAG
<< r
))
575 * Don't include <1,x> combo frames,
576 * treat it as a closed three in a row instead.
578 fcb
.s
= fsp
->s_fval
[curcolor
][r
].s
;
583 * If this is an open ended frame, use
584 * the combo value with the end closed.
586 if (fsp
->s_occ
== EMPTY
) {
588 cb
.c
.a
= fcb
.c
.a
+ 1;
592 makecombo(cbp
, fsp
, 0, cb
.s
);
596 * The next four spots are handled the same for both
597 * open and closed ended frames.
601 for (i
= 1; i
< 5; i
++, sp
+= d
) {
602 if (sp
->s_occ
!= EMPTY
)
604 makecombo(cbp
, sp
, i
, fcb
.s
);
606 } while ((cbp
= cbp
->c_next
) != ecbp
);
608 /* put all the combos in the hash list on the sorted list */
609 cbpp
= &hashcombos
[FAREA
];
612 if (cbp
== (struct combostr
*)0)
614 *cbpp
= (struct combostr
*)0;
616 if (ecbp
== (struct combostr
*)0)
619 /* append to sort list */
622 ecbp
->c_prev
= cbp
->c_prev
;
623 cbp
->c_prev
->c_next
= ecbp
;
626 } while (cbpp
!= hashcombos
);
630 * Compute all level N combos of frames intersecting spot 'osp'
631 * within the frame 'ocbp' and combo value 's'.
634 makecombo(struct combostr
*ocbp
, struct spotstr
*osp
, int off
, int s
)
636 struct combostr
*cbp
, *ncbp
;
641 struct combostr
**scbpp
;
642 int baseB
, fcnt
, emask
, verts
;
644 struct overlap_info vertices
[1];
648 baseB
= ocb
.c
.a
+ ocb
.c
.b
- 1;
650 emask
= fcnt
? ((ocb
.c
.b
? 0x1E : 0x1F) & ~(1 << off
)) : 0;
651 for (ep
= osp
->s_empty
; ep
; ep
= ep
->e_next
) {
652 /* check for various kinds of overlap */
654 verts
= checkframes(cbp
, ocbp
, osp
, s
, vertices
);
658 /* check to see if this frame forms a valid loop */
660 sp
= &board
[vertices
[0].o_intersect
];
662 if (sp
->s_occ
!= EMPTY
) {
663 debuglog("loop: %c %s", "BW"[curcolor
],
669 * It is a valid loop if the intersection spot
670 * of the frame we are trying to attach is one
671 * of the completion spots of the combostr
672 * we are trying to attach the frame to.
674 for (nep
= sp
->s_empty
; nep
; nep
= nep
->e_next
) {
675 if (nep
->e_combo
== cbp
)
677 if (nep
->e_combo
->c_nframes
< cbp
->c_nframes
)
680 /* frame overlaps but not at a valid spot */
686 /* compute the first half of the combo value */
687 c
= cbp
->c_combo
.c
.a
+ ocb
.c
.a
- verts
- 3;
691 /* compute the second half of the combo value */
692 n
= ep
->e_fval
.c
.a
+ ep
->e_fval
.c
.b
- 1;
696 /* make a new combo! */
697 ncbp
= (struct combostr
*)malloc(sizeof(struct combostr
) +
698 (cbp
->c_nframes
+ 1) * sizeof(struct combostr
*));
700 panic("Out of memory!");
701 scbpp
= (struct combostr
**)(ncbp
+ 1);
702 if (sortcombo(scbpp
, (struct combostr
**)(cbp
+ 1), ocbp
)) {
708 ncbp
->c_combo
.c
.a
= c
;
709 ncbp
->c_combo
.c
.b
= n
;
710 ncbp
->c_link
[0] = cbp
;
711 ncbp
->c_link
[1] = ocbp
;
712 ncbp
->c_linkv
[1].s
= ocb
.s
;
713 ncbp
->c_voff
[1] = off
;
714 ncbp
->c_vertex
= osp
- board
;
715 ncbp
->c_nframes
= cbp
->c_nframes
+ 1;
716 ncbp
->c_flags
= ocb
.c
.b
? C_OPEN_1
: 0;
717 ncbp
->c_frameindex
= ep
->e_frameindex
;
719 * Update the completion spot mask of the frame we
720 * are attaching 'ocbp' to so the intersection isn't
723 ncbp
->c_framecnt
[0] = ep
->e_framecnt
;
724 ncbp
->c_emask
[0] = ep
->e_emask
;
726 ncbp
->c_flags
|= C_LOOP
;
727 ncbp
->c_dir
= vertices
[0].o_frameindex
;
728 ncbp
->c_framecnt
[1] = fcnt
- 1;
729 if (ncbp
->c_framecnt
[1]) {
730 n
= (vertices
[0].o_intersect
- ocbp
->c_vertex
) /
732 ncbp
->c_emask
[1] = emask
& ~(1 << n
);
734 ncbp
->c_emask
[1] = 0;
735 ncbp
->c_voff
[0] = vertices
[0].o_off
;
738 ncbp
->c_framecnt
[1] = fcnt
;
739 ncbp
->c_emask
[1] = emask
;
740 ncbp
->c_voff
[0] = ep
->e_off
;
743 if ((c
== 1 && debug
> 1) || debug
> 3) {
744 debuglog("%c v%d i%d d%d c %d %d m %x %x o %d %d",
745 "bw"[curcolor
], verts
, ncbp
->c_frameindex
, ncbp
->c_dir
,
746 ncbp
->c_framecnt
[0], ncbp
->c_framecnt
[1],
747 ncbp
->c_emask
[0], ncbp
->c_emask
[1],
748 ncbp
->c_voff
[0], ncbp
->c_voff
[1]);
749 printcombo(ncbp
, tmp
, sizeof(tmp
));
753 /* record the empty spots that will complete this combo */
757 /* update board values */
758 updatecombo(ncbp
, curcolor
);
761 if (c
== 1 && debug
> 1 || debug
> 4) {
772 struct elist einfo
[MAXDEPTH
];
773 struct combostr
*ecombo
[MAXDEPTH
]; /* separate from elist to save space */
776 * Add the combostr 'ocbp' to the empty spots list for each empty spot
777 * in 'ocbp' that will complete the combo.
780 makeempty(struct combostr
*ocbp
)
782 struct combostr
*cbp
, *tcbp
, **cbpp
;
783 struct elist
*ep
, *nep
;
785 int s
, d
, m
, emask
, i
;
790 printcombo(ocbp
, tmp
, sizeof(tmp
));
791 debuglog("E%c %s", "bw"[curcolor
], tmp
);
794 /* should never happen but check anyway */
795 if ((nframes
= ocbp
->c_nframes
) >= MAXDEPTH
)
799 * The lower level combo can be pointed to by more than one
800 * higher level 'struct combostr' so we can't modify the
801 * lower level. Therefore, higher level combos store the
802 * real mask of the lower level frame in c_emask[0] and the
803 * frame number in c_frameindex.
805 * First we traverse the tree from top to bottom and save the
806 * connection info. Then we traverse the tree from bottom to
807 * top overwriting lower levels with the newer emask information.
809 ep
= &einfo
[nframes
];
810 cbpp
= &ecombo
[nframes
];
811 for (cbp
= ocbp
; (tcbp
= cbp
->c_link
[1]) != NULL
;
812 cbp
= cbp
->c_link
[0]) {
815 *--cbpp
= cbp
->c_link
[1];
816 ep
->e_off
= cbp
->c_voff
[1];
817 ep
->e_frameindex
= cbp
->c_frameindex
;
818 ep
->e_fval
.s
= cbp
->c_linkv
[1].s
;
819 ep
->e_framecnt
= cbp
->c_framecnt
[1];
820 ep
->e_emask
= cbp
->c_emask
[1];
825 *--cbpp
= cbp
->c_link
[0];
826 ep
->e_off
= cbp
->c_voff
[0];
827 ep
->e_frameindex
= 0;
828 ep
->e_fval
.s
= cbp
->c_linkv
[0].s
;
829 ep
->e_framecnt
= cbp
->c_framecnt
[0];
830 ep
->e_emask
= cbp
->c_emask
[0];
832 /* now update the emask info */
834 for (i
= 2, ep
+= 2; i
< nframes
; i
++, ep
++) {
836 nep
= &einfo
[ep
->e_frameindex
];
837 nep
->e_framecnt
= cbp
->c_framecnt
[0];
838 nep
->e_emask
= cbp
->c_emask
[0];
840 if (cbp
->c_flags
& C_LOOP
) {
843 * Account for the fact that this frame connects
844 * to a previous one (thus forming a loop).
846 nep
= &einfo
[cbp
->c_dir
];
847 if (--nep
->e_framecnt
)
848 nep
->e_emask
&= ~(1 << cbp
->c_voff
[0]);
855 * We only need to update the emask values of "complete" loops
856 * to include the intersection spots.
858 if (s
&& ocbp
->c_combo
.c
.a
== 2) {
859 /* process loops from the top down */
860 ep
= &einfo
[nframes
];
864 if (!(cbp
->c_flags
& C_LOOP
))
868 * Update the emask values to include the
869 * intersection spots.
871 nep
= &einfo
[cbp
->c_dir
];
873 nep
->e_emask
= 1 << cbp
->c_voff
[0];
875 ep
->e_emask
= 1 << ep
->e_off
;
876 ep
= &einfo
[ep
->e_frameindex
];
879 ep
->e_emask
= 1 << ep
->e_off
;
880 ep
= &einfo
[ep
->e_frameindex
];
882 } while (ep
!= einfo
);
885 /* check all the frames for completion spots */
886 for (i
= 0, ep
= einfo
, cbpp
= ecombo
; i
< nframes
; i
++, ep
++, cbpp
++) {
887 /* skip this frame if there are no incomplete spots in it */
888 if ((emask
= ep
->e_emask
) == 0)
891 sp
= &board
[cbp
->c_vertex
];
893 for (s
= 0, m
= 1; s
< 5; s
++, sp
+= d
, m
<<= 1) {
894 if (sp
->s_occ
!= EMPTY
|| !(emask
& m
))
897 /* add the combo to the list of empty spots */
898 nep
= (struct elist
*)malloc(sizeof(struct elist
));
900 panic("Out of memory!");
903 nep
->e_frameindex
= i
;
904 if (ep
->e_framecnt
> 1) {
905 nep
->e_framecnt
= ep
->e_framecnt
- 1;
906 nep
->e_emask
= emask
& ~m
;
911 nep
->e_fval
.s
= ep
->e_fval
.s
;
913 debuglog("e %s o%d i%d c%d m%x %x",
922 /* sort by the number of frames in the combo */
923 nep
->e_next
= sp
->s_nempty
;
931 * Update the board value based on the combostr.
932 * This is called only if 'cbp' is a <1,x> combo.
933 * We handle things differently depending on whether the next move
934 * would be trying to "complete" the combo or trying to block it.
937 updatecombo(struct combostr
*cbp
, int color
)
940 struct combostr
*tcbp
;
942 int nframes
, flags
, s
;
946 /* save the top level value for the whole combo */
947 cb
.c
.a
= cbp
->c_combo
.c
.a
;
948 nframes
= cbp
->c_nframes
;
950 if (color
!= nextcolor
)
951 memset(tmpmap
, 0, sizeof(tmpmap
));
953 for (; (tcbp
= cbp
->c_link
[1]) != NULL
; cbp
= cbp
->c_link
[0]) {
954 flags
= cbp
->c_flags
;
955 cb
.c
.b
= cbp
->c_combo
.c
.b
;
956 if (color
== nextcolor
) {
957 /* update the board value for the vertex */
958 sp
= &board
[cbp
->c_vertex
];
959 sp
->s_nforce
[color
]++;
960 if (cb
.s
<= sp
->s_combo
[color
].s
) {
961 if (cb
.s
!= sp
->s_combo
[color
].s
) {
962 sp
->s_combo
[color
].s
= cb
.s
;
963 sp
->s_level
[color
] = nframes
;
964 } else if (nframes
< sp
->s_level
[color
])
965 sp
->s_level
[color
] = nframes
;
968 /* update the board values for each spot in frame */
969 sp
= &board
[s
= tcbp
->c_vertex
];
971 i
= (flags
& C_OPEN_1
) ? 6 : 5;
972 for (; --i
>= 0; sp
+= d
, s
+= d
) {
973 if (sp
->s_occ
!= EMPTY
)
975 sp
->s_nforce
[color
]++;
976 if (cb
.s
<= sp
->s_combo
[color
].s
) {
977 if (cb
.s
!= sp
->s_combo
[color
].s
) {
978 sp
->s_combo
[color
].s
= cb
.s
;
979 sp
->s_level
[color
] = nframes
;
980 } else if (nframes
< sp
->s_level
[color
])
981 sp
->s_level
[color
] = nframes
;
987 /* mark the frame as being part of a <1,x> combo */
988 board
[tcbp
->c_vertex
].s_flags
|= FFLAG
<< tcbp
->c_dir
;
991 if (color
!= nextcolor
) {
992 /* update the board values for each spot in frame */
993 sp
= &board
[s
= cbp
->c_vertex
];
995 i
= (flags
& C_OPEN_0
) ? 6 : 5;
996 for (; --i
>= 0; sp
+= d
, s
+= d
) {
997 if (sp
->s_occ
!= EMPTY
)
999 sp
->s_nforce
[color
]++;
1000 if (cb
.s
<= sp
->s_combo
[color
].s
) {
1001 if (cb
.s
!= sp
->s_combo
[color
].s
) {
1002 sp
->s_combo
[color
].s
= cb
.s
;
1003 sp
->s_level
[color
] = nframes
;
1004 } else if (nframes
< sp
->s_level
[color
])
1005 sp
->s_level
[color
] = nframes
;
1010 memcpy(forcemap
, tmpmap
, sizeof(tmpmap
));
1012 for (i
= 0; (unsigned int)i
< MAPSZ
; i
++)
1013 forcemap
[i
] &= tmpmap
[i
];
1018 /* mark the frame as being part of a <1,x> combo */
1019 board
[cbp
->c_vertex
].s_flags
|= FFLAG
<< cbp
->c_dir
;
1023 * Add combo to the end of the list.
1026 appendcombo(struct combostr
*cbp
, int color __unused
)
1028 struct combostr
*pcbp
, *ncbp
;
1032 if (ncbp
== (struct combostr
*)0) {
1038 pcbp
= ncbp
->c_prev
;
1046 * Return zero if it is valid to combine frame 'fcbp' with the frames
1047 * in 'cbp' and forms a linked chain of frames (i.e., a tree; no loops).
1048 * Return positive if combining frame 'fcbp' to the frames in 'cbp'
1049 * would form some kind of valid loop. Also return the intersection spots
1050 * in 'vertices[]' beside the known intersection at spot 'osp'.
1051 * Return -1 if 'fcbp' should not be combined with 'cbp'.
1052 * 's' is the combo value for frame 'fcpb'.
1055 checkframes(struct combostr
*cbp
, struct combostr
*fcbp
, struct spotstr
*osp
,
1056 int s
, struct overlap_info
*vertices
)
1058 struct combostr
*tcbp
, *lcbp
;
1059 int i
, n
, mask
, flags
, verts
, loop
, myindex
, fcnt
;
1071 myindex
= cbp
->c_nframes
;
1072 n
= (fcbp
- frames
) * FAREA
;
1076 * i == which overlap bit to test based on whether 'fcbp' is
1077 * an open or closed frame.
1080 for (; (tcbp
= cbp
->c_link
[1]) != NULL
;
1081 lcbp
= cbp
, cbp
= cbp
->c_link
[0]) {
1083 return (-1); /* fcbp is already included */
1085 /* check for intersection of 'tcbp' with 'fcbp' */
1087 mask
= str
[tcbp
- frames
];
1088 flags
= cbp
->c_flags
;
1089 n
= i
+ ((flags
& C_OPEN_1
) != 0);
1090 if (mask
& (1 << n
)) {
1092 * The two frames are not independent if they
1093 * both lie in the same line and intersect at
1094 * more than one point.
1096 if (tcbp
->c_dir
== fcbp
->c_dir
&& (mask
& (0x10 << n
)))
1099 * If this is not the spot we are attaching
1100 * 'fcbp' to and it is a reasonable intersection
1101 * spot, then there might be a loop.
1103 n
= ip
[tcbp
- frames
];
1104 if (osp
!= &board
[n
]) {
1105 /* check to see if this is a valid loop */
1108 if (fcnt
== 0 || cbp
->c_framecnt
[1] == 0)
1111 * Check to be sure the intersection is not
1112 * one of the end points if it is an open
1115 if ((flags
& C_OPEN_1
) &&
1116 (n
== tcbp
->c_vertex
||
1117 n
== tcbp
->c_vertex
+ 5 * dd
[tcbp
->c_dir
]))
1118 return (-1); /* invalid overlap */
1120 (n
== fcbp
->c_vertex
||
1121 n
== fcbp
->c_vertex
+ 5 * dd
[fcbp
->c_dir
]))
1122 return (-1); /* invalid overlap */
1124 vertices
->o_intersect
= n
;
1125 vertices
->o_fcombo
= cbp
;
1126 vertices
->o_link
= 1;
1127 vertices
->o_off
= (n
- tcbp
->c_vertex
) /
1129 vertices
->o_frameindex
= myindex
;
1133 n
= i
+ ((flags
& C_OPEN_0
) != 0);
1136 return (-1); /* fcbp is already included */
1138 /* check for intersection of 'cbp' with 'fcbp' */
1139 mask
= str
[cbp
- frames
];
1140 if (mask
& (1 << n
)) {
1142 * The two frames are not independent if they
1143 * both lie in the same line and intersect at
1144 * more than one point.
1146 if (cbp
->c_dir
== fcbp
->c_dir
&& (mask
& (0x10 << n
)))
1149 * If this is not the spot we are attaching
1150 * 'fcbp' to and it is a reasonable intersection
1151 * spot, then there might be a loop.
1153 n
= ip
[cbp
- frames
];
1154 if (osp
!= &board
[n
]) {
1155 /* check to see if this is a valid loop */
1158 if (fcnt
== 0 || lcbp
->c_framecnt
[0] == 0)
1161 * Check to be sure the intersection is not
1162 * one of the end points if it is an open
1165 if ((flags
& C_OPEN_0
) &&
1166 (n
== cbp
->c_vertex
||
1167 n
== cbp
->c_vertex
+ 5 * dd
[cbp
->c_dir
]))
1168 return (-1); /* invalid overlap */
1170 (n
== fcbp
->c_vertex
||
1171 n
== fcbp
->c_vertex
+ 5 * dd
[fcbp
->c_dir
]))
1172 return (-1); /* invalid overlap */
1174 vertices
->o_intersect
= n
;
1175 vertices
->o_fcombo
= lcbp
;
1176 vertices
->o_link
= 0;
1177 vertices
->o_off
= (n
- cbp
->c_vertex
) /
1179 vertices
->o_frameindex
= 0;
1187 * Merge sort the frame 'fcbp' and the sorted list of frames 'cbpp' and
1188 * store the result in 'scbpp'. 'curlevel' is the size of the 'cbpp' array.
1189 * Return true if this list of frames is already in the hash list.
1190 * Otherwise, add the new combo to the hash list.
1193 sortcombo(struct combostr
**scbpp
, struct combostr
**cbpp
,
1194 struct combostr
*fcbp
)
1196 struct combostr
**spp
, **cpp
;
1197 struct combostr
*cbp
, *ecbp
;
1205 debuglog("sortc: %s%c l%d", stoc(fcbp
->c_vertex
),
1206 pdir
[fcbp
->c_dir
], curlevel
);
1208 for (cpp
= cbpp
; cpp
< cbpp
+ curlevel
; cpp
++) {
1209 snprintf(buf
+ pos
, sizeof(buf
) - pos
, " %s%c",
1210 stoc((*cpp
)->c_vertex
), pdir
[(*cpp
)->c_dir
]);
1211 pos
+= strlen(buf
+ pos
);
1213 debuglog("%s", buf
);
1217 /* first build the new sorted list */
1220 cpp
= cbpp
+ curlevel
;
1227 while (cpp
-- != cbpp
);
1231 } while (cpp
!= cbpp
);
1235 /* now check to see if this list of frames has already been seen */
1236 cbp
= hashcombos
[inx
= *scbpp
- frames
];
1237 if (cbp
== (struct combostr
*)0) {
1239 * Easy case, this list hasn't been seen.
1240 * Add it to the hash list.
1242 fcbp
= (struct combostr
*)
1243 ((char *)scbpp
- sizeof(struct combostr
));
1244 hashcombos
[inx
] = fcbp
;
1245 fcbp
->c_next
= fcbp
->c_prev
= fcbp
;
1250 cbpp
= (struct combostr
**)(cbp
+ 1);
1253 cbpp
++; /* first frame is always the same */
1255 if (*--spp
!= *--cpp
)
1257 } while (cpp
!= cbpp
);
1258 /* we found a match */
1264 debuglog("sort1: n%d", n
);
1266 for (cpp
= scbpp
; cpp
< scbpp
+ n
; cpp
++) {
1267 snprintf(buf
+ pos
, sizeof(buf
) - pos
, " %s%c",
1268 stoc((*cpp
)->c_vertex
),
1269 pdir
[(*cpp
)->c_dir
]);
1270 pos
+= strlen(buf
+ pos
);
1272 debuglog("%s", buf
);
1273 printcombo(cbp
, buf
, sizeof(buf
));
1274 debuglog("%s", buf
);
1277 for (cpp
= cbpp
; cpp
< cbpp
+ n
; cpp
++) {
1278 snprintf(buf
+ pos
, sizeof(buf
) - pos
, " %s%c",
1279 stoc((*cpp
)->c_vertex
),
1280 pdir
[(*cpp
)->c_dir
]);
1281 pos
+= strlen(buf
+ pos
);
1283 debuglog("%s", buf
);
1289 } while ((cbp
= cbp
->c_next
) != ecbp
);
1291 * This list of frames hasn't been seen.
1292 * Add it to the hash list.
1295 fcbp
= (struct combostr
*)((char *)scbpp
- sizeof(struct combostr
));
1297 fcbp
->c_prev
= ecbp
;
1299 ecbp
->c_next
= fcbp
;
1304 * Print the combo into string buffer 'buf'.
1307 printcombo(struct combostr
*cbp
, char *buf
, size_t max
)
1309 struct combostr
*tcbp
;
1312 snprintf(buf
+ pos
, max
- pos
, "%x/%d",
1313 cbp
->c_combo
.s
, cbp
->c_nframes
);
1314 pos
+= strlen(buf
+ pos
);
1316 for (; (tcbp
= cbp
->c_link
[1]) != NULL
; cbp
= cbp
->c_link
[0]) {
1317 snprintf(buf
+ pos
, max
- pos
, " %s%c%x",
1318 stoc(tcbp
->c_vertex
), pdir
[tcbp
->c_dir
], cbp
->c_flags
);
1319 pos
+= strlen(buf
+ pos
);
1321 snprintf(buf
+ pos
, max
- pos
, " %s%c",
1322 stoc(cbp
->c_vertex
), pdir
[cbp
->c_dir
]);
1327 markcombo(struct combostr
*ocbp
)
1329 struct combostr
*cbp
, *tcbp
, **cbpp
;
1330 struct elist
*ep
, *nep
, **epp
;
1334 int r
, n
, flags
, cmask
, omask
;
1336 /* should never happen but check anyway */
1337 if ((nframes
= ocbp
->c_nframes
) >= MAXDEPTH
)
1341 * The lower level combo can be pointed to by more than one
1342 * higher level 'struct combostr' so we can't modify the
1343 * lower level. Therefore, higher level combos store the
1344 * real mask of the lower level frame in c_emask[0] and the
1345 * frame number in c_frameindex.
1347 * First we traverse the tree from top to bottom and save the
1348 * connection info. Then we traverse the tree from bottom to
1349 * top overwriting lower levels with the newer emask information.
1351 ep
= &einfo
[nframes
];
1352 cbpp
= &ecombo
[nframes
];
1353 for (cbp
= ocbp
; tcbp
= cbp
->c_link
[1]; cbp
= cbp
->c_link
[0]) {
1356 *--cbpp
= cbp
->c_link
[1];
1357 ep
->e_off
= cbp
->c_voff
[1];
1358 ep
->e_frameindex
= cbp
->c_frameindex
;
1359 ep
->e_fval
.s
= cbp
->c_linkv
[1].s
;
1360 ep
->e_framecnt
= cbp
->c_framecnt
[1];
1361 ep
->e_emask
= cbp
->c_emask
[1];
1366 *--cbpp
= cbp
->c_link
[0];
1367 ep
->e_off
= cbp
->c_voff
[0];
1368 ep
->e_frameindex
= 0;
1369 ep
->e_fval
.s
= cbp
->c_linkv
[0].s
;
1370 ep
->e_framecnt
= cbp
->c_framecnt
[0];
1371 ep
->e_emask
= cbp
->c_emask
[0];
1373 /* now update the emask info */
1375 for (i
= 2, ep
+= 2; i
< nframes
; i
++, ep
++) {
1377 nep
= &einfo
[ep
->e_frameindex
];
1378 nep
->e_framecnt
= cbp
->c_framecnt
[0];
1379 nep
->e_emask
= cbp
->c_emask
[0];
1381 if (cbp
->c_flags
& C_LOOP
) {
1384 * Account for the fact that this frame connects
1385 * to a previous one (thus forming a loop).
1387 nep
= &einfo
[cbp
->c_dir
];
1388 if (--nep
->e_framecnt
)
1389 nep
->e_emask
&= ~(1 << cbp
->c_voff
[0]);
1396 * We only need to update the emask values of "complete" loops
1397 * to include the intersection spots.
1399 if (s
&& ocbp
->c_combo
.c
.a
== 2) {
1400 /* process loops from the top down */
1401 ep
= &einfo
[nframes
];
1405 if (!(cbp
->c_flags
& C_LOOP
))
1409 * Update the emask values to include the
1410 * intersection spots.
1412 nep
= &einfo
[cbp
->c_dir
];
1413 nep
->e_framecnt
= 1;
1414 nep
->e_emask
= 1 << cbp
->c_voff
[0];
1416 ep
->e_emask
= 1 << ep
->e_off
;
1417 ep
= &einfo
[ep
->e_frameindex
];
1420 ep
->e_emask
= 1 << ep
->e_off
;
1421 ep
= &einfo
[ep
->e_frameindex
];
1423 } while (ep
!= einfo
);
1426 /* mark all the frames with the completion spots */
1427 for (i
= 0, ep
= einfo
, cbpp
= ecombo
; i
< nframes
; i
++, ep
++, cbpp
++) {
1430 sp
= &board
[cbp
->c_vertex
];
1431 d
= dd
[s
= cbp
->c_dir
];
1433 omask
= (IFLAG
| CFLAG
) << s
;
1434 s
= ep
->e_fval
.c
.b
? 6 : 5;
1435 for (; --s
>= 0; sp
+= d
, m
>>= 1)
1436 sp
->s_flags
|= (m
& 1) ? omask
: cmask
;
1441 clearcombo(struct combostr
*cbp
, int open
)
1444 struct combostr
*tcbp
;
1447 for (; tcbp
= cbp
->c_link
[1]; cbp
= cbp
->c_link
[0]) {
1448 clearcombo(tcbp
, cbp
->c_flags
& C_OPEN_1
);
1449 open
= cbp
->c_flags
& C_OPEN_0
;
1451 sp
= &board
[cbp
->c_vertex
];
1452 d
= dd
[n
= cbp
->c_dir
];
1453 mask
= ~((IFLAG
| CFLAG
) << n
);
1455 for (; --n
>= 0; sp
+= d
)
1456 sp
->s_flags
&= mask
;
1460 list_eq(struct combostr
**scbpp
, struct combostr
**cbpp
, int n
)
1462 struct combostr
**spp
, **cpp
;
1467 if (*--spp
!= *--cpp
)
1469 } while (cpp
!= cbpp
);
1470 /* we found a match */