Skip to content

Commit

Permalink
bug fixes for database board text
Browse files Browse the repository at this point in the history
This patch fixes extra '\0' recorded in text of database records, which are accidentally caused by the use of std::string::append(). It will automatically remove such '\0' in the string if there is any.

Also, when there are board texts recorded but not corresponding child database records, the board texts are not shown which may cause confusion. This patch fixes this, and all children with either a record or a board text will be displayed.

[skip_fishtest]
  • Loading branch information
dhbloo committed Jul 21, 2024
1 parent 2c4c6ce commit cc6d45a
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 86 deletions.
65 changes: 43 additions & 22 deletions Rapfi/command/gomocup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,27 +789,49 @@ void queryDatabaseAll(bool getPosition)

DBClient dbClient(*Search::Threads.dbStorage(), RECORD_MASK_ALL);

std::vector<std::pair<Pos, DBRecord>> childRecords;
dbClient.queryChildren(*board, options.rule, childRecords);
// Get all child records and child board texts
auto childRecords = dbClient.queryChildren(*board, options.rule);
auto boardPosAndTexts = dbClient.queryBoardTexts(*board, options.rule);

for (auto &[pos, record] : childRecords) {
std::string displayLabel = record.displayLabel();
// Iterate all empty positions
auto childRecordIt = childRecords.begin();
auto boardPosAndTextsIt = boardPosAndTexts.begin();
FOR_EVERY_EMPTY_POS(board, pos)
{
bool printThisPos = false;
int displayLabelValue = -1;
if (!displayLabel.empty()) {
displayLabelValue = 0;
if (displayLabel.length() > 4)
displayLabel = displayLabel.substr(0, 4);
for (char c : displayLabel)
displayLabelValue = (displayLabelValue << 8) | c;
std::string boardTextUTF8;
DBRecord record {}; // init as null record

if (childRecordIt != childRecords.end() && childRecordIt->first == pos) {
record = childRecordIt->second;
std::string displayLabel = record.displayLabel();
if (!displayLabel.empty()) {
// Encode the display label (maximum 4 chars) as an int32
if (displayLabel.length() > 4)
displayLabel = displayLabel.substr(0, 4);
displayLabelValue = 0;
for (char c : displayLabel)
displayLabelValue = (displayLabelValue << 8) | c;
}
childRecordIt++;
printThisPos = true;
}

if (boardPosAndTextsIt != boardPosAndTexts.end() && boardPosAndTextsIt->first == pos) {
boardTextUTF8 = std::move(boardPosAndTextsIt->second);
boardPosAndTextsIt++;
printThisPos = true;
}

std::string boardTextUTF8 = dbClient.queryBoardText(*board, options.rule, pos);
MESSAGEL("DATABASE " << outputCoordXConvert(pos, board->size()) << ' '
<< outputCoordYConvert(pos, board->size()) << ' '
<< displayLabelValue << ' ' << record.value << ' '
<< record.depth() << ' ' << int(record.bound()) << ' '
<< int(!record.comment().empty()) << ' '
<< UTF8ToConsoleCP(boardTextUTF8));
// Print this position if it has DBRecord or board text
if (printThisPos)
MESSAGEL("DATABASE " << outputCoordXConvert(pos, board->size()) << ' '
<< outputCoordYConvert(pos, board->size()) << ' '
<< displayLabelValue << ' ' << record.value << ' '
<< record.depth() << ' ' << int(record.bound()) << ' '
<< int(!record.comment().empty()) << ' '
<< UTF8ToConsoleCP(boardTextUTF8));
}

MESSAGEL("DATABASE DONE");
Expand Down Expand Up @@ -894,8 +916,8 @@ void editDatabaseText()
DBRecord record;
if (!dbClient.query(*board, options.rule, record))
record = DBRecord {LABEL_NONE};
std::string newTextUTF8 = ConsoleCPToUTF8(trimInplace(newText));
record.setComment(newTextUTF8);

record.setComment(ConsoleCPToUTF8(newText));
dbClient.save(*board, options.rule, record, OverwriteRule::Always);
}
}
Expand Down Expand Up @@ -926,9 +948,8 @@ void editDatabaseBoardLabel()
}

if (Search::Threads.dbStorage() && !Config::DatabaseReadonlyMode) {
DBClient dbClient(*Search::Threads.dbStorage(), RECORD_MASK_TEXT);
std::string newTextUTF8 = ConsoleCPToUTF8(trimInplace(newText));
dbClient.setBoardText(*board, options.rule, pos, newTextUTF8);
DBClient dbClient(*Search::Threads.dbStorage(), RECORD_MASK_TEXT);
dbClient.setBoardText(*board, options.rule, pos, ConsoleCPToUTF8(newText));
}
}

Expand Down
70 changes: 54 additions & 16 deletions Rapfi/database/dbclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,13 +526,12 @@ bool DBClient::query(const Board &board, Rule rule, DBRecord &record)
return false;
}

