in go/board.cc [1083:1179]
bool Play(Board *board, const GroupId4 *ids) {
assert(board, "Play: Board is nil!");
assert(ids, "Play: GroupIds4 is nil!");
board->_num_group_removed = 0;
// Place the stone on the coordinate, and update other structures.
Coord c = ids->c;
Stone player = ids->player;
if (c == M_PASS || c == M_RESIGN) {
update_next_move(board, c, player);
return IsGameEnd(board);
}
short new_id = 0;
unsigned short liberty = ids->liberty;
short total_capture = 0;
Coord capture_c = 0;
bool merge_two_groups_called = false;
for (int i = 0; i < 4; ++i) {
// printf("Analysis #%d: id = %d, color = %d, liberty = %d\n", i, ids->ids[i], ids->colors[i], ids->group_liberties[i]);
// Skip NULL group.
if (ids->ids[i] == 0) continue;
unsigned short id = ids->ids[i];
Group* g = &board->_groups[id];
Stone s = g->color;
// The group adjacent to it lose one liberty.
-- g->liberties;
if (s == player) {
// Self-group.
if (new_id == 0) {
// Merge the current stone with the current group.
MergeToGroup(board, c, id);
new_id = id;
// printf("Merge with group %d, preducing id = %d", id, new_id);
}
else {
// int prev_new_id = new_id;
// Merge two large groups.
new_id = MergeGroups(board, new_id, id);
merge_two_groups_called = true;
// printf("Merge with group %d with existing id %d, producing id = %d", id, prev_new_id, new_id);
}
} else {
// Enemy group, If the enemy group has zero liberties, it is killed.
if (g->liberties == 0) {
// printf("kill group %d of size %d\n", id, g->stones);
if (player == S_BLACK) board->_b_cap += g->stones;
else board->_w_cap += g->stones;
total_capture += g->stones;
// Compute the adjacent enemy point.
capture_c = c + delta4[i];
// Add our liberties if the new stone is not yet forming a group.
// Otherwise the liberties of a dead group's surrounding groups will be taken care of automatically.
if (new_id == 0) {
FOR4(c, _, c4) {
if (board->_infos[c4].id == id) liberty ++;
} ENDFOR4
}
// Remove stones of the group.
EmptyGroup(board, id);
}
}
}
// if (new_id > 0) RecomputeGroupLiberties(board, new_id);
if (merge_two_groups_called) RecomputeGroupLiberties(board, new_id);
if (new_id == 0) {
// It has not merged with other groups, create a new one.
board->_infos[c].color = player;
// Place the stone.
board->_infos[c].last_placed = board->_ply;
new_id = CreateNewGroup(board, c, liberty);
}
// Check simple ko conditions.
const Group* g = &board->_groups[new_id];
if (g->liberties == 1 && g->stones == 1 && total_capture == 1) {
board->_simple_ko = capture_c;
board->_simple_ko_color = OPPONENT(player);
board->_ko_age = 0;
} else {
board->_ko_age ++;
// board->_simple_ko = M_PASS;
}
// We need to run it in the end. After that all group index will be invalid.
RemoveAllEmptyGroups(board);
// Finally add the counter.
update_next_move(board, c, player);
return false;
}