Fix after disconnect the change of parentID bug

This commit is contained in:
2025-12-07 12:06:40 +08:00
parent a6403953ef
commit a66c70f0b7
3 changed files with 143 additions and 19 deletions

View File

@@ -136,8 +136,24 @@ int Board::getComponentID(int row, int col) const{
}
std::unordered_set<int> 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<int>(); // 返回空集合
}
// 检查 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;
}

View File

@@ -1,5 +1,5 @@
#include "ComponentManager.h"
#include <iostream>
ComponentManager::ComponentManager(int maxPossiblePieces)
: m_maxPossiblePieces(maxPossiblePieces) {
//初始化数组大小 ROWS * COLS
@@ -30,15 +30,43 @@ void ComponentManager::addPiece(int PieceID, const std::vector<int>& adjacentPie
}
void ComponentManager::removePiece(int PieceID) {
std::cout << "try to remove piece " << PieceID << " ";
// 先检查棋子是否存在
if (m_parent[PieceID] == -1){
std::cout << "piece don't extist" <<std::endl;
}
// 1. 断开所有连接(这会为棋子创建独立组件)
disconnectFromComponent(PieceID);
/* // 2. 现在将棋子标记为不存在
m_parent[PieceID] = -1;
m_rank[PieceID] = 0;
// 3. 从组件映射中移除
m_pieceToComponent.erase(PieceID);
// 4. 从独立组件中移除
if (m_componentPieces.count(PieceID)) {
m_componentPieces.erase(PieceID);
}
//m_rank[PieceID] = 0; 重复设置了
//m_componentPieces.erase(PieceID);
*/
}
int ComponentManager::find(int pieceID) {
std::cout << "DEBUG find: pieceID=" << pieceID;
// 添加边界检查
if (pieceID < 0 || pieceID >= m_maxPossiblePieces) {
std::cout << " -> 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<int> 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<int> ComponentManager::bfsConnectedRegion(int startPiece, const std::unordered_set<int>& availablepieces) {
std::unordered_set<int> connectedRegion;
// 如果起始棋子不存在,返回空区域
if (m_parent[startPiece] == -1) {
return connectedRegion;
}
std::queue<int> 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<int>& ComponentManager::getSelectedComponent() const {
@@ -243,7 +344,12 @@ const std::unordered_set<int>& 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<int>& 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;
}

View File

@@ -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; // 有棋子不能生长
}