void DBClient::queryChildren(const Board &board,
Rule rule,
std::vector<std::pair<Pos, DBRecord>> &childRecords)
std::vector<std::pair<Pos, DBRecord>> DBClient::queryChildren(const Board &board, Rule rule)
{
DBRecord record;
Board &b = const_cast<Board &>(board);

std::vector<std::pair<Pos, DBRecord>> childRecords;
FOR_EVERY_EMPTY_POS(&b, pos)
{
if (rule == RENJU && board.sideToMove() == BLACK && board.checkForbiddenPoint(pos))
Expand All @@ -543,30 +542,69 @@ void DBClient::queryChildren(const Board &board,
childRecords.emplace_back(pos, record);
b.undo(rule);
}
return childRecords;
}

std::string DBClient::queryBoardText(const Board &board, Rule rule, Pos pos)
std::vector<std::pair<Pos, std::string>> DBClient::queryBoardTexts(const Board &board, Rule rule)
{
if (!board.isEmpty(pos))
return {};

DBRecord record;
if (!query(board, rule, record))
return {};

// Get the list of all canonical positions with board texts
auto canonicalPosAndTexts = record.getAllBoardTexts();
if (canonicalPosAndTexts.empty())
return {};

// Sort the list by canonical pos in ascending order
std::sort(canonicalPosAndTexts.begin(),
canonicalPosAndTexts.end(),
[](const auto &lhs, const auto &rhs) { return lhs.first._pos < rhs.first._pos; });

// Get the list of all empty positions
std::vector<Pos> emptyPosList;
FOR_EVERY_EMPTY_POS(&board, pos)
{
if (rule == RENJU && board.sideToMove() == BLACK && board.checkForbiddenPoint(pos))
continue;
emptyPosList.push_back(pos);
}

// Find the smallest canonical pos considering symmetries to query board text
TransformType parentTrans;
DBKey parentKey = constructDBKey(board, rule, &parentTrans);
Pos canonicalPos = applyTransform(pos, board.size(), parentTrans);
for (int t = IDENTITY + 1; t < TRANS_NB; t++) {
TransformType trans = (TransformType)t;
if (isDBKeySymmetry(parentKey, trans)) {
Pos tPos = applyTransform(canonicalPos, board.size(), trans);
canonicalPos = std::min(canonicalPos, tPos);
DBKey parentKey = constructDBKey(board, rule, &parentTrans);
bool isParentSymmetry[TRANS_NB];
for (int t = IDENTITY + 1; t < TRANS_NB; t++)
isParentSymmetry[t] = isDBKeySymmetry(parentKey, (TransformType)t);

// Map all empty pos into canonical pos, and get their board text
std::vector<std::pair<Pos, std::string>> childBoardTexts;
for (Pos pos : emptyPosList) {
// Find the smallest canonical considering all symmetries
Pos canonicalPos = applyTransform(pos, board.size(), parentTrans);
for (int t = IDENTITY + 1; t < TRANS_NB; t++) {
if (isParentSymmetry[t]) {
Pos transformedPos = applyTransform(canonicalPos, board.size(), (TransformType)t);
canonicalPos = std::min(canonicalPos, transformedPos);
}
}
}

return record.boardText(canonicalPos);
// Find the board text of this canonical pos
auto itBegin = std::lower_bound(
canonicalPosAndTexts.begin(),
canonicalPosAndTexts.end(),
canonicalPos,
[](const auto &lhs, const Pos &rhs) { return lhs.first._pos < rhs._pos; });
auto itEnd = std::upper_bound(
canonicalPosAndTexts.begin(),
canonicalPosAndTexts.end(),
canonicalPos,
[](const Pos &lhs, const auto &rhs) { return lhs._pos < rhs.first._pos; });
if (itBegin < itEnd)
childBoardTexts.emplace_back(pos, std::string {itBegin->second});
}

return childBoardTexts;
}

void DBClient::setBoardText(const Board &board, Rule rule, Pos pos, std::string text)
Expand Down
11 changes: 6 additions & 5 deletions Rapfi/database/dbclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,13 @@ class DBClient

/// Query all existing children of the current position.
/// @return The list of all children, in forms of (Pos, Record).
void queryChildren(const Board &board,
Rule rule,
std::vector<std::pair<Pos, DBRecord>> &childRecords);
/// The list is sorted by Pos's board traversal order (ascending order).
std::vector<std::pair<Pos, DBRecord>> queryChildren(const Board &board, Rule rule);

/// Query the utf-8 board text of an empty pos on board.
std::string queryBoardText(const Board &board, Rule rule, Pos pos);
/// Query the utf-8 board text of every legal empty pos on board.
/// @return The list of all children, in forms of (Pos, Text).
/// The list is sorted by Pos's board traversal order (ascending order).
std::vector<std::pair<Pos, std::string>> queryBoardTexts(const Board &board, Rule rule);

/// Update the utf-8 board text of an empty pos on board.
void setBoardText(const Board &board, Rule rule, Pos pos, std::string text);
Expand Down
Loading

0 comments on commit cc6d45a

Please sign in to comment.