diff --git a/src/fast_cal/CMakeLists.txt b/src/fast_cal/CMakeLists.txt index 5b21746..7a0967c 100644 --- a/src/fast_cal/CMakeLists.txt +++ b/src/fast_cal/CMakeLists.txt @@ -1,4 +1,4 @@ cmake_minimum_required(VERSION 3.0) -add_library(fast_cal fast_cal.cc) +add_library(fast_cal cal_core.cc fast_cal.cc) target_link_libraries(fast_cal core) diff --git a/src/fast_cal/cal_core.cc b/src/fast_cal/cal_core.cc new file mode 100644 index 0000000..94944e9 --- /dev/null +++ b/src/fast_cal/cal_core.cc @@ -0,0 +1,93 @@ +#include "core.h" +#include "fast_cal.h" + +Core FastCal::init(uint64_t code) { // initialize process + /// clear working data + cases.clear(); + std::queue{}.swap(cache); + + // TODO: test the speed without hashmap reserve + cases.reserve(65536); + + /// insert root node + cache.emplace(&cases.emplace(code, fast_cal_t { + .code = code, + .mask = 0, + .last = nullptr, // without parent node + }).first->second); + + /// import klotski core + return Core( + [this](auto &&code, auto &&mask) { // lambda as function pointer + new_case(std::forward(code), std::forward(mask)); + } + ); +} + +/// callback function for new case +void FastCal::new_case(uint64_t code, uint64_t mask) { + auto current = cases.find(code); + if (current != cases.end()) { // find existed case + current->second.mask |= mask; // update mask info + return; + } + cache.emplace(&cases.emplace(code, fast_cal_t { // record new case + .code = code, + .mask = mask, + .last = cache.front(), // link parent case + }).first->second); +} + +/// found first matched target +uint64_t FastCal::target(uint64_t code, const check_t &match) { + auto core = init(code); + while (!cache.empty()) { // bfs search + if (match(cache.front()->code)) { + return cache.front()->code; // match target + } + core.next_cases(cache.front()->code, cache.front()->mask); + cache.pop(); + } + return FastCal::NOT_FOUND; // target not found +} + +/// found multi-targets matched in first same layer +std::vector FastCal::target_multi(uint64_t code, const check_t &match) { + auto core = init(code); + auto layer_end = cache.back(); + std::vector matched; // matched list + while (!cache.empty()) { // bfs search + if (match(cache.front()->code)) { // match target + matched.emplace_back(cache.front()->code); + } + core.next_cases(cache.front()->code, cache.front()->mask); + if (cache.front() == layer_end) { // reach layer ending + if (!matched.empty()) { + return matched; // stop at first matched layer + } + layer_end = cache.back(); // reset layer ending + } + cache.pop(); + } + return std::vector{}; // no target found +} + +/// found all of the furthest cases +std::vector FastCal::furthest(uint64_t code) { + auto core = init(code); + auto layer_end = cache.back(); + std::vector layer_cases; + while (!cache.empty()) { // bfs search + core.next_cases(cache.front()->code, cache.front()->mask); + layer_cases.emplace_back(cache.front()->code); // record layer cases + if (cache.front() == layer_end) { // reach layer ending + if (cache.size() == 1) { + break; // stop loop at last layer + } + layer_cases.clear(); + layer_end = cache.back(); // reset layer ending + } + cache.pop(); + } + return layer_cases; // release latest layer cases +} diff --git a/src/fast_cal/fast_cal.cc b/src/fast_cal/fast_cal.cc index bee5e8b..f18b53a 100644 --- a/src/fast_cal/fast_cal.cc +++ b/src/fast_cal/fast_cal.cc @@ -7,33 +7,16 @@ #include #include -Core FastCal::init() { // initialization process - /// clear working data - cases.clear(); - std::queue{}.swap(cache); - - // TODO: test the speed without hashmap reserve - cases.reserve(65536); - - /// import klotski core - return Core( - [this](auto &&code, auto &&mask) { // lambda as function pointer - new_case(std::forward(code), std::forward(mask)); - } - ); +uint64_t FastCal::solve(uint64_t code) { + return FastCal::target(code, [](uint64_t code) { + return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address + }); } -void FastCal::new_case(uint64_t code, uint64_t mask) { // callback function for new case - auto current = cases.find(code); - if (current != cases.end()) { // find existed case - current->second.mask |= mask; // update mask info - return; - } - cache.emplace(&cases.emplace(code, fast_cal_t { // record new case - .code = code, - .mask = mask, - .last = cache.front(), // link parent case - }).first->second); +std::vector FastCal::solve_multi(uint64_t code) { + return FastCal::target_multi(code, [](uint64_t code) { + return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address + }); } std::vector FastCal::backtrack(uint64_t code) { @@ -52,138 +35,7 @@ std::vector FastCal::backtrack(uint64_t code) { } -uint64_t FastCal::solve(uint64_t code) { - return FastCal::target(code, [](uint64_t code) { - return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address - }); -} - -std::vector FastCal::solve_multi(uint64_t code) { - return FastCal::target_multi(code, [](uint64_t code) { - return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address - }); -} - -uint64_t FastCal::target(uint64_t code, const check_t &match) { - auto core = init(); - - cache.emplace(&cases.emplace(code, fast_cal_t { - .code = code, - .mask = 0, - .last = nullptr, // without parent node - }).first->second); - - while (!cache.empty()) { - if (match(cache.front()->code)) { - return cache.front()->code; // match target - } - core.next_cases(cache.front()->code, cache.front()->mask); - cache.pop(); - } - return FastCal::NOT_FOUND; // target not found -} - -std::vector FastCal::target_multi(uint64_t code, const FastCal::check_t &match) { - - auto core = init(); - - cache.emplace(&cases.emplace(code, fast_cal_t { - .code = code, - .mask = 0, - .last = nullptr, // without parent node - }).first->second); - - auto layer_end = cache.back(); - - int layer_num = 0; - -// bool matched = false; - - std::vector matched; - - while (!cache.empty()) { - - if (match(cache.front()->code)) { -// matched = true; - matched.emplace_back(cache.front()->code); -// std::cout << "found: " << std::endl; -// std::cout << RawCode(cache.front()->code); - - } - - core.next_cases(cache.front()->code, cache.front()->mask); - - if (cache.front() == layer_end) { - - if (!matched.empty()) { - std::cout << "layer " << layer_num << " end -> exit search" << std::endl; - return matched; - } - - std::cout << "reach layer " << layer_num << " ending" << std::endl; - ++layer_num; - - layer_end = cache.back(); - - } - - cache.pop(); - - } - - return std::vector{}; // no target found - -} - -std::vector FastCal::furthest(uint64_t code) { - - auto core = init(); - - cache.emplace(&cases.emplace(code, fast_cal_t { - .code = code, - .mask = 0, - .last = nullptr, // without parent node - }).first->second); - - auto layer_end = cache.back(); - - int layer_num = 0; - - std::vector layer_cases; - - while (!cache.empty()) { - - core.next_cases(cache.front()->code, cache.front()->mask); - - layer_cases.emplace_back(cache.front()->code); - if (cache.front() == layer_end) { - - std::cout << "layer size -> " << layer_cases.size() << std::endl; - std::cout << "reach layer " << layer_num << " ending -> " << cache.size() << std::endl; - - if (cache.size() == 1) { // almost exit -> last layer - break; -// return layer_cases; - - } - - layer_cases.clear(); - - ++layer_num; - - layer_end = cache.back(); - - } - - cache.pop(); - - } - - - return layer_cases; - -} uint32_t FastCal::step_num(uint64_t code) { @@ -198,7 +50,3 @@ uint32_t FastCal::step_num(uint64_t code) { return num; } - - - - diff --git a/src/fast_cal/fast_cal.h b/src/fast_cal/fast_cal.h index 302694c..cf1cd5d 100644 --- a/src/fast_cal/fast_cal.h +++ b/src/fast_cal/fast_cal.h @@ -1,41 +1,28 @@ #pragma once #include +#include #include #include -#include - class FastCal { public: - - typedef std::function check_t; - const static auto NOT_FOUND = (uint64_t)0; - -// explicit FastCal(uint64_t code) : root(code) {} - - // search resolve - // search all min-step resolve - // search the furthest cases - // search target by code - // search target by lambda + typedef std::function check_t; /// xxx_multi only search until same layer -// solve_multi - - // TODO: shall we using RawCode instead of uint64_t? + // TODO: shall we use RawCode instead of uint64_t? uint64_t solve(uint64_t code); - uint64_t target(uint64_t code, const check_t &match); + std::vector furthest(uint64_t code); std::vector solve_multi(uint64_t code); - std::vector target_multi(uint64_t code, const check_t &match); - std::vector furthest(uint64_t code); + // TODO: search / search_multi / resolve / resolve_multi + // TODO: static furthest function std::vector backtrack(uint64_t code); @@ -51,14 +38,9 @@ private: fast_cal_t *last; }; - -// uint64_t root; - std::queue cache; std::unordered_map cases; - Core init(); - + Core init(uint64_t code); void new_case(uint64_t code, uint64_t mask); - };