mirror of
https://github.com/zhenyan121/SporeBG-Conid.git
synced 2026-04-10 06:14:08 +08:00
change core to game
This commit is contained in:
@@ -1,182 +0,0 @@
|
||||
#include "Board.h"
|
||||
|
||||
Board::Board(int rows, int cols) :
|
||||
m_rows(rows),
|
||||
m_cols(cols)
|
||||
{
|
||||
m_grid.resize(m_rows * m_cols);
|
||||
m_component = std::make_unique<ComponentManager>(m_rows * m_cols);
|
||||
}
|
||||
|
||||
Board::~Board() {
|
||||
|
||||
}
|
||||
//将二维坐标转化成一维坐标
|
||||
int Board::getPieceID(int row, int col) const {
|
||||
if (row < 0 || row >= m_rows || col < 0 || col >= m_cols) {
|
||||
std::cout << "PieceID over!!" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return row * m_cols + col;
|
||||
}
|
||||
|
||||
std::pair<int, int> Board::getCoordFromID(int PieceID) const {
|
||||
int row = PieceID / m_cols;
|
||||
int col = PieceID % m_cols;
|
||||
return {row, col};
|
||||
}
|
||||
|
||||
const Piece* Board::getPieceAt(int row, int col) const {
|
||||
int PieceID = getPieceID(row, col);
|
||||
return m_grid[PieceID].get();
|
||||
}
|
||||
|
||||
void Board::placePieceAt(int row, int col, PlayerID ID) {
|
||||
int PieceID = getPieceID(row, col);
|
||||
if (!Rule::canPlacePiece(m_grid[PieceID].get())) {
|
||||
std::cout << "can't place piece at " << row << ", " << col << "\n";
|
||||
return;
|
||||
}
|
||||
m_grid[PieceID] = std::make_unique<Piece>(ID);
|
||||
//创建方向数组
|
||||
const int dx[] = {0, 0, -1, 1};
|
||||
const int dy[] = {-1, 1, 0, 0};
|
||||
|
||||
std::vector<int> existingNeighbors; //记录附近的同色邻居
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int nx = row + dx[i];
|
||||
int ny = col + dy[i];
|
||||
if (nx < 0 || nx >= m_rows || ny < 0 || ny >= m_cols) {
|
||||
continue;
|
||||
}
|
||||
int pos = getPieceID(nx, ny);
|
||||
//添加邻居
|
||||
if (Rule::canConnect(m_grid[PieceID].get(), m_grid[pos].get())) {
|
||||
existingNeighbors.push_back(pos);
|
||||
|
||||
}
|
||||
}
|
||||
// 调用componet处理一片的添加和连接操作
|
||||
m_component->addPiece(PieceID, existingNeighbors);
|
||||
std::cout << "Place piece at" << row << " " << col << "\n";
|
||||
|
||||
}
|
||||
|
||||
void Board::removePieceAt(int row, int col) {
|
||||
|
||||
int PieceID = getPieceID(row, col);
|
||||
if (m_grid[PieceID] == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_grid[PieceID].reset();
|
||||
|
||||
m_component->removePiece(PieceID);
|
||||
std::cout << "Remove piece at" << row << " " << col << "\n";
|
||||
}
|
||||
|
||||
bool Board::initialize() {
|
||||
placePieceAt(0, 0, PlayerID::P1);
|
||||
placePieceAt(0 ,2, PlayerID::P1);
|
||||
placePieceAt(6, 6, PlayerID::P2);
|
||||
placePieceAt(5, 5, PlayerID::P2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Board::printBoard() {
|
||||
//removePieceAt(0, 0);
|
||||
std::vector<std::string> gameBoard(m_rows);
|
||||
for (int i = 0; i < m_rows * m_cols; i++) {
|
||||
if (m_grid[i] == nullptr) {
|
||||
gameBoard[i / m_cols] += "0";
|
||||
} else if (m_grid[i]->getPieceOwner() == PlayerID::P1) {
|
||||
gameBoard[i / m_cols] += "1";
|
||||
} else {
|
||||
gameBoard[i / m_cols] += "2";
|
||||
}
|
||||
}
|
||||
for (std::string& s : gameBoard) {
|
||||
std::cout << s << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<int> Board::getAllPlayerComponent(PlayerID ID) const {
|
||||
std::unordered_set<int> PlayerComponentIDs;
|
||||
auto allComponents = m_component->getAllComponents();
|
||||
//因为组件没有区分玩家,所以先要获取所有的组件判断组件是否是玩家的在添加进去
|
||||
for (const auto& [componentID, pieceSet] : allComponents) {
|
||||
|
||||
if (pieceSet.empty()) continue;
|
||||
|
||||
// 取组件中任意一个棋子(比如第一个)
|
||||
int somePieceID = *pieceSet.begin();
|
||||
|
||||
// 安全检查:确保该位置有棋子
|
||||
if (m_grid[somePieceID] != nullptr &&
|
||||
m_grid[somePieceID]->getPieceOwner() == ID) {
|
||||
PlayerComponentIDs.insert(componentID);
|
||||
}
|
||||
}
|
||||
return PlayerComponentIDs;
|
||||
}
|
||||
|
||||
std::unordered_map<int, int> Board::getALLPiecetoComponent() const {
|
||||
return m_component->getAllPiecetoComponent();
|
||||
}
|
||||
|
||||
int Board::getComponentID(int row, int col) const{
|
||||
int pieceID = getPieceID(row, col);
|
||||
int componentID = m_component->getComponentID(pieceID);
|
||||
if (pieceID == -1) {
|
||||
std::cout << "can't find component id\n";
|
||||
}
|
||||
return componentID;
|
||||
}
|
||||
|
||||
std::unordered_set<int> Board::getComponentByPieceID(int PieceID) const {
|
||||
m_component->selectComponentByPiece(PieceID);
|
||||
auto SelectedComponent = m_component->getSelectedComponent();
|
||||
return SelectedComponent;
|
||||
}
|
||||
|
||||
std::unordered_set<int> Board::getOrthogonalNeighbors(int PieceID) const {
|
||||
auto [row, col] = getCoordFromID(PieceID);
|
||||
std::unordered_set<int> neighbors;
|
||||
|
||||
// 上 (row-1, col)
|
||||
if (row > 0) neighbors.insert(getPieceID(row - 1, col));
|
||||
// 下 (row+1, col)
|
||||
if (row < m_rows - 1) neighbors.insert(getPieceID(row + 1, col));
|
||||
// 左 (row, col-1)
|
||||
if (col > 0) neighbors.insert(getPieceID(row, col - 1));
|
||||
// 右 (row, col+1)
|
||||
if (col < m_cols - 1) neighbors.insert(getPieceID(row, col + 1));
|
||||
|
||||
return neighbors;
|
||||
|
||||
}
|
||||
|
||||
std::unordered_set<int> Board::getSporeRange(int PieceID) const {
|
||||
auto [row, col] = getCoordFromID(PieceID);
|
||||
std::unordered_set<int> SporeRegion;
|
||||
const std::vector<std::pair<int, int>> dir = {
|
||||
{1, 0}, {-1, 0}, {0, 1}, {0, -1},
|
||||
{1, 1}, {1, -1}, {-1, 1}, {-1, -1},
|
||||
{2, 0}, {-2, 0}, {0, 2}, {0, -2}
|
||||
};
|
||||
|
||||
for (auto [dx, dy] : dir) {
|
||||
int nx = row + dx;
|
||||
int ny = col + dy;
|
||||
if (nx < 0 || nx >= m_rows || ny < 0 || ny >= m_cols) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SporeRegion.insert(getPieceID(nx, ny));
|
||||
}
|
||||
|
||||
|
||||
return SporeRegion;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
#include "Piece.h"
|
||||
#include "ComponentManager.h"
|
||||
#include "Rule.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
// 用 (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<std::unique_ptr<Piece>> m_grid;
|
||||
// 连接片管理
|
||||
std::unique_ptr<ComponentManager> m_component;
|
||||
const int m_rows;
|
||||
const int m_cols;
|
||||
public:
|
||||
Board(int rows, int cols);
|
||||
~Board();
|
||||
// 获取一维索引
|
||||
int getPieceID(int row, int col) const;
|
||||
// 从一维反推二维
|
||||
std::pair<int, int> getCoordFromID(int PieceID) const;
|
||||
//获取棋子指针(不可修改)
|
||||
const Piece* getPieceAt(int row, int col) const;
|
||||
//初始化
|
||||
bool initialize();
|
||||
// 放置棋子
|
||||
void placePieceAt(int row, int col, PlayerID ID);
|
||||
//删除棋子
|
||||
void removePieceAt(int row, int col);
|
||||
//打印棋盘
|
||||
void printBoard();
|
||||
//获取相同玩家棋子的所有棋子块的根节点
|
||||
std::unordered_set<int> getAllPlayerComponent(PlayerID ID) const;
|
||||
//获取棋子ID到组件ID的映射
|
||||
std::unordered_map<int, int> getALLPiecetoComponent() const;
|
||||
// 获取坐标对应的块的ID
|
||||
int getComponentID(int row, int col) const;
|
||||
// 获取组件ID对应的组件
|
||||
std::unordered_set<int> getComponentByPieceID(int PieceID) const;
|
||||
// 获取 上下左右四个相邻位置(即 4-邻域)
|
||||
std::unordered_set<int> getOrthogonalNeighbors(int PieceID) const;
|
||||
// 获取扩散范围
|
||||
std::unordered_set<int> getSporeRange(int PieceID) const;
|
||||
};
|
||||
@@ -1,278 +0,0 @@
|
||||
#include "ComponentManager.h"
|
||||
|
||||
ComponentManager::ComponentManager(int maxPossiblePieces)
|
||||
: m_maxPossiblePieces(maxPossiblePieces) {
|
||||
//初始化数组大小 ROWS * COLS
|
||||
m_parent.resize(maxPossiblePieces, -1); // -1表示无棋子
|
||||
m_rank.resize(maxPossiblePieces, 0);
|
||||
m_adjacentList.resize(maxPossiblePieces);
|
||||
|
||||
}
|
||||
|
||||
void ComponentManager::addPiece(int PieceID, const std::vector<int>& adjacentPiece) {
|
||||
if (PieceID < 0 || PieceID >= m_maxPossiblePieces) return;
|
||||
if (m_parent[PieceID] != -1) return; // 已存在
|
||||
|
||||
m_parent[PieceID] = PieceID;
|
||||
m_rank[PieceID] = 0;
|
||||
m_componentPieces[PieceID] = {PieceID};
|
||||
m_pieceToComponent[PieceID] = PieceID;
|
||||
|
||||
for (int neighbor : adjacentPiece) {
|
||||
if (neighbor < 0 || neighbor >= m_maxPossiblePieces || m_parent[neighbor] == -1)
|
||||
continue; // 邻居无效或不存在
|
||||
// 合并连通组件(unite 会自动处理是否已在同一组件)
|
||||
unite(PieceID, neighbor);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ComponentManager::removePiece(int PieceID) {
|
||||
disconnectFromComponent(PieceID);
|
||||
m_parent[PieceID] = -1;
|
||||
//m_rank[PieceID] = 0; 重复设置了
|
||||
//m_componentPieces.erase(PieceID);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int ComponentManager::find(int pieceID) {
|
||||
if (m_parent[pieceID] != pieceID) {
|
||||
m_parent[pieceID] = find(m_parent[pieceID]);
|
||||
}
|
||||
return m_parent[pieceID];
|
||||
}
|
||||
|
||||
void ComponentManager::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 ComponentManager::addConnection(int pieceID1, int pieceID2) {
|
||||
//将元素放入邻接表
|
||||
m_adjacentList[pieceID1].insert(pieceID2);
|
||||
m_adjacentList[pieceID2].insert(pieceID1);
|
||||
|
||||
}
|
||||
/*
|
||||
bool ComponentManager::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 ComponentManager::disconnectFromComponent(int pieceID) {
|
||||
int oldComponentID = find(pieceID);
|
||||
if (oldComponentID == -1) return false;
|
||||
|
||||
// 记录所有直接连接
|
||||
auto neighbors = m_adjacentList[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);
|
||||
}
|
||||
|
||||
m_pieceToComponent.erase(pieceID);
|
||||
// 如果原组件还有其他棋子,需要重新计算连通性
|
||||
if (!m_componentPieces[oldComponentID].empty()) {
|
||||
recomputeComponentsAfterDisconnection(oldComponentID, m_componentPieces[oldComponentID]);
|
||||
} else {
|
||||
m_componentPieces.erase(oldComponentID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ComponentManager::recomputeComponentsAfterDisconnection(int oldComponentID, const std::unordered_set<int>& remainingPieces) {
|
||||
|
||||
|
||||
|
||||
// 安全检查:remainingPieces 至少要有 2 个棋子才可能分裂
|
||||
if (remainingPieces.size() <= 1) {
|
||||
// 如果只剩 0 或 1 个棋子,不需要分裂
|
||||
// (如果剩 1 个,它自己就是一个新组件;如果为 0,调用方应已处理)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//处理组件分裂
|
||||
handleComponentSplit(oldComponentID, remainingPieces);
|
||||
}
|
||||
|
||||
void ComponentManager::handleComponentSplit(int oldComponentID, const std:: unordered_set<int>& remainingPieces ) {
|
||||
std::unordered_set<int> visited;
|
||||
std::vector<std::unordered_set<int>> newComponents;
|
||||
|
||||
//;// 对剩余棋子进行BFS,找到所有连通区域
|
||||
for (int piece : remainingPieces) {
|
||||
if (visited.find(piece) != visited.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 找到一个新的连通区域
|
||||
std::unordered_set<int> 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<int> ComponentManager::bfsConnectedRegion(int startPiece, const std::unordered_set<int>& availablepieces) {
|
||||
std::unordered_set<int> connectedRegion;
|
||||
std::queue<int> 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 ComponentManager::createNewComponent(int rootPiece) {
|
||||
m_parent[rootPiece] = rootPiece;
|
||||
m_rank[rootPiece] = 0;
|
||||
m_componentPieces[rootPiece] = {rootPiece};
|
||||
m_pieceToComponent[rootPiece] = rootPiece;
|
||||
return rootPiece;
|
||||
}
|
||||
|
||||
void ComponentManager::selectComponentByPiece(int pieceID) {
|
||||
m_selectedComponentID = find(pieceID);
|
||||
}
|
||||
|
||||
const std::unordered_set<int>& ComponentManager::getSelectedComponent() const {
|
||||
static std::unordered_set<int> emptySet;
|
||||
if (m_selectedComponentID == -1 ||
|
||||
m_componentPieces.find(m_selectedComponentID) == m_componentPieces.end()) {
|
||||
|
||||
return emptySet;
|
||||
}
|
||||
return m_componentPieces.at(m_selectedComponentID);
|
||||
}
|
||||
|
||||
int ComponentManager::getComponentID(int pieceID) const {
|
||||
auto it = m_pieceToComponent.find(pieceID);
|
||||
return (it != m_pieceToComponent.end()) ? it->second : -1;
|
||||
}
|
||||
|
||||
const std::unordered_set<int>& ComponentManager::getPiecesInComponent(int componentID) const {
|
||||
static std::unordered_set<int> emptySet;
|
||||
auto it = m_componentPieces.find(componentID);
|
||||
|
||||
return (it != m_componentPieces.end()) ? it->second : emptySet;
|
||||
}
|
||||
|
||||
bool ComponentManager::areConnected(int pieceID1, int pieceID2) {
|
||||
return find(pieceID1) == find(pieceID2);
|
||||
}
|
||||
|
||||
const std::unordered_set<int>& ComponentManager::getPieceConnections(int pieceID) const {
|
||||
static std::unordered_set<int> emptySet;
|
||||
if (pieceID < 0 || pieceID >= m_maxPossiblePieces) return emptySet;
|
||||
return m_adjacentList[pieceID];
|
||||
}
|
||||
|
||||
bool ComponentManager::areDirectlyConnected(int pieceID1, int pieceID2) const {
|
||||
if (pieceID1 < 0 || pieceID1 >= m_maxPossiblePieces ||
|
||||
pieceID2 < 0 || pieceID2 >= m_maxPossiblePieces) {
|
||||
return false;
|
||||
}
|
||||
return m_adjacentList[pieceID1].find(pieceID2) != m_adjacentList[pieceID1].end();
|
||||
}
|
||||
|
||||
void ComponentManager::clearSelection() {
|
||||
m_selectedComponentID = -1;
|
||||
}
|
||||
|
||||
std:: unordered_map<int, std::unordered_set<int>> ComponentManager::getAllComponents() const {
|
||||
return m_componentPieces;
|
||||
|
||||
}
|
||||
|
||||
std::unordered_map<int, int> ComponentManager::getAllPiecetoComponent() const {
|
||||
return m_pieceToComponent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
|
||||
class ComponentManager {
|
||||
private:
|
||||
// 并查集的父节点数组,使用连续内存存储
|
||||
std::vector<int> m_parent;
|
||||
//记录根节点的大小(按秩合并)
|
||||
std::vector<int> m_rank;
|
||||
// 记录每个棋子的直接连接关系(邻接表)
|
||||
std::vector<std::unordered_set<int>> m_adjacentList;
|
||||
// 组件ID到棋子集合的映射
|
||||
std::unordered_map<int, std::unordered_set<int>> m_componentPieces;
|
||||
// 棋子ID到组件ID的映射
|
||||
std::unordered_map<int, int> m_pieceToComponent;
|
||||
// 当前选中的组件ID
|
||||
int m_selectedComponentID = -1;
|
||||
// 总棋子数
|
||||
int m_maxPossiblePieces;
|
||||
|
||||
// 重新计算连通性(断开后调用)
|
||||
void recomputeComponentsAfterDisconnection(int oldComponentID, const std::unordered_set<int>& remainingPieces);
|
||||
// 处理组件分裂
|
||||
void handleComponentSplit(int oldComponentID, const std::unordered_set<int>& affectedPieces);
|
||||
|
||||
// 使用BFS查找连通区域
|
||||
std::unordered_set<int> bfsConnectedRegion(int startPiece, const std::unordered_set<int>& afftedPieces);
|
||||
|
||||
// 创建新组件
|
||||
int createNewComponent(int rootPiece);
|
||||
|
||||
public:
|
||||
// 构造函数:初始化指定数量的棋子
|
||||
explicit ComponentManager(int maxPossiblePieces);
|
||||
//添加棋子
|
||||
void addPiece(int PieceID, const std::vector<int>& adjacentPiece);
|
||||
//移除棋子
|
||||
void removePiece(int PieceID);
|
||||
// 查找操作(带路径压缩)
|
||||
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<int>& getSelectedComponent() const;
|
||||
// 获取棋子所属的组件ID
|
||||
int getComponentID(int pieceID) const;
|
||||
// 获取组件内所有棋子
|
||||
const std::unordered_set<int>& getPiecesInComponent(int pieceID) const;
|
||||
// 检查两个棋子是否在同一个组件中
|
||||
bool areConnected(int pieceID1, int pieceID2);
|
||||
// 获取棋子的所有直接连接
|
||||
const std::unordered_set<int>& getPieceConnections(int pieceID) const;
|
||||
// 检查两个棋子是否直接相连
|
||||
bool areDirectlyConnected(int pieceID1, int pieceID2) const;
|
||||
// 清除选中状态
|
||||
void clearSelection();
|
||||
// 不能返回引用因为要保存旧的组件
|
||||
//获取所有组件
|
||||
std::unordered_map<int, std::unordered_set<int>> getAllComponents() const;
|
||||
//获取棋子ID到组件ID的映射
|
||||
std::unordered_map<int, int> getAllPiecetoComponent() const;
|
||||
|
||||
};
|
||||
@@ -1,193 +0,0 @@
|
||||
// src/core/GameSession.cpp
|
||||
#include "GameSession.h"
|
||||
|
||||
|
||||
GameSession::GameSession()
|
||||
{
|
||||
m_board = std::make_unique<Board>(7, 7);
|
||||
}
|
||||
|
||||
|
||||
GameSession::~GameSession() {
|
||||
cleanup();
|
||||
}
|
||||
//清理资源
|
||||
void GameSession::cleanup() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool GameSession::initialize() {
|
||||
// 初始化游戏特定资源(棋盘、棋子等)
|
||||
if (!m_board->initialize()) {
|
||||
return false;
|
||||
}
|
||||
m_board->printBoard();
|
||||
resetActionableComponents();
|
||||
resetOldPieceIDtoComponent();
|
||||
|
||||
|
||||
|
||||
// ...
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameSession::resetActionableComponents() {
|
||||
|
||||
m_actionableComponents = m_board->getAllPlayerComponent(m_currentPlayer);
|
||||
}
|
||||
|
||||
void GameSession::resetOldPieceIDtoComponent() {
|
||||
m_oldPieceIDtoComponentID = m_board->getALLPiecetoComponent();
|
||||
}
|
||||
|
||||
void GameSession::setPlayerAction(ActionType type) {
|
||||
m_currentActionType = type;
|
||||
}
|
||||
|
||||
|
||||
bool GameSession::executeAction(int toRow, int toCol) {
|
||||
auto [fromRow, fromCol] = *m_seletedPiece;
|
||||
if (m_currentActionType == ActionType::GROW) {
|
||||
if (Rule::canGrow(m_board.get(), fromRow, fromCol, toRow, toCol, m_currentPlayer)) {
|
||||
m_board->placePieceAt(toRow, toCol, m_currentPlayer);
|
||||
// 如果执行了操作就擦除
|
||||
markComponentAsUsed(getOldComponentID(fromRow, fromCol));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (m_currentActionType == ActionType::MOVE) {
|
||||
if (Rule::canMove(m_board.get(), fromRow, fromCol, toRow, toCol, m_currentPlayer)) {
|
||||
m_board->removePieceAt(fromRow, fromCol);
|
||||
m_board->removePieceAt(toRow, toCol);
|
||||
m_board->placePieceAt(toRow, toCol, m_currentPlayer);
|
||||
|
||||
markComponentAsUsed(getOldComponentID(fromRow, fromCol));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (m_currentActionType == ActionType::SPORE) {
|
||||
if (Rule::canSpore(m_board.get(), fromRow, fromCol, toRow, toCol, m_currentPlayer)) {
|
||||
m_board->removePieceAt(fromRow, fromCol);
|
||||
m_board->placePieceAt(toRow, toCol, m_currentPlayer);
|
||||
|
||||
markComponentAsUsed(getOldComponentID(fromRow, fromCol));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void GameSession::markComponentAsUsed(int componentID) {
|
||||
std::cout << "try erase the componentID is " << componentID <<"\n";
|
||||
int num = m_actionableComponents.erase(componentID);
|
||||
if (num == 1) {
|
||||
std::cout << "erase successful\n";
|
||||
} else {
|
||||
std::cout << "erase error\n";
|
||||
}
|
||||
}
|
||||
|
||||
PlayerID GameSession::getCurrentPlayer() const {
|
||||
return m_currentPlayer;
|
||||
}
|
||||
|
||||
void GameSession::printBoard() const {
|
||||
m_board->printBoard();
|
||||
}
|
||||
|
||||
void GameSession::nextTurn() {
|
||||
std::cout << "switch to " << ((m_currentPlayer == PlayerID::P1) ? "P2" : "P1") << "\n";
|
||||
m_seletedPiece = std::nullopt;
|
||||
m_currentPlayer = (m_currentPlayer == PlayerID::P1) ? PlayerID::P2 : PlayerID::P1;
|
||||
resetOldPieceIDtoComponent();
|
||||
resetActionableComponents();
|
||||
|
||||
m_currentActionType = ActionType::GROW;
|
||||
}
|
||||
|
||||
bool GameSession::handleCoordinateInput(int row, int col) {
|
||||
// 如果当前没有选择棋子就选择棋子
|
||||
if (m_seletedPiece == std::nullopt) {
|
||||
if (!Rule::canbeSelect(m_board->getPieceAt(row, col), m_currentPlayer)) {
|
||||
std::cout << "sorry you can't select the piece\n";
|
||||
return false;
|
||||
}
|
||||
m_seletedPiece = {row, col};
|
||||
std::cout << "selcte piece successful\n";
|
||||
return true;
|
||||
}
|
||||
std::cout << "selectedpiece is " << m_seletedPiece->first << " " << m_seletedPiece->second << "\n";
|
||||
// 如果点击了选择的棋子就切换行动方式
|
||||
std::pair<int ,int> newSelectedPiece = {row, col};
|
||||
if (m_seletedPiece == newSelectedPiece) {
|
||||
switch (m_currentActionType)
|
||||
{
|
||||
case ActionType::GROW:
|
||||
m_currentActionType = ActionType::MOVE;
|
||||
std::cout << "switch actiontype to MOVE successful\n";
|
||||
break;
|
||||
case ActionType::MOVE:
|
||||
m_currentActionType = ActionType::SPORE;
|
||||
std::cout << "switch actiontype to SPORE successful\n";
|
||||
break;
|
||||
case ActionType::SPORE:
|
||||
m_currentActionType = ActionType::GROW;
|
||||
std::cout << "switch actiontype to GROW successful\n";
|
||||
break;
|
||||
default:
|
||||
std::cout << "switch actiontype wrong\n";
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//如果点击了属于当前玩家且没有行动的的其它棋子,就切换选择棋子到其它棋子
|
||||
int selectComponentID = getOldComponentID(row, col);
|
||||
if (m_actionableComponents.find(selectComponentID) != m_actionableComponents.end()) {
|
||||
m_seletedPiece = newSelectedPiece;
|
||||
std::cout << "switch the selectedpiece to " << m_seletedPiece->first << " " << m_seletedPiece->second << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果点击了已经行动的棋子,则不进行处理,已行动的棋子如果是在一个单独的区域不用处理,但如果是在一个未行动的组件中欧是可以再次行动的,
|
||||
//但是如果点击同一块 也无需处理,因为 在m_actionableComponents已经不存在了,直接尝试执行行动,但因为rule处理了所以不用管
|
||||
|
||||
// 其它情况则执行行动
|
||||
if(!executeAction(row, col)) {
|
||||
std::cout << "action pos invaild!\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 执行完之后检查是否m_actionableComponents为空,
|
||||
|
||||
// m_actionableComponents只保存了ID,但是在执行棋子之后会处理组件的连通性,rule会获取到新的连通性,不过这样更符合逻辑
|
||||
|
||||
//如果不是空的这默认将m_seletedPiece切换到这个组件之中
|
||||
//如果是空的则进行下一轮切换玩家
|
||||
if (m_actionableComponents.empty()) {
|
||||
nextTurn();
|
||||
return true;
|
||||
} else {
|
||||
for (auto leftcomponentID : m_actionableComponents) {
|
||||
std::cout << "leftcomponentID is " << leftcomponentID << "\n";
|
||||
}
|
||||
auto leftcomponent = m_actionableComponents.begin();
|
||||
m_seletedPiece = m_board->getCoordFromID(*leftcomponent);
|
||||
std::cout << "switch the selectedpiece to " << m_seletedPiece->first << " " << m_seletedPiece->second << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int GameSession::getOldComponentID(int row, int col) {
|
||||
int pieceID = m_board->getPieceID(row, col);
|
||||
auto it = m_oldPieceIDtoComponentID.find(pieceID);
|
||||
//for (auto [pieceID, y] : m_oldPieceIDtoComponentID)
|
||||
return (it != m_oldPieceIDtoComponentID.end()) ? it->second : -1;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// src/core/Game.h
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
#include "Board.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class GameSession {
|
||||
private:
|
||||
std::unique_ptr<Board> m_board;
|
||||
PlayerID m_currentPlayer = PlayerID::P1;
|
||||
ActionType m_currentActionType = ActionType::GROW;
|
||||
std::optional<std::pair<int, int>> m_seletedPiece = std::nullopt; //表示“可能有值,也可能没有值”
|
||||
std::unordered_set<int> m_actionableComponents;;
|
||||
// 保存旧的componentid与pieceid的对应关系
|
||||
std::unordered_map<int, int> m_oldPieceIDtoComponentID;
|
||||
// 如果操作执行成功就从
|
||||
void markComponentAsUsed(int componentID);
|
||||
|
||||
|
||||
public:
|
||||
GameSession();
|
||||
~GameSession();
|
||||
void cleanup();
|
||||
bool initialize();
|
||||
//获取当前玩家的拥有的组件
|
||||
void resetActionableComponents();
|
||||
//旧的componentid与pieceid的对应关系
|
||||
void resetOldPieceIDtoComponent();
|
||||
// 设置行动类型
|
||||
void setPlayerAction(ActionType type);
|
||||
// 执行玩家的行动
|
||||
bool executeAction(int row, int col);
|
||||
// 获取当前玩家
|
||||
PlayerID getCurrentPlayer() const;
|
||||
// 打印棋盘
|
||||
void printBoard() const;
|
||||
// 下一个轮次
|
||||
void nextTurn();
|
||||
|
||||
// 根据当前状态自动处理坐标输入:
|
||||
// - 如果尚未选中棋子 → 尝试选中
|
||||
// - 如果已选中棋子 → 尝试执行当前动作类型(GROW/MOVE/SPORE)
|
||||
bool handleCoordinateInput(int row, int col);
|
||||
|
||||
int getOldComponentID(int row, int col);
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
// 这里存储游戏的各种状态
|
||||
|
||||
|
||||
|
||||
enum class PlayerID {
|
||||
P1,
|
||||
P2
|
||||
};
|
||||
|
||||
enum class ActionType {
|
||||
GROW,
|
||||
MOVE,
|
||||
SPORE
|
||||
};
|
||||
|
||||
enum class GameState {
|
||||
MAIN_MENU, // 主菜单(开始界面)
|
||||
SETTINGS, // 设置界面(音量、画质等)
|
||||
GAME_SETUP, // 对局前的设置(选择模式、玩家类型等)
|
||||
IN_GAME, // 正在对局中(核心逻辑运行)
|
||||
PAUSED, // 游戏暂停(可返回菜单或继续)
|
||||
GAME_OVER, // 对局结束(显示胜负/平局)
|
||||
TUTORIAL, // 教程模式(可选)
|
||||
EXITING // 退出确认或正在退出
|
||||
};
|
||||
|
||||
enum class GameMode {
|
||||
LOCAL_PVP, // 本地两人对战
|
||||
VS_AI, // 玩家 vs AI
|
||||
ONLINE_PVP, // 网络对战
|
||||
TUTORIAL_MODE // 教程(可视为特殊模式)
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "Piece.h"
|
||||
|
||||
Piece::Piece(PlayerID ID) : m_owner(ID) {
|
||||
|
||||
}
|
||||
|
||||
Piece::~Piece() {
|
||||
|
||||
}
|
||||
|
||||
PlayerID Piece::getPieceOwner() const {
|
||||
return m_owner;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#include "GameTypes.h"
|
||||
|
||||
|
||||
class Piece {
|
||||
private:
|
||||
PlayerID m_owner;
|
||||
public:
|
||||
Piece(PlayerID ID);
|
||||
~Piece();
|
||||
PlayerID getPieceOwner() const;
|
||||
|
||||
|
||||
};
|
||||
@@ -1,116 +0,0 @@
|
||||
#include "Rule.h"
|
||||
#include "Piece.h"
|
||||
#include "Board.h"
|
||||
|
||||
bool Rule::canConnect(const Piece* a, const Piece* b) {
|
||||
if (a == nullptr || b == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (a->getPieceOwner() != b->getPieceOwner()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Rule::canPlacePiece(const Piece* piecePos) {
|
||||
if (piecePos != nullptr) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rule::canbeSelect(const Piece* PieceID, PlayerID ID) {
|
||||
if (PieceID == nullptr || PieceID->getPieceOwner() != ID) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rule::canGrow(const Board* board, const int fromRow, const int fromCol, const int toRow, const int toCol, const PlayerID player) {
|
||||
|
||||
|
||||
|
||||
// 检查是否有棋子并且属于自己
|
||||
const Piece* fromPiece = board->getPieceAt(fromRow, fromCol);
|
||||
std::cout << "fromRow fromCol = " << fromRow << " " << fromCol << "\n";
|
||||
std::cout << "toRow toCol = " << toRow << " " << toCol << "\n";
|
||||
if (fromPiece == nullptr || fromPiece->getPieceOwner() != player) {
|
||||
std::cout << "not belong to player\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (board->getPieceAt(toRow, toCol) != nullptr) {
|
||||
return false; // 有棋子不能生长
|
||||
}
|
||||
|
||||
int fromPieceID = board->getPieceID(fromRow, fromCol);
|
||||
int toPieceID = board->getPieceID(toRow, toCol);
|
||||
//std::cout << "fromPieceID= " << fromPieceID << ", toPieceID= " << toPieceID << "\n";
|
||||
auto selectedComponent = board->getComponentByPieceID(fromPieceID);
|
||||
std::cout << "before action Component size: " << selectedComponent.size() << "\n";
|
||||
for (auto PieceID : selectedComponent) {
|
||||
auto Neighbors = board->getOrthogonalNeighbors(PieceID);
|
||||
if (Neighbors.find(toPieceID) != Neighbors.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Rule::canMove(const Board* board, const int fromRow, const int fromCol, const int toRow, const int toCol, const PlayerID player) {
|
||||
|
||||
// 检查是否有棋子并且属于自己
|
||||
const Piece* fromPiece = board->getPieceAt(fromRow, fromCol);
|
||||
std::cout << "fromRow fromCol = " << fromRow << " " << fromCol << "\n";
|
||||
std::cout << "toRow toCol = " << toRow << " " << toCol << "\n";
|
||||
if (fromPiece == nullptr || fromPiece->getPieceOwner() != player) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否是对方棋子或者空格
|
||||
const Piece* toPiece = board->getPieceAt(toRow, toCol);
|
||||
if (toPiece != nullptr && toPiece->getPieceOwner() == player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int fromPieceID = board->getPieceID(fromRow, fromCol);
|
||||
int toPieceID = board->getPieceID(toRow, toCol);
|
||||
auto selectedComponent = board->getComponentByPieceID(fromPieceID);
|
||||
std::cout << "before action Component size: " << selectedComponent.size() << "\n";
|
||||
for (auto PieceID : selectedComponent) {
|
||||
auto Neighbors = board->getOrthogonalNeighbors(PieceID);
|
||||
if (Neighbors.find(toPieceID) != Neighbors.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Rule::canSpore(const Board* board, const int fromRow, const int fromCol, const int toRow, const int toCol, const PlayerID player) {
|
||||
// 检查是否有棋子并且属于自己
|
||||
const Piece* fromPiece = board->getPieceAt(fromRow, fromCol);
|
||||
std::cout << "fromRow fromCol = " << fromRow << " " << fromCol << "\n";
|
||||
std::cout << "toRow toCol = " << toRow << " " << toCol << "\n";
|
||||
if (fromPiece == nullptr || fromPiece->getPieceOwner() != player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (board->getPieceAt(toRow, toCol) != nullptr) {
|
||||
return false; // 有棋子不能扩散
|
||||
}
|
||||
|
||||
int fromPieceID = board->getPieceID(fromRow, fromCol);
|
||||
int toPieceID = board->getPieceID(toRow, toCol);
|
||||
auto selectedComponent = board->getComponentByPieceID(fromPieceID);
|
||||
std::cout << "before action Component size: " << selectedComponent.size() << "\n";
|
||||
for (auto PieceID : selectedComponent) {
|
||||
auto SporeRegion = board->getSporeRange(PieceID);
|
||||
if (SporeRegion.find(toPieceID) != SporeRegion.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#include "GameTypes.h"
|
||||
class Piece; // 前向声明
|
||||
class Board;
|
||||
|
||||
class Rule {
|
||||
public:
|
||||
static bool canConnect(const Piece* a, const Piece* b);
|
||||
static bool canPlacePiece(const Piece* piecePos);
|
||||
static bool canbeSelect(const Piece* PieceID, const PlayerID ID);
|
||||
static bool canGrow(const Board* board, const int fromRow, const int fromCol, const int toRow, const int toCol, const PlayerID player);
|
||||
static bool canMove(const Board* board, const int fromRow, const int fromCol, const int toRow, const int toCol, const PlayerID player);
|
||||
static bool canSpore(const Board* board, const int fromRow, const int fromCol, const int toRow, const int toCol, const PlayerID player);
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
// main.cpp
|
||||
#include "GameSession.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
GameSession game;
|
||||
if (!game.initialize()) {
|
||||
std::cerr << "Failed to initialize game.\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 简单控制台循环
|
||||
while (true) {
|
||||
std::cout << "Current player: "
|
||||
<< (game.getCurrentPlayer() == PlayerID::P1 ? "P1" : "P2") << "\n";
|
||||
|
||||
|
||||
std::cout << "input piece (row col): ";
|
||||
int r, c;
|
||||
std::cin >> r >> c;
|
||||
game.handleCoordinateInput(r, c);
|
||||
|
||||
game.printBoard();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user