#include #include #include #include #include #include #include #include template void printVector(std::vector vec){ for (size_t i = 0; i < vec.size(); i++) { std::cout< void printMatrix(std::vector> mat){ for (size_t i = 0; i < mat.size(); i++) { printVector(mat[i]); } } class Color { public: Color():r(0), g(0), b(0){} Color(const Color& color) { r = color.r; g = color.g; b = color.b; } Color(uint32_t color){ Color c = Color::decode(color); r = c.r; g = c.g; b = c.b; } Color(int _r, int _g, int _b){ r = uint8_t(_r); g = uint8_t(_g); b = uint8_t(_b); } uint32_t encode(void) const{ return (uint32_t(r)<<16) + (uint32_t(g)<<8) + uint32_t(b); } static Color decode(uint32_t val) { uint8_t r = (val>>16) & 0xff; uint8_t g = (val>>8) & 0xff; uint8_t b = val & 0xff; return Color(r, g, b); } void show(void) { std::cout<<"(r, g, b) = ("<& current, std::vector>& ans){ if (choice <= 0) { std::vector compose; for (size_t i = 0; i < current.size(); i++) { compose.push_back(current[current.size() - 1 - i]); } ans.push_back(compose); return; } if (total<=0 || choice <=0 || choice > total) return; // do not choose current number generateCompose(total-1, choice, current, ans); // choose current number. current.push_back(total); generateCompose(total-1, choice-1, current, ans); current.pop_back(); } std::vector composeToRecipe(const std::vector& compose, int num) { std::vector pre = compose; std::vector post = compose; pre.insert(pre.begin(), 0); post.push_back(num); std::vector recipe; for (size_t i = 1; i < pre.size(); i++) { recipe.push_back(post[i] - pre[i] - 1); } return recipe; } class Recipe { public: Recipe(const std::vector& _counts){ counts = _counts; } public: uint64_t encode(void) { uint64_t val = 0; uint64_t bits = 1; for (size_t i = 0; i < counts.size(); i++) { val += bits * counts[i]; bits *= 9; } return val; } static Recipe decode(uint64_t encoded) { std::vector counts; for (size_t i = 0; i < 16; i++) { counts.push_back(int(encoded%9)); encoded /= 9; } return Recipe(counts); } void preCraft(const std::vector& colorlist) { for (size_t i = 0; i < counts.size(); i++) { for (int j = 0; j < counts[i]; j++) { table.addColor(colorlist[i]); } } } Color getTableColor(void) { return table.craft(); } Color getCraftedArmorColor(const Color armorColor) { ColorCraftingTable temp = table; if (!(armorColor == Color(0, 0, 0))) { temp.addColor(armorColor); } return temp.craft(); } std::vector getCounts(void){ return counts; } private: std::vector counts; ColorCraftingTable table; }; void dumpPossibleRecipe(const std::string& path) { std::vector> ans; std::vector current; std::fstream recipes; recipes.open(path, std::fstream::out|std::fstream::binary); generateCompose(24, 16, current, ans); size_t counts = 0; for (size_t i = 0; i < ans.size(); i++) { Recipe recipe(composeToRecipe(ans[i], 25)); uint64_t encoded = recipe.encode(); if (encoded == 0) continue; // this recipe is empty. recipes.write((char*) &encoded, sizeof(encoded)); counts += 1; } recipes.close(); std::cout<<"we have write "< class SyncholizedHeapBitset { public: SyncholizedHeapBitset(void) { bitmap = new std::bitset; } ~SyncholizedHeapBitset(void) { delete bitmap; } bool test(size_t pos) {return bitmap->test(pos);} void set(size_t pos, bool val) {bitmap->set(pos, val);} size_t count(void) {return bitmap->count();} private: std::bitset* bitmap; }; void searchBlock( std::mutex& lock, std::vector& recipes,// readonly SyncholizedHeapBitset<(2<<24)>& colormap, // thread-safe std::vector& oldColors, // read-only std::vector& newColors, //write-only std::fstream& searched, // write-only. size_t start, size_t end ) { for (size_t i = start; i < end; i++) { for(size_t j = 0; j < recipes.size(); j++) { Color crafted = recipes[j].getCraftedArmorColor(oldColors[i]); uint32_t encodedColor = crafted.encode(); if (!colormap.test(encodedColor)) { lock.lock(); // for thread safety. if (!colormap.test(encodedColor)) { // double check after locked to avoid duplication. colormap.set(encodedColor, true); newColors.push_back(crafted); uint32_t encodedOldColor = oldColors[i].encode(); searched.write((const char*) &encodedOldColor, sizeof(encodedOldColor)); uint64_t encodedRecipe = recipes[j].encode(); searched.write((const char*) &encodedRecipe, sizeof(encodedRecipe)); searched.write((const char*) &encodedColor, sizeof(encodedColor)); } lock.unlock(); } } } } void searchAllColors(const std::vector& colorlist, int numThreads=8, int blockSize=32) { std::cout<<"preparing..."< recipes; std::vector> ans; std::vector current; std::cout<<"Generating compose..."< colormap; std::vector oldColors; // color #0x000000 do not exist in minecraft, so it is okay to be used as empty color. oldColors.push_back(Color(uint32_t(0))); std::mutex lock; size_t layer = 1; while (oldColors.size() > 0) { std::cout<<"processing layer "< newColors; auto start = std::chrono::high_resolution_clock::now(); auto last = start; for (size_t i = 0; i < oldColors.size(); i+=numThreads*blockSize) { // create threads and dispatch jobs. std::vector threads; for(int j = 0; j < numThreads; j++) { int start = i + j*blockSize; int end = i + (j+1)*blockSize; if (end > (int) oldColors.size()) { end = (int) oldColors.size(); } if (start > end) {start = end;} std::thread* t = new std::thread( searchBlock, std::ref(lock), std::ref(recipes), std::ref(colormap), std::ref(oldColors), std::ref(newColors), std::ref(output), start, end ); threads.push_back(t); } // wait for all threads to finish. for(size_t j = 0; j < threads.size(); j++) { threads[j]->join(); delete threads[j]; threads[j] = nullptr; } auto now = std::chrono::high_resolution_clock::now(); std::chrono::duration diff = now - start; std::chrono::duration interval = now - last; if (interval.count() >= 5) { last = now; std::cout<<"progress: "< colors = { Color(176, 46, 38), Color(94, 124, 22), Color(137, 50, 184), Color(22, 156, 156), Color(157, 157, 151), Color(71, 79, 82), Color(243, 139, 170), Color(128, 199, 31), Color(254, 216, 61), Color(58, 179, 218), Color(199, 78, 189), Color(249, 128, 29), Color(29, 29, 33), Color(131, 84, 50), Color(60, 68, 170), Color(249, 255, 254), }; // useless in this script, but useful for interpreting encoded recipe. std::vector keys = { "red", "green", "purple", "cyan", "silver", "gray", "pink", "lime", "yellow", "lightBlue", "magenta", "orange", "black", "brown", "blue", "white" }; // parse numThreads. if (argc == 2) { int numThreads = std::stoi(std::string(argv[1])); searchAllColors(colors, numThreads); } else { std::cout<<"Usage: ./leatherColorCombinationsCalculator "<