diff --git a/src/core/Board.cpp b/src/core/Board.cpp index e69de29..09b3f04 100644 --- a/src/core/Board.cpp +++ b/src/core/Board.cpp @@ -0,0 +1,6 @@ +#include "Board.h" + +Board::Board(int rows, int cols) : + m_rows(rows), + m_cols(cols), + m_grid(rows, ) \ No newline at end of file diff --git a/src/core/Board.h b/src/core/Board.h index e69de29..77fcf32 100644 --- a/src/core/Board.h +++ b/src/core/Board.h @@ -0,0 +1,24 @@ +#pragma once +#include "Piece.h" +#include +#include +// 用 (row, col) 表示坐标,0-based +struct Position { + int row; + int col; + //运算符重载用于判断位置是否相等 + bool operator==(const Position& other) const { + return row == other.row && col == other.col; + } +}; + +class Board { +private: + std::vector>> m_grid; + const int m_rows; + const int m_cols; +public: + Board(int rows, int cols); + ~Board(); + +}; \ No newline at end of file diff --git a/src/core/ConnectedComponentManager.cpp b/src/core/ConnectedComponentManager.cpp new file mode 100644 index 0000000..15c82fc --- /dev/null +++ b/src/core/ConnectedComponentManager.cpp @@ -0,0 +1,238 @@ +#include "ConnectedComponentManager.h" + +ConnectedComponentManager::ConnectedComponentManager(int numPieces) + : m_totalPieces(numPieces) { + //初始化数组大小 ROWS * COLS + m_parent.resize(numPieces); + m_rank.resize(numPieces, 0); + m_adjacentList.resize(numPieces); + //初始化每个棋子为独立组件 + for (int i = 0; i < numPieces; i++) { + m_parent[i] = i; + m_componentPieces[i] = {i}; //每个组件初始包含一个棋子 + m_pieceToComponent[i] = i; //棋子指向的组件 + } +} + +int ConnectedComponentManager::find(int pieceId) { + if (m_parent[pieceId] != pieceId) { + m_parent[pieceId] = find(m_parent[pieceId]); + } + return m_parent[pieceId]; +} + +void ConnectedComponentManager::unite(int pieceId1, int pieceId2) { + int root1 = find(pieceId1); + int root2 = find(pieceId2); + + if (root1 == root2) { + return; + + } + if (m_rank[root1] < m_rank[root2]) { + m_parent[root1] = root2; + // 合并棋子集合 + m_componentPieces[root2].merge(m_componentPieces[root1]); + m_componentPieces.erase(root1); + // 更新棋子到组件的映射 + for (int piece : m_componentPieces[root2]) { + m_pieceToComponent[piece] = root2; + } + } else { + m_parent[root2] = root1; + m_componentPieces[root1].merge(m_componentPieces[root2]); + m_componentPieces.erase(root2); + for (int piece : m_componentPieces[root1]) { + m_pieceToComponent[piece] = root1; + } + } + addConnection(pieceId1, pieceId2); +} + +void ConnectedComponentManager::addConnection(int pieceId1, int pieceId2) { + //将元素放入邻接表 + m_adjacentList[pieceId1].insert(pieceId2); + m_adjacentList[pieceId2].insert(pieceId1); + +} + +bool ConnectedComponentManager::disconnectFromNeighbor(int pieceId, int neighborId){ + // 检查是否真的相连 + if (!areDirectlyConnected(pieceId, neighborId)) { + return false; + } + // 从邻接表中移除连接 + m_adjacentList[pieceId].erase(neighborId); + m_adjacentList[neighborId].erase(pieceId); + // 重新计算连通性 + recomputeComponentsAfterDisconnection(pieceId); + + return true; +} + +bool ConnectedComponentManager::disconnectFromComponent(int pieceId) { + int oldComponentId = find(pieceId); + if (oldComponentId == -1) return false; + + // 记录所有直接连接 + auto neighbors = m_adjacentList[pieceId]; + + // 断开所有连接 + for (int neighborId : neighbors) { + m_adjacentList[pieceId].erase(neighborId); + m_adjacentList[neighborId].erase(pieceId); + } + + // 将被断开的棋子设为独立组件 + m_parent[pieceId] = pieceId; + m_rank[pieceId] = 0; + m_componentPieces[pieceId] = {pieceId}; + m_pieceToComponent[pieceId] = pieceId; + + // 如果原组件还有其他棋子,需要重新计算连通性 + if (!neighbors.empty()) { + recomputeComponentsAfterDisconnection(pieceId); + } + return true; +} + +void ConnectedComponentManager::recomputeComponentsAfterDisconnection(int disconnectedPiece) { + int oldComponentId = find(disconnectedPiece); + if (oldComponentId = -1 || m_componentPieces[disconnectedPiece].size() <= 1) { + return; + } + + // 获取原组件中除断开棋子外的所有棋子 + std::unordered_set remainingPieces = m_componentPieces[oldComponentId]; + remainingPieces.erase(disconnectedPiece); + + //处理组件分裂 + handleComponentSplit(oldComponentId, remainingPieces); +} + +void ConnectedComponentManager::handleComponentSplit(int oldComponentId, const std:: unordered_set& remainingPieces ) { + std::unordered_set visited; + std::vector> newComponents; + + //;// 对剩余棋子进行BFS,找到所有连通区域 + for (int piece : remainingPieces) { + if (visited.find(piece) != visited.end()) { + continue; + } + + // 找到一个新的连通区域 + std::unordered_set connectedRegion = bfsConnectedRegion(piece, remainingPieces); + + // 标记为已访问 + visited.insert(connectedRegion.begin(), connectedRegion.end()); + newComponents.push_back(connectedRegion); + } + // 删除原组件 + m_componentPieces.erase(oldComponentId); + + // 为每个新连通区域创建组件 + for (const auto& region : newComponents) { + if (!region.empty()) { + int newRoot = *region.begin(); + createNewComponent(newRoot); + + // 设置新组件的父节点和棋子集合 + for (int piece : region) { + m_parent[piece] = newRoot; + m_pieceToComponent[piece] = newRoot; + } + m_componentPieces[newRoot] = region; + } + } + +} + + +std::unordered_set ConnectedComponentManager::bfsConnectedRegion(int startPiece, const std::unordered_set& availablepieces) { + std::unordered_set connectedRegion; + std::queue queue; + + queue.push(startPiece); + connectedRegion.insert(startPiece); + + while(!queue.empty()) { + int current = queue.front(); + queue.pop(); + // 遍历当前棋子的所有邻居 + for (int neighbor : m_adjacentList[current]) { + // 如果邻居在可用棋子中且未被访问 + if (availablepieces.find(neighbor) != availablepieces.end() && + connectedRegion.find(neighbor) == connectedRegion.end()) { + connectedRegion.insert(neighbor); + queue.push(neighbor); + } + } + } + + + return connectedRegion; +} + +int ConnectedComponentManager::createNewComponent(int rootPiece) { + m_parent[rootPiece] = rootPiece; + m_rank[rootPiece] = 0; + m_componentPieces[rootPiece] = {rootPiece}; + m_pieceToComponent[rootPiece] = rootPiece; + return rootPiece; +} + +void ConnectedComponentManager::selectComponentByPiece(int pieceId) { + m_slelectedComponentId = find(pieceId); +} + +const std::unordered_set& ConnectedComponentManager::getSelectedComponent() const { + static std::unordered_set emptySet; + if (m_slelectedComponentId == -1 || + m_componentPieces.find(m_slelectedComponentId) == m_componentPieces.end()) { + + return emptySet; + } + return m_componentPieces.at(m_slelectedComponentId); +} + +int ConnectedComponentManager::getComponentId(int pieceId) const { + auto it = m_pieceToComponent.find(pieceId); + return (it != m_pieceToComponent.end()) ? it->second : -1; +} + +const std::unordered_set& ConnectedComponentManager::getPiecesInComponent(int componentId) const { + static std::unordered_set emptySet; + auto it = m_componentPieces.find(componentId); + + return (it != m_componentPieces.end()) ? it->second : emptySet; +} + +bool ConnectedComponentManager::areConnected(int pieceId1, int pieceId2) { + return find(pieceId1) == find(pieceId2); +} + +const std::unordered_set& ConnectedComponentManager::getPieceConnections(int pieceId) const { + static std::unordered_set emptySet; + if (pieceId < 0 || pieceId >= m_totalPieces) return emptySet; + return m_adjacentList[pieceId]; +} + +bool ConnectedComponentManager::areDirectlyConnected(int pieceId1, int pieceId2) const { + if (pieceId1 < 0 || pieceId1 >= m_totalPieces || + pieceId2 < 0 || pieceId2 >= m_totalPieces) { + return false; + } + return m_adjacentList[pieceId1].find(pieceId2) != m_adjacentList[pieceId1].end(); +} + +void ConnectedComponentManager::clearSelection() { + m_slelectedComponentId = -1; +} + +std:: unordered_map> ConnectedComponentManager::getAllComponents() const { + return m_componentPieces; +} + + + + diff --git a/src/core/ConnectedComponentManager.h b/src/core/ConnectedComponentManager.h new file mode 100644 index 0000000..5406d8e --- /dev/null +++ b/src/core/ConnectedComponentManager.h @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include +#include +#include + +class ConnectedComponentManager { +private: + // 并查集的父节点数组,使用连续内存存储 + std::vector m_parent; + //记录根节点的大小(按秩合并) + std::vector m_rank; + // 记录每个棋子的直接连接关系(邻接表) + std::vector> m_adjacentList; + // 组件ID到棋子集合的映射 + std::unordered_map> m_componentPieces; + // 棋子ID到组件ID的映射 + std::unordered_map m_pieceToComponent; + // 当前选中的组件ID + int m_slelectedComponentId = -1; + // 总棋子数 + int m_totalPieces; + + // 重新计算连通性(断开后调用) + void recomputeComponentsAfterDisconnection(int disconnectedPiece); + // 处理组件分裂 + void handleComponentSplit(int oldComponentId, const std::unordered_set& affectedPieces); + + // 使用BFS查找连通区域 + std::unordered_set bfsConnectedRegion(int startPiece, const std::unordered_set& afftedPieces); + + // 创建新组件 + int createNewComponent(int rootPiece); + +public: + // 构造函数:初始化指定数量的棋子 + explicit ConnectedComponentManager(int numPieces); + // 查找操作(带路径压缩) + int find(int pieceId); + // 合并两个棋子所在的组件(按秩合并) + void unite(int pieceId1, int pieceId2); + // 连接两个组件 + void addConnection(int pieceId1, int pieceId2); + // 断开棋子与指定邻居的连接 + bool disconnectFromNeighbor(int pieceId, int neighborId); + // 将棋子完全从当前组件断开,成为独立组件 + bool disconnectFromComponent(int pieceId); + // 通过棋子选择整个连通片 + void selectComponentByPiece(int pieceId); + // 获取当前选中的组件中的所有棋子 + const std::unordered_set& getSelectedComponent() const; + // 获取棋子所属的组件ID + int getComponentId(int pieceId) const; + // 获取组件内所有棋子 + const std::unordered_set& getPiecesInComponent(int pieceId) const; + // 检查两个棋子是否在同一个组件中 + bool areConnected(int pieceId1, int pieceId2); + // 获取棋子的所有直接连接 + const std::unordered_set& getPieceConnections(int pieceId) const; + // 检查两个棋子是否直接相连 + bool areDirectlyConnected(int pieceId1, int pieceId2) const; + // 清除选中状态 + void clearSelection(); + + //获取所有组件 + std::unordered_map> getAllComponents() const; + + +}; \ No newline at end of file diff --git a/src/core/Piece.cpp b/src/core/Piece.cpp index e69de29..2eefd55 100644 --- a/src/core/Piece.cpp +++ b/src/core/Piece.cpp @@ -0,0 +1,13 @@ +#include "Piece.h" + +Piece::Piece(PlayerColer color) : m_color(color) { + +} + +Piece::~Piece() { + +} + +PlayerColer Piece::getPlayerColor() const { + return m_color; +} \ No newline at end of file diff --git a/src/core/Piece.h b/src/core/Piece.h index e69de29..a63d39e 100644 --- a/src/core/Piece.h +++ b/src/core/Piece.h @@ -0,0 +1,18 @@ +#pragma once + +enum class PlayerColer { + WHITE, + BLACK +}; + + +class Piece { +private: + PlayerColer m_color; +public: + Piece(PlayerColer color); + ~Piece(); + PlayerColer getPlayerColor() const; + + +}; \ No newline at end of file diff --git a/src/core/Rule.h b/src/core/Rule.h index e69de29..7b9637e 100644 --- a/src/core/Rule.h +++ b/src/core/Rule.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/src/ui/Render.cpp b/src/ui/Render.cpp index 38c58c7..f94a47c 100644 --- a/src/ui/Render.cpp +++ b/src/ui/Render.cpp @@ -1,10 +1,10 @@ #include "Render.h" -Renderer::Renderer(int WIDTH, int HEIGHT) : Width(WIDTH), Height(HEIGHT) { +Renderer::Renderer(int WIDTH, int HEIGHT) : m_Width(WIDTH), m_Height(HEIGHT) { } -Renderer::Renderer() : Width(1600), Height(900) { +Renderer::Renderer() : m_Width(1600), m_Height(900) { } @@ -17,8 +17,8 @@ bool Renderer::initialize() { // 创建窗口(支持高DPI和横屏)[3,4](@ref) m_window = SDL_CreateWindow( "孢子棋", // 窗口标题,显示在标题栏上 - Width, // 窗口的逻辑宽度(例如 800),用于统一布局,不受屏幕 DPI 影响 - Height, // 窗口的逻辑高度(例如 600) + m_Width, // 窗口的逻辑宽度(例如 800),用于统一布局,不受屏幕 DPI 影响 + m_Height, // 窗口的逻辑高度(例如 600) SDL_WINDOW_HIGH_PIXEL_DENSITY | // 启用高像素密度支持(HiDPI/Retina),确保在高分屏上画面清晰 SDL_WINDOW_RESIZABLE // 允许用户调整窗口大小(可拉伸) ); @@ -38,10 +38,10 @@ bool Renderer::initialize() { // 设置逻辑呈现模式,实现分辨率自适应[3](@ref) SDL_SetRenderLogicalPresentation(m_renderer, - Width, - Height, + m_Width, + m_Height, SDL_LOGICAL_PRESENTATION_LETTERBOX); - SDL_SetWindowSize(m_window, Width, Height); + SDL_SetWindowSize(m_window, m_Width, m_Height); return true; } diff --git a/src/ui/Render.h b/src/ui/Render.h index 61e60d7..24ea5bf 100644 --- a/src/ui/Render.h +++ b/src/ui/Render.h @@ -7,8 +7,8 @@ class Renderer private: SDL_Window* m_window = nullptr; SDL_Renderer* m_renderer = nullptr; - int Width; - int Height; + int m_Width; + int m_Height; public: Renderer(int WIDTH, int HEIGHT); Renderer();