bool Play()

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;
}