/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
* http://www.gnu.org/software/gnugo/ for more information. *
* Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
* 2008 and 2009 by the Free Software Foundation. *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation - version 3 or *
* (at your option) any later version. *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License in file COPYING for more details. *
* You should have received a copy of the GNU General Public *
* License along with this program; if not, write to the Free *
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02111, USA. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* ================================================================ */
/* Set up fixed placement handicap stones for black side */
/* ================================================================ */
/* Handicap stones are set up according to the following diagrams:
* A B C D E F G H J A B C D E F G H J
* 9 . . . . . . . . . 9 9 . . . . . . . . . 9
* 8 . . . . . . . . . 8 8 . . . . . . . . . 8
* 7 . . + . . . X . . 7 7 . . X . . . X . . 7
* 6 . . . . . . . . . 6 6 . . . . . . . . . 6
* 5 . . . . + . . . . 5 5 . . . . + . . . . 5
* 4 . . . . . . . . . 4 4 . . . . . . . . . 4
* 3 . . X . . . + . . 3 3 . . X . . . + . . 3
* 2 . . . . . . . . . 2 2 . . . . . . . . . 2
* 1 . . . . . . . . . 1 1 . . . . . . . . . 1
* A B C D E F G H J A B C D E F G H J
* A B C D E F G H J A B C D E F G H J
* 9 . . . . . . . . . 9 9 . . . . . . . . . 9
* 8 . . . . . . . . . 8 8 . . . . . . . . . 8
* 7 . . X . . . X . . 7 7 . . X . . . X . . 7
* 6 . . . . . . . . . 6 6 . . . . . . . . . 6
* 5 . . . . + . . . . 5 5 . . . . X . . . . 5
* 4 . . . . . . . . . 4 4 . . . . . . . . . 4
* 3 . . X . . . X . . 3 3 . . X . . . X . . 3
* 2 . . . . . . . . . 2 2 . . . . . . . . . 2
* 1 . . . . . . . . . 1 1 . . . . . . . . . 1
* A B C D E F G H J A B C D E F G H J
* A B C D E F G H J A B C D E F G H J
* 9 . . . . . . . . . 9 9 . . . . . . . . . 9
* 8 . . . . . . . . . 8 8 . . . . . . . . . 8
* 7 . . X . . . X . . 7 7 . . X . . . X . . 7
* 6 . . . . . . . . . 6 6 . . . . . . . . . 6
* 5 . . X . + . X . . 5 5 . . X . X . X . . 5
* 4 . . . . . . . . . 4 4 . . . . . . . . . 4
* 3 . . X . . . X . . 3 3 . . X . . . X . . 3
* 2 . . . . . . . . . 2 2 . . . . . . . . . 2
* 1 . . . . . . . . . 1 1 . . . . . . . . . 1
* A B C D E F G H J A B C D E F G H J
* A B C D E F G H J A B C D E F G H J
* 9 . . . . . . . . . 9 9 . . . . . . . . . 9
* 8 . . . . . . . . . 8 8 . . . . . . . . . 8
* 7 . . X . X . X . . 7 7 . . X . X . X . . 7
* 6 . . . . . . . . . 6 6 . . . . . . . . . 6
* 5 . . X . + . X . . 5 5 . . X . X . X . . 5
* 4 . . . . . . . . . 4 4 . . . . . . . . . 4
* 3 . . X . X . X . . 3 3 . . X . X . X . . 3
* 2 . . . . . . . . . 2 2 . . . . . . . . . 2
* 1 . . . . . . . . . 1 1 . . . . . . . . . 1
* A B C D E F G H J A B C D E F G H J
* For odd-sized boards larger than 9x9, the same pattern is followed,
* except that the edge stones are moved to the fourth line for 13x13
* For even-sized boards at least 8x8, only the four first diagrams
* are used, because there is no way to place the center stones
* symmetrically. As for odd-sized boards, the edge stones are moved
* to the fourth line for boards larger than 11x11.
* At most four stones are placed on 7x7 boards too (this size may or
* may not be supported by the rest of the engine). No handicap stones
* are ever placed on smaller boards.
* Notice that this function only deals with fixed handicap placement.
* Larger handicaps can be added by free placement if the used
/* This table contains the (coded) positions of the stones.
* 2 maps to 2 or 3, depending on board size
* -ve numbers map to board_size - number
* The stones are placed in this order, *except* if there are
* 5 or 7 stones, in which case center ({0, 0}) is placed, and
static const int places
[][2] = {
{2, -2}, {-2, 2}, {2, 2}, {-2, -2}, /* first 4 are easy */
/* for 5, {0,0} is explicitly placed */
{0, 2}, {0, -2}, /* for 6 these two are placed */
/* for 7, {0,0} is explicitly placed */
{2, 0}, {-2, 0}, /* for 8, these two are placed */
{0, 0}, /* finally tengen for 9 */
* Sets up fixed handicap placement stones, returning the number of
* placed handicap stones and also setting the global variable
* handicap to the same value.
place_fixed_handicap(int desired_handicap
)
int three
= board_size
> 11 ? 3 : 2;
/* A handicap of 1 just means that B plays first, no komi.
* Black is not told where to play the first stone so no handicap
if (desired_handicap
< 2) {
if ((board_size
% 2 == 1) && (board_size
>= 9))
else if (board_size
>= 7)
/* It's up to the caller of this function to notice if the handicap
* was too large for fixed placement and act upon that.
if (desired_handicap
> max_handicap
)
handicap
= desired_handicap
;
remaining_stones
= handicap
;
/* special cases: 5 and 7 */
if (desired_handicap
== 5 || desired_handicap
== 7) {
add_stone(POS(mid
, mid
), BLACK
);
for (r
= 0; r
< remaining_stones
; r
++) {
/* Translate the encoded values to board co-ordinates. */
i
= board_size
- 1 - three
;
j
= board_size
- 1 - three
;
add_stone(POS(i
, j
), BLACK
);
/* ================================================================ */
/* Set up free placement handicap stones for black side */
/* ================================================================ */
* Sets up free handicap placement stones, returning the number of
* placed handicap stones.
static int remaining_handicap_stones
= -1;
static int total_handicap_stones
= -1;
static int find_free_handicap_pattern(void);
static void free_handicap_callback(int anchor
, int color
,
* Sets up free placement handicap stones, returning the number of
* placed handicap stones and also setting the global variable
* handicap to the same value.
place_free_handicap(int desired_handicap
)
gg_assert(desired_handicap
== 0 || desired_handicap
>= 2);
if (desired_handicap
== 0) {
total_handicap_stones
= desired_handicap
;
remaining_handicap_stones
= desired_handicap
;
/* First place black stones in the four corners to enable the
* pattern matching scheme.
add_stone(POS(0, 0), BLACK
);
add_stone(POS(0, board_size
- 1), BLACK
);
add_stone(POS(board_size
- 1, 0), BLACK
);
add_stone(POS(board_size
- 1, board_size
- 1), BLACK
);
/* Find and place free handicap stones by pattern matching. */
while (remaining_handicap_stones
> 0) {
if (!find_free_handicap_pattern())
/* Remove the artificial corner stones. */
remove_stone(POS(0, board_size
- 1));
remove_stone(POS(board_size
- 1, 0));
remove_stone(POS(board_size
- 1, board_size
- 1));
/* Find and place additional free handicap stones by the aftermath
while (remaining_handicap_stones
> 0) {
/* Call genmove_conservative() in order to prepare the engine for
* an aftermath_genmove() call. We discard the genmove result.
genmove_conservative(BLACK
, NULL
);
move
= aftermath_genmove(BLACK
, 0, NULL
);
remaining_handicap_stones
--;
/* Set handicap to the number of actually placed stones. */
handicap
= desired_handicap
- remaining_handicap_stones
;
/* Reset these to invalid values, so that improper use of handicap
* helper functions can be detected.
total_handicap_stones
= -1;
remaining_handicap_stones
= -1;
#define MAX_HANDICAP_MATCHES 40
static struct handicap_match handicap_matches
[MAX_HANDICAP_MATCHES
];
static int number_of_matches
;
find_free_handicap_pattern()
matchpat(free_handicap_callback
, BLACK
, &handipat_db
, NULL
, NULL
);
if (number_of_matches
== 0)
/* Find the highest value among the matched patterns. */
for (k
= 0; k
< number_of_matches
; k
++)
if (highest_value
< handicap_matches
[k
].value
)
highest_value
= handicap_matches
[k
].value
;
/* Replace the values by 2^(value - highest_value + 10) and compute
* the sum of these values. Fractional values are discarded.
for (k
= 0; k
< number_of_matches
; k
++) {
if (handicap_matches
[k
].value
< highest_value
- 10)
handicap_matches
[k
].value
= 0;
handicap_matches
[k
].value
= 1 << (handicap_matches
[k
].value
sum_values
+= handicap_matches
[k
].value
;
/* Pick a random number between 0 and sum_values. Don't bother with
* the fact that lower numbers will tend to be very slightly
r
= gg_rand() % sum_values
;
/* Find the chosen pattern. */
for (k
= 0; k
< number_of_matches
; k
++) {
r
-= handicap_matches
[k
].value
;
/* Place handicap stones according to pattern k. */
anchor
= handicap_matches
[k
].anchor
;
pattern
= handicap_matches
[k
].pattern
;
ll
= handicap_matches
[k
].ll
;
/* Pick up the location of the move */
move
= AFFINE_TRANSFORM(pattern
->move_offset
, ll
, anchor
);
remaining_handicap_stones
--;
/* Add stones at all '!' in the pattern. */
for (k
= 0; k
< pattern
->patlen
; k
++) {
if (pattern
->patn
[k
].att
== ATT_not
) {
int pos
= AFFINE_TRANSFORM(pattern
->patn
[k
].offset
, ll
, anchor
);
remaining_handicap_stones
--;
free_handicap_callback(int anchor
, int color
, struct pattern
*pattern
,
int number_of_stones
= 1;
/* Pick up the location of the move */
int move
= AFFINE_TRANSFORM(pattern
->move_offset
, ll
, anchor
);
/* Check how many stones are placed by the pattern. This must not be
* larger than the number of remaining handicap stones.
for (k
= 0; k
< pattern
->patlen
; k
++) {
if (pattern
->patn
[k
].att
== ATT_not
)
if (number_of_stones
> remaining_handicap_stones
)
/* If the pattern has a constraint, call the autohelper to see
* if the pattern must be rejected.
if (pattern
->autohelper_flag
& HAVE_CONSTRAINT
) {
if (!pattern
->autohelper(ll
, move
, color
, 0))
if (number_of_matches
< MAX_HANDICAP_MATCHES
) {
int least_value
= handicap_matches
[0].value
+ 1;
for (k
= 0; k
< number_of_matches
; k
++) {
if (handicap_matches
[k
].value
< least_value
) {
least_value
= handicap_matches
[k
].value
;
gg_assert(r
>= 0 && r
< MAX_HANDICAP_MATCHES
);
handicap_matches
[r
].value
= pattern
->value
;
handicap_matches
[r
].anchor
= anchor
;
handicap_matches
[r
].pattern
= pattern
;
handicap_matches
[r
].ll
= ll
;
free_handicap_remaining_stones()
gg_assert(remaining_handicap_stones
>= 0);
return remaining_handicap_stones
;
free_handicap_total_stones()
gg_assert(total_handicap_stones
>= 0);
return total_handicap_stones
;