From 36d41b7501c9c1b5467eb1831d91d1b525307b0c Mon Sep 17 00:00:00 2001 From: Joker2770 <1214220480@qq.com> Date: Tue, 9 Jul 2024 15:37:46 +0800 Subject: [PATCH] feats: add importing SGF related :heavy_plus_sign: --- src/SGFOption.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++++ src/SGFOption.h | 5 +++ src/mainwindow.cpp | 56 ++++++++++++++++++++++++ src/mainwindow.h | 2 + 4 files changed, 168 insertions(+) diff --git a/src/SGFOption.cpp b/src/SGFOption.cpp index 0caf034..8787d37 100644 --- a/src/SGFOption.cpp +++ b/src/SGFOption.cpp @@ -54,6 +54,18 @@ std::string SGFOption::idx_2_s(const std::pair &idx) return sTmp; } +std::pair SGFOption::s_2_idx(const std::string &StringPropertyValue) +{ + std::pair idx(-1, -1); + if (!StringPropertyValue.empty() && StringPropertyValue.length() == 2) + { + idx.first = StringPropertyValue.at(0) - 'a'; + idx.second = StringPropertyValue.at(1) - 'a'; + } + + return idx; +} + /// @brief Prints the raw message text of all ISgfcMessage objects in the /// supplied collection to standard output. /// @@ -88,6 +100,35 @@ void SGFOption::PrintDocumentContent(std::shared_ptr document) std::cout << std::endl; } +/// @brief Reads the SGF file @a inputFilePath. If @a printOutput is true also +/// prints the document content to standard output. +/// +/// This demonstrates the usage of ISgfcDocumentReader. +std::shared_ptr SGFOption::ReadDocument(const std::string &inputFilePath, bool printOutput) +{ + std::shared_ptr documentReader = SgfcPlusPlusFactory::CreateDocumentReader(); + + // Uncomment the following to see an invalid command line + // documentReader->GetArguments()->AddArgument(SgfcArgumentType::DeletePropertyType, SgfcPropertyType::BO); + + std::shared_ptr result = documentReader->ReadSgfFile(inputFilePath); + + if (printOutput) + { + std::cout << "ReadSgfFile sgfcExitCode = " << static_cast(result->GetExitCode()) << std::endl; + std::cout << "IsSgfDataValid = " << result->IsSgfDataValid() << std::endl; + std::cout << std::endl; + + std::cout << "Printing parse results..." << std::endl; + PrintMessages(result->GetParseResult()); + + if (result->GetExitCode() != SgfcExitCode::FatalError) + PrintDocumentContent(result->GetDocument()); + } + + return result->GetDocument(); +} + /// @brief Writes the content of @a document to the SGF file @a outputFilePath. /// /// This demonstrates the usage of ISgfcDocumentWriter. @@ -170,3 +211,67 @@ void SGFOption::record_2_sgf(const std::string &outputFilePath, std::vector> &vRecord, unsigned int *bSize) +{ + int iFlag = -1; + Board bTmp; + vRecord.clear(); + std::shared_ptr document = ReadDocument(inputFilePath, true); + if (document->IsEmpty()) + { + return iFlag; + } + + std::shared_ptr game = document->GetGame(); + if (SgfcGameType::GomokuAndRenju != game->GetGameType()) + { + return iFlag; + } + + std::shared_ptr rootNode = game->GetRootNode(); + if (nullptr != rootNode) + { + if (rootNode->HasProperties()) + { + std::shared_ptr property; + property = rootNode->GetProperty(SgfcPropertyType::SZ); + if (nullptr != property && property->HasPropertyValues()) + { + std::string s_size = property->GetPropertyValue()->ToSingleValue()->GetRawValue(); + *bSize = (unsigned int)std::stoi(s_size); + } + } + std::shared_ptr currentNode; + currentNode = rootNode; + + while (currentNode->HasChildren()) + { + currentNode = currentNode->GetFirstChild(); + if (currentNode->HasProperties()) + { + std::shared_ptr property; + property = currentNode->GetProperty(SgfcPropertyType::W); + if (nullptr == property) + { + property = currentNode->GetProperty(SgfcPropertyType::B); + } + if (nullptr != property && property->HasPropertyValues()) + { + std::string sTmp = property->GetPropertyValue()->ToSingleValue()->GetRawValue(); + int coord = bTmp.idx2Coord((s_2_idx(sTmp))); + int color = SgfcPropertyType::B == property->GetPropertyType() ? STONECOLOR::BLACK : STONECOLOR::WHITE; + std::pair pTmp(coord, color); + vRecord.push_back(pTmp); + } + } + } + } + else + { + return iFlag; + } + iFlag = 0; + + return iFlag; +} diff --git a/src/SGFOption.h b/src/SGFOption.h index 6e1c1f5..c845813 100644 --- a/src/SGFOption.h +++ b/src/SGFOption.h @@ -30,7 +30,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -49,10 +51,13 @@ class SGFOption SGFOption(); ~SGFOption(); std::string idx_2_s(const std::pair &idx); + std::pair s_2_idx(const std::string &propertyValue); void PrintMessages(const std::vector> &messages); void PrintDocumentContent(std::shared_ptr document); + std::shared_ptr ReadDocument(const std::string &inputFilePath, bool printOutput); int WriteDocument(std::shared_ptr document, const std::string &outputFilePath); void record_2_sgf(const std::string &outputFilePath, std::vector> &vRecord, unsigned int bSize); + int loadSgf(const std::string &inputFilePath, std::vector> &vRecord, unsigned int *bSize); }; #endif diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index b89c90d..5c6d59c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -46,6 +46,7 @@ MainWindow::MainWindow(QWidget *parent) this->pMenuShow = new QMenu(tr("Show"), this); this->pMenuAbout = new QMenu(tr("About"), this); this->pSubMenuOfLanguage = new QMenu(tr("LanguageSubMenu"), this); + this->pActionImportSgf = new QAction(tr("Import from SGF"), this); this->pActionExportSgf = new QAction(tr("Export to SGF"), this); this->pActionBoardSize = new QAction(tr("Board Size"), this); this->pActionTimeoutMatch = new QAction(tr("Match Timeout"), this); @@ -78,6 +79,7 @@ MainWindow::MainWindow(QWidget *parent) this->pActionVer = new QAction(tr("Ver Info"), this); this->pActionFeedback = new QAction(tr("Feedback"), this); this->pActionLicense = new QAction(tr("License"), this); + this->pActionImportSgf->setShortcut(QKeySequence(Qt::Key_I)); this->pActionExportSgf->setShortcut(QKeySequence(Qt::Key_E)); this->pActionStart->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S)); this->pActionPause->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P)); @@ -127,6 +129,7 @@ MainWindow::MainWindow(QWidget *parent) this->pMenuSetting->addAction(this->pActionTimeoutMatch); this->pMenuSetting->addAction(this->pActionTimeoutTurn); this->pMenuSetting->addAction(this->pActionMaxMemory); + this->pMenuFile->addAction(this->pActionImportSgf); this->pMenuFile->addAction(this->pActionExportSgf); this->pMenuGame->addAction(this->pActionStart); this->pMenuGame->addAction(this->pActionPause); @@ -270,6 +273,7 @@ MainWindow::MainWindow(QWidget *parent) this->m_effect = new QSoundEffect(this); + connect(this->pActionImportSgf, SIGNAL(triggered()), this, SLOT(OnActionImport2SGF())); connect(this->pActionExportSgf, SIGNAL(triggered()), this, SLOT(OnActionExport2SGF())); connect(this->pActionStart, SIGNAL(triggered()), this, SLOT(OnActionStart())); connect(this->pActionPause, SIGNAL(triggered()), this, SLOT(OnActionPause())); @@ -524,6 +528,16 @@ MainWindow::~MainWindow() delete this->pActionVer; this->pActionVer = nullptr; } + if (nullptr != this->pActionExportSgf) + { + delete this->pActionExportSgf; + this->pActionExportSgf = nullptr; + } + if (nullptr != this->pActionImportSgf) + { + delete this->pActionImportSgf; + this->pActionImportSgf = nullptr; + } if (nullptr != this->pMenuFile) { delete this->pMenuFile; @@ -3480,3 +3494,45 @@ void MainWindow::OnActionExport2SGF() this->mSgfOpt->record_2_sgf(aFileName.toStdString(), this->mBoard->getVRecord(), this->mBoard->getBSize().first); } } + +void MainWindow::OnActionImport2SGF() +{ + QString curPath = QDir::currentPath(); + QString dlgTitle = tr("Choose a file"); + // QString filter="executable file(*.exe)"; + QString aFileName = QFileDialog::getOpenFileName(this, dlgTitle, curPath, "SGF files(*.sgf)"); + if (!aFileName.isEmpty()) + { + unsigned int b_size = 0; + std::vector> vRec; + this->mSgfOpt->loadSgf(aFileName.toStdString(), vRec, &b_size); + + this->OnActionClearBoard(); + std::pair pTmp(b_size, b_size); + if (this->mBoard->setBSize(pTmp)) + { + resize((this->mBoard->getBSize().first + 2) * RECT_WIDTH, (this->mBoard->getBSize().second + 3) * RECT_HEIGHT + 2 * this->pMenuBar->height()); + } + + this->mBoard->Notify(); + + if (nullptr != this->m_T1) + this->m_T1->stop(); + if (nullptr != this->m_T2) + this->m_T2->stop(); + + this->mState = GAME_STATE::IDLE; + this->pRuleActionGroup->setEnabled(true); + this->m_customs->setCfgValue("Board", "size", b_size); + + if (this->mState == GAME_STATE::IDLE) + { + for (const auto &v : vRec) + { + this->mBoard->placeStone(this->mBoard->coord2idx(v.first), (STONECOLOR::BLACK == v.second) ? STONECOLOR::BLACK : STONECOLOR::WHITE); + } + + this->mBoard->Notify(); + } + } +} diff --git a/src/mainwindow.h b/src/mainwindow.h index b57b262..e1301e2 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -104,6 +104,7 @@ class MainWindow : public QMainWindow QMenu *pMenuShow; QMenu *pMenuAbout; QMenu *pSubMenuOfLanguage; + QAction *pActionImportSgf; QAction *pActionExportSgf; QAction *pActionBoardSize; QAction *pActionTimeoutMatch; @@ -140,6 +141,7 @@ class MainWindow : public QMainWindow QActionGroup *pLanguageActionGroup; public slots: + void OnActionImport2SGF(); void OnActionExport2SGF(); void OnActionStart(); void OnActionPause();