JS中 [] == ![]结果为true,而 {} == !{}却为false, 追根刨底

本文深入探讨了JavaScript中相等性和全等性的概念,详细解析了在不同数据类型间进行比较时的转换规则,尤其针对引用类型进行了详细的解释,并通过具体示例[]==![]和{}
console.log( [] == ![] )  // true
console.log( {} == !{} )  // false

在比较字符串、数值和布尔值的相等性时,问题还比较简单。但在涉及到对象的比较时,问题就变得复杂了。最早的ECMAScript中的相等和不相等操作符会在执行比较之前,先将对象转换成相似的类型。后来,有人提出了这种转换到底是否合理的质疑。最后,ECMAScript的解决方案就是提供两组操作符:

相等和不相等——先转换再比较      (==)

全等和不全等——仅比较而不转换  (===)

ECMAScript中相等操作符由两个等于号(==)表示,如果两个操作数相等,则返回true,这种操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性

在转换不同的数据类型时,对于相等和不相等操作符:在JS高程中一书中给出如下的基本转换规则

①、如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false转换为0,而true转换为1;

②、如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值

③、如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较

这两个操作符在进行比较时则要遵循下列规则。

①、null 和undefined 是相等的

②、要比较相等性之前,不能将null 和 undefined 转换成其他任何值

③、如果有一个操作数是NaN,则相等操作符返回 false ,而不相等操作符返回 true。重要提示:即使两个操作数都是NaN,相等操作符也返回 false了;因为按照规则, NaN 不等于 NaN

④、如果两个操作数都是对象,则比较它们是不是同一个对象,如果两个操作数都指向同一个对象,则相等操作符返回 true;否则, 返回false

这里说一下题外话:[] 和 {} 都是属于引用类型,引用类型是存放在堆内存中的,而在栈内存中会有一个或者多个地址来指向这个堆内存相对应的数据。所以在使用 == 操作符的时候,对于引用类型的数据,比较的是地址,而不是真实的值。

现在来探讨 [] == ! [] 的结果为什么会是true

①、根据运算符优先级 ,! 的优先级是大于 == 的,所以先会执行 ![]

!可将变量转换成boolean类型,null、undefined、NaN以及空字符串('')取反都为true,其余都为false。

所以 ! [] 运算后的结果就是 false

也就是 [] == ! [] 相当于 [] == false

②、根据上面提到的规则(如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false转换为0,而true转换为1),则需要把 false 转成 0

也就是 [] == ! [] 相当于 [] == false 相当于 [] == 0

