mirror of
https://github.com/zhenyan121/SporeBG-Conid.git
synced 2026-04-10 06:14:08 +08:00
Finish the Core
This commit is contained in:
@@ -16,6 +16,10 @@ set(SOURCE_FILES
|
|||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/core/Game.cpp
|
src/core/Game.cpp
|
||||||
src/ui/Render.cpp
|
src/ui/Render.cpp
|
||||||
|
src/core/Board.cpp
|
||||||
|
src/core/Piece.cpp
|
||||||
|
src/core/Rule.cpp
|
||||||
|
src/core/ComponentManager.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 添加可执行文件
|
# 添加可执行文件
|
||||||
|
|||||||
@@ -12,41 +12,167 @@ Board::~Board() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
//将二维坐标转化成一维坐标
|
//将二维坐标转化成一维坐标
|
||||||
const int Board::getIndex(int row, int col) {
|
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;
|
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) {
|
void Board::placePieceAt(int row, int col, PlayerID ID) {
|
||||||
int index = getIndex(row, col);
|
int PieceID = getPieceID(row, col);
|
||||||
m_grid[index] = std::make_unique<Piece>(ID);
|
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 dx[] = {0, 0, -1, 1};
|
||||||
const int dy[] = {-1, 1, 0, 0};
|
const int dy[] = {-1, 1, 0, 0};
|
||||||
|
|
||||||
std::vector<int> existingNeighbors; //记录附近的同色邻居
|
std::vector<int> existingNeighbors; //记录附近的同色邻居
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
int nx = row + dx[i];
|
int nx = row + dx[i];
|
||||||
int ny = col + dy[i];
|
int ny = col + dy[i];
|
||||||
int pos = getIndex(nx, ny);
|
if (nx < 0 || nx >= m_rows || ny < 0 || ny >= m_cols) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int pos = getPieceID(nx, ny);
|
||||||
//添加邻居
|
//添加邻居
|
||||||
if (m_grid[pos] != nullptr && Rule::canConnect(m_grid[index]->getPieceOwner(), m_grid[pos]->getPieceOwner())) {
|
if (Rule::canConnect(m_grid[PieceID].get(), m_grid[pos].get())) {
|
||||||
existingNeighbors.push_back(pos);
|
existingNeighbors.push_back(pos);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 调用componet处理一片的添加和连接操作
|
// 调用componet处理一片的添加和连接操作
|
||||||
m_component->addPiece(index, existingNeighbors);
|
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() {
|
bool Board::initialize() {
|
||||||
placePieceAt(0, 0, PlayerID::P1);
|
placePieceAt(0, 0, PlayerID::P1);
|
||||||
placePieceAt(0 ,2, PlayerID::P1);
|
placePieceAt(0 ,2, PlayerID::P1);
|
||||||
placePieceAt(6, 6, PlayerID::P2);
|
placePieceAt(6, 6, PlayerID::P2);
|
||||||
placePieceAt(5, 5, PlayerID::P2);
|
placePieceAt(5, 5, PlayerID::P2);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Piece>& Board::at(int row, int col) {
|
|
||||||
return m_grid[row * m_cols + col];
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "Rule.h"
|
#include "Rule.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
// 用 (row, col) 表示坐标,0-based
|
// 用 (row, col) 表示坐标,0-based
|
||||||
struct Position {
|
struct Position {
|
||||||
int row;
|
int row;
|
||||||
@@ -25,9 +27,28 @@ private:
|
|||||||
public:
|
public:
|
||||||
Board(int rows, int cols);
|
Board(int rows, int cols);
|
||||||
~Board();
|
~Board();
|
||||||
const int getIndex(int row, int col);
|
// 获取一维索引
|
||||||
std::unique_ptr<Piece>& at(int row, int col);
|
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();
|
bool initialize();
|
||||||
// 放置棋子
|
// 放置棋子
|
||||||
void placePieceAt(int row, int col, PlayerID ID);
|
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
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
@@ -11,10 +11,10 @@ ComponentManager::ComponentManager(int maxPossiblePieces)
|
|||||||
|
|
||||||
void ComponentManager::addPiece(int PieceID, const std::vector<int>& adjacentPiece) {
|
void ComponentManager::addPiece(int PieceID, const std::vector<int>& adjacentPiece) {
|
||||||
if (PieceID < 0 || PieceID >= m_maxPossiblePieces) return;
|
if (PieceID < 0 || PieceID >= m_maxPossiblePieces) return;
|
||||||
if (m_parent[PieceID] == -1) return; // 已存在
|
if (m_parent[PieceID] != -1) return; // 已存在
|
||||||
|
|
||||||
m_parent[PieceID] = PieceID;
|
m_parent[PieceID] = PieceID;
|
||||||
m_rank[PieceID] = PieceID;
|
m_rank[PieceID] = 0;
|
||||||
m_componentPieces[PieceID] = {PieceID};
|
m_componentPieces[PieceID] = {PieceID};
|
||||||
m_pieceToComponent[PieceID] = PieceID;
|
m_pieceToComponent[PieceID] = PieceID;
|
||||||
|
|
||||||
@@ -24,11 +24,20 @@ void ComponentManager::addPiece(int PieceID, const std::vector<int>& adjacentPie
|
|||||||
// 合并连通组件(unite 会自动处理是否已在同一组件)
|
// 合并连通组件(unite 会自动处理是否已在同一组件)
|
||||||
unite(PieceID, neighbor);
|
unite(PieceID, neighbor);
|
||||||
|
|
||||||
addConnection(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) {
|
int ComponentManager::find(int pieceID) {
|
||||||
if (m_parent[pieceID] != pieceID) {
|
if (m_parent[pieceID] != pieceID) {
|
||||||
m_parent[pieceID] = find(m_parent[pieceID]);
|
m_parent[pieceID] = find(m_parent[pieceID]);
|
||||||
@@ -70,7 +79,7 @@ void ComponentManager::addConnection(int pieceID1, int pieceID2) {
|
|||||||
m_adjacentList[pieceID2].insert(pieceID1);
|
m_adjacentList[pieceID2].insert(pieceID1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
bool ComponentManager::disconnectFromNeighbor(int pieceID, int neighborID){
|
bool ComponentManager::disconnectFromNeighbor(int pieceID, int neighborID){
|
||||||
// 检查是否真的相连
|
// 检查是否真的相连
|
||||||
if (!areDirectlyConnected(pieceID, neighborID)) {
|
if (!areDirectlyConnected(pieceID, neighborID)) {
|
||||||
@@ -84,7 +93,7 @@ bool ComponentManager::disconnectFromNeighbor(int pieceID, int neighborID){
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
bool ComponentManager::disconnectFromComponent(int pieceID) {
|
bool ComponentManager::disconnectFromComponent(int pieceID) {
|
||||||
int oldComponentID = find(pieceID);
|
int oldComponentID = find(pieceID);
|
||||||
if (oldComponentID == -1) return false;
|
if (oldComponentID == -1) return false;
|
||||||
@@ -94,33 +103,44 @@ bool ComponentManager::disconnectFromComponent(int pieceID) {
|
|||||||
|
|
||||||
// 断开所有连接
|
// 断开所有连接
|
||||||
for (int neighborID : neighbors) {
|
for (int neighborID : neighbors) {
|
||||||
m_adjacentList[pieceID].erase(neighborID);
|
|
||||||
m_adjacentList[neighborID].erase(pieceID);
|
m_adjacentList[neighborID].erase(pieceID);
|
||||||
}
|
}
|
||||||
|
// 删除pieceID的邻接表
|
||||||
// 将被断开的棋子设为独立组件
|
m_adjacentList[pieceID].clear();
|
||||||
|
/* // 将被断开的棋子设为独立组件
|
||||||
m_parent[pieceID] = pieceID;
|
m_parent[pieceID] = pieceID;
|
||||||
m_rank[pieceID] = 0;
|
m_rank[pieceID] = 0;
|
||||||
m_componentPieces[pieceID] = {pieceID};
|
m_componentPieces[pieceID] = {pieceID};
|
||||||
m_pieceToComponent[pieceID] = pieceID;
|
m_pieceToComponent[pieceID] = pieceID;
|
||||||
|
*/
|
||||||
|
// 从原组件中移除 pieceID
|
||||||
|
if (m_componentPieces.count(oldComponentID)) {
|
||||||
|
m_componentPieces[oldComponentID].erase(pieceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pieceToComponent.erase(pieceID);
|
||||||
// 如果原组件还有其他棋子,需要重新计算连通性
|
// 如果原组件还有其他棋子,需要重新计算连通性
|
||||||
if (!neighbors.empty()) {
|
if (!m_componentPieces[oldComponentID].empty()) {
|
||||||
recomputeComponentsAfterDisconnection(pieceID);
|
recomputeComponentsAfterDisconnection(oldComponentID, m_componentPieces[oldComponentID]);
|
||||||
|
} else {
|
||||||
|
m_componentPieces.erase(oldComponentID);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentManager::recomputeComponentsAfterDisconnection(int disconnectedPiece) {
|
void ComponentManager::recomputeComponentsAfterDisconnection(int oldComponentID, const std::unordered_set<int>& remainingPieces) {
|
||||||
int oldComponentID = find(disconnectedPiece);
|
|
||||||
if (oldComponentID == -1 || m_componentPieces[disconnectedPiece].size() <= 1) {
|
|
||||||
|
|
||||||
|
// 安全检查:remainingPieces 至少要有 2 个棋子才可能分裂
|
||||||
|
if (remainingPieces.size() <= 1) {
|
||||||
|
// 如果只剩 0 或 1 个棋子,不需要分裂
|
||||||
|
// (如果剩 1 个,它自己就是一个新组件;如果为 0,调用方应已处理)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取原组件中除断开棋子外的所有棋子
|
|
||||||
std::unordered_set<int> remainingPieces = m_componentPieces[oldComponentID];
|
|
||||||
remainingPieces.erase(disconnectedPiece);
|
|
||||||
|
|
||||||
//处理组件分裂
|
//处理组件分裂
|
||||||
handleComponentSplit(oldComponentID, remainingPieces);
|
handleComponentSplit(oldComponentID, remainingPieces);
|
||||||
}
|
}
|
||||||
@@ -246,6 +266,7 @@ void ComponentManager::clearSelection() {
|
|||||||
|
|
||||||
std:: unordered_map<int, std::unordered_set<int>> ComponentManager::getAllComponents() const {
|
std:: unordered_map<int, std::unordered_set<int>> ComponentManager::getAllComponents() const {
|
||||||
return m_componentPieces;
|
return m_componentPieces;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ private:
|
|||||||
int m_maxPossiblePieces;
|
int m_maxPossiblePieces;
|
||||||
|
|
||||||
// 重新计算连通性(断开后调用)
|
// 重新计算连通性(断开后调用)
|
||||||
void recomputeComponentsAfterDisconnection(int disconnectedPiece);
|
void recomputeComponentsAfterDisconnection(int oldComponentID, const std::unordered_set<int>& remainingPieces);
|
||||||
// 处理组件分裂
|
// 处理组件分裂
|
||||||
void handleComponentSplit(int oldComponentID, const std::unordered_set<int>& affectedPieces);
|
void handleComponentSplit(int oldComponentID, const std::unordered_set<int>& affectedPieces);
|
||||||
|
|
||||||
@@ -38,6 +38,8 @@ public:
|
|||||||
explicit ComponentManager(int maxPossiblePieces);
|
explicit ComponentManager(int maxPossiblePieces);
|
||||||
//添加棋子
|
//添加棋子
|
||||||
void addPiece(int PieceID, const std::vector<int>& adjacentPiece);
|
void addPiece(int PieceID, const std::vector<int>& adjacentPiece);
|
||||||
|
//移除棋子
|
||||||
|
void removePiece(int PieceID);
|
||||||
// 查找操作(带路径压缩)
|
// 查找操作(带路径压缩)
|
||||||
int find(int pieceID);
|
int find(int pieceID);
|
||||||
// 合并两个棋子所在的组件(按秩合并)
|
// 合并两个棋子所在的组件(按秩合并)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Game::Game()
|
Game::Game()
|
||||||
{
|
{
|
||||||
m_board = std::make_unique<Board>();
|
m_board = std::make_unique<Board>(7, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ bool Game::initialize() {
|
|||||||
if (!m_board->initialize()) {
|
if (!m_board->initialize()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
m_board->printBoard();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -32,5 +33,67 @@ bool Game::initialize() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::resetActionableComponents() {
|
||||||
|
|
||||||
|
m_actionableComponents = m_board->getAllPlayerComponent(m_currentPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Game::playerSelectPiece(int row, int col) {
|
||||||
|
if (Rule::canbeSelect(m_board->getPieceAt(row, col), m_currentPlayer)) {
|
||||||
|
/*if (m_seletedPiece == std::nullopt) {
|
||||||
|
m_seletedPiece = {row, col};
|
||||||
|
}*/
|
||||||
|
m_seletedPiece = {row, col};
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::setPlayerAction(ActionType type) {
|
||||||
|
m_currentActionType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Game::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(m_board->getComponentID(fromRow, fromCol));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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(m_board->getComponentID(fromRow, fromCol));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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(m_board->getComponentID(fromRow, fromCol));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::markComponentAsUsed(int componentID) {
|
||||||
|
m_actionableComponents.erase(componentID);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerID Game::getCurrentPlayer() const {
|
||||||
|
return m_currentPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::printBoard() const {
|
||||||
|
m_board->printBoard();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// src/core/Game.h
|
// src/core/Game.h
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <SDL3/SDL.h>
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Board.h"
|
#include "Board.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -10,14 +12,28 @@
|
|||||||
class Game {
|
class Game {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Board> m_board;
|
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::unordered_set<int> m_actionableComponents;;
|
||||||
|
// 如果操作执行成功就从
|
||||||
|
void markComponentAsUsed(int componentID);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Game();
|
Game();
|
||||||
~Game();
|
~Game();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
bool initialize();
|
bool initialize();
|
||||||
|
//获取当前玩家的拥有的组件
|
||||||
|
void resetActionableComponents();
|
||||||
|
// 获取用户选择的棋子
|
||||||
|
bool playerSelectPiece(int row, int col);
|
||||||
|
// 设置行动类型
|
||||||
|
void setPlayerAction(ActionType type);
|
||||||
|
// 执行玩家的行动
|
||||||
|
void executeAction(int row, int col);
|
||||||
|
// 获取当前玩家
|
||||||
|
PlayerID getCurrentPlayer() const;
|
||||||
|
// 打印棋盘
|
||||||
|
void printBoard() const;
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
// 这里存储游戏的各种状态
|
// 这里存储游戏的各种状态
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum class PlayerID {
|
enum class PlayerID {
|
||||||
P1,
|
P1,
|
||||||
P2
|
P2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ActionType {
|
||||||
|
GROW,
|
||||||
|
MOVE,
|
||||||
|
SPORE
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,116 @@
|
|||||||
#include "Rule.h"
|
#include "Rule.h"
|
||||||
|
#include "Piece.h"
|
||||||
|
#include "Board.h"
|
||||||
|
|
||||||
|
bool Rule::canConnect(const Piece* a, const Piece* b) {
|
||||||
bool Rule::canConnect(const PlayerID a, const PlayerID b) {
|
if (a == nullptr || b == nullptr) {
|
||||||
if (a == b) {
|
return false;
|
||||||
return true;
|
}
|
||||||
}
|
if (a->getPieceOwner() != b->getPieceOwner()) {
|
||||||
return false;
|
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->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,10 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "GameTypes.h"
|
#include "GameTypes.h"
|
||||||
|
class Piece; // 前向声明
|
||||||
|
class Board;
|
||||||
|
|
||||||
class Rule {
|
class Rule {
|
||||||
public:
|
public:
|
||||||
static bool canConnect(const PlayerID a, PlayerID b);
|
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);
|
||||||
};
|
};
|
||||||
32
src/core/testcore.cpp
Normal file
32
src/core/testcore.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// main.cpp
|
||||||
|
#include "Game.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Game 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 << "Action type (0=GROW, 1=MOVE, 2=SPORE): ";
|
||||||
|
int act;
|
||||||
|
std::cin >> act;
|
||||||
|
game.setPlayerAction(static_cast<ActionType>(act));
|
||||||
|
|
||||||
|
std::cout << "Select piece (row col): ";
|
||||||
|
int r, c;
|
||||||
|
std::cin >> r >> c;
|
||||||
|
game.playerSelectPiece(r, c);
|
||||||
|
|
||||||
|
std::cout << "Target position (row col): ";
|
||||||
|
std::cin >> r >> c;
|
||||||
|
game.executeAction(r, c);
|
||||||
|
|
||||||
|
game.printBoard();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user