Skip to content

Commit

Permalink
Merge pull request #99 from lemonsqueeze/fixes
Browse files Browse the repository at this point in the history
Fixes
  • Loading branch information
lemonsqueeze authored Feb 11, 2019
2 parents 4d8e916 + 14d273e commit 1d45610
Show file tree
Hide file tree
Showing 18 changed files with 730 additions and 203 deletions.
81 changes: 50 additions & 31 deletions board.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "fbook.h"
#include "mq.h"
#include "random.h"
#include "ownermap.h"

#ifdef BOARD_PAT3
#include "pattern3.h"
Expand Down Expand Up @@ -1494,17 +1495,17 @@ board_play_random(struct board *b, enum stone color, coord_t *coord, ppr_permit
}


/* XXX: We attempt false eye detection but we will yield false
* positives in case of http://senseis.xmp.net/?TwoHeadedDragon :-( */
bool
board_is_false_eyelike(struct board *board, coord_t coord, enum stone eye_color)
{
enum stone color_diag_libs[S_MAX] = {0, 0, 0, 0};

/* XXX: We attempt false eye detection but we will yield false
* positives in case of http://senseis.xmp.net/?TwoHeadedDragon :-( */

foreach_diag_neighbor(board, coord) {
color_diag_libs[(enum stone) board_at(board, c)]++;
} foreach_diag_neighbor_end;

/* For false eye, we need two enemy stones diagonally in the
* middle of the board, or just one enemy stone at the edge
* or in the corner. */
Expand All @@ -1513,21 +1514,18 @@ board_is_false_eyelike(struct board *board, coord_t coord, enum stone eye_color)
}

bool
board_is_one_point_eye(struct board *board, coord_t coord, enum stone eye_color)
board_is_one_point_eye(struct board *b, coord_t c, enum stone eye_color)
{
return board_is_eyelike(board, coord, eye_color)
&& !board_is_false_eyelike(board, coord, eye_color);
return (board_is_eyelike(b, c, eye_color) &&
!board_is_false_eyelike(b, c, eye_color));
}

enum stone
board_get_one_point_eye(struct board *board, coord_t coord)
board_eye_color(struct board *b, coord_t c)
{
if (board_is_one_point_eye(board, coord, S_WHITE))
return S_WHITE;
else if (board_is_one_point_eye(board, coord, S_BLACK))
return S_BLACK;
else
return S_NONE;
if (board_is_eyelike(b, c, S_WHITE)) return S_WHITE;
if (board_is_eyelike(b, c, S_BLACK)) return S_BLACK;
return S_NONE;
}

floating_t
Expand All @@ -1538,7 +1536,7 @@ board_fast_score(struct board *board)
foreach_point(board) {
enum stone color = board_at(board, c);
if (color == S_NONE && board->rules != RULES_STONES_ONLY)
color = board_get_one_point_eye(board, c);
color = board_eye_color(board, c);
scores[color]++;
// fprintf(stderr, "%d, %d ++%d = %d\n", coord_x(c, board), coord_y(c, board), color, scores[color]);
} foreach_point_end;
Expand Down Expand Up @@ -1622,8 +1620,12 @@ board_score(struct board *b, int scores[S_MAX])
int handi_comp = board_score_handicap_compensation(b);
floating_t score = b->komi + handi_comp + scores[S_WHITE] - scores[S_BLACK];

/* Aja's formula for converting playouts area scoring to territory.
* http://computer-go.org/pipermail/computer-go/2010-April/000209.html */
/* Aja's formula for converting area scoring to territory:
* http://computer-go.org/pipermail/computer-go/2010-April/000209.html
* Under normal circumstances there's a relationship between area
* and territory scoring so we can derive one from the other. If
* the board has been artificially edited however the relationship
* is broken and japanese score will be off. */
if (b->rules == RULES_JAPANESE)
score += (b->last_move.color == S_BLACK) + (b->passes[S_WHITE] - b->passes[S_BLACK]);
return score;
Expand All @@ -1644,9 +1646,11 @@ board_print_official_ownermap(struct board *b, int *final_ownermap)
}

