1 /* $NetBSD: pickmove.c,v 1.22 2013/10/19 17:23:08 christos 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
34 * @(#)pickmove.c 8.2 (Berkeley) 5/3/95
44 #define BITS_PER_INT (sizeof(int) * CHAR_BIT)
45 #define MAPSZ (BAREA / BITS_PER_INT)
47 #define BIT_SET(a, b) ((a)[(b)/BITS_PER_INT] |= (1 << ((b) % BITS_PER_INT)))
48 #define BIT_CLR(a, b) ((a)[(b)/BITS_PER_INT] &= ~(1 << ((b) % BITS_PER_INT)))
49 #define BIT_TEST(a, b) ((a)[(b)/BITS_PER_INT] & (1 << ((b) % BITS_PER_INT)))
51 static struct combostr
*hashcombos
[FAREA
];/* hash list for finding duplicates */
52 static struct combostr
*sortcombos
; /* combos at higher levels */
53 static int combolen
; /* number of combos in sortcombos */
54 static int nextcolor
; /* color of next move */
55 static int elistcnt
; /* count of struct elist allocated */
56 static int combocnt
; /* count of struct combostr allocated */
57 static int forcemap
[MAPSZ
]; /* map for blocking <1,x> combos */
58 static int tmpmap
[MAPSZ
]; /* map for blocking <1,x> combos */
59 static int nforce
; /* count of opponent <1,x> combos */
61 static int better(const struct spotstr
*, const struct spotstr
*, int);
62 static void scanframes(int);
63 static void makecombo2(struct combostr
*, struct spotstr
*, int, int);
64 static void addframes(int);
65 static void makecombo(struct combostr
*, struct spotstr
*, int, int);
66 static void appendcombo(struct combostr
*, int);
67 static void updatecombo(struct combostr
*, int);
68 static void makeempty(struct combostr
*);
69 static int checkframes(struct combostr
*, struct combostr
*, struct spotstr
*,
70 int, struct overlap_info
*);
71 static int sortcombo(struct combostr
**, struct combostr
**, struct combostr
*);
72 static void printcombo(struct combostr
*, char *, size_t);
77 struct spotstr
*sp
, *sp1
, *sp2
;
78 union comboval
*Ocp
, *Tcp
;
82 /* first move is easy */
86 /* initialize all the board values */
87 for (pos
= PT(T
,20); pos
-- > PT(A
,1); ) {
89 sp
->s_combo
[BLACK
].s
= MAXCOMBO
+ 1;
90 sp
->s_combo
[WHITE
].s
= MAXCOMBO
+ 1;
91 sp
->s_level
[BLACK
] = 255;
92 sp
->s_level
[WHITE
] = 255;
93 sp
->s_nforce
[BLACK
] = 0;
94 sp
->s_nforce
[WHITE
] = 0;
95 sp
->s_flags
&= ~(FFLAGALL
| MFLAGALL
);
98 memset(forcemap
, 0, sizeof(forcemap
));
100 /* compute new values */
105 /* find the spot with the highest value */
107 sp1
= sp2
= &board
[pos
];
108 for ( ; pos
-- > PT(A
,1); ) {
110 if (sp
->s_occ
!= EMPTY
)
112 if (debug
&& (sp
->s_combo
[BLACK
].c
.a
== 1 ||
113 sp
->s_combo
[WHITE
].c
.a
== 1)) {
114 debuglog("- %s %x/%d %d %x/%d %d %d", stoc(sp
- board
),
115 sp
->s_combo
[BLACK
].s
, sp
->s_level
[BLACK
],
117 sp
->s_combo
[WHITE
].s
, sp
->s_level
[WHITE
],
121 /* pick the best black move */
122 if (better(sp
, sp1
, BLACK
))
124 /* pick the best white move */
125 if (better(sp
, sp2
, WHITE
))
130 debuglog("B %s %x/%d %d %x/%d %d %d",
132 sp1
->s_combo
[BLACK
].s
, sp1
->s_level
[BLACK
],
133 sp1
->s_nforce
[BLACK
],
134 sp1
->s_combo
[WHITE
].s
, sp1
->s_level
[WHITE
],
135 sp1
->s_nforce
[WHITE
], sp1
->s_wval
);
136 debuglog("W %s %x/%d %d %x/%d %d %d",
138 sp2
->s_combo
[WHITE
].s
, sp2
->s_level
[WHITE
],
139 sp2
->s_nforce
[WHITE
],
140 sp2
->s_combo
[BLACK
].s
, sp2
->s_level
[BLACK
],
141 sp2
->s_nforce
[BLACK
], sp2
->s_wval
);
143 * Check for more than one force that can't
144 * all be blocked with one move.
146 sp
= (us
== BLACK
) ? sp2
: sp1
;
148 if (sp
->s_combo
[!us
].c
.a
== 1 && !BIT_TEST(forcemap
, m
))
149 debuglog("*** Can't be blocked");
152 Ocp
= &sp1
->s_combo
[BLACK
];
153 Tcp
= &sp2
->s_combo
[WHITE
];
155 Tcp
= &sp1
->s_combo
[BLACK
];
156 Ocp
= &sp2
->s_combo
[WHITE
];
162 * Block their combo only if we have to (i.e., if they are one move
163 * away from completing a force and we don't have a force that
164 * we can complete which takes fewer moves to win).
166 if (Tcp
->c
.a
<= 1 && (Ocp
->c
.a
> 1 ||
167 Tcp
->c
.a
+ Tcp
->c
.b
< Ocp
->c
.a
+ Ocp
->c
.b
))
168 return (sp2
- board
);
169 return (sp1
- board
);
173 * Return true if spot 'sp' is better than spot 'sp1' for color 'us'.
176 better(const struct spotstr
*sp
, const struct spotstr
*sp1
, int us
)
180 if (sp
->s_combo
[us
].s
< sp1
->s_combo
[us
].s
)
182 if (sp
->s_combo
[us
].s
!= sp1
->s_combo
[us
].s
)
184 if (sp
->s_level
[us
] < sp1
->s_level
[us
])
186 if (sp
->s_level
[us
] != sp1
->s_level
[us
])
188 if (sp
->s_nforce
[us
] > sp1
->s_nforce
[us
])
190 if (sp
->s_nforce
[us
] != sp1
->s_nforce
[us
])
196 if (BIT_TEST(forcemap
, s
) && !BIT_TEST(forcemap
, s1
))
198 if (!BIT_TEST(forcemap
, s
) && BIT_TEST(forcemap
, s1
))
200 if (sp
->s_combo
[them
].s
< sp1
->s_combo
[them
].s
)
202 if (sp
->s_combo
[them
].s
!= sp1
->s_combo
[them
].s
)
204 if (sp
->s_level
[them
] < sp1
->s_level
[them
])
206 if (sp
->s_level
[them
] != sp1
->s_level
[them
])
208 if (sp
->s_nforce
[them
] > sp1
->s_nforce
[them
])
210 if (sp
->s_nforce
[them
] != sp1
->s_nforce
[them
])
213 if (sp
->s_wval
> sp1
->s_wval
)
215 if (sp
->s_wval
!= sp1
->s_wval
)
218 return (random() & 1);
221 static int curcolor
; /* implicit parameter to makecombo() */
222 static int curlevel
; /* implicit parameter to makecombo() */
225 * Scan the sorted list of non-empty frames and
226 * update the minimum combo values for each empty spot.
227 * Also, try to combine frames to find more complex (chained) moves.
230 scanframes(int color
)
232 struct combostr
*cbp
, *ecbp
;
235 struct elist
*ep
, *nep
;
242 /* check for empty list of frames */
243 cbp
= sortframes
[color
];
244 if (cbp
== (struct combostr
*)0)
247 /* quick check for four in a row */
248 sp
= &board
[cbp
->c_vertex
];
249 cb
.s
= sp
->s_fval
[color
][d
= cbp
->c_dir
].s
;
252 for (i
= 5 + cb
.c
.b
; --i
>= 0; sp
+= d
) {
253 if (sp
->s_occ
!= EMPTY
)
255 sp
->s_combo
[color
].s
= cb
.s
;
256 sp
->s_level
[color
] = 1;
262 * Update the minimum combo value for each spot in the frame
263 * and try making all combinations of two frames intersecting at
269 sp
= &board
[cbp
->c_vertex
];
270 cp
= &sp
->s_fval
[color
][r
= cbp
->c_dir
];
274 * Since this is the first spot of an open ended
275 * frame, we treat it as a closed frame.
277 cb
.c
.a
= cp
->c
.a
+ 1;
279 if (cb
.s
< sp
->s_combo
[color
].s
) {
280 sp
->s_combo
[color
].s
= cb
.s
;
281 sp
->s_level
[color
] = 1;
284 * Try combining other frames that intersect
287 makecombo2(cbp
, sp
, 0, cb
.s
);
290 else if (color
!= nextcolor
)
291 memset(tmpmap
, 0, sizeof(tmpmap
));
298 for (; i
< 5; i
++, sp
+= d
) { /* for each spot */
299 if (sp
->s_occ
!= EMPTY
)
301 if (cp
->s
< sp
->s_combo
[color
].s
) {
302 sp
->s_combo
[color
].s
= cp
->s
;
303 sp
->s_level
[color
] = 1;
305 if (cp
->s
== 0x101) {
306 sp
->s_nforce
[color
]++;
307 if (color
!= nextcolor
) {
313 * Try combining other frames that intersect
316 makecombo2(cbp
, sp
, i
, cb
.s
);
318 if (cp
->s
== 0x101 && color
!= nextcolor
) {
320 memcpy(forcemap
, tmpmap
, sizeof(tmpmap
));
322 for (i
= 0; (unsigned int)i
< MAPSZ
; i
++)
323 forcemap
[i
] &= tmpmap
[i
];
326 /* mark frame as having been processed */
327 board
[cbp
->c_vertex
].s_flags
|= MFLAG
<< r
;
328 } while ((cbp
= cbp
->c_next
) != ecbp
);
331 * Try to make new 3rd level combos, 4th level, etc.
332 * Limit the search depth early in the game.
335 while (d
<= ((movenum
+ 1) >> 1) && combolen
> n
) {
337 debuglog("%cL%d %d %d %d", "BW"[color
],
338 d
, combolen
- n
, combocnt
, elistcnt
);
346 /* scan for combos at empty spots */
347 for (pos
= PT(T
,20); pos
-- > PT(A
,1); ) {
349 for (ep
= sp
->s_empty
; ep
; ep
= nep
) {
351 if (cbp
->c_combo
.s
<= sp
->s_combo
[color
].s
) {
352 if (cbp
->c_combo
.s
!= sp
->s_combo
[color
].s
) {
353 sp
->s_combo
[color
].s
= cbp
->c_combo
.s
;
354 sp
->s_level
[color
] = cbp
->c_nframes
;
355 } else if (cbp
->c_nframes
< sp
->s_level
[color
])
356 sp
->s_level
[color
] = cbp
->c_nframes
;
362 sp
->s_empty
= (struct elist
*)0;
363 for (ep
= sp
->s_nempty
; ep
; ep
= nep
) {
365 if (cbp
->c_combo
.s
<= sp
->s_combo
[color
].s
) {
366 if (cbp
->c_combo
.s
!= sp
->s_combo
[color
].s
) {
367 sp
->s_combo
[color
].s
= cbp
->c_combo
.s
;
368 sp
->s_level
[color
] = cbp
->c_nframes
;
369 } else if (cbp
->c_nframes
< sp
->s_level
[color
])
370 sp
->s_level
[color
] = cbp
->c_nframes
;
376 sp
->s_nempty
= (struct elist
*)0;
379 /* remove old combos */
380 if ((cbp
= sortcombos
) != (struct combostr
*)0) {
381 struct combostr
*ncbp
;
389 } while ((cbp
= ncbp
) != ecbp
);
390 sortcombos
= (struct combostr
*)0;
396 debuglog("scanframes: %c combocnt %d", "BW"[color
],
401 debuglog("scanframes: %c elistcnt %d", "BW"[color
],
409 * Compute all level 2 combos of frames intersecting spot 'osp'
410 * within the frame 'ocbp' and combo value 's'.
413 makecombo2(struct combostr
*ocbp
, struct spotstr
*osp
, int off
, int s
)
416 struct combostr
*ncbp
;
418 int baseB
, fcnt
, emask
, bmask
, n
;
419 union comboval ocb
, fcb
;
420 struct combostr
**scbpp
, *fcbp
;
423 /* try to combine a new frame with those found so far */
425 baseB
= ocb
.c
.a
+ ocb
.c
.b
- 1;
427 emask
= fcnt
? ((ocb
.c
.b
? 0x1E : 0x1F) & ~(1 << off
)) : 0;
428 for (r
= 4; --r
>= 0; ) { /* for each direction */
429 /* don't include frames that overlap in the same direction */
430 if (r
== ocbp
->c_dir
)
434 * Frame A combined with B is the same value as B combined with A
435 * so skip frames that have already been processed (MFLAG).
436 * Also skip blocked frames (BFLAG) and frames that are <1,x>
437 * since combining another frame with it isn't valid.
439 bmask
= (BFLAG
| FFLAG
| MFLAG
) << r
;
441 for (f
= 0; f
< 5; f
++, fsp
-= d
) { /* for each frame */
442 if (fsp
->s_occ
== BORDER
)
444 if (fsp
->s_flags
& bmask
)
447 /* don't include frames of the wrong color */
448 fcb
.s
= fsp
->s_fval
[curcolor
][r
].s
;
453 * Get the combo value for this frame.
454 * If this is the end point of the frame,
455 * use the closed ended value for the frame.
457 if ((f
== 0 && fcb
.c
.b
) || fcb
.s
== 0x101) {
462 /* compute combo value */
463 c
= fcb
.c
.a
+ ocb
.c
.a
- 3;
466 n
= fcb
.c
.a
+ fcb
.c
.b
- 1;
470 /* make a new combo! */
471 ncbp
= (struct combostr
*)malloc(sizeof(struct combostr
) +
472 2 * sizeof(struct combostr
*));
474 panic("Out of memory!");
475 scbpp
= (struct combostr
**)(ncbp
+ 1);
476 fcbp
= fsp
->s_frame
[r
];
484 ncbp
->c_combo
.c
.a
= c
;
485 ncbp
->c_combo
.c
.b
= n
;
486 ncbp
->c_link
[0] = ocbp
;
487 ncbp
->c_link
[1] = fcbp
;
488 ncbp
->c_linkv
[0].s
= ocb
.s
;
489 ncbp
->c_linkv
[1].s
= fcb
.s
;
490 ncbp
->c_voff
[0] = off
;
492 ncbp
->c_vertex
= osp
- board
;
495 ncbp
->c_frameindex
= 0;
496 ncbp
->c_flags
= (ocb
.c
.b
) ? C_OPEN_0
: 0;
498 ncbp
->c_flags
|= C_OPEN_1
;
499 ncbp
->c_framecnt
[0] = fcnt
;
500 ncbp
->c_emask
[0] = emask
;
501 ncbp
->c_framecnt
[1] = fcb
.c
.a
- 2;
502 ncbp
->c_emask
[1] = ncbp
->c_framecnt
[1] ?
503 ((fcb
.c
.b
? 0x1E : 0x1F) & ~(1 << f
)) : 0;
506 if ((c
== 1 && debug
> 1) || debug
> 3) {
507 debuglog("%c c %d %d m %x %x o %d %d",
509 ncbp
->c_framecnt
[0], ncbp
->c_framecnt
[1],
510 ncbp
->c_emask
[0], ncbp
->c_emask
[1],
511 ncbp
->c_voff
[0], ncbp
->c_voff
[1]);
512 printcombo(ncbp
, tmp
, sizeof(tmp
));
516 /* record the empty spots that will complete this combo */
519 /* add the new combo to the end of the list */
520 appendcombo(ncbp
, curcolor
);
522 updatecombo(ncbp
, curcolor
);
527 if ((c
== 1 && debug
> 1) || debug
> 5) {
539 * Scan the sorted list of frames and try to add a frame to
540 * combinations of 'level' number of frames.
545 struct combostr
*cbp
, *ecbp
;
546 struct spotstr
*sp
, *fsp
;
547 struct elist
*ep
, *nep
;
549 struct combostr
**cbpp
, *pcbp
;
550 union comboval fcb
, cb
;
555 /* scan for combos at empty spots */
557 for (pos
= PT(T
,20); pos
-- > PT(A
,1); ) {
559 for (ep
= sp
->s_empty
; ep
; ep
= nep
) {
561 if (cbp
->c_combo
.s
<= sp
->s_combo
[i
].s
) {
562 if (cbp
->c_combo
.s
!= sp
->s_combo
[i
].s
) {
563 sp
->s_combo
[i
].s
= cbp
->c_combo
.s
;
564 sp
->s_level
[i
] = cbp
->c_nframes
;
565 } else if (cbp
->c_nframes
< sp
->s_level
[i
])
566 sp
->s_level
[i
] = cbp
->c_nframes
;
572 sp
->s_empty
= sp
->s_nempty
;
573 sp
->s_nempty
= (struct elist
*)0;
576 /* try to add frames to the uncompleted combos at level curlevel */
577 cbp
= ecbp
= sortframes
[curcolor
];
579 fsp
= &board
[cbp
->c_vertex
];
581 /* skip frames that are part of a <1,x> combo */
582 if (fsp
->s_flags
& (FFLAG
<< r
))
586 * Don't include <1,x> combo frames,
587 * treat it as a closed three in a row instead.
589 fcb
.s
= fsp
->s_fval
[curcolor
][r
].s
;
594 * If this is an open ended frame, use
595 * the combo value with the end closed.
597 if (fsp
->s_occ
== EMPTY
) {
599 cb
.c
.a
= fcb
.c
.a
+ 1;
603 makecombo(cbp
, fsp
, 0, cb
.s
);
607 * The next four spots are handled the same for both
608 * open and closed ended frames.
612 for (i
= 1; i
< 5; i
++, sp
+= d
) {
613 if (sp
->s_occ
!= EMPTY
)
615 makecombo(cbp
, sp
, i
, fcb
.s
);
617 } while ((cbp
= cbp
->c_next
) != ecbp
);
619 /* put all the combos in the hash list on the sorted list */
620 cbpp
= &hashcombos
[FAREA
];
623 if (cbp
== (struct combostr
*)0)
625 *cbpp
= (struct combostr
*)0;
627 if (ecbp
== (struct combostr
*)0)
630 /* append to sort list */
633 ecbp
->c_prev
= cbp
->c_prev
;
634 cbp
->c_prev
->c_next
= ecbp
;
637 } while (cbpp
!= hashcombos
);
641 * Compute all level N combos of frames intersecting spot 'osp'
642 * within the frame 'ocbp' and combo value 's'.
645 makecombo(struct combostr
*ocbp
, struct spotstr
*osp
, int off
, int s
)
647 struct combostr
*cbp
, *ncbp
;
652 struct combostr
**scbpp
;
653 int baseB
, fcnt
, emask
, verts
;
655 struct overlap_info vertices
[1];
659 * XXX: when I made functions static gcc started warning about
660 * some members of vertices[0] maybe being used uninitialized.
661 * For now I'm just going to clear it rather than wade through
662 * the logic to find out whether gcc or the code is wrong. I
663 * wouldn't be surprised if it were the code though. - dholland
665 memset(vertices
, 0, sizeof(vertices
));
668 baseB
= ocb
.c
.a
+ ocb
.c
.b
- 1;
670 emask
= fcnt
? ((ocb
.c
.b
? 0x1E : 0x1F) & ~(1 << off
)) : 0;
671 for (ep
= osp
->s_empty
; ep
; ep
= ep
->e_next
) {
672 /* check for various kinds of overlap */
674 verts
= checkframes(cbp
, ocbp
, osp
, s
, vertices
);
678 /* check to see if this frame forms a valid loop */
680 sp
= &board
[vertices
[0].o_intersect
];
682 if (sp
->s_occ
!= EMPTY
) {
683 debuglog("loop: %c %s", "BW"[curcolor
],
689 * It is a valid loop if the intersection spot
690 * of the frame we are trying to attach is one
691 * of the completion spots of the combostr
692 * we are trying to attach the frame to.
694 for (nep
= sp
->s_empty
; nep
; nep
= nep
->e_next
) {
695 if (nep
->e_combo
== cbp
)
697 if (nep
->e_combo
->c_nframes
< cbp
->c_nframes
)
700 /* frame overlaps but not at a valid spot */
706 /* compute the first half of the combo value */
707 c
= cbp
->c_combo
.c
.a
+ ocb
.c
.a
- verts
- 3;
711 /* compute the second half of the combo value */
712 n
= ep
->e_fval
.c
.a
+ ep
->e_fval
.c
.b
- 1;
716 /* make a new combo! */
717 ncbp
= (struct combostr
*)malloc(sizeof(struct combostr
) +
718 (cbp
->c_nframes
+ 1) * sizeof(struct combostr
*));
720 panic("Out of memory!");
721 scbpp
= (struct combostr
**)(ncbp
+ 1);
722 if (sortcombo(scbpp
, (struct combostr
**)(cbp
+ 1), ocbp
)) {
728 ncbp
->c_combo
.c
.a
= c
;
729 ncbp
->c_combo
.c
.b
= n
;
730 ncbp
->c_link
[0] = cbp
;
731 ncbp
->c_link
[1] = ocbp
;
732 ncbp
->c_linkv
[1].s
= ocb
.s
;
733 ncbp
->c_voff
[1] = off
;
734 ncbp
->c_vertex
= osp
- board
;
735 ncbp
->c_nframes
= cbp
->c_nframes
+ 1;
736 ncbp
->c_flags
= ocb
.c
.b
? C_OPEN_1
: 0;
737 ncbp
->c_frameindex
= ep
->e_frameindex
;
739 * Update the completion spot mask of the frame we
740 * are attaching 'ocbp' to so the intersection isn't
743 ncbp
->c_framecnt
[0] = ep
->e_framecnt
;
744 ncbp
->c_emask
[0] = ep
->e_emask
;
746 ncbp
->c_flags
|= C_LOOP
;
747 ncbp
->c_dir
= vertices
[0].o_frameindex
;
748 ncbp
->c_framecnt
[1] = fcnt
- 1;
749 if (ncbp
->c_framecnt
[1]) {
750 n
= (vertices
[0].o_intersect
- ocbp
->c_vertex
) /
752 ncbp
->c_emask
[1] = emask
& ~(1 << n
);
754 ncbp
->c_emask
[1] = 0;
755 ncbp
->c_voff
[0] = vertices
[0].o_off
;
758 ncbp
->c_framecnt
[1] = fcnt
;
759 ncbp
->c_emask
[1] = emask
;
760 ncbp
->c_voff
[0] = ep
->e_off
;
763 if ((c
== 1 && debug
> 1) || debug
> 3) {
764 debuglog("%c v%d i%d d%d c %d %d m %x %x o %d %d",
765 "bw"[curcolor
], verts
, ncbp
->c_frameindex
, ncbp
->c_dir
,
766 ncbp
->c_framecnt
[0], ncbp
->c_framecnt
[1],
767 ncbp
->c_emask
[0], ncbp
->c_emask
[1],
768 ncbp
->c_voff
[0], ncbp
->c_voff
[1]);
769 printcombo(ncbp
, tmp
, sizeof(tmp
));
773 /* record the empty spots that will complete this combo */
777 /* update board values */
778 updatecombo(ncbp
, curcolor
);
781 if ((c
== 1 && debug
> 1) || debug
> 4) {
792 static struct elist einfo
[MAXDEPTH
];
793 static struct combostr
*ecombo
[MAXDEPTH
]; /* separate from elist to save space */
796 * Add the combostr 'ocbp' to the empty spots list for each empty spot
797 * in 'ocbp' that will complete the combo.
800 makeempty(struct combostr
*ocbp
)
802 struct combostr
*cbp
, *tcbp
, **cbpp
;
803 struct elist
*ep
, *nep
;
805 int s
, d
, m
, emask
, i
;
810 printcombo(ocbp
, tmp
, sizeof(tmp
));
811 debuglog("E%c %s", "bw"[curcolor
], tmp
);
814 /* should never happen but check anyway */
815 if ((nframes
= ocbp
->c_nframes
) >= MAXDEPTH
)
819 * The lower level combo can be pointed to by more than one
820 * higher level 'struct combostr' so we can't modify the
821 * lower level. Therefore, higher level combos store the
822 * real mask of the lower level frame in c_emask[0] and the
823 * frame number in c_frameindex.
825 * First we traverse the tree from top to bottom and save the
826 * connection info. Then we traverse the tree from bottom to
827 * top overwriting lower levels with the newer emask information.
829 ep
= &einfo
[nframes
];
830 cbpp
= &ecombo
[nframes
];
831 for (cbp
= ocbp
; (tcbp
= cbp
->c_link
[1]) != NULL
;
832 cbp
= cbp
->c_link
[0]) {
835 *--cbpp
= cbp
->c_link
[1];
836 ep
->e_off
= cbp
->c_voff
[1];
837 ep
->e_frameindex
= cbp
->c_frameindex
;
838 ep
->e_fval
.s
= cbp
->c_linkv
[1].s
;
839 ep
->e_framecnt
= cbp
->c_framecnt
[1];
840 ep
->e_emask
= cbp
->c_emask
[1];
845 *--cbpp
= cbp
->c_link
[0];
846 ep
->e_off
= cbp
->c_voff
[0];
847 ep
->e_frameindex
= 0;
848 ep
->e_fval
.s
= cbp
->c_linkv
[0].s
;
849 ep
->e_framecnt
= cbp
->c_framecnt
[0];
850 ep
->e_emask
= cbp
->c_emask
[0];
852 /* now update the emask info */
854 for (i
= 2, ep
+= 2; i
< nframes
; i
++, ep
++) {
856 nep
= &einfo
[ep
->e_frameindex
];
857 nep
->e_framecnt
= cbp
->c_framecnt
[0];
858 nep
->e_emask
= cbp
->c_emask
[0];
860 if (cbp
->c_flags
& C_LOOP
) {
863 * Account for the fact that this frame connects
864 * to a previous one (thus forming a loop).
866 nep
= &einfo
[cbp
->c_dir
];
867 if (--nep
->e_framecnt
)
868 nep
->e_emask
&= ~(1 << cbp
->c_voff
[0]);
875 * We only need to update the emask values of "complete" loops
876 * to include the intersection spots.
878 if (s
&& ocbp
->c_combo
.c
.a
== 2) {
879 /* process loops from the top down */
880 ep
= &einfo
[nframes
];
884 if (!(cbp
->c_flags
& C_LOOP
))
888 * Update the emask values to include the
889 * intersection spots.
891 nep
= &einfo
[cbp
->c_dir
];
893 nep
->e_emask
= 1 << cbp
->c_voff
[0];
895 ep
->e_emask
= 1 << ep
->e_off
;
896 ep
= &einfo
[ep
->e_frameindex
];
899 ep
->e_emask
= 1 << ep
->e_off
;
900 ep
= &einfo
[ep
->e_frameindex
];
902 } while (ep
!= einfo
);
905 /* check all the frames for completion spots */
906 for (i
= 0, ep
= einfo
, cbpp
= ecombo
; i
< nframes
; i
++, ep
++, cbpp
++) {
907 /* skip this frame if there are no incomplete spots in it */
908 if ((emask
= ep
->e_emask
) == 0)
911 sp
= &board
[cbp
->c_vertex
];
913 for (s
= 0, m
= 1; s
< 5; s
++, sp
+= d
, m
<<= 1) {
914 if (sp
->s_occ
!= EMPTY
|| !(emask
& m
))
917 /* add the combo to the list of empty spots */
918 nep
= (struct elist
*)malloc(sizeof(struct elist
));
920 panic("Out of memory!");
923 nep
->e_frameindex
= i
;
924 if (ep
->e_framecnt
> 1) {
925 nep
->e_framecnt
= ep
->e_framecnt
- 1;
926 nep
->e_emask
= emask
& ~m
;
931 nep
->e_fval
.s
= ep
->e_fval
.s
;
933 debuglog("e %s o%d i%d c%d m%x %x",
942 /* sort by the number of frames in the combo */
943 nep
->e_next
= sp
->s_nempty
;
951 * Update the board value based on the combostr.
952 * This is called only if 'cbp' is a <1,x> combo.
953 * We handle things differently depending on whether the next move
954 * would be trying to "complete" the combo or trying to block it.
957 updatecombo(struct combostr
*cbp
, int color
)
960 struct combostr
*tcbp
;
962 int nframes
, flags
, s
;
966 /* save the top level value for the whole combo */
967 cb
.c
.a
= cbp
->c_combo
.c
.a
;
968 nframes
= cbp
->c_nframes
;
970 if (color
!= nextcolor
)
971 memset(tmpmap
, 0, sizeof(tmpmap
));
973 for (; (tcbp
= cbp
->c_link
[1]) != NULL
; cbp
= cbp
->c_link
[0]) {
974 flags
= cbp
->c_flags
;
975 cb
.c
.b
= cbp
->c_combo
.c
.b
;
976 if (color
== nextcolor
) {
977 /* update the board value for the vertex */
978 sp
= &board
[cbp
->c_vertex
];
979 sp
->s_nforce
[color
]++;
980 if (cb
.s
<= sp
->s_combo
[color
].s
) {
981 if (cb
.s
!= sp
->s_combo
[color
].s
) {
982 sp
->s_combo
[color
].s
= cb
.s
;
983 sp
->s_level
[color
] = nframes
;
984 } else if (nframes
< sp
->s_level
[color
])
985 sp
->s_level
[color
] = nframes
;
988 /* update the board values for each spot in frame */
989 sp
= &board
[s
= tcbp
->c_vertex
];
991 i
= (flags
& C_OPEN_1
) ? 6 : 5;
992 for (; --i
>= 0; sp
+= d
, s
+= d
) {
993 if (sp
->s_occ
!= EMPTY
)
995 sp
->s_nforce
[color
]++;
996 if (cb
.s
<= sp
->s_combo
[color
].s
) {
997 if (cb
.s
!= sp
->s_combo
[color
].s
) {
998 sp
->s_combo
[color
].s
= cb
.s
;
999 sp
->s_level
[color
] = nframes
;
1000 } else if (nframes
< sp
->s_level
[color
])
1001 sp
->s_level
[color
] = nframes
;
1007 /* mark the frame as being part of a <1,x> combo */
1008 board
[tcbp
->c_vertex
].s_flags
|= FFLAG
<< tcbp
->c_dir
;
1011 if (color
!= nextcolor
) {
1012 /* update the board values for each spot in frame */
1013 sp
= &board
[s
= cbp
->c_vertex
];
1015 i
= (flags
& C_OPEN_0
) ? 6 : 5;
1016 for (; --i
>= 0; sp
+= d
, s
+= d
) {
1017 if (sp
->s_occ
!= EMPTY
)
1019 sp
->s_nforce
[color
]++;
1020 if (cb
.s
<= sp
->s_combo
[color
].s
) {
1021 if (cb
.s
!= sp
->s_combo
[color
].s
) {
1022 sp
->s_combo
[color
].s
= cb
.s
;
1023 sp
->s_level
[color
] = nframes
;
1024 } else if (nframes
< sp
->s_level
[color
])
1025 sp
->s_level
[color
] = nframes
;
1030 memcpy(forcemap
, tmpmap
, sizeof(tmpmap
));
1032 for (i
= 0; (unsigned int)i
< MAPSZ
; i
++)
1033 forcemap
[i
] &= tmpmap
[i
];
1038 /* mark the frame as being part of a <1,x> combo */
1039 board
[cbp
->c_vertex
].s_flags
|= FFLAG
<< cbp
->c_dir
;
1043 * Add combo to the end of the list.
1046 appendcombo(struct combostr
*cbp
, int color __unused
)
1048 struct combostr
*pcbp
, *ncbp
;
1052 if (ncbp
== (struct combostr
*)0) {
1058 pcbp
= ncbp
->c_prev
;
1066 * Return zero if it is valid to combine frame 'fcbp' with the frames
1067 * in 'cbp' and forms a linked chain of frames (i.e., a tree; no loops).
1068 * Return positive if combining frame 'fcbp' to the frames in 'cbp'
1069 * would form some kind of valid loop. Also return the intersection spots
1070 * in 'vertices[]' beside the known intersection at spot 'osp'.
1071 * Return -1 if 'fcbp' should not be combined with 'cbp'.
1072 * 's' is the combo value for frame 'fcpb'.
1075 checkframes(struct combostr
*cbp
, struct combostr
*fcbp
, struct spotstr
*osp
,
1076 int s
, struct overlap_info
*vertices
)
1078 struct combostr
*tcbp
, *lcbp
;
1079 int i
, n
, mask
, flags
, verts
, myindex
, fcnt
;
1090 myindex
= cbp
->c_nframes
;
1091 n
= (fcbp
- frames
) * FAREA
;
1095 * i == which overlap bit to test based on whether 'fcbp' is
1096 * an open or closed frame.
1099 for (; (tcbp
= cbp
->c_link
[1]) != NULL
;
1100 lcbp
= cbp
, cbp
= cbp
->c_link
[0]) {
1102 return (-1); /* fcbp is already included */
1104 /* check for intersection of 'tcbp' with 'fcbp' */
1106 mask
= str
[tcbp
- frames
];
1107 flags
= cbp
->c_flags
;
1108 n
= i
+ ((flags
& C_OPEN_1
) != 0);
1109 if (mask
& (1 << n
)) {
1111 * The two frames are not independent if they
1112 * both lie in the same line and intersect at
1113 * more than one point.
1115 if (tcbp
->c_dir
== fcbp
->c_dir
&& (mask
& (0x10 << n
)))
1118 * If this is not the spot we are attaching
1119 * 'fcbp' to and it is a reasonable intersection
1120 * spot, then there might be a loop.
1122 n
= ip
[tcbp
- frames
];
1123 if (osp
!= &board
[n
]) {
1124 /* check to see if this is a valid loop */
1127 if (fcnt
== 0 || cbp
->c_framecnt
[1] == 0)
1130 * Check to be sure the intersection is not
1131 * one of the end points if it is an open
1134 if ((flags
& C_OPEN_1
) &&
1135 (n
== tcbp
->c_vertex
||
1136 n
== tcbp
->c_vertex
+ 5 * dd
[tcbp
->c_dir
]))
1137 return (-1); /* invalid overlap */
1139 (n
== fcbp
->c_vertex
||
1140 n
== fcbp
->c_vertex
+ 5 * dd
[fcbp
->c_dir
]))
1141 return (-1); /* invalid overlap */
1143 vertices
->o_intersect
= n
;
1144 vertices
->o_fcombo
= cbp
;
1145 vertices
->o_link
= 1;
1146 vertices
->o_off
= (n
- tcbp
->c_vertex
) /
1148 vertices
->o_frameindex
= myindex
;
1152 n
= i
+ ((flags
& C_OPEN_0
) != 0);
1155 return (-1); /* fcbp is already included */
1157 /* check for intersection of 'cbp' with 'fcbp' */
1158 mask
= str
[cbp
- frames
];
1159 if (mask
& (1 << n
)) {
1161 * The two frames are not independent if they
1162 * both lie in the same line and intersect at
1163 * more than one point.
1165 if (cbp
->c_dir
== fcbp
->c_dir
&& (mask
& (0x10 << n
)))
1168 * If this is not the spot we are attaching
1169 * 'fcbp' to and it is a reasonable intersection
1170 * spot, then there might be a loop.
1172 n
= ip
[cbp
- frames
];
1173 if (osp
!= &board
[n
]) {
1174 /* check to see if this is a valid loop */
1177 if (fcnt
== 0 || lcbp
->c_framecnt
[0] == 0)
1180 * Check to be sure the intersection is not
1181 * one of the end points if it is an open
1184 if ((flags
& C_OPEN_0
) &&
1185 (n
== cbp
->c_vertex
||
1186 n
== cbp
->c_vertex
+ 5 * dd
[cbp
->c_dir
]))
1187 return (-1); /* invalid overlap */
1189 (n
== fcbp
->c_vertex
||
1190 n
== fcbp
->c_vertex
+ 5 * dd
[fcbp
->c_dir
]))
1191 return (-1); /* invalid overlap */
1193 vertices
->o_intersect
= n
;
1194 vertices
->o_fcombo
= lcbp
;
1195 vertices
->o_link
= 0;
1196 vertices
->o_off
= (n
- cbp
->c_vertex
) /
1198 vertices
->o_frameindex
= 0;
1206 * Merge sort the frame 'fcbp' and the sorted list of frames 'cbpp' and
1207 * store the result in 'scbpp'. 'curlevel' is the size of the 'cbpp' array.
1208 * Return true if this list of frames is already in the hash list.
1209 * Otherwise, add the new combo to the hash list.
1212 sortcombo(struct combostr
**scbpp
, struct combostr
**cbpp
,
1213 struct combostr
*fcbp
)
1215 struct combostr
**spp
, **cpp
;
1216 struct combostr
*cbp
, *ecbp
;
1224 debuglog("sortc: %s%c l%d", stoc(fcbp
->c_vertex
),
1225 pdir
[fcbp
->c_dir
], curlevel
);
1227 for (cpp
= cbpp
; cpp
< cbpp
+ curlevel
; cpp
++) {
1228 snprintf(buf
+ pos
, sizeof(buf
) - pos
, " %s%c",
1229 stoc((*cpp
)->c_vertex
), pdir
[(*cpp
)->c_dir
]);
1230 pos
+= strlen(buf
+ pos
);
1232 debuglog("%s", buf
);
1236 /* first build the new sorted list */
1239 cpp
= cbpp
+ curlevel
;
1246 while (cpp
-- != cbpp
);
1250 } while (cpp
!= cbpp
);
1254 /* now check to see if this list of frames has already been seen */
1255 cbp
= hashcombos
[inx
= *scbpp
- frames
];
1256 if (cbp
== (struct combostr
*)0) {
1258 * Easy case, this list hasn't been seen.
1259 * Add it to the hash list.
1261 fcbp
= (struct combostr
*)
1262 ((char *)scbpp
- sizeof(struct combostr
));
1263 hashcombos
[inx
] = fcbp
;
1264 fcbp
->c_next
= fcbp
->c_prev
= fcbp
;
1269 cbpp
= (struct combostr
**)(cbp
+ 1);
1272 cbpp
++; /* first frame is always the same */
1274 if (*--spp
!= *--cpp
)
1276 } while (cpp
!= cbpp
);
1277 /* we found a match */
1283 debuglog("sort1: n%d", n
);
1285 for (cpp
= scbpp
; cpp
< scbpp
+ n
; cpp
++) {
1286 snprintf(buf
+ pos
, sizeof(buf
) - pos
, " %s%c",
1287 stoc((*cpp
)->c_vertex
),
1288 pdir
[(*cpp
)->c_dir
]);
1289 pos
+= strlen(buf
+ pos
);
1291 debuglog("%s", buf
);
1292 printcombo(cbp
, buf
, sizeof(buf
));
1293 debuglog("%s", buf
);
1296 for (cpp
= cbpp
; cpp
< cbpp
+ n
; cpp
++) {
1297 snprintf(buf
+ pos
, sizeof(buf
) - pos
, " %s%c",
1298 stoc((*cpp
)->c_vertex
),
1299 pdir
[(*cpp
)->c_dir
]);
1300 pos
+= strlen(buf
+ pos
);
1302 debuglog("%s", buf
);
1308 } while ((cbp
= cbp
->c_next
) != ecbp
);
1310 * This list of frames hasn't been seen.
1311 * Add it to the hash list.
1314 fcbp
= (struct combostr
*)((char *)scbpp
- sizeof(struct combostr
));
1316 fcbp
->c_prev
= ecbp
;
1318 ecbp
->c_next
= fcbp
;
1323 * Print the combo into string buffer 'buf'.
1326 printcombo(struct combostr
*cbp
, char *buf
, size_t max
)
1328 struct combostr
*tcbp
;
1331 snprintf(buf
+ pos
, max
- pos
, "%x/%d",
1332 cbp
->c_combo
.s
, cbp
->c_nframes
);
1333 pos
+= strlen(buf
+ pos
);
1335 for (; (tcbp
= cbp
->c_link
[1]) != NULL
; cbp
= cbp
->c_link
[0]) {
1336 snprintf(buf
+ pos
, max
- pos
, " %s%c%x",
1337 stoc(tcbp
->c_vertex
), pdir
[tcbp
->c_dir
], cbp
->c_flags
);
1338 pos
+= strlen(buf
+ pos
);
1340 snprintf(buf
+ pos
, max
- pos
, " %s%c",
1341 stoc(cbp
->c_vertex
), pdir
[cbp
->c_dir
]);
1346 markcombo(struct combostr
*ocbp
)
1348 struct combostr
*cbp
, *tcbp
, **cbpp
;
1349 struct elist
*ep
, *nep
;
1355 /* should never happen but check anyway */
1356 if ((nframes
= ocbp
->c_nframes
) >= MAXDEPTH
)
1360 * The lower level combo can be pointed to by more than one
1361 * higher level 'struct combostr' so we can't modify the
1362 * lower level. Therefore, higher level combos store the
1363 * real mask of the lower level frame in c_emask[0] and the
1364 * frame number in c_frameindex.
1366 * First we traverse the tree from top to bottom and save the
1367 * connection info. Then we traverse the tree from bottom to
1368 * top overwriting lower levels with the newer emask information.
1370 ep
= &einfo
[nframes
];
1371 cbpp
= &ecombo
[nframes
];
1372 for (cbp
= ocbp
; (tcbp
= cbp
->c_link
[1]) != NULL
; cbp
= cbp
->c_link
[0]) {
1375 *--cbpp
= cbp
->c_link
[1];
1376 ep
->e_off
= cbp
->c_voff
[1];
1377 ep
->e_frameindex
= cbp
->c_frameindex
;
1378 ep
->e_fval
.s
= cbp
->c_linkv
[1].s
;
1379 ep
->e_framecnt
= cbp
->c_framecnt
[1];
1380 ep
->e_emask
= cbp
->c_emask
[1];
1385 *--cbpp
= cbp
->c_link
[0];
1386 ep
->e_off
= cbp
->c_voff
[0];
1387 ep
->e_frameindex
= 0;
1388 ep
->e_fval
.s
= cbp
->c_linkv
[0].s
;
1389 ep
->e_framecnt
= cbp
->c_framecnt
[0];
1390 ep
->e_emask
= cbp
->c_emask
[0];
1392 /* now update the emask info */
1394 for (i
= 2, ep
+= 2; i
< nframes
; i
++, ep
++) {
1396 nep
= &einfo
[ep
->e_frameindex
];
1397 nep
->e_framecnt
= cbp
->c_framecnt
[0];
1398 nep
->e_emask
= cbp
->c_emask
[0];
1400 if (cbp
->c_flags
& C_LOOP
) {
1403 * Account for the fact that this frame connects
1404 * to a previous one (thus forming a loop).
1406 nep
= &einfo
[cbp
->c_dir
];
1407 if (--nep
->e_framecnt
)
1408 nep
->e_emask
&= ~(1 << cbp
->c_voff
[0]);
1415 * We only need to update the emask values of "complete" loops
1416 * to include the intersection spots.
1418 if (s
&& ocbp
->c_combo
.c
.a
== 2) {
1419 /* process loops from the top down */
1420 ep
= &einfo
[nframes
];
1424 if (!(cbp
->c_flags
& C_LOOP
))
1428 * Update the emask values to include the
1429 * intersection spots.
1431 nep
= &einfo
[cbp
->c_dir
];
1432 nep
->e_framecnt
= 1;
1433 nep
->e_emask
= 1 << cbp
->c_voff
[0];
1435 ep
->e_emask
= 1 << ep
->e_off
;
1436 ep
= &einfo
[ep
->e_frameindex
];
1439 ep
->e_emask
= 1 << ep
->e_off
;
1440 ep
= &einfo
[ep
->e_frameindex
];
1442 } while (ep
!= einfo
);
1445 /* mark all the frames with the completion spots */
1446 for (i
= 0, ep
= einfo
, cbpp
= ecombo
; i
< nframes
; i
++, ep
++, cbpp
++) {
1449 sp
= &board
[cbp
->c_vertex
];
1450 d
= dd
[s
= cbp
->c_dir
];
1452 omask
= (IFLAG
| CFLAG
) << s
;
1453 s
= ep
->e_fval
.c
.b
? 6 : 5;
1454 for (; --s
>= 0; sp
+= d
, m
>>= 1)
1455 sp
->s_flags
|= (m
& 1) ? omask
: cmask
;
1460 clearcombo(struct combostr
*cbp
, int open
)
1463 struct combostr
*tcbp
;
1466 for (; (tcbp
= cbp
->c_link
[1]) != NULL
; cbp
= cbp
->c_link
[0]) {
1467 clearcombo(tcbp
, cbp
->c_flags
& C_OPEN_1
);
1468 open
= cbp
->c_flags
& C_OPEN_0
;
1470 sp
= &board
[cbp
->c_vertex
];
1471 d
= dd
[n
= cbp
->c_dir
];
1472 mask
= ~((IFLAG
| CFLAG
) << n
);
1474 for (; --n
>= 0; sp
+= d
)
1475 sp
->s_flags
&= mask
;
1479 list_eq(struct combostr
**scbpp
, struct combostr
**cbpp
, int n
)
1481 struct combostr
**spp
, **cpp
;
1486 if (*--spp
!= *--cpp
)
1488 } while (cpp
!= cbpp
);
1489 /* we found a match */