From a66c70f0b7340ce2ff1f0c7e4b90e94acebf661f Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sun, 7 Dec 2025 12:06:40 +0800 Subject: [PATCH] Fix after disconnect the change of parentID bug --- src/game/Board.cpp | 16 ++++ src/game/ComponentManager.cpp | 143 +++++++++++++++++++++++++++++----- src/game/Rule.cpp | 3 +- 3 files changed, 143 insertions(+), 19 deletions(-) diff --git a/src/game/Board.cpp b/src/game/Board.cpp index 98387e0..6bd3659 100644 --- a/src/game/Board.cpp +++ b/src/game/Board.cpp @@ -136,8 +136,24 @@ int Board::getComponentID(int row, int col) const{ } std::unordered_set Board::getComponentByPieceID(int PieceID) const { + std::cout << "DEBUG: getComponentByPieceID(" << PieceID << ")" << std::endl; + // 检查该位置是否有棋子 + auto [row, col] = getCoordFromID(PieceID); + if (getPieceAt(row, col) == nullptr) { + std::cout << "this postion don't have piece\n"; + return std::unordered_set(); // 返回空集合 + } + + // 检查 ComponentManager 的状态 + int componentID = m_component->getComponentID(PieceID); + std::cout << "DEBUG: componentID = " << componentID << std::endl; + // 临时选中组件 m_component->selectComponentByPiece(PieceID); auto SelectedComponent = m_component->getSelectedComponent(); + + // 立即清除选中状态 + m_component->clearSelection(); + std::cout << "DEBUG: Component size = " << SelectedComponent.size() << std::endl; return SelectedComponent; } diff --git a/src/game/ComponentManager.cpp b/src/game/ComponentManager.cpp index 56a2e45..8ace80f 100644 --- a/src/game/ComponentManager.cpp +++ b/src/game/ComponentManager.cpp @@ -1,5 +1,5 @@ #include "ComponentManager.h" - +#include ComponentManager::ComponentManager(int maxPossiblePieces) : m_maxPossiblePieces(maxPossiblePieces) { //初始化数组大小 ROWS * COLS @@ -30,15 +30,43 @@ void ComponentManager::addPiece(int PieceID, const std::vector& adjacentPie } void ComponentManager::removePiece(int PieceID) { + std::cout << "try to remove piece " << PieceID << " "; + // 先检查棋子是否存在 + if (m_parent[PieceID] == -1){ + std::cout << "piece don't extist" < Invalid range" << std::endl; + return -1; // 返回无效值 + } + if (m_parent[pieceID] == -1) { + std::cout << " -> No parent (piece not exists)" << std::endl; + return -1; // 棋子不存在 + } if (m_parent[pieceID] != pieceID) { m_parent[pieceID] = find(m_parent[pieceID]); } @@ -105,21 +133,55 @@ bool ComponentManager::disconnectFromComponent(int pieceID) { for (int neighborID : neighbors) { m_adjacentList[neighborID].erase(pieceID); + } // 删除pieceID的邻接表 m_adjacentList[pieceID].clear(); - /* // 将被断开的棋子设为独立组件 - m_parent[pieceID] = pieceID; - m_rank[pieceID] = 0; - m_componentPieces[pieceID] = {pieceID}; - m_pieceToComponent[pieceID] = pieceID; -*/ - // 从原组件中移除 pieceID - if (m_componentPieces.count(oldComponentID)) { - m_componentPieces[oldComponentID].erase(pieceID); - } + + // 从原组件中移除 pieceID + + if (m_componentPieces.count(oldComponentID)) { + // 1. 先从组件集合中移除这个棋子 + m_componentPieces[oldComponentID].erase(pieceID); + // 如果断开的是根节点这重新选择根节点 + if (oldComponentID == pieceID) { + int newRoot = -1; + for (int remainingPiece : m_componentPieces[oldComponentID]) { + if (remainingPiece != pieceID) { + newRoot = remainingPiece; + break; + } + } + if (newRoot != -1) { + // 3. 如果找到新的根节点,更新组件映射 + // 将原组件的数据迁移到新根节点 + m_componentPieces[newRoot] = std::move(m_componentPieces[oldComponentID]); + m_componentPieces.erase(oldComponentID); + + // 更新所有棋子的组件映射到新根节点 + for (int piece : m_componentPieces[newRoot]) { + m_pieceToComponent[piece] = newRoot; + // 注意:这里不修改 m_parent,因为会通过后续的重新计算来重建 + } + oldComponentID = newRoot; // 更新oldRoot指向新的根节点 + } else { + // 4. 如果没有其他棋子了,删除这个空组件 + m_componentPieces.erase(oldComponentID); + } + } + + } + // 将被断开的棋子设为独立组件 + //createNewComponent(pieceID); + + + // 删除这个组件 + m_parent[pieceID] = -1; m_pieceToComponent.erase(pieceID); + + + // 如果原组件还有其他棋子,需要重新计算连通性 if (!m_componentPieces[oldComponentID].empty()) { recomputeComponentsAfterDisconnection(oldComponentID, m_componentPieces[oldComponentID]); @@ -135,6 +197,14 @@ void ComponentManager::recomputeComponentsAfterDisconnection(int oldComponentID, // 安全检查:remainingPieces 至少要有 2 个棋子才可能分裂 if (remainingPieces.size() <= 1) { + int leftpieceID = *remainingPieces.begin(); + // 将剩下的一个的棋子设为独立组件 + createNewComponent(leftpieceID); + // 遍历那个棋子的邻接表 + if (!m_adjacentList[leftpieceID].empty()) + for (int neighbor : m_adjacentList[leftpieceID]) { + unite(leftpieceID, neighbor); + } // 如果只剩 0 或 1 个棋子,不需要分裂 // (如果剩 1 个,它自己就是一个新组件;如果为 0,调用方应已处理) return; @@ -160,7 +230,16 @@ void ComponentManager::handleComponentSplit(int oldComponentID, const std:: unor // 标记为已访问 visited.insert(connectedRegion.begin(), connectedRegion.end()); - newComponents.push_back(connectedRegion); + // 确保区域中的棋子都是存在的(parent != -1) + std::unordered_set validRegion; + for (int p : connectedRegion) { + if (m_parent[p] != -1) { // 只保留存在的棋子 + validRegion.insert(p); + } + } + if (!validRegion.empty()) { + newComponents.push_back(validRegion); + } } // 删除原组件 m_componentPieces.erase(oldComponentID); @@ -168,13 +247,30 @@ void ComponentManager::handleComponentSplit(int oldComponentID, const std:: unor // 为每个新连通区域创建组件 for (const auto& region : newComponents) { if (!region.empty()) { - int newRoot = *region.begin(); - createNewComponent(newRoot); + // 需要选择一个确实存在的棋子作为根 + int newRoot = -1; + for (int piece : region) { + if (m_parent[piece] != -1) { // 找到第一个存在的棋子 + newRoot = piece; + break; + } + } + + if (newRoot == -1) continue; // 没有有效的棋子 + + // 确保根节点指向自己 + m_parent[newRoot] = newRoot; + m_rank[newRoot] = 0; + + // int newRoot = *region.begin(); + // createNewComponent(newRoot); // 设置新组件的父节点和棋子集合 for (int piece : region) { - m_parent[piece] = newRoot; - m_pieceToComponent[piece] = newRoot; + if (m_parent[piece] != -1) { // 只处理存在的棋子 + m_parent[piece] = newRoot; + m_pieceToComponent[piece] = newRoot; + } } m_componentPieces[newRoot] = region; } @@ -185,6 +281,10 @@ void ComponentManager::handleComponentSplit(int oldComponentID, const std:: unor std::unordered_set ComponentManager::bfsConnectedRegion(int startPiece, const std::unordered_set& availablepieces) { std::unordered_set connectedRegion; + // 如果起始棋子不存在,返回空区域 + if (m_parent[startPiece] == -1) { + return connectedRegion; + } std::queue queue; queue.push(startPiece); @@ -218,6 +318,7 @@ int ComponentManager::createNewComponent(int rootPiece) { void ComponentManager::selectComponentByPiece(int pieceID) { m_selectedComponentID = find(pieceID); + std::cout << "DEBUG selectedComponentID is" << m_selectedComponentID << std::endl; } const std::unordered_set& ComponentManager::getSelectedComponent() const { @@ -243,7 +344,12 @@ const std::unordered_set& ComponentManager::getPiecesInComponent(int compon } bool ComponentManager::areConnected(int pieceID1, int pieceID2) { - return find(pieceID1) == find(pieceID2); + int root1 = find(pieceID1); + int root2 = find(pieceID2); + if (root1 == -1 || root2 == -1) { + return false; + } + return root1 == root2; } const std::unordered_set& ComponentManager::getPieceConnections(int pieceID) const { @@ -261,6 +367,7 @@ bool ComponentManager::areDirectlyConnected(int pieceID1, int pieceID2) const { } void ComponentManager::clearSelection() { + std::cout << "DEBUG clear selected componentID is" << m_selectedComponentID << std::endl; m_selectedComponentID = -1; } diff --git a/src/game/Rule.cpp b/src/game/Rule.cpp index e9c3c1b..2f3b7df 100644 --- a/src/game/Rule.cpp +++ b/src/game/Rule.cpp @@ -29,7 +29,7 @@ bool Rule::canbeSelect(const Piece* PieceID, PlayerID ID) { bool Rule::canGrow(const Board* board, const int fromRow, const int fromCol, const int toRow, const int toCol, const PlayerID player) { - + std::cout << "try to grow\n"; // 检查是否有棋子并且属于自己 const Piece* fromPiece = board->getPieceAt(fromRow, fromCol); @@ -42,6 +42,7 @@ bool Rule::canGrow(const Board* board, const int fromRow, const int fromCol, con if (board->getPieceAt(toRow, toCol) != nullptr) { + std::cout << "is exist a piece can't grow\n"; return false; // 有棋子不能生长 }