整合这个代码与之前的合成表系统,并请你解决使用任意格数的合成方块输入合成表时依然是9格输入的问题,并且在设置了输出槽后,不应该有输出数量询问了(直接在输出槽里回答),并且,统计材料和逐步合成都是看输入框里的物品的,合成出的是输出框里的物品,此外,我们发现程序在启动时并不能找到之前的保存位置,请用一个文件来设置保存位置,另外,由于一些问题,导致输入的代码补全,请你补全他。
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include <unordered_map>
#include <unordered_set>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include <type_traits>
#include <string_view>
using namespace std;
namespace fs = filesystem;
using namespace std::literals;
// ===================== 函数预定义 =====================
void clear(), wait(int),pause();
// ====================== 类型定义 ======================
using CraftGrid = array<array<pair<string, short>, 3>, 3>;
using MaterialMap = unordered_map<string, long long>;
// ====================== 常量定义 ======================
constexpr short DEFAULT_MAX_STACK = 64;
constexpr short MAX_RECIPES_PER_ITEM = 10;
constexpr short MAX_CRAFTING_BLOCKS = 20;
// ====================== 合成表类 ======================
class ItemTable {
public:
enum PathMode : uint8_t { SHORTEST, LONGEST, EXACT };
enum BatchMode : uint8_t { EXACT_BATCH, MERGE_BATCH };
private:
CraftGrid grid;
vector<pair<string, short>> outputs; // 多输出槽支持
string blockID; // 关联的合成方块ID
short craftCount = 1; // 每次合成产出数量
public:
ItemTable() = default;
// 设置网格项 void setItem(int x, int y, const string& id, short count) noexcept { if (x >= 0 && x < 3 && y >= 0 && y < 3) { grid[x][y] = make_pair(id, count); } } // 获取网格项 const pair<string, short>& getItem(int x, int y) const noexcept { static const pair<string, short> empty = make_pair("", 0); return (x >= 0 && x < 3 && y >= 0 && y < 3) ? grid[x][y] : empty; } // 设置输出槽 void setOutputSlot(size_t slot, const string& id, short count) { if (slot >= outputs.size()) outputs.resize(slot + 1, make_pair("", 0)); outputs[slot] = make_pair(id, count); } // 获取输出槽 const pair<string, short>& getOutputSlot(size_t slot) const noexcept { static const pair<string, short> empty = make_pair("", 0); return (slot < outputs.size()) ? outputs[slot] : empty; } // 获取所有输出 const vector<pair<string, short>>& getAllOutputs() const noexcept { return outputs; } // 获取主输出 pair<string, short> getMainOutput() const noexcept { for (const auto& output : outputs) { if (!output.first.empty() && output.second > 0) { return output; } } return make_pair("", 0); } // 设置关联的合成方块 void setBlockID(const string& id) noexcept { blockID = id; } const string& getBlockID() const noexcept { return blockID; } // 设置每次合成产出数量 void setCraftCount(short count) noexcept { craftCount = max<short>(1, count); } short getCraftCount() const noexcept { return craftCount; } // 移除对特定物品的引用 void removeReferencesTo(const string& id) noexcept { // 清理输入网格 for (auto& row : grid) { for (auto& slot : row) { if (slot.first == id) { slot.first = ""; slot.second = 0; } } } // 清理输出槽 for (auto& output : outputs) { if (output.first == id) { output.first = ""; output.second = 0; } } } // 获取路径描述 string getPathDescription() const { ostringstream oss; if (!blockID.empty()) oss << "[" << blockID << "] "; const auto& mainOut = getMainOutput(); if (!mainOut.first.empty()) { oss << mainOut.first << " x" << mainOut.second; if (outputs.size() > 1) { oss << " (+" << (outputs.size() - 1) << " 其他输出)"; } } return oss.str(); }
};
// ====================== 物品类 ======================
class Item {
string id;
short maxStack = DEFAULT_MAX_STACK;
vector tables;
public:
explicit Item(string id, short maxStack = DEFAULT_MAX_STACK)
: id(move(id)), maxStack(maxStack) {
tables.reserve(MAX_RECIPES_PER_ITEM);
}
const string& getID() const noexcept { return id; } short getMaxStack() const noexcept { return maxStack; } // 添加合成表 void addTable(ItemTable table) { if (tables.size() < MAX_RECIPES_PER_ITEM) { tables.emplace_back(move(table)); } } // 获取所有合成表 const vector<ItemTable>& getTables() const noexcept { return tables; } // 移除对特定物品的引用 void removeReferencesTo(const string& id) noexcept { for (auto& table : tables) { table.removeReferencesTo(id); } }
};
// ====================== 合成方块类 ======================
class CraftingBlock {
string id;
string name;
int inputSlots;
int outputSlots;
vector recipes; // 关联的合成配方
public:
CraftingBlock(string id, string name, int inSlots, int outSlots)
: id(move(id)), name(move(name)), inputSlots(inSlots), outputSlots(outSlots) {
recipes.reserve(MAX_RECIPES_PER_ITEM);
}
// 添加配方 void addRecipe(const ItemTable& recipe) { if (recipes.size() < MAX_RECIPES_PER_ITEM) { recipes.push_back(recipe); } } // 获取属性 const string& getID() const noexcept { return id; } const string& getName() const noexcept { return name; } int getInputSlots() const noexcept { return inputSlots; } int getOutputSlots() const noexcept { return outputSlots; } const vector<ItemTable>& getRecipes() const noexcept { return recipes; }
};
// ====================== 物品集合类 ======================
class ItemCollection {
unordered_map<string, Item> items;
unordered_map<string, CraftingBlock> craftingBlocks;
public:
// 添加物品
bool add(Item item) {
auto [it, inserted] = items.try_emplace(item.getID(), move(item));
return inserted;
}
// 获取物品 Item* getItem(const string& id) noexcept { auto it = items.find(id); return (it != items.end()) ? &it->second : nullptr; } const Item* getItem(const string& id) const noexcept { auto it = items.find(id); return (it != items.end()) ? &it->second : nullptr; } // 删除物品 bool removeItem(const string& id) { auto it = items.find(id); if (it == items.end()) return false; // 移除所有引用 for (auto& [_, item] : items) { item.removeReferencesTo(id); } // 从方块中移除引用 for (auto& [_, block] : craftingBlocks) { for (auto& recipe : const_cast<vector<ItemTable>&>(block.getRecipes())) { recipe.removeReferencesTo(id); } } items.erase(it); return true; } // 获取所有物品ID(排序后) vector<string> getSortedIDs() const { vector<string> ids; ids.reserve(items.size()); for (const auto& [id, _] : items) ids.push_back(id); sort(ids.begin(), ids.end()); return ids; } // 检查物品是否存在 bool contains(const string& id) const noexcept { return items.find(id) != items.end(); } // 物品数量 size_t size() const noexcept { return items.size(); } // 添加合成方块 bool addCraftingBlock(CraftingBlock block) { auto [it, inserted] = craftingBlocks.try_emplace(block.getID(), move(block)); return inserted; } // 获取合成方块 CraftingBlock* getCraftingBlock(const string& id) noexcept { auto it = craftingBlocks.find(id); return (it != craftingBlocks.end()) ? &it->second : nullptr; } // 获取所有合成方块 const unordered_map<string, CraftingBlock>& getAllCraftingBlocks() const noexcept { return craftingBlocks; } // 删除合成方块 bool removeCraftingBlock(const string& id) { auto it = craftingBlocks.find(id); if (it == craftingBlocks.end()) return false; // 移除所有关联的配方引用 for (auto& [_, item] : items) { auto& tables = const_cast<vector<ItemTable>&>(item.getTables()); for (auto itTable = tables.begin(); itTable != tables.end(); ) { if (itTable->getBlockID() == id) { itTable = tables.erase(itTable); } else { ++itTable; } } } craftingBlocks.erase(it); return true; } // 文件存储 void saveToFile(const fs::path& path) const { ofstream out(path, ios::binary); if (!out) throw runtime_error("无法打开文件进行写入: " + path.string()); // 保存物品 size_t itemCount = items.size(); out.write(reinterpret_cast<const char*>(&itemCount), sizeof(itemCount)); for (const auto& [id, item] : items) { // 保存ID size_t len = id.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(id.c_str(), len); // 保存属性 short maxStack = item.getMaxStack(); out.write(reinterpret_cast<const char*>(&maxStack), sizeof(maxStack)); // 保存合成表 size_t tableCount = item.getTables().size(); out.write(reinterpret_cast<const char*>(&tableCount), sizeof(tableCount)); for (const auto& table : item.getTables()) { // 保存输入网格 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = table.getItem(x, y); len = slot.first.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(slot.first.c_str(), len); out.write(reinterpret_cast<const char*>(&slot.second), sizeof(slot.second)); } } // 保存输出槽 const auto& outputs = table.getAllOutputs(); size_t outputCount = outputs.size(); out.write(reinterpret_cast<const char*>(&outputCount), sizeof(outputCount)); for (const auto& output : outputs) { len = output.first.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(output.first.c_str(), len); out.write(reinterpret_cast<const char*>(&output.second), sizeof(output.second)); } // 保存关联方块ID const string& blockID = table.getBlockID(); len = blockID.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(blockID.c_str(), len); // 保存每次合成产出数量 short craftCount = table.getCraftCount(); out.write(reinterpret_cast<const char*>(&craftCount), sizeof(craftCount)); } } // 保存合成方块 size_t blockCount = craftingBlocks.size(); out.write(reinterpret_cast<const char*>(&blockCount), sizeof(blockCount)); for (const auto& [id, block] : craftingBlocks) { // 保存ID size_t len = id.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(id.c_str(), len); // 保存名称 len = block.getName().size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(block.getName().c_str(), len); // 保存槽位 int slots = block.getInputSlots(); out.write(reinterpret_cast<const char*>(&slots), sizeof(slots)); slots = block.getOutputSlots(); out.write(reinterpret_cast<const char*>(&slots), sizeof(slots)); // 保存关联配方 size_t recipeCount = block.getRecipes().size(); out.write(reinterpret_cast<const char*>(&recipeCount), sizeof(recipeCount)); for (const auto& recipe : block.getRecipes()) { // 保存配方数据 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = recipe.getItem(x, y); len = slot.first.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(slot.first.c_str(), len); out.write(reinterpret_cast<const char*>(&slot.second), sizeof(slot.second)); } } const auto& outputs = recipe.getAllOutputs(); size_t outputCount = outputs.size(); out.write(reinterpret_cast<const char*>(&outputCount), sizeof(outputCount)); for (const auto& output : outputs) { len = output.first.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(output.first.c_str(), len); out.write(reinterpret_cast<const char*>(&output.second), sizeof(output.second)); } const string& blockID = recipe.getBlockID(); len = blockID.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(blockID.c_str(), len); short craftCount = recipe.getCraftCount(); out.write(reinterpret_cast<const char*>(&craftCount), sizeof(craftCount)); } } } // 文件加载 void loadFromFile(const fs::path& path) { ifstream in(path, ios::binary); if (!in) throw runtime_error("无法打开文件进行读取: " + path.string()); items.clear(); craftingBlocks.clear(); // 加载物品 size_t itemCount; in.read(reinterpret_cast<char*>(&itemCount), sizeof(itemCount)); for (size_t i = 0; i < itemCount; i++) { // 加载ID size_t len; in.read(reinterpret_cast<char*>(&len), sizeof(len)); string id(len, ' '); in.read(id.data(), len); // 加载属性 short maxStack; in.read(reinterpret_cast<char*>(&maxStack), sizeof(maxStack)); Item item(id, maxStack); // 加载合成表 size_t tableCount; in.read(reinterpret_cast<char*>(&tableCount), sizeof(tableCount)); for (size_t j = 0; j < tableCount; j++) { ItemTable table; // 加载输入网格 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { in.read(reinterpret_cast<char*>(&len), sizeof(len)); string id(len, ' '); in.read(id.data(), len); short cnt; in.read(reinterpret_cast<char*>(&cnt), sizeof(cnt)); table.setItem(x, y, id, cnt); } } // 加载输出槽 size_t outputCount; in.read(reinterpret_cast<char*>(&outputCount), sizeof(outputCount)); for (size_t k = 0; k < outputCount; k++) { in.read(reinterpret_cast<char*>(&len), sizeof(len)); string id(len, ' '); in.read(id.data(), len); short cnt; in.read(reinterpret_cast<char*>(&cnt), sizeof(cnt)); table.setOutputSlot(k, id, cnt); } // 加载关联方块ID in.read(reinterpret_cast<char*>(&len), sizeof(len));
string blockID(len, ’ ');
in.read(blockID.data(), len);
table.setBlockID(blockID);
// 加载每次合成产出数量
short craftCount;
in.read(reinterpret_cast<char*>(&craftCount), sizeof(craftCount));
table.setCraftCount(craftCount);
item.addTable(move(table));
}
items.emplace(id, move(item));
}
// 加载合成方块
size_t blockCount;
in.read(reinterpret_cast<char*>(&blockCount), sizeof(blockCount));
for (size_t i = 0; i < blockCount; i++) {
// 加载ID
size_t len;
in.read(reinterpret_cast<char*>(&len), sizeof(len));
string id(len, ’ ');
in.read(id.data(), len);
// 加载名称 in.read(reinterpret_cast<char*>(&len), sizeof(len)); string name(len, ' '); in.read(name.data(), len); // 加载槽位 int inSlots, outSlots; in.read(reinterpret_cast<char*>(&inSlots), sizeof(inSlots)); in.read(reinterpret_cast<char*>(&outSlots), sizeof(outSlots)); CraftingBlock block(id, name, inSlots, outSlots); // 加载关联配方 size_t recipeCount; in.read(reinterpret_cast<char*>(&recipeCount), sizeof(recipeCount)); for (size_t j = 0; j < recipeCount; j++) { ItemTable table; // 加载输入网格 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { in.read(reinterpret_cast<char*>(&len), sizeof(len)); string id(len, ' '); in.read(id.data(), len); short cnt; in.read(reinterpret_cast<char*>(&cnt), sizeof(cnt)); table.setItem(x, y, id, cnt); } } // 加载输出槽 size_t outputCount; in.read(reinterpret_cast<char*>(&outputCount), sizeof(outputCount)); for (size_t k = 0; k < outputCount; k++) { in.read(reinterpret_cast<char*>(&len), sizeof(len)); string id(len, ' '); in.read(id.data(), len); short cnt; in.read(reinterpret_cast<char*>(&cnt), sizeof(cnt)); table.setOutputSlot(k, id, cnt); } // 加载关联方块ID in.read(reinterpret_cast<char*>(&len), sizeof(len)); string blockID(len, ' '); in.read(blockID.data(), len); table.setBlockID(blockID); // 加载每次合成产出数量 short craftCount; in.read(reinterpret_cast<char*>(&craftCount), sizeof(craftCount)); table.setCraftCount(craftCount); block.addRecipe(table); } craftingBlocks.emplace(id, move(block));
}
}
};
// ====================== 材料计算引擎 ======================
class MaterialCalculator {
const ItemCollection& itemDB;
mutable unordered_map<string, int> depthCache;
public:
explicit MaterialCalculator(const ItemCollection& db) : itemDB(db) {}
// 计算材料需求 MaterialMap calculateMaterials(const string& id, long long count, ItemTable::PathMode pathMode = ItemTable::SHORTEST, ItemTable::BatchMode batchMode = ItemTable::EXACT_BATCH) { MaterialMap materials; set<string> visited; CalcMaterialsRecursive(id, count, materials, visited, pathMode, batchMode); return materials; }
private:
void CalcMaterialsRecursive(const string& id, long long count, MaterialMap& materials,
set& visited, ItemTable::PathMode pathMode,
ItemTable::BatchMode batchMode) {
// 检查循环依赖
if (visited.find(id) != visited.end()) return;
visited.insert(id);
// 获取物品 const Item* item = itemDB.getItem(id); if (!item || item->getTables().empty()) { materials[id] += count; // 基础材料 return; } // 选择最佳合成路径 const ItemTable* bestTable = selectBestTable(id, pathMode); if (!bestTable) return; // 计算合成批次 long long craftCnt = bestTable->getCraftCount(); long long batches = (batchMode == ItemTable::EXACT_BATCH) ? (count + craftCnt - 1) / craftCnt : static_cast<long long>(ceil(static_cast<double>(count) / craftCnt)); // 处理输入材料 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = bestTable->getItem(x, y); if (!slot.first.empty() && slot.second > 0) { long long totalNeeded = batches * slot.second; CalcMaterialsRecursive(slot.first, totalNeeded, materials, visited, pathMode, batchMode); } } } } const ItemTable* selectBestTable(const string& id, ItemTable::PathMode mode) { const Item* item = itemDB.getItem(id); if (!item || item->getTables().empty()) return nullptr; const ItemTable* bestTable = &item->getTables()[0]; if (mode == ItemTable::SHORTEST || mode == ItemTable::LONGEST) { int bestDepth = (mode == ItemTable::SHORTEST) ? INT_MAX : 0; for (const auto& table : item->getTables()) { int depth = getCachedPathDepth(table); if ((mode == ItemTable::SHORTEST && depth < bestDepth) || (mode == ItemTable::LONGEST && depth > bestDepth)) { bestDepth = depth; bestTable = &table; } } } return bestTable; } int getCachedPathDepth(const ItemTable& table) const { int maxDepth = 0; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = table.getItem(x, y); if (!slot.first.empty() && slot.second > 0) { // 使用缓存查询 auto it = depthCache.find(slot.first); if (it != depthCache.end()) { maxDepth = max(maxDepth, it->second); } else { int depth = calculateItemDepth(slot.first); depthCache[slot.first] = depth; maxDepth = max(maxDepth, depth); } } } } return maxDepth; } int calculateItemDepth(const string& id) const { // 获取物品 const Item* item = itemDB.getItem(id); if (!item || item->getTables().empty()) { return 0; // 基础材料 } // 计算最大深度 int maxDepth = 0; for (const auto& table : item->getTables()) { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = table.getItem(x, y); if (!slot.first.empty() && slot.second > 0) { int depth = calculateItemDepth(slot.first) + 1; maxDepth = max(maxDepth, depth); } } } } return maxDepth; }
};
// ====================== 逐步合成状态 ======================
struct CraftingStep {
string itemID;
long long required;
uint8_t recipeIndex;
bool completed;
};
class StepByStepCrafting {
const ItemCollection& db;
MaterialCalculator& calc;
string targetID;
long long targetCount;
stack stepStack;
unordered_set synthesizedItems;
MaterialMap totalMaterials;
public:
StepByStepCrafting(const ItemCollection& db, MaterialCalculator& calc,
const string& id, long long count)
: db(db), calc(calc), targetID(id), targetCount(count) {}
// 开始逐步合成 void start() { // 初始化第一个步骤 stepStack.push({targetID, targetCount, 0, false}); synthesizedItems.clear(); totalMaterials.clear(); // 开始交互 interactiveCrafting(); }
private:
// 交互式合成过程
void interactiveCrafting() {
while (!stepStack.empty()) {
CraftingStep& current = stepStack.top();
// 显示当前步骤信息 clear(); displayCurrentStep(current); // 获取用户选择 int choice = getUserChoice(); // 处理用户选择 switch (choice) { case 0: handleUndo(); break; case 1: processCurrentStep(current); break; case 2: stepStack.pop(); break; // 跳过 case 3: displayMaterialSummary(); pause(); break; case 4: return; // 退出 default: cout << "无效选择!" << endl; wait(1); } } cout << "恭喜! 所有材料已准备完成!" << endl; pause(); } void handleUndo() { if (stepStack.size() > 1) { CraftingStep current = stepStack.top(); stepStack.pop(); synthesizedItems.erase(current.itemID); if (db.getItem(current.itemID) == nullptr || db.getItem(current.itemID)->getTables().empty()) { totalMaterials[current.itemID] -= current.required; } } else { cout << "已在第一步,无法返回!" << endl; wait(1); } } // 显示当前步骤信息 void displayCurrentStep(const CraftingStep& step) const { cout << "===== 当前合成步骤 =====" << endl; cout << "物品: " << step.itemID << " x " << step.required << endl; const Item* item = db.getItem(step.itemID); if (!item || item->getTables().empty()) { cout << "\n这是基础材料,无法合成!" << endl; return; } // 显示当前配方 const auto& table = item->getTables()[step.recipeIndex]; cout << "使用配方: " << table.getPathDescription() << endl; // 显示当前材料 cout << "\n所需材料:" << endl; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = table.getItem(x, y); if (!slot.first.empty() && slot.second > 0) { long long totalNeeded = step.required * slot.second; cout << " - " << slot.first << " x " << totalNeeded << endl; } } } // 显示当前状态 cout << "\n当前状态: " << (step.completed ? "已完成" : "待处理") << "\n========================" << endl; } // 获取用户选择 int getUserChoice() const { cout << "\n选项:" << endl; cout << "0. 返回上一步" << endl; cout << "1. 合成此物品" << endl; cout << "2. 跳过此物品" << endl; cout << "3. 查看材料汇总" << endl; cout << "4. 退出逐步合成" << endl; cout << "选择: "; int choice; cin >> choice; return choice; } // 处理当前步骤 void processCurrentStep(CraftingStep& step) { const Item* item = db.getItem(step.itemID); if (!item || item->getTables().empty()) { // 基础材料,直接完成 totalMaterials[step.itemID] += step.required; stepStack.pop(); return; } const auto& table = item->getTables()[step.recipeIndex]; short craftCount = table.getCraftCount(); long long batches = (step.required + craftCount - 1) / craftCount; // 整数除法 // 添加子步骤 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = table.getItem(x, y); // 跳过空槽位和已合成物品 if (slot.first.empty() || slot.second == 0 || synthesizedItems.find(slot.first) != synthesizedItems.end()) continue; // 创建新步骤 stepStack.push({slot.first, batches * slot.second, 0, false}); } } // 标记当前步骤为已完成 step.completed = true; synthesizedItems.insert(step.itemID); } // 显示材料汇总 void displayMaterialSummary() const { clear(); cout << "===== 材料汇总 =====" << endl; cout << "目标: " << targetID << " x " << targetCount << endl; cout << "已准备材料:" << endl; for (const auto& [id, cnt] : totalMaterials) { cout << " - " << id << ": " << cnt << endl; } cout << "=====================" << endl; }
};
// ====================== 用户界面工具 ======================
void clear() {
#ifdef _WIN32
system(“cls”);
#else
system(“clear”);
#endif
}
void pause() {
cout << “\n按回车键继续…”;
cin.ignore(numeric_limits::max(), ‘\n’);
cin.get();
}
void wait(int seconds) {
this_thread::sleep_for(chrono::seconds(seconds));
}
// ====================== 全局数据 ======================
ItemCollection itemDB;
MaterialCalculator calculator(itemDB);
fs::path savePath = fs::current_path() / “items.dat”;
// ====================== 文件操作 ======================
void SaveItems(bool showMessage = true) {
try {
if (!fs::exists(savePath.parent_path())) {
fs::create_directories(savePath.parent_path());
}
itemDB.saveToFile(savePath);
if (showMessage) cout << “物品数据已保存!” << endl;
} catch (const exception& e) {
cerr << "保存错误: " << e.what() << endl;
}
}
void LoadItems() {
try {
if (fs::exists(savePath)) {
itemDB.loadFromFile(savePath);
cout << “物品数据已加载 (” << itemDB.size() << " 物品)" << endl;
} else {
cout << “未找到保存文件,创建新数据库” << endl;
}
} catch (const exception& e) {
cerr << "加载错误: " << e.what() << endl;
}
}
// ====================== 用户界面功能 ======================
void CreateItem() {
clear();
string id;
short maxStack;
cout << "物品ID: "; cin >> id; if (itemDB.contains(id)) { cout << "物品已存在!" << endl; pause(); return; } cout << "最大堆叠数 (默认64): "; cin >> maxStack; if (maxStack <= 0) maxStack = 64; itemDB.add(Item(id, maxStack)); SaveItems(false); cout << "物品创建成功!" << endl; wait(1);
}
void DeleteItem() {
clear();
auto ids = itemDB.getSortedIDs();
if (ids.empty()) { cout << "没有可删除的物品!" << endl; pause(); return; } cout << "可用物品:\n"; for (const auto& id : ids) { cout << " - " << id << "\n"; } string target; cout << "\n输入要删除的物品ID: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } cout << "确认删除? (Y/N): "; char confirm; cin >> confirm; if (toupper(confirm) == 'Y') { if (itemDB.removeItem(target)) { SaveItems(false); cout << "物品已删除!" << endl; } else { cout << "删除失败!" << endl; } } else { cout << "操作取消" << endl; } wait(1);
}
void AddRecipeToItem() {
clear();
auto ids = itemDB.getSortedIDs();
if (ids.empty()) { cout << "请先创建物品!" << endl; pause(); return; } cout << "可用物品:\n"; for (const auto& id : ids) { cout << " - " << id << "\n"; } string target; cout << "\n输入要添加配方的物品ID: "; cin >> target; Item* item = itemDB.getItem(target); if (!item) { cout << "物品不存在!" << endl; pause(); return; } // 选择合成方块 cout << "选择合成方块 (输入ID,留空使用默认): "; string blockID; cin.ignore(); getline(cin, blockID); CraftingBlock* block = nullptr; if (!blockID.empty()) { block = itemDB.getCraftingBlock(blockID); if (!block) { cout << "方块不存在,使用默认合成" << endl; wait(1); } } // 创建新合成表 ItemTable newTable; if (block) { newTable.setBlockID(block->getID()); cout << "使用方块: " << block->getName() << endl; } // 设置输入网格(支持"0"表示空槽位) cout << "\n输入3x3合成网格 (输入'0'表示空槽,格式: 物品ID 数量)\n"; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { string id; short cnt; cout << "位置 [" << x << "," << y << "]: "; cin >> id; // 处理"0"输入 if (id == "0") { newTable.setItem(x, y, "", 0); cin.ignore(numeric_limits<streamsize>::max(), '\n'); continue; } // 处理正常输入 cin >> cnt; if (!itemDB.contains(id)) { cout << "物品不存在,跳过此位置!" << endl; newTable.setItem(x, y, "", 0); continue; } newTable.setItem(x, y, id, cnt); } } // 设置每次合成产出数量 short craftCount; cout << "每次合成产出数量: "; cin >> craftCount; newTable.setCraftCount(craftCount > 0 ? craftCount : 1); // 设置输出槽数量 int outputSlots = block ? block->getOutputSlots() : 1; cout << "\n设置输出槽 (共 " << outputSlots << " 个槽位)\n"; for (int i = 0; i < outputSlots; i++) { string outID; short outCnt; cout << "输出槽 #" << (i+1) << " (物品ID 数量,留空跳过): "; cin >> outID; if (outID.empty() || outID == "0") { newTable.setOutputSlot(i, "", 0); cin.ignore(numeric_limits<streamsize>::max(), '\n'); continue; } cin >> outCnt; if (!itemDB.contains(outID)) { cout << "物品不存在,跳过此输出槽!" << endl; newTable.setOutputSlot(i, "", 0); continue; } newTable.setOutputSlot(i, outID, outCnt); } // 添加到物品或方块 if (block) { block->addRecipe(newTable); } else { item->addTable(newTable); } SaveItems(false); cout << "合成表添加成功!" << endl; wait(1);
}
void ViewRecipes() {
clear();
auto ids = itemDB.getSortedIDs();
if (ids.empty()) { cout << "没有可查看的物品!" << endl; pause(); return; } cout << "可用物品:\n"; for (size_t i = 0; i < ids.size(); i++) { cout << setw(2) << i+1 << ". " << ids[i] << "\n"; } int choice; cout << "\n选择物品 (0返回): "; cin >> choice; if (choice <= 0 || choice > static_cast<int>(ids.size())) return; string target = ids[choice-1]; Item* item = itemDB.getItem(target); if (!item) return; clear(); cout << "物品: " << target << "\n"; cout << "最大堆叠: " << item->getMaxStack() << "\n\n"; if (item->getTables().empty()) { cout << "此物品没有合成配方!" << endl; pause(); return; } cout << "合成配方:\n"; for (size_t i = 0; i < item->getTables().size(); i++) { const auto& table = item->getTables()[i]; cout << "配方 #" << i+1 << ": " << table.getPathDescription() << "\n"; } cout << "\n输入配方编号查看详情 (0返回): "; cin >> choice; if (choice <= 0 || choice > static_cast<int>(item->getTables().size())) return; const auto& table = item->getTables()[choice-1]; clear(); cout << "配方详情: " << table.getPathDescription() << "\n"; // 显示输入网格 cout << "\n输入网格:\n"; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& slot = table.getItem(x, y); cout << "[" << (slot.first.empty() ? " " : slot.first.substr(0,2)) << (slot.second > 0 ? to_string(slot.second) : " ") << "] "; } cout << "\n"; } // 显示输出槽 cout << "\n输出槽:\n"; for (size_t i = 0; i < table.getAllOutputs().size(); i++) { const auto& slot = table.getOutputSlot(i); if (!slot.first.empty() && slot.second > 0) { cout << "槽位 #" << i+1 << ": " << slot.first << " x" << slot.second << "\n"; } } pause();
}
void AddCraftingBlock() {
clear();
string id, name;
int inSlots, outSlots;
cout << "方块ID: "; cin >> id; cout << "方块名称: "; cin.ignore(); getline(cin, name); cout << "输入槽数量: "; cin >> inSlots; cout << "输出槽数量: "; cin >> outSlots; if (inSlots <= 0 || outSlots <= 0) { cout << "槽位数量必须大于0!" << endl; pause(); return; } if (itemDB.getCraftingBlock(id)) { cout << "方块ID已存在!" << endl; pause(); return; } itemDB.addCraftingBlock(CraftingBlock(id, name, inSlots, outSlots)); SaveItems(false); cout << "合成方块添加成功!" << endl; wait(1);
}
void DeleteCraftingBlock() {
clear();
const auto& blocks = itemDB.getAllCraftingBlocks();
if (blocks.empty()) { cout << "没有可用的合成方块!" << endl; pause(); return; } cout << "可用合成方块:\n"; for (const auto& [id, block] : blocks) { cout << " - " << id << " (" << block.getName() << ")\n"; } string target; cout << "\n输入要删除的方块ID: "; cin >> target; if (!itemDB.getCraftingBlock(target)) { cout << "方块不存在!" << endl; pause(); return; } cout << "确认删除? (Y/N): "; char confirm; cin >> confirm; if (toupper(confirm) == 'Y') { if (itemDB.removeCraftingBlock(target)) { SaveItems(false); cout << "方块已删除!" << endl; } else { cout << "删除失败!" << endl; } } else { cout << "操作取消" << endl; } wait(1);
}
void CalculateMaterials() {
clear();
auto ids = itemDB.getSortedIDs();
if (ids.empty()) { cout << "没有可计算的物品!" << endl; pause(); return; } cout << "可用物品:\n"; for (size_t i = 0; i < ids.size(); i++) { cout << setw(2) << i+1 << ". " << ids[i] << "\n"; } int choice; cout << "\n选择物品 (0返回): "; cin >> choice; if (choice <= 0 || choice > static_cast<int>(ids.size())) return; string target = ids[choice-1]; long long count; cout << "需要数量: "; cin >> count; // 选择计算模式 cout << "\n选择计算模式:\n" << "1. 最短路径 (默认)\n" << "2. 最长路径\n" << "3. 精确匹配\n" << "选择: "; int modeChoice; cin >> modeChoice; ItemTable::PathMode pathMode = ItemTable::SHORTEST; ItemTable::BatchMode batchMode = ItemTable::EXACT_BATCH; if (modeChoice == 2) pathMode = ItemTable::LONGEST; else if (modeChoice == 3) pathMode = ItemTable::EXACT; // 计算材料 MaterialMap materials = calculator.calculateMaterials(target, count, pathMode, batchMode); // 显示结果 clear(); cout << "合成 " << count << " 个 " << target << " 需要:\n"; cout << "================================\n"; long long totalItems = 0; for (const auto& [id, cnt] : materials) { cout << setw(15) << left << id << ": " << cnt << "\n"; totalItems += cnt; } cout << "================================\n"; cout << "总计材料: " << totalItems << " 个\n"; pause();
}
void StepByStepCraftingUI() {
clear();
auto ids = itemDB.getSortedIDs();
if (ids.empty()) { cout << "没有可合成的物品!" << endl; pause(); return; } cout << "可用物品:\n"; for (size_t i = 0; i < ids.size(); i++) { cout << setw(2) << i+1 << ". " << ids[i] << "\n"; } int choice; cout << "\n选择物品 (0返回): "; cin >> choice; if (choice <= 0 || choice > static_cast<int>(ids.size())) return; string target = ids[choice-1]; long long count; cout << "需要数量: "; cin >> count; // 启动逐步合成 StepByStepCrafting stepper(itemDB, calculator, target, count); stepper.start();
}
void SetSavePath() {
clear();
cout << "当前保存路径: " << savePath << “\n\n”;
cout << "输入新路径: ";
string newPath;
cin.ignore();
getline(cin, newPath);
if (!newPath.empty()) { savePath = fs::path(newPath); cout << "路径已更新!" << endl; wait(1); }
}
// ====================== 主程序 ======================
int main() {
LoadItems();
while (true) { clear(); cout << "===== 合成系统 =====" << endl; cout << "1. 创建物品" << endl; cout << "2. 删除物品" << endl; cout << "3. 添加合成表" << endl; cout << "4. 查看物品配方" << endl; cout << "5. 材料计算" << endl; cout << "6. 逐步合成" << endl; cout << "7. 添加合成方块" << endl; cout << "8. 删除合成方块" << endl; cout << "9. 设置保存路径" << endl; cout << "10. 保存数据" << endl; cout << "11. 退出" << endl; cout << "=====================" << endl; cout << "物品数: " << itemDB.size() << " | 方块数: " << itemDB.getAllCraftingBlocks().size() << " | 路径: " << savePath.filename() << endl; cout << "选项: "; int choice; cin >> choice; switch (choice) { case 1: CreateItem(); break; case 2: DeleteItem(); break; case 3: AddRecipeToItem(); break; case 4: ViewRecipes(); break; case 5: CalculateMaterials(); break; case 6: StepByStepCraftingUI(); break; case 7: AddCraftingBlock(); break; case 8: DeleteCraftingBlock(); break; case 9: SetSavePath(); break; case 10: SaveItems(); pause(); break; case 11: SaveItems(false); cout << "再见!" << endl; return 0; default: cout << "无效选项!" << endl; wait(1); } }
}
最新发布