/* Official score after removing dead groups and Tromp-Taylor counting.
* Number of dames is saved in @dames, final ownermap in @ownermap. */
* Returns number of dames, sekis, final ownermap in @dame, @seki, @ownermap.
* (only distinguishes between dames/sekis if @po is not NULL) */
floating_t
board_official_score_details(struct board *board, struct move_queue *dead, int *dames, int *ownermap)
board_official_score_details(struct board *b, struct move_queue *dead,
int *dame, int *seki, int *ownermap, struct ownermap *po)
{
/* A point P, not colored C, is said to reach C, if there is a path of
* (vertically or horizontally) adjacent points of P's color from P to
Expand All @@ -1657,16 +1661,16 @@ board_official_score_details(struct board *board, struct move_queue *dead, int *

int s[4] = {0};
const int o[4] = {0, 1, 2, 0};
foreach_point(board) {
ownermap[c] = o[board_at(board, c)];
s[board_at(board, c)]++;
foreach_point(b) {
ownermap[c] = o[board_at(b, c)];
s[board_at(b, c)]++;
} foreach_point_end;

if (dead) {
/* Process dead groups. */
for (unsigned int i = 0; i < dead->moves; i++) {
foreach_in_group(board, dead->move[i]) {
enum stone color = board_at(board, c);
foreach_in_group(b, dead->move[i]) {
enum stone color = board_at(b, c);
ownermap[c] = o[stone_other(color)];
s[color]--; s[stone_other(color)]++;
} foreach_in_group_end;
Expand All @@ -1675,28 +1679,43 @@ board_official_score_details(struct board *board, struct move_queue *dead, int *

/* We need to special-case empty board. */
if (!s[S_BLACK] && !s[S_WHITE])
return board->komi;
return b->komi;

while (board_tromp_taylor_iter(board, ownermap))
while (board_tromp_taylor_iter(b, ownermap))
/* Flood-fill... */;

int scores[S_MAX] = { 0, };

foreach_point(board) {
assert(board_at(board, c) == S_OFFBOARD || ownermap[c] != 0);
foreach_point(b) {
assert(board_at(b, c) == S_OFFBOARD || ownermap[c] != 0);
scores[ownermap[c]]++;
} foreach_point_end;
*dames = scores[3];
*dame = scores[3];
*seki = 0;

if (po) {
foreach_point(b) {
if (ownermap_judge_point(po, c, GJ_THRES) != PJ_SEKI) continue;
(*seki)++; (*dame)--;
} foreach_point_end;
}

return board_score(board, scores);
return board_score(b, scores);
}

floating_t
board_official_score(struct board *b, struct move_queue *dead)
{
int dame;
int dame, seki;
int ownermap[board_size2(b)];
return board_official_score_details(b, dead, &dame, ownermap);
return board_official_score_details(b, dead, &dame, &seki, ownermap, NULL);
}

floating_t
board_official_score_color(struct board *b, struct move_queue *dead, enum stone color)
{
floating_t score = board_official_score(b, dead);
return (color == S_WHITE ? score : -score);
}

bool
Expand Down
55 changes: 7 additions & 48 deletions board.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "mq.h"

struct fbook;

struct ownermap;

/* Maximum supported board size. (Without the S_OFFBOARD edges.) */
#define BOARD_MAX_SIZE 19
Expand Down Expand Up @@ -382,10 +382,6 @@ static bool board_is_valid_play(struct board *b, enum stone color, coord_t coord
static bool board_is_valid_move(struct board *b, struct move *m);
/* Returns true if ko was just taken. */
static bool board_playing_ko_threat(struct board *b);
/* Returns 0 or ID of neighboring group in atari. */
static group_t board_get_atari_neighbor(struct board *b, coord_t coord, enum stone group_color);
/* Get all neighboring groups in atari */
static void board_get_atari_neighbors(struct board *b, coord_t coord, enum stone group_color, struct move_queue *q);
/* Returns true if the move is not obvious self-atari. */
static bool board_safe_to_play(struct board *b, coord_t coord, enum stone color);

Expand All @@ -408,8 +404,8 @@ bool board_is_false_eyelike(struct board *board, coord_t coord, enum stone eye_c
/* Returns true if given coordinate is a 1-pt eye (checks against false eyes, or
* at least tries to). */
bool board_is_one_point_eye(struct board *board, coord_t c, enum stone eye_color);
/* Returns color of a 1pt eye owner, S_NONE if not an eye. */
enum stone board_get_one_point_eye(struct board *board, coord_t c);
/* Returns 1pt eye color (can be false-eye) */
enum stone board_eye_color(struct board *board, coord_t c);

/* board_official_score() is the scoring method for yielding score suitable
* for external presentation. For fast scoring of entirely filled boards
Expand All @@ -421,7 +417,8 @@ floating_t board_score(struct board *b, int scores[S_MAX]);
/* Tromp-Taylor scoring, assuming given groups are actually dead. */
struct move_queue;
floating_t board_official_score(struct board *board, struct move_queue *dead);
floating_t board_official_score_details(struct board *board, struct move_queue *dead, int *dame, int *final_ownermap);
floating_t board_official_score_color(struct board *board, struct move_queue *dead, enum stone color);
floating_t board_official_score_details(struct board *board, struct move_queue *dead, int *dame, int *seki, int *ownermap, struct ownermap *po);
void board_print_official_ownermap(struct board *b, int *final_ownermap);

/* Set board rules according to given string. Returns false in case
Expand Down Expand Up @@ -551,8 +548,8 @@ void board_quick_undo(struct board *b, struct move *m, struct board_undo *u);
static inline bool
board_is_eyelike(struct board *board, coord_t coord, enum stone eye_color)
{
return (neighbor_count_at(board, coord, eye_color)
+ neighbor_count_at(board, coord, S_OFFBOARD)) == 4;
return (neighbor_count_at(board, coord, eye_color) +
neighbor_count_at(board, coord, S_OFFBOARD)) == 4;
}

/* Group suicides allowed */
Expand Down Expand Up @@ -616,44 +613,6 @@ board_playing_ko_threat(struct board *b)
return !is_pass(b->ko.coord);
}

static inline group_t
board_get_atari_neighbor(struct board *b, coord_t coord, enum stone group_color)
{
assert(coord != pass);
foreach_neighbor(b, coord, {
group_t g = group_at(b, c);
if (g && board_at(b, c) == group_color && board_group_info(b, g).libs == 1)
return g;
/* We return first match. */
});
return 0;
}

static inline void
board_get_atari_neighbors(struct board *b, coord_t c, enum stone group_color, struct move_queue *q)
{
assert(c != pass);
q->moves = 0;
foreach_neighbor(b, c, {
group_t g = group_at(b, c);
if (g && board_at(b, c) == group_color && board_group_info(b, g).libs == 1) {
mq_add(q, g, 0);
mq_nodup(q);
}
});
}

#define foreach_atari_neighbor(b, c, group_color) \
do { \
struct move_queue __q; \
board_get_atari_neighbors(b, (c), (group_color), &__q); \
for (unsigned int __i = 0; __i < __q.moves; __i++) { \
group_t g = __q.move[__i];

#define foreach_atari_neighbor_end \
} \
} while (0)


static inline bool
board_safe_to_play(struct board *b, coord_t coord, enum stone color)
Expand Down
4 changes: 2 additions & 2 deletions gogui.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,9 +438,9 @@ cmd_gogui_final_score(struct board *b, struct engine *e, struct time_info *ti, g
struct move_queue q = { .moves = 0 };
if (e->dead_group_list) e->dead_group_list(e, b, &q);

int dame;
int dame, seki;
int ownermap[board_size2(b)];
floating_t score = board_official_score_details(b, &q, &dame, ownermap);
floating_t score = board_official_score_details(b, &q, &dame, &seki, ownermap, NULL);
char buffer[5000]; strbuf_t strbuf;
strbuf_t *buf = strbuf_init(&strbuf, buffer, sizeof(buffer));

Expand Down
2 changes: 1 addition & 1 deletion gtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ cmd_final_status_list_seki(char *arg, struct board *b, struct engine *e, gtp_t *
struct move_queue sekis = { .moves = 0 };
foreach_point(b) {
if (board_at(b, c) == S_OFFBOARD) continue;
if (ownermap_judge_point(ownermap, c, 0.80) != PJ_DAME) continue;
if (ownermap_judge_point(ownermap, c, 0.80) != PJ_SEKI) continue;

foreach_neighbor(b, c, {
group_t g = group_at(b, c);
Expand Down
Loading

0 comments on commit 1d45610

Please sign in to comment.