③、根据上面提到的规则(如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较,如果对象没有valueOf()方法,则调用 toString()

而对于空数组,[].toString() ->  '' (返回的是空字符串)

也就是  [] == 0 相当于 '' == 0

④、根据上面提到的规则(如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值

Number('') -> 返回的是 0

相当于 0 == 0 自然就返回 true了

总结一下:

[] == ! []   ->   [] == false  ->  [] == 0  ->   '' == 0   ->  0 == 0   ->  true

 

那么对于 {} == !{} 也是同理的

关键在于  {}.toString() ->  NaN(返回的是NaN)

根据上面的规则(如果有一个操作数是NaN,则相等操作符返回 false

总结一下:

{} == ! {}   ->   {} == false  ->  {} == 0  ->   NaN == 0    ->  false

在修复代码编译错误的基础上增加一条功能:在查看合成表的时候可以按键删除对应的合成表,并且会给与问询确认。 代码: #include <iostream> #include <fstream> #include <map> #include <vector> #include <set> #include <string> #include <windows.h> #include <filesystem> #include <shlobj.h> #include <iomanip> #include <algorithm> #include <queue> #include <cctype> #include <cmath> using namespace std; namespace fs = filesystem; // 类型别名简化 using CraftGrid = pair<string, short>[3][3]; using MaterialMap = map<string, long long>; // 计算模式枚举 enum CalculationMode { EXACT, // 精确计算 BATCHED // 批次计算(向上取整) }; // 全局配置 const string CONFIG_FILE = "save_path.cfg"; fs::path savePath; // 前置声明 class ItemTable; class Item; class ItemCollection; void LoadSavePath(), SaveSavePath(); void ShowSaveInfo(), SetSavePath(), CreateItem(), CalculateMaterials(); void SaveItems(bool); void LoadItems(), clear(), pause(); bool CreateCraftingTable(Item&); void ShowItemList(), ShowItemRecipe(); void AddRecipeToItem(), TraceMaterials(); void CalcMaterialsWithMerge(const string&, long long, MaterialMap&, set<string>&, CalculationMode); // 获取程序所在目录 fs::path GetProgramDirectory() { wchar_t buffer[MAX_PATH] = {0}; GetModuleFileNameW(nullptr, buffer, MAX_PATH); fs::path exePath(buffer); return exePath.parent_path(); } // 获取用户文档目录 fs::path GetDocumentsPath() { wchar_t path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) { return path; } return GetProgramDirectory(); } class ItemTable { CraftGrid grid; short count; public: ItemTable() : count(0) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { grid[i][j] = make_pair("", 0); } } } void setItem(short x, short y, const string& id, short c) { grid[x][y] = make_pair(id, c); } void setCount(short c) { count = c; } short getCount() const { return count; } pair<string, short> getItem(short x, short y) const { return grid[x][y]; } // 计算合成表的分量值(值越小表示越基础) double calculateWeight() const { double weight = 0; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { if (grid[x][y].second > 0 && !grid[x][y].first.empty()) { weight += 1.0 / grid[x][y].second; } } } return weight; } }; class Item { string id; short maxStack; vector<ItemTable> tables; public: Item(string id = "", short stack = 0) : id(id), maxStack(stack) {} void addTable(const ItemTable& t) { tables.push_back(t); } string getID() const { return id; } short getStack() const { return maxStack; } const vector<ItemTable>& getTables() const { return tables; } bool hasRecipe() const { return !tables.empty(); } // 获取最基础的合成表(分量值最小的) const ItemTable* getMostBasicTable() const { if (tables.empty()) return nullptr; const ItemTable* bestTable = &tables[0]; double minWeight = bestTable->calculateWeight(); for (size_t i = 1; i < tables.size(); i++) { double weight = tables[i].calculateWeight(); if (weight < minWeight) { minWeight = weight; bestTable = &tables[i]; } } return bestTable; } }; class ItemCollection { map<string, Item> items; public: void add(const Item& it) { if (!contains(it.getID())) items[it.getID()] = it; } Item& operator[](const string& id) { if (items.find(id) == items.end()) { items[id] = Item(id, 64); } return items[id]; } bool contains(const string& id) const { return items.find(id) != items.end(); } size_t size() const { return items.size(); } void clear() { items.clear(); } const map<string, Item>& getAll() const { return items; } // 获取排序后的物品ID列表 vector<string> getSortedIDs() const { vector<string> ids; for (const auto& pair : items) { ids.push_back(pair.first); } sort(ids.begin(), ids.end()); return ids; } } itemDB; // 辅助函数实现 void clear() { system("cls"); } void pause() { system("pause"); } void wait(double sec) { Sleep(static_cast<DWORD>(sec * 1000)); } // 显示网格的辅助函数(增强空槽位处理) void DisplayGrid(const CraftGrid& grid) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { const auto& [id, count] = grid[i][j]; if (count > 0 && !id.empty()) { cout << setw(15) << left << (id + " x" + to_string(count)); } else { cout << setw(15) << left << "[空]"; } } cout << endl; } } void LoadSavePath() { ifstream in(CONFIG_FILE); if (in) { string pathStr; getline(in, pathStr); savePath = fs::u8path(pathStr); } if (savePath.empty()) { savePath = GetProgramDirectory() / "items.dat"; } } void SaveSavePath() { ofstream out(CONFIG_FILE); if (out) out << savePath.u8string(); } void ShowSaveInfo() { clear(); cout << "当前路径: " << savePath.u8string() << "\n物品总数: " << itemDB.size() << endl; pause(); } void SetSavePath() { clear(); cout << "当前路径: " << savePath.u8string() << "\n新路径: "; cin.ignore(); string newPathStr; getline(cin, newPathStr); fs::path newPath = fs::u8path(newPathStr); if (savePath != newPath) { if (fs::exists(savePath)) { cout << "正在移动文件: " << savePath.u8string() << " -> " << newPath.u8string() << endl; try { fs::rename(savePath, newPath); } catch (fs::filesystem_error& e) { cerr << "移动文件失败: " << e.what() << endl; } } savePath = newPath; SaveSavePath(); } cout << "路径已更新!" << endl; wait(1); } // 文件I/O优化(增强空槽位处理) void SaveItems(bool showMsg) { if (showMsg) { clear(); cout << "保存数据到: " << savePath.u8string() << "..." << endl; } try { if (!savePath.parent_path().empty() && !fs::exists(savePath.parent_path())) { fs::create_directories(savePath.parent_path()); } } catch (fs::filesystem_error& e) { if (showMsg) { cout << "创建目录失败: " << e.what() << endl; pause(); } return; } ofstream out(savePath, ios::binary); if (out) { size_t count = itemDB.size(); out.write(reinterpret_cast<char*>(&count), sizeof(count)); for (const auto& [id, item] : itemDB.getAll()) { size_t len = id.size(); out.write(reinterpret_cast<char*>(&len), sizeof(len)); out.write(id.c_str(), len); short stack = item.getStack(); out.write(reinterpret_cast<const char*>(&stack), sizeof(stack)); size_t tableCount = item.getTables().size(); out.write(reinterpret_cast<char*>(&tableCount), sizeof(tableCount)); for (const auto& table : item.getTables()) { short craftCnt = table.getCount(); out.write(reinterpret_cast<const char*>(&craftCnt), sizeof(craftCnt)); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { auto [ing, cnt] = table.getItem(x, y); // 跳过空槽位 if (cnt <= 0 || ing.empty()) continue; size_t ingLen = ing.size(); out.write(reinterpret_cast<char*>(&ingLen), sizeof(ingLen)); out.write(ing.c_str(), ingLen); out.write(reinterpret_cast<const char*>(&cnt), sizeof(cnt)); } } } } if (showMsg) { cout << "保存成功! 物品数: " << count << endl; pause(); } } else if (showMsg) { cout << "保存失败! 错误: " << strerror(errno) << endl; pause(); } } void LoadItems() { clear(); cout << "加载数据: " << savePath.u8string() << "..." << endl; itemDB.clear(); ifstream in(savePath, ios::binary); if (in) { try { size_t itemCount; in.read(reinterpret_cast<char*>(&itemCount), sizeof(itemCount)); for (size_t i = 0; i < itemCount; i++) { size_t len; in.read(reinterpret_cast<char*>(&len), sizeof(len)); string id(len, ' '); in.read(&id[0], len); short stack; in.read(reinterpret_cast<char*>(&stack), sizeof(stack)); Item item(id, stack); size_t tableCount; in.read(reinterpret_cast<char*>(&tableCount), sizeof(tableCount)); for (size_t j = 0; j < tableCount; j++) { short craftCnt; in.read(reinterpret_cast<char*>(&craftCnt), sizeof(craftCnt)); ItemTable table; table.setCount(craftCnt); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { size_t ingLen; in.read(reinterpret_cast<char*>(&ingLen), sizeof(ingLen)); string ing(ingLen, ' '); if (ingLen > 0) { in.read(&ing[0], ingLen); } short cnt; in.read(reinterpret_cast<char*>(&cnt), sizeof(cnt)); // 处理空槽位 if (ingLen == 0 || ing.empty()) { table.setItem(x, y, "", 0); } else { table.setItem(x, y, ing, cnt); } } } item.addTable(table); } itemDB.add(item); } cout << "加载成功! 物品数: " << itemDB.size() << endl; } catch (...) { cout << "文件损坏!" << endl; } } else { cout << "加载失败! 错误: " << strerror(errno) << endl; } pause(); } // 合成表创建优化(增强空槽位处理) bool CreateCraftingTable(Item& item) { short tableCount; cout << "合成表数量: "; cin >> tableCount; short success = 0; for (short i = 0; i < tableCount; i++) { clear(); cout << "合成表 #" << i+1 << " (输入3行,每行3组'名称 数量',空槽位输入0):\n"; CraftGrid grid; vector<string> missing; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { cin >> grid[x][y].first >> grid[x][y].second; // 处理空槽位:如果数量为0,清空材料名称 if (grid[x][y].second == 0) { grid[x][y].first = ""; } // 只检查数量大于0且物品不存在的情况 if (grid[x][y].second > 0 && !itemDB.contains(grid[x][y].first)) { missing.push_back(grid[x][y].first); } } } if (!missing.empty()) { cout << "缺失物品: "; for (size_t j = 0; j < missing.size(); j++) { cout << missing[j]; if (j < missing.size() - 1) cout << ", "; } cout << "\n重试? (Y/N): "; char ans; cin >> ans; if (ans == 'Y' || ans == 'y') i--; continue; } short outputCnt; cout << "产出数量: "; cin >> outputCnt; ItemTable table; table.setCount(outputCnt); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { table.setItem(x, y, grid[x][y].first, grid[x][y].second); } } item.addTable(table); success++; cout << "添加成功!" << endl; wait(1); } return success > 0; } void CreateItem() { clear(); string id; short stack; char hasTable; cout << "物品名称: "; cin >> id; cout << "最大堆叠: "; cin >> stack; cout << "有合成表? (Y/N): "; cin >> hasTable; Item item(id, stack); bool success = true; if (hasTable == 'Y' || hasTable == 'y') { success = CreateCraftingTable(item); } if (success) { itemDB.add(item); SaveItems(false); cout << "物品创建成功! 已保存" << endl; } else { cout << "创建失败!" << endl; } wait(1); } // 新增:支持材料需求合并的计算函数 void CalcMaterialsWithMerge(const string& id, long long count, MaterialMap& globalMats, set<string>& globalVisited, CalculationMode mode) { // 检查循环依赖 if (globalVisited.find(id) != globalVisited.end()) { cerr << "循环依赖: " << id << endl; return; } globalVisited.insert(id); if (!itemDB.contains(id)) { cerr << "未知物品: " << id << endl; globalVisited.erase(id); return; } const Item& item = itemDB.getAll().at(id); if (item.getTables().empty()) { globalMats[id] += count; globalVisited.erase(id); return; } // 使用最基础的合成表(分量最小的) const ItemTable* tablePtr = item.getMostBasicTable(); if (!tablePtr) { globalMats[id] += count; globalVisited.erase(id); return; } const ItemTable& table = *tablePtr; short craftCnt = table.getCount() > 0 ? table.getCount() : 1; // 根据模式选择计算方法 long long batches = 0; if (mode == EXACT) { double exact = static_cast<double>(count) / craftCnt; batches = static_cast<long long>(ceil(exact)); } else { batches = (count + craftCnt - 1) / craftCnt; } // 临时存储当前材料的子需求 MaterialMap localMats; set<string> localVisited; // 先计算所有子材料需求(不立即加入全局映射) for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { auto [ing, cnt] = table.getItem(x, y); if (cnt <= 0 || ing.empty()) continue; // 计算子材料需求但不立即加入全局映射 CalcMaterialsWithMerge(ing, batches * cnt, localMats, localVisited, mode); } } // 合并子材料需求到全局映射 for (const auto& [matId, amount] : localMats) { globalMats[matId] += amount; } globalVisited.erase(id); } void CalculateMaterials() { clear(); string target; long long count; cout << "目标物品: "; cin >> target; cout << "合成数量: "; cin >> count; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } // 使用全局材料映射进行合并计算 MaterialMap globalMaterials; set<string> globalVisited; cout << "计算模式: (E)精确计算/(B)批次计算 [默认:B]: "; char modeChoice; cin >> modeChoice; CalculationMode mode = (toupper(modeChoice) == 'E') ? EXACT : BATCHED; CalcMaterialsWithMerge(target, count, globalMaterials, globalVisited, mode); clear(); cout << "合成 " << count << " 个 " << target << " 需要:\n"; cout << "================================\n"; for (const auto& [id, amt] : globalMaterials) { short stack = itemDB.contains(id) ? itemDB[id].getStack() : 64; if (stack <= 0) stack = 64; long long groups = (amt + stack - 1) / stack; cout << id << ": " << amt << " (" << groups << "组)\n"; } cout << "================================\n"; pause(); } // 查看物品列表 void ShowItemList() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } vector<string> itemIDs = itemDB.getSortedIDs(); const int nameWidth = 25; const int stackWidth = 10; const int recipeWidth = 10; cout << setw(nameWidth) << left << "物品名称" << setw(stackWidth) << left << "最大堆叠" << setw(recipeWidth) << left << " 有配方" << endl; cout << string(nameWidth + stackWidth + recipeWidth, '-') << endl; for (const auto& id : itemIDs) { const Item& item = itemDB.getAll().at(id); cout << setw(nameWidth) << left << id << setw(stackWidth) << left << item.getStack() << setw(recipeWidth) << left << (item.hasRecipe() ? "是" : "否") << endl; } cout << "\n共 " << itemDB.size() << " 个物品" << endl; pause(); } // 查看物品配方(增强版:支持翻页) void ShowItemRecipe() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "查看配方的物品: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } const Item& item = itemDB.getAll().at(target); if (!item.hasRecipe()) { cout << "该物品没有合成配方!" << endl; pause(); return; } const vector<ItemTable>& tables = item.getTables(); size_t currentIndex = 0; const int totalTables = tables.size(); while (true) { clear(); cout << "配方 #" << currentIndex+1 << "/" << totalTables << " - 产出: " << target << " x" << tables[currentIndex].getCount() << "\n\n"; CraftGrid grid; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { grid[x][y] = tables[currentIndex].getItem(x, y); } } DisplayGrid(grid); cout << "\n所需材料:\n"; map<string, short> materials; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& [id, cnt] = grid[x][y]; if (cnt > 0 && !id.empty()) materials[id] += cnt; } } for (const auto& [id, cnt] : materials) { cout << " - " << id << " x" << cnt << endl; } cout << "\n操作: (N)下一页, (P)上一页, (Q)退出"; if (totalTables > 1) { cout << ", (S)跳转到: "; } else { cout << ": "; } char choice; cin >> choice; choice = toupper(choice); switch (choice) { case 'N': if (currentIndex < totalTables - 1) currentIndex++; break; case 'P': if (currentIndex > 0) currentIndex--; break; case 'S': if (totalTables > 1) { int index; cout << "输入配方编号(1-" << totalTables << "): "; cin >> index; if (index >= 1 && index <= static_cast<int>(totalTables)) { currentIndex = index - 1; } } break; case 'Q': return; default: cout << "无效选项!" << endl; wait(1); } } } // 新增功能:为已有物品添加合成表(增强空槽位处理) void AddRecipeToItem() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "为哪个物品添加合成表: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } Item& item = itemDB[target]; // 显示现有合成表数量 cout << "当前已有 " << item.getTables().size() << " 个合成表" << endl; // 创建新合成表 ItemTable newTable; CraftGrid grid; vector<string> missing; cout << "输入新合成表 (3行,每行3组'名称 数量',空槽位输入0):\n"; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { cin >> grid[x][y].first >> grid[x][y].second; // 处理空槽位 if (grid[x][y].second == 0) { grid[x][y].first = ""; } // 只检查有效材料 if (grid[x][y].second > 0 && !itemDB.contains(grid[x][y].first)) { missing.push_back(grid[x][y].first); } } } if (!missing.empty()) { cout << "缺失物品: "; for (size_t j = 0; j < missing.size(); j++) { cout << missing[j]; if (j < missing.size() - 1) cout << ", "; } cout << "\n添加失败!" << endl; pause(); return; } short outputCnt; cout << "产出数量: "; cin >> outputCnt; newTable.setCount(outputCnt); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { newTable.setItem(x, y, grid[x][y].first, grid[x][y].second); } } item.addTable(newTable); SaveItems(false); cout << "成功为 " << target << " 添加新合成表!" << endl; wait(1); } // 追根求源的材料计算(使用合并计算机制) void TraceMaterials() { clear(); string target; long long count; cout << "目标物品: "; cin >> target; cout << "合成数量: "; cin >> count; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } // 使用合并计算机制 MaterialMap globalMaterials; set<string> globalVisited; // 使用精确计算模式 CalculationMode mode = EXACT; CalcMaterialsWithMerge(target, count, globalMaterials, globalVisited, mode); // 显示结果 clear(); cout << "追根求源 - 合成 " << count << " 个 " << target << " 需要:\n"; cout << "================================\n"; for (const auto& [id, amt] : globalMaterials) { short stack = itemDB.contains(id) ? itemDB[id].getStack() : 64; if (stack <= 0) stack = 64; long long groups = (amt + stack - 1) / stack; cout << id << ": " << amt << " (" << groups << "组)\n"; } cout << "================================\n"; pause(); } int main() { LoadSavePath(); clear(); cout << "启动中...\n路径: " << savePath.u8string() << endl; wait(1); LoadItems(); while (true) { clear(); cout << "===== 合成系统 =====\n" << "1. 创建物品\n" << "2. 材料计算\n" << "3. 追根求源\n" << "4. 手动保存\n" << "5. 设置路径\n" << "6. 保存信息\n" << "7. 查看物品列表\n" << "8. 查看物品配方\n" << "9. 添加合成表\n" << "10. 退出\n" << "路径: " << savePath.u8string() << "\n物品: " << itemDB.size() << "\n选项: "; int choice; cin >> choice; switch (choice) { case 1: CreateItem(); break; case 2: CalculateMaterials(); break; case 3: TraceMaterials(); break; case 4: SaveItems(true); break; case 5: SetSavePath(); break; case 6: ShowSaveInfo(); break; case 7: ShowItemList(); break; case 8: ShowItemRecipe(); break; case 9: AddRecipeToItem(); break; case 10: clear(); cout << "退出中...\n自动保存..."; SaveItems(false); wait(1); return 0; default: cout << "无效选项!" << endl; wait(1); } } }
08-05
第二部分(请将2部分代码整合后再优化): // 查看物品配方 void ShowItemRecipe() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "查看配方的物品: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } Item& item = itemDB[target]; if (!item.hasRecipe()) { cout << "该物品没有合成配方!" << endl; pause(); return; } vector<ItemTable>& tables = const_cast<vector<ItemTable>&>(item.getTables()); size_t currentIndex = 0; const int totalTables = tables.size(); while (true) { clear(); cout << "配方 #" << currentIndex+1 << "/" << totalTables << " - 产出: " << target << " x" << tables[currentIndex].getCount() << "\n\n"; CraftGrid grid; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { grid[x][y] = tables[currentIndex].getItem(x, y); } } DisplayGrid(grid); cout << "\n所需材料:\n"; map<string, short> materials; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& [id, cnt] = grid[x][y]; if (cnt > 0 && !id.empty()) materials[id] += cnt; } } for (const auto& [id, cnt] : materials) { cout << " - " << id << " x" << cnt << endl; } cout << "\n操作: (N)下一页, (P)上一页, (D)删除, (Q)退出"; if (totalTables > 1) { cout << ", (S)跳转到"; } cout << ": "; char choice; cin >> choice; choice = toupper(choice); switch (choice) { case 'N': if ((int)currentIndex < totalTables - 1) currentIndex++; break; case 'P': if (currentIndex > 0) currentIndex--; break; case 'S': if (totalTables > 1) { int index; cout << "输入配方编号(1-" << totalTables << "): "; cin >> index; if (index >= 1 && index <= static_cast<int>(totalTables)) { currentIndex = index - 1; } } break; case 'D': cout << "确认删除当前合成表? (Y/N): "; char confirm; cin >> confirm; if (toupper(confirm) == 'Y') { tables.erase(tables.begin() + currentIndex); SaveItems(false); cout << "合成表已删除!" << endl; wait(1); if (tables.empty()) { cout << "该物品已无合成表,返回主菜单" << endl; wait(1); return; } if (currentIndex >= tables.size()) { currentIndex = tables.size() - 1; } } break; case 'Q': return; default: cout << "无效选项!" << endl; wait(1); } } } // 为已有物品添加合成表 void AddRecipeToItem() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "为哪个物品添加合成表: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } Item& item = itemDB[target]; // 显示现有合成表数量 cout << "当前已有 " << item.getTables().size() << " 个合成表" << endl; // 创建新合成表 ItemTable newTable; CraftGrid grid; vector<string> missing; cout << "输入新合成表 (3行,每行3组'名称 数量',空槽位输入0):\n"; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { cin >> grid[x][y].first >> grid[x][y].second; // 处理空槽位 if (grid[x][y].second == 0) { grid[x][y].first = ""; } // 只检查有效材料 if (grid[x][y].second > 0 && !itemDB.contains(grid[x][y].first)) { missing.push_back(grid[x][y].first); } } } if (!missing.empty()) { cout << "缺失物品: "; for (size_t j = 0; j < missing.size(); j++) { cout << missing[j]; if (j < missing.size() - 1) cout << ", "; } cout << "\n添加失败!" << endl; pause(); return; } short outputCnt; cout << "产出数量: "; cin >> outputCnt; newTable.setCount(outputCnt); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { newTable.setItem(x, y, grid[x][y].first, grid[x][y].second); } } item.addTable(newTable); SaveItems(false); cout << "成功为 " << target << " 添加新合成表!" << endl; wait(1); } // 追根求源的材料计算(支持多条最短路径选择) void TraceMaterials() { clear(); string target; long long count; cout << "目标物品: "; cin >> target; cout << "合成数量: "; cin >> count; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } // 使用合并计算机制 MaterialMap globalMaterials; set<string> globalVisited; map<string, const ItemTable*> choices; // 存储用户选择的合成表 // 使用精确计算模式 CalculationMode mode = EXACT; CalcMaterialsWithMerge(target, count, globalMaterials, globalVisited, mode, choices); // 显示结果 clear(); cout << "追根求源 - 合成 " << count << " 个 " << target << " 需要:\n"; cout << "================================\n"; for (const auto& [id, amt] : globalMaterials) { short stack = itemDB.contains(id) ? itemDB[id].getStack() : 64; if (stack <= 0) stack = 64; long long groups = (amt + stack - 1) / stack; cout << id << ": " << amt << " (" << groups << "组)\n"; } cout << "================================\n"; pause(); } // 删除方块功能(移除未使用的hasRecipes变量) void DeleteItem() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "输入要删除的物品名称: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } // 获取目标物品信息 const Item& item = itemDB[target]; int recipeCount = item.getTables().size(); // 显示警告信息 cout << "警告: 删除物品 " << target << " 将永久移除以下内容:" << "\n- 物品基本信息 (堆叠大小: " << item.getStack() << ")" << "\n- " << recipeCount << " 个合成表"; // 检查是否有其他物品依赖此物品 int referenceCount = 0; for (const auto& [id, otherItem] : itemDB.getAll()) { for (const auto& table : otherItem.getTables()) { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { if (table.getItem(x, y).first == target) { referenceCount++; } } } } } if (referenceCount > 0) { cout << "\n- " << referenceCount << " 个其他物品的合成表引用"; } // 确认删除 cout << "\n\n确认删除? (Y/N): "; char confirm; cin >> confirm; if (toupper(confirm) != 'Y') { cout << "删除操作已取消" << endl; wait(1); return; } // 执行删除 if (itemDB.removeItem(target)) { minPathLengthCache.clear(); // 清除路径缓存 SaveItems(false); cout << "物品 " << target << " 已成功删除!" << endl; } else { cout << "删除失败!" << endl; } pause(); } int main() { LoadSavePath(); clear(); cout << "启动中...\n路径: " << savePath.u8string() << endl; wait(1); LoadItems(); while (true) { clear(); cout << "===== 合成系统 =====\n" << "1. 创建物品\n" << "2. 追根求源\n" << "3. 手动保存\n" << "4. 设置路径\n" << "5. 保存信息\n" << "6. 查看物品列表\n" << "7. 查看物品配方\n" << "8. 添加合成表\n" << "9. 删除物品\n" << "10. 退出\n" << "路径: " << savePath.u8string() << "\n物品: " << itemDB.size() << "\n选项: "; int choice; cin >> choice; switch (choice) { case 1: CreateItem(); break; case 2: TraceMaterials(); break; case 3: SaveItems(true); break; case 4: SetSavePath(); break; case 5: ShowSaveInfo(); break; case 6: ShowItemList(); break; case 7: ShowItemRecipe(); break; case 8: AddRecipeToItem(); break; case 9: DeleteItem(); break; case 10: clear(); cout << "退出中...\n自动保存..."; SaveItems(false); wait(1); return 0; default: cout << "无效选项!" << endl; wait(1); } } }
08-07
delete函数中的hasrecipe变量似乎并没有用到。 修理好报错后的代码: #include <iostream> #include <fstream> #include <map> #include <vector> #include <set> #include <string> #include <windows.h> #include <filesystem> #include <shlobj.h> #include <iomanip> #include <algorithm> #include <queue> #include <cctype> #include <cmath> #include <climits> #include <sstream> #include <functional> using namespace std; namespace fs = filesystem; // 类型别名简化 using CraftGrid = pair<string, short>[3][3]; using MaterialMap = map<string, long long>; // 计算模式枚举 enum CalculationMode { EXACT // 精确计算 }; // 全局配置 const string CONFIG_FILE = "save_path.cfg"; fs::path savePath; map<string, int> minPathLengthCache; // 缓存最小路径长度 // 前置声明 class ItemTable; class Item; class ItemCollection; void LoadSavePath(), SaveSavePath(); void ShowSaveInfo(), SetSavePath(), CreateItem(); void SaveItems(bool); void LoadItems(), clear(), pause(); bool CreateCraftTable(Item&); void ShowItemList(), ShowItemRecipe(); void AddRecipeToItem(), TraceMaterials(); void DeleteItem(); void CalcMaterialsWithMerge(const string&, long long, MaterialMap&, set<string>&, CalculationMode, map<string, const ItemTable*>&); int calculatePathLength(const string& id, set<string>& visited, int currentDepth, int minDepth); vector<const ItemTable*> getShortestPathTables(const string& id); // 获取程序所在目录 fs::path GetProgramDirectory() { wchar_t buffer[MAX_PATH] = {0}; GetModuleFileNameW(nullptr, buffer, MAX_PATH); fs::path exePath(buffer); return exePath.parent_path(); } // 获取用户文档目录 fs::path GetDocumentsPath() { wchar_t path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) { return path; } return GetProgramDirectory(); } class ItemTable { CraftGrid grid; short count; public: ItemTable() : count(0) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { grid[i][j] = make_pair("", 0); } } } void setItem(short x, short y, const string& id, short c) { grid[x][y] = make_pair(id, c); } void setCount(short c) { count = c; } short getCount() const { return count; } pair<string, short> getItem(short x, short y) const { return grid[x][y]; } // 从合成表中移除对指定物品的引用 void removeReferencesTo(const string& id) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (grid[i][j].first == id) { grid[i][j] = make_pair("", 0); } } } } // 获取合成表的路径描述 string getPathDescription() const { stringstream ss; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (grid[i][j].second > 0 && !grid[i][j].first.empty()) { if (!ss.str().empty()) ss << ", "; ss << grid[i][j].first << " x" << grid[i][j].second; } } } return ss.str(); } }; class Item { string id; short maxStack; vector<ItemTable> tables; public: Item(string id = "", short stack = 0) : id(id), maxStack(stack) {} void addTable(const ItemTable& t) { tables.push_back(t); } string getID() const { return id; } short getStack() const { return maxStack; } const vector<ItemTable>& getTables() const { return tables; } bool hasRecipe() const { return !tables.empty(); } // 删除指定索引的合成表 void removeTable(size_t index) { if (index < tables.size()) { tables.erase(tables.begin() + index); } } // 从所有合成表中移除对指定物品的引用 void removeReferencesTo(const string& id) { for (auto& table : tables) { table.removeReferencesTo(id); } } }; class ItemCollection { map<string, Item> items; public: void add(const Item& it) { if (!contains(it.getID())) items[it.getID()] = it; } Item& operator[](const string& id) { if (items.find(id) == items.end()) { items[id] = Item(id, 64); } return items[id]; } bool contains(const string& id) const { return items.find(id) != items.end(); } size_t size() const { return items.size(); } void clear() { items.clear(); } const map<string, Item>& getAll() const { return items; } // 获取排序后的物品ID列表 vector<string> getSortedIDs() const { vector<string> ids; for (const auto& pair : items) { ids.push_back(pair.first); } sort(ids.begin(), ids.end()); return ids; } // 删除物品及其所有引用 bool removeItem(const string& id) { if (!contains(id)) return false; // 首先从所有物品的合成表中移除对该物品的引用 for (auto& [itemID, item] : items) { item.removeReferencesTo(id); } // 然后删除该物品 items.erase(id); return true; } } itemDB; // 计算物品的路径长度(带剪枝优化) int calculatePathLength(const string& id, set<string>& visited, int currentDepth = 0, int minDepth = INT_MAX) { // 剪枝:如果当前深度已超过最小深度,直接返回 if (currentDepth > minDepth) { return INT_MAX; } // 检查循环依赖 if (visited.find(id) != visited.end()) { return 0; } visited.insert(id); if (!itemDB.contains(id)) { visited.erase(id); return 0; } const Item& item = itemDB.getAll().at(id); if (item.getTables().empty()) { visited.erase(id); 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++) { auto [ing, cnt] = table.getItem(x, y); if (cnt > 0 && !ing.empty()) { int depth = calculatePathLength(ing, visited, currentDepth + 1, minDepth); if (depth > maxDepth) { maxDepth = depth; } } } } } visited.erase(id); return maxDepth + 1; } // 获取所有最短路径的合成表 vector<const ItemTable*> getShortestPathTables(const string& id) { if (!itemDB.contains(id)) { return {}; } const Item& item = itemDB.getAll().at(id); if (item.getTables().empty()) { return {}; } // 计算最小路径长度(带缓存) if (minPathLengthCache.find(id) == minPathLengthCache.end()) { set<string> visited; minPathLengthCache[id] = calculatePathLength(id, visited); } int minPathLength = minPathLengthCache[id]; // 收集所有路径长度等于最小值的合成表 vector<const ItemTable*> result; for (const auto& table : item.getTables()) { set<string> visited; int pathLength = 1; // 当前合成表本身算一级 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { auto [ing, cnt] = table.getItem(x, y); if (cnt > 0 && !ing.empty()) { int depth = calculatePathLength(ing, visited); if (depth >= pathLength) { pathLength = depth + 1; } } } } if (pathLength == minPathLength) { result.push_back(&table); } } return result; } // 辅助函数实现 void clear() { system("cls"); } void pause() { system("pause"); } void wait(double sec) { Sleep(static_cast<DWORD>(sec * 1000)); } // 显示网格的辅助函数 void DisplayGrid(const CraftGrid& grid) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { const auto& [id, count] = grid[i][j]; if (count > 0 && !id.empty()) { cout << setw(15) << left << (id + " x" + to_string(count)); } else { cout << setw(15) << left << "[空]"; } } cout << endl; } } void LoadSavePath() { ifstream in(CONFIG_FILE); if (in) { string pathStr; getline(in, pathStr); savePath = fs::u8path(pathStr); } if (savePath.empty()) { savePath = GetProgramDirectory() / "items.dat"; } } void SaveSavePath() { ofstream out(CONFIG_FILE); if (out) out << savePath.u8string(); } void ShowSaveInfo() { clear(); cout << "当前路径: " << savePath.u8string() << "\n物品总数: " << itemDB.size() << endl; pause(); } void SetSavePath() { clear(); cout << "当前路径: " << savePath.u8string() << "\n新路径: "; cin.ignore(); string newPathStr; getline(cin, newPathStr); fs::path newPath = fs::u8path(newPathStr); if (savePath != newPath) { if (fs::exists(savePath)) { cout << "正在移动文件: " << savePath.u8string() << " -> " << newPath.u8string() << endl; try { fs::rename(savePath, newPath); } catch (fs::filesystem_error& e) { cerr << "移动文件失败: " << e.what() << endl; } } savePath = newPath; SaveSavePath(); } cout << "路径已更新!" << endl; wait(1); } // 文件I/O优化(修复编译错误) void SaveItems(bool showMsg) { if (showMsg) { clear(); cout << "保存数据到: " << savePath.u8string() << "..." << endl; } try { if (!savePath.parent_path().empty() && !fs::exists(savePath.parent_path())) { fs::create_directories(savePath.parent_path()); } } catch (fs::filesystem_error& e) { if (showMsg) { cout << "创建目录失败: " << e.what() << endl; pause(); } return; } ofstream out(savePath, ios::binary); if (out) { size_t count = itemDB.size(); out.write(reinterpret_cast<char*>(&count), sizeof(count)); for (const auto& [id, item] : itemDB.getAll()) { size_t len = id.size(); out.write(reinterpret_cast<char*>(&len), sizeof(len)); out.write(id.c_str(), len); short stack = item.getStack(); out.write(reinterpret_cast<const char*>(&stack), sizeof(stack)); // 修复此行 size_t tableCount = item.getTables().size(); out.write(reinterpret_cast<char*>(&tableCount), sizeof(tableCount)); for (const auto& table : item.getTables()) { short craftCnt = table.getCount(); out.write(reinterpret_cast<const char*>(&craftCnt), sizeof(craftCnt)); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { auto [ing, cnt] = table.getItem(x, y); // 跳过空槽位 if (cnt <= 0 || ing.empty()) continue; size_t ingLen = ing.size(); out.write(reinterpret_cast<char*>(&ingLen), sizeof(ingLen)); out.write(ing.c_str(), ingLen); out.write(reinterpret_cast<const char*>(&cnt), sizeof(cnt)); } } } } if (showMsg) { cout << "保存成功! 物品数: " << count << endl; pause(); } } else if (showMsg) { cout << "保存失败! 错误: " << strerror(errno) << endl; pause(); } } void LoadItems() { clear(); cout << "加载数据: " << savePath.u8string() << "..." << endl; itemDB.clear(); minPathLengthCache.clear(); // 清除缓存 ifstream in(savePath, ios::binary); if (in) { try { size_t itemCount; in.read(reinterpret_cast<char*>(&itemCount), sizeof(itemCount)); for (size_t i = 0; i < itemCount; i++) { size_t len; in.read(reinterpret_cast<char*>(&len), sizeof(len)); string id(len, ' '); in.read(&id[0], len); short stack; in.read(reinterpret_cast<char*>(&stack), sizeof(stack)); Item item(id, stack); size_t tableCount; in.read(reinterpret_cast<char*>(&tableCount), sizeof(tableCount)); for (size_t j = 0; j < tableCount; j++) { short craftCnt; in.read(reinterpret_cast<char*>(&craftCnt), sizeof(craftCnt)); ItemTable table; table.setCount(craftCnt); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { size_t ingLen; in.read(reinterpret_cast<char*>(&ingLen), sizeof(ingLen)); string ing(ingLen, ' '); if (ingLen > 0) { in.read(&ing[0], ingLen); } short cnt; in.read(reinterpret_cast<char*>(&cnt), sizeof(cnt)); // 处理空槽位 if (ingLen == 0 || ing.empty()) { table.setItem(x, y, "", 0); } else { table.setItem(x, y, ing, cnt); } } } item.addTable(table); } itemDB.add(item); } cout << "加载成功! 物品数: " << itemDB.size() << endl; } catch (...) { cout << "文件损坏!" << endl; } } else { cout << "加载失败! 错误: " << strerror(errno) << endl; } pause(); } // 合成表创建优化 bool CreateCraftTable(Item& item) { short tableCount; cout << "合成表数量: "; cin >> tableCount; short success = 0; for (short i = 0; i < tableCount; i++) { clear(); cout << "合成表 #" << i+1 << " (输入3行,每行3组'名称 数量',空槽位输入0):\n"; CraftGrid grid; vector<string> missing; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { cin >> grid[x][y].first >> grid[x][y].second; // 处理空槽位:如果数量为0,清空材料名称 if (grid[x][y].second == 0) { grid[x][y].first = ""; } // 只检查数量大于0且物品不存在的情况 if (grid[x][y].second > 0 && !itemDB.contains(grid[x][y].first)) { missing.push_back(grid[x][y].first); } } } if (!missing.empty()) { cout << "缺失物品: "; for (size_t j = 0; j < missing.size(); j++) { cout << missing[j]; if (j < missing.size() - 1) cout << ", "; } cout << "\n重试? (Y/N): "; char ans; cin >> ans; if (ans == 'Y' || ans == 'y') i--; continue; } short outputCnt; cout << "产出数量: "; cin >> outputCnt; ItemTable table; table.setCount(outputCnt); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { table.setItem(x, y, grid[x][y].first, grid[x][y].second); } } item.addTable(table); success++; cout << "添加成功!" << endl; wait(1); } return success > 0; } void CreateItem() { clear(); string id; short stack; char hasTable; cout << "物品名称: "; cin >> id; cout << "最大堆叠: "; cin >> stack; cout << "有合成表? (Y/N): "; cin >> hasTable; Item item(id, stack); bool success = true; if (hasTable == 'Y' || hasTable == 'y') { success = CreateCraftTable(item); } if (success) { itemDB.add(item); SaveItems(false); cout << "物品创建成功! 已保存" << endl; } else { cout << "创建失败!" << endl; } wait(1); } // 支持材料需求合并的计算函数(支持多条最短路径选择) void CalcMaterialsWithMerge(const string& id, long long count, MaterialMap& globalMats, set<string>& globalVisited, CalculationMode mode, map<string, const ItemTable*>& choices) { // 检查循环依赖 if (globalVisited.find(id) != globalVisited.end()) { cerr << "循环依赖: " << id << endl; return; } globalVisited.insert(id); if (!itemDB.contains(id)) { cerr << "未知物品: " << id << endl; globalVisited.erase(id); return; } const Item& item = itemDB.getAll().at(id); if (item.getTables().empty()) { globalMats[id] += count; globalVisited.erase(id); return; } // 检查是否已有选择 const ItemTable* tablePtr = nullptr; if (choices.find(id) != choices.end()) { tablePtr = choices[id]; } else { // 获取所有最短路径的合成表 vector<const ItemTable*> shortestTables = getShortestPathTables(id); if (shortestTables.empty()) { globalMats[id] += count; globalVisited.erase(id); return; } else if (shortestTables.size() == 1) { tablePtr = shortestTables[0]; } else { // 让用户选择合成路径 clear(); cout << "物品 " << id << " 有多个最短路径的合成表:\n"; for (int i = 0; i < (int)shortestTables.size(); i++) { cout << "路径 " << (i+1) << ": " << shortestTables[i]->getPathDescription() << endl; } cout << "\n请选择合成路径 (1-" << shortestTables.size() << "): "; int choice; cin >> choice; if (choice < 1 || choice > (int)shortestTables.size()) { choice = 1; } tablePtr = shortestTables[choice-1]; choices[id] = tablePtr; } } if (!tablePtr) { globalMats[id] += count; globalVisited.erase(id); return; } const ItemTable& table = *tablePtr; short craftCnt = table.getCount() > 0 ? table.getCount() : 1; // 根据模式选择计算方法 long long batches = 0; if (mode == EXACT) { double exact = static_cast<double>(count) / craftCnt; batches = static_cast<long long>(ceil(exact)); } // 临时存储当前材料的子需求 MaterialMap localMats; set<string> localVisited; // 先计算所有子材料需求 for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { auto [ing, cnt] = table.getItem(x, y); if (cnt <= 0 || ing.empty()) continue; CalcMaterialsWithMerge(ing, batches * cnt, localMats, localVisited, mode, choices); } } // 合并子材料需求到全局映射 for (const auto& [matId, amount] : localMats) { globalMats[matId] += amount; } globalVisited.erase(id); } // 查看物品列表 void ShowItemList() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } vector<string> itemIDs = itemDB.getSortedIDs(); const int nameWidth = 25; const int stackWidth = 10; const int recipeWidth = 10; cout << setw(nameWidth) << left << "物品名称" << setw(stackWidth) << left << "最大堆叠" << setw(recipeWidth) << left << " 有配方" << endl; cout << string(nameWidth + stackWidth + recipeWidth, '-') << endl; for (const auto& id : itemIDs) { const Item& item = itemDB.getAll().at(id); cout << setw(nameWidth) << left << id << setw(stackWidth) << left << item.getStack() << setw(recipeWidth) << left << (item.hasRecipe() ? "是" : "否") << endl; } cout << "\n共 " << itemDB.size() << " 个物品" << endl; pause(); } // 查看物品配方 void ShowItemRecipe() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "查看配方的物品: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } Item& item = itemDB[target]; if (!item.hasRecipe()) { cout << "该物品没有合成配方!" << endl; pause(); return; } vector<ItemTable>& tables = const_cast<vector<ItemTable>&>(item.getTables()); size_t currentIndex = 0; const int totalTables = tables.size(); while (true) { clear(); cout << "配方 #" << currentIndex+1 << "/" << totalTables << " - 产出: " << target << " x" << tables[currentIndex].getCount() << "\n\n"; CraftGrid grid; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { grid[x][y] = tables[currentIndex].getItem(x, y); } } DisplayGrid(grid); cout << "\n所需材料:\n"; map<string, short> materials; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { const auto& [id, cnt] = grid[x][y]; if (cnt > 0 && !id.empty()) materials[id] += cnt; } } for (const auto& [id, cnt] : materials) { cout << " - " << id << " x" << cnt << endl; } cout << "\n操作: (N)下一页, (P)上一页, (D)删除, (Q)退出"; if (totalTables > 1) { cout << ", (S)跳转到"; } cout << ": "; char choice; cin >> choice; choice = toupper(choice); switch (choice) { case 'N': if ((int)currentIndex < totalTables - 1) currentIndex++; break; case 'P': if (currentIndex > 0) currentIndex--; break; case 'S': if (totalTables > 1) { int index; cout << "输入配方编号(1-" << totalTables << "): "; cin >> index; if (index >= 1 && index <= static_cast<int>(totalTables)) { currentIndex = index - 1; } } break; case 'D': cout << "确认删除当前合成表? (Y/N): "; char confirm; cin >> confirm; if (toupper(confirm) == 'Y') { tables.erase(tables.begin() + currentIndex); SaveItems(false); cout << "合成表已删除!" << endl; wait(1); if (tables.empty()) { cout << "该物品已无合成表,返回主菜单" << endl; wait(1); return; } if (currentIndex >= tables.size()) { currentIndex = tables.size() - 1; } } break; case 'Q': return; default: cout << "无效选项!" << endl; wait(1); } } } // 为已有物品添加合成表 void AddRecipeToItem() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "为哪个物品添加合成表: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } Item& item = itemDB[target]; // 显示现有合成表数量 cout << "当前已有 " << item.getTables().size() << " 个合成表" << endl; // 创建新合成表 ItemTable newTable; CraftGrid grid; vector<string> missing; cout << "输入新合成表 (3行,每行3组'名称 数量',空槽位输入0):\n"; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { cin >> grid[x][y].first >> grid[x][y].second; // 处理空槽位 if (grid[x][y].second == 0) { grid[x][y].first = ""; } // 只检查有效材料 if (grid[x][y].second > 0 && !itemDB.contains(grid[x][y].first)) { missing.push_back(grid[x][y].first); } } } if (!missing.empty()) { cout << "缺失物品: "; for (size_t j = 0; j < missing.size(); j++) { cout << missing[j]; if (j < missing.size() - 1) cout << ", "; } cout << "\n添加失败!" << endl; pause(); return; } short outputCnt; cout << "产出数量: "; cin >> outputCnt; newTable.setCount(outputCnt); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { newTable.setItem(x, y, grid[x][y].first, grid[x][y].second); } } item.addTable(newTable); SaveItems(false); cout << "成功为 " << target << " 添加新合成表!" << endl; wait(1); } // 追根求源的材料计算(支持多条最短路径选择) void TraceMaterials() { clear(); string target; long long count; cout << "目标物品: "; cin >> target; cout << "合成数量: "; cin >> count; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } // 使用合并计算机制 MaterialMap globalMaterials; set<string> globalVisited; map<string, const ItemTable*> choices; // 存储用户选择的合成表 // 使用精确计算模式 CalculationMode mode = EXACT; CalcMaterialsWithMerge(target, count, globalMaterials, globalVisited, mode, choices); // 显示结果 clear(); cout << "追根求源 - 合成 " << count << " 个 " << target << " 需要:\n"; cout << "================================\n"; for (const auto& [id, amt] : globalMaterials) { short stack = itemDB.contains(id) ? itemDB[id].getStack() : 64; if (stack <= 0) stack = 64; long long groups = (amt + stack - 1) / stack; cout << id << ": " << amt << " (" << groups << "组)\n"; } cout << "================================\n"; pause(); } // 删除方块功能 void DeleteItem() { clear(); if (itemDB.size() == 0) { cout << "物品数据库为空!" << endl; pause(); return; } string target; cout << "输入要删除的物品名称: "; cin >> target; if (!itemDB.contains(target)) { cout << "物品不存在!" << endl; pause(); return; } // 获取目标物品信息 const Item& item = itemDB[target]; bool hasRecipes = item.hasRecipe(); int recipeCount = item.getTables().size(); // 显示警告信息 cout << "警告: 删除物品 " << target << " 将永久移除以下内容:" << "\n- 物品基本信息 (堆叠大小: " << item.getStack() << ")" << "\n- " << recipeCount << " 个合成表"; // 检查是否有其他物品依赖此物品 int referenceCount = 0; for (const auto& [id, otherItem] : itemDB.getAll()) { for (const auto& table : otherItem.getTables()) { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { if (table.getItem(x, y).first == target) { referenceCount++; } } } } } if (referenceCount > 0) { cout << "\n- " << referenceCount << " 个其他物品的合成表引用"; } // 确认删除 cout << "\n\n确认删除? (Y/N): "; char confirm; cin >> confirm; if (toupper(confirm) != 'Y') { cout << "删除操作已取消" << endl; wait(1); return; } // 执行删除 if (itemDB.removeItem(target)) { minPathLengthCache.clear(); // 清除路径缓存 SaveItems(false); cout << "物品 " << target << " 已成功删除!" << endl; } else { cout << "删除失败!" << endl; } pause(); } int main() { LoadSavePath(); clear(); cout << "启动中...\n路径: " << savePath.u8string() << endl; wait(1); LoadItems(); while (true) { clear(); cout << "===== 合成系统 =====\n" << "1. 创建物品\n" << "2. 追根求源\n" << "3. 手动保存\n" << "4. 设置路径\n" << "5. 保存信息\n" << "6. 查看物品列表\n" << "7. 查看物品配方\n" << "8. 添加合成表\n" << "9. 删除物品\n" << "10. 退出\n" << "路径: " << savePath.u8string() << "\n物品: " << itemDB.size() << "\n选项: "; int choice; cin >> choice; switch (choice) { case 1: CreateItem(); break; case 2: TraceMaterials(); break; case 3: SaveItems(true); break; case 4: SetSavePath(); break; case 5: ShowSaveInfo(); break; case 6: ShowItemList(); break; case 7: ShowItemRecipe(); break; case 8: AddRecipeToItem(); break; case 9: DeleteItem(); break; case 10: clear(); cout << "退出中...\n自动保存..."; SaveItems(false); wait(1); return 0; default: cout << "无效选项!" << endl; wait(1); } } }
最新发布
08-07
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值