Skip to content

Commit

Permalink
feat(NodeTree): 实现NodeTree类
Browse files Browse the repository at this point in the history
  • Loading branch information
engsr6982 committed Oct 28, 2024
1 parent 1cf38bf commit ac3140c
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 15 deletions.
113 changes: 113 additions & 0 deletions include/plotcraft/data/NodeTree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#pragma once
#include <cstddef>
#include <functional>
#include <optional>
#include <queue>
#include <string>
#include <type_traits>
#include <unordered_set>
#include <utility>
#include <vector>

namespace plot {

class NodeTree {
public:
using NodePair = std::pair<int, int>;

struct Node {
int x, z; // 坐标
double distance{0.0}; // 距离

Node() = default;
Node(int x, int z) : x(x), z(z) {}
Node(NodePair const& p) : x(p.first), z(p.second) {}
Node(int x, int z, double distance) : x(x), z(z), distance(distance) {}


template <typename T = Node>
Node(T const& cl) {
static_assert(std::is_class<T>::value, "T must be a class");

// 检查T是否有int成员x,z
static_assert(std::is_member_object_pointer<decltype(&T::x)>::value, "T must have an int member x");
static_assert(std::is_member_object_pointer<decltype(&T::z)>::value, "T must have an int member z");
static_assert(std::is_same<decltype(T::x), int>::value, "x must be of type int");
static_assert(std::is_same<decltype(T::z), int>::value, "z must be of type int");

this->x = cl.x;
this->z = cl.z;
}

operator NodePair() const { return {x, z}; }
operator std::string() const { return "Node(" + std::to_string(x) + ", " + std::to_string(z) + ")"; }
bool operator<(Node const& other) const {
return distance > other.distance; // 优先按距离排序
}
};

struct PairHash {
std::size_t operator()(NodePair const& p) const {
return std::hash<int>()(p.first) ^ std::hash<int>()(p.second);
}
};


// member
std::unordered_set<NodePair, PairHash> nodes; // 节点集合

// method
bool contains(NodePair const& p) const { return nodes.contains(p); }
bool contains(int x, int z) const { return contains({x, z}); }

void insert(NodePair const& p) { nodes.insert(p); }
void insert(int x, int z) { insert({x, z}); }

void remove(NodePair const& p) { nodes.erase(p); }
void remove(int x, int z) { remove({x, z}); }

void clear() { nodes.clear(); }

// 查找距离 root 最近的未标记节点
std::optional<Node> findNearestUnmarkedNodeFromRoot(NodePair const& root = {0, 0}) {
static std::vector<NodePair> directions = {
{1, 0 },
{-1, 0 },
{0, 1 },
{0, -1}
};

// 优先队列初始化
std::priority_queue<Node> pq;
pq.push(root);

// 记录已访问的节点
std::unordered_set<NodePair, PairHash> visited;
visited.emplace(root);

while (!pq.empty()) {
Node current = pq.top();
pq.pop();

// 检查是否未被标记
if (nodes.find({current.x, current.z}) == nodes.end()) {
return current;
}

// 将邻近的节点加入优先队列
for (const auto& dir : directions) {
int newX = current.x + dir.first;
int newZ = current.z + dir.second;
if (visited.find({newX, newZ}) == visited.end()) {
double dist = std::sqrt(newX * newX + newZ * newZ);
pq.push(Node{newX, newZ, dist});
visited.emplace(newX, newZ);
}
}
}
return std::nullopt;
}
};


} // namespace plot
8 changes: 2 additions & 6 deletions include/plotcraft/data/PlotDBStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ class PlotDBStorage {
private:
std::unique_ptr<ll::data::KeyValueDB> mDB;

bool mThreadRunning{false}; // 保存线程是否正在运行
bool mThreadRequiredExit{false}; // 保存线程是否需要退出

// Cache:
std::vector<UUIDs> mAdminList; // 管理
std::unordered_map<PlotID, PlotMetadataPtr> mPlotList; // 地皮
Expand Down Expand Up @@ -62,9 +59,8 @@ class PlotDBStorage {
PLAPI void save(); // 保存所有数据
PLAPI void save(PlotMetadata const& plot);

PLAPI void initSaveThread(); // 初始化保存线程
PLAPI bool isSaveThreadRunning() const;
PLAPI void stopSaveThread(); // 停止保存线程
std::jthread mSaveThread; // 保存线程
PLAPI void initSaveThread(); // 初始化保存线程

// Admin API:
PLAPI bool hasAdmin(const UUIDs& uuid) const;
Expand Down
13 changes: 4 additions & 9 deletions src/plotcraft/data/PlotDBStorage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "plugin/MyPlugin.h"
#include <memory>
#include <stdexcept>
#include <stop_token>
#include <thread>
#include <vector>

Expand All @@ -18,19 +19,13 @@ using namespace plot::utils;

namespace plot::data {

bool PlotDBStorage::isSaveThreadRunning() const { return mThreadRunning; }
void PlotDBStorage::stopSaveThread() { mThreadRequiredExit = true; }
void PlotDBStorage::initSaveThread() {
if (mThreadRunning) return;
mThreadRunning = true;
std::thread([this]() {
while (!this->mThreadRequiredExit) {
mSaveThread = std::jthread([this](std::stop_token st) {
while (!st.stop_requested()) {
this->save();
std::this_thread::sleep_for(std::chrono::minutes(2));
}
this->mThreadRunning = false; // 重置标志位
this->mThreadRequiredExit = false; // 重置标志位
}).detach();
});
}


Expand Down
155 changes: 155 additions & 0 deletions test/test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#pragma once
#include <cstddef>
#include <cstdio>
#include <functional>
#include <optional>
#include <queue>
#include <string>
#include <type_traits>
#include <unordered_set>
#include <utility>
#include <vector>


class NodeTree {
public:
using NodePair = std::pair<int, int>;

struct Node {
int x, z; // 坐标
double distance{0.0}; // 距离

Node() = default;
Node(int x, int z) : x(x), z(z) {}
Node(NodePair const& p) : x(p.first), z(p.second) {}
Node(int x, int z, double distance) : x(x), z(z), distance(distance) {}

template <typename T = Node>
Node(T const& cl) {
static_assert(std::is_class<T>::value, "T must be a class");

// 检查T是否有int成员x,z
static_assert(std::is_member_object_pointer<decltype(&T::x)>::value, "T must have an int member x");
static_assert(std::is_member_object_pointer<decltype(&T::z)>::value, "T must have an int member z");
static_assert(std::is_same<decltype(T::x), int>::value, "x must be of type int");
static_assert(std::is_same<decltype(T::z), int>::value, "z must be of type int");

this->x = cl.x;
this->z = cl.z;
}

operator NodePair() const { return {x, z}; }
operator std::string() const { return "Node(" + std::to_string(x) + ", " + std::to_string(z) + ")"; }
bool operator<(Node const& other) const {
return distance > other.distance; // 优先按距离排序
}
};

struct PairHash {
std::size_t operator()(NodePair const& p) const {
return std::hash<int>()(p.first) ^ std::hash<int>()(p.second);
}
};


// member
std::unordered_set<NodePair, PairHash> nodes; // 节点集合

// method
bool contains(NodePair const& p) const { return nodes.contains(p); }
bool contains(int x, int z) const { return contains({x, z}); }

void insert(NodePair const& p) { nodes.insert(p); }
void insert(int x, int z) { insert({x, z}); }

void remove(NodePair const& p) { nodes.erase(p); }
void remove(int x, int z) { remove({x, z}); }

void clear() { nodes.clear(); }

// 查找距离 root 最近的未标记节点
std::optional<Node> findNearestUnmarkedNodeFromRoot(NodePair const& root = {0, 0}) {
static std::vector<NodePair> directions = {
{1, 0 },
{-1, 0 },
{0, 1 },
{0, -1}
};

// 优先队列初始化
std::priority_queue<Node> pq;
pq.push(root);

// 记录已访问的节点
std::unordered_set<NodePair, PairHash> visited;
visited.emplace(root);

while (!pq.empty()) {
Node current = pq.top();
pq.pop();

// 检查是否未被标记
if (nodes.find({current.x, current.z}) == nodes.end()) {
return current;
}

// 将邻近的节点加入优先队列
for (const auto& dir : directions) {
int newX = current.x + dir.first;
int newZ = current.z + dir.second;
if (visited.find({newX, newZ}) == visited.end()) {
double dist = std::sqrt(newX * newX + newZ * newZ);
pq.push(Node{newX, newZ, dist});
visited.emplace(newX, newZ);
}
}
}
return std::nullopt;
}
};


#include <iostream>

// cl /EHsc /utf-8 /std:c++20 .\test.cc

int main() {
NodeTree tree;
tree.insert(0, 0);
tree.insert(1, 0);
tree.insert(0, 1);
tree.insert(0, -1);
tree.insert(-1, 0);
// tree.insert(1, 1);
tree.insert(1, -1);
tree.insert(-1, 1);
tree.insert(-1, -1);

auto nearest = tree.findNearestUnmarkedNodeFromRoot();
if (nearest) {
std::cout << "Nearest unmarked node: " << (std::string)(*nearest) << std::endl;
} else {
std::cout << "No unmarked node found." << std::endl;
}

{
class a {
public:
int x = 11;
int z = 45;
};

struct b {
int x, z = 8848;
};

NodeTree::Node a1{a{}};
NodeTree::Node b1{b{}};

std::cout << (std::string)a1 << std::endl;
std::cout << (std::string)b1 << std::endl;
}

std::cout << std::endl;
return 0;
}

0 comments on commit ac3140c

Please sign in to comment.