diff --git a/src/core/fast_cal/fast_cal.h b/src/core/fast_cal/fast_cal.h index f50d188..5b7aef8 100644 --- a/src/core/fast_cal/fast_cal.h +++ b/src/core/fast_cal/fast_cal.h @@ -109,17 +109,39 @@ private: namespace klotski::fast_cal { -class FCDemo { +class FastCalPro { public: - explicit FCDemo(RawCode raw_code); + FastCalPro() = delete; - std::optional DoCal(); + explicit FastCalPro(RawCode raw_code); - std::vector DoCalMulti(); + // ------------------------------------------------------------------------------------- // - std::vector DoCalFurthest(); + /// Calculate the case with minimum steps. + std::optional solve(); + + /// Calculate the cases with maximum steps. + std::vector furthest(); + + /// Calculate all of the minimum-step cases. + std::vector solve_multi(); + + /// Calculate the first case that meets the requirement. + std::optional achieve(std::function &&match); + + // ------------------------------------------------------------------------------------- // private: + // ------------------------------------------------------------------------------------- // + + /// Search next step cases and pop current. + KLSK_INLINE void spawn_next(MaskMover &mover); + + /// Try to emplace the searched info into the cache. + KLSK_INLINE bool try_emplace(uint64_t code, uint64_t mask); + + // ------------------------------------------------------------------------------------- // + struct data_t { uint64_t mask; uint64_t back; @@ -127,6 +149,8 @@ private: LayerQueue codes_; phmap::flat_hash_map cases_; + + // ------------------------------------------------------------------------------------- // }; } // namespace klotski::fast_cal diff --git a/src/core/fast_cal/internal/demo.cc b/src/core/fast_cal/internal/demo.cc index fef2285..f1dacf3 100644 --- a/src/core/fast_cal/internal/demo.cc +++ b/src/core/fast_cal/internal/demo.cc @@ -16,64 +16,63 @@ using klotski::cases::RangesUnion; using klotski::mover::MaskMover; using klotski::cases::GroupUnion; -using klotski::fast_cal::FCDemo; - -std::optional FCDemo::DoCal() { - uint64_t result = 0; - auto core = MaskMover([this, &result](uint64_t code, uint64_t mask) { - if (const auto match = cases_.find(code); match != cases_.end()) { - match->second.mask |= mask; // update mask - return; - } - cases_.emplace(code, data_t { - .mask = mask, - .back = codes_.current(), - }); - codes_.emplace(code); - - if (((code >> 39) & 0b111) == 0b100) { - result = code; +using klotski::fast_cal::FastCalPro; + +static KLSK_INLINE bool is_solved(uint64_t raw_code) { + return ((raw_code >> 39) & 0b111) == 0b100; +} + +std::optional FastCalPro::solve() { + // TODO: check root case + + uint64_t solution = 0; + auto mover = MaskMover([this, &solution](uint64_t code, uint64_t mask) { + if (try_emplace(code, mask) && is_solved(code)) { + solution = code; } }); - while (!codes_.is_ending()) { - auto curr = codes_.current(); - core.next_cases(curr, cases_.find(curr)->second.mask); + spawn_next(mover); + if (solution != 0) { + return RawCode::unsafe_create(solution); + } + } + return std::nullopt; +} + +std::optional FastCalPro::achieve(std::function &&match) { + // TODO: check root case - codes_.next(); - if (result != 0) { - return RawCode::unsafe_create(result); + uint64_t target = 0; + auto mover = MaskMover([this, &target, match = std::move(match)](uint64_t code, uint64_t mask) { + if (try_emplace(code, mask) && match(RawCode::unsafe_create(code))) { + target = code; + } + }); + while (!codes_.is_ending()) { + spawn_next(mover); + if (target != 0) { + return RawCode::unsafe_create(target); } } return std::nullopt; } -std::vector FCDemo::DoCalMulti() { +std::vector FastCalPro::solve_multi() { + // TODO: check root case + bool stop_flag = false; std::vector results {}; - auto core = MaskMover([this, &stop_flag, &results](uint64_t code, uint64_t mask) { - if (const auto match = cases_.find(code); match != cases_.end()) { - match->second.mask |= mask; // update mask - return; - } - cases_.emplace(code, data_t { - .mask = mask, - .back = codes_.current(), - }); - codes_.emplace(code); - - if (((code >> 39) & 0b111) == 0b100) { + auto mover = MaskMover([this, &stop_flag, &results](uint64_t code, uint64_t mask) { + if (try_emplace(code, mask) && is_solved(code)) { stop_flag = true; results.emplace_back(RawCode::unsafe_create(code)); } }); while (!codes_.is_ending()) { - auto curr = codes_.current(); - core.next_cases(curr, cases_.find(curr)->second.mask); - - codes_.next(); + spawn_next(mover); if (codes_.is_new_layer() && stop_flag) { // TODO: fix when solutions at last layer return results; @@ -83,24 +82,12 @@ std::vector FCDemo::DoCalMulti() { return {}; } -std::vector FCDemo::DoCalFurthest() { - auto core = MaskMover([this](uint64_t code, uint64_t mask) { - if (const auto match = cases_.find(code); match != cases_.end()) { - match->second.mask |= mask; // update mask - return; - } - cases_.emplace(code, data_t { - .mask = mask, - .back = codes_.current(), - }); - codes_.emplace(code); +std::vector FastCalPro::furthest() { + auto mover = MaskMover([this](uint64_t code, uint64_t mask) { + try_emplace(code, mask); }); - while (true) { - auto curr = codes_.current(); - core.next_cases(curr, cases_.find(curr)->second.mask); - - codes_.next(); + spawn_next(mover); if (codes_.is_ending()) { return codes_.layer_cases() | std::views::transform([](uint64_t code) { return RawCode::unsafe_create(code); @@ -110,21 +97,26 @@ std::vector FCDemo::DoCalFurthest() { } RawCode FastCal_demo(RawCode raw_code) { - klotski::fast_cal::FCDemo fc {raw_code}; -// return fc.DoCal().value(); + klotski::fast_cal::FastCalPro fc {raw_code}; + return fc.solve().value(); -// auto tmp = fc.DoCal(); +// auto tmp = fc.solve(); // std::cout << tmp.value().to_common_code() << std::endl; -// auto tmp = fc.DoCalMulti(); +// auto tmp = fc.solve_multi(); // for (const auto x : tmp) { // std::cout << x.to_common_code() << std::endl; // } - auto tmp = fc.DoCalFurthest(); +// auto tmp = fc.furthest(); // for (const auto x : tmp) { // std::cout << x.to_common_code() << std::endl; // } - return RawCode::unsafe_create(0); +// auto tmp = fc.achieve([](RawCode r) { +// return r == 0x7F87E0E5BFFF492; +// }); +// std::cout << tmp.value().to_common_code() << std::endl; + +// return RawCode::unsafe_create(0); } diff --git a/src/core/fast_cal/internal/fast_cal.inl b/src/core/fast_cal/internal/fast_cal.inl index b0c40ba..463a679 100644 --- a/src/core/fast_cal/internal/fast_cal.inl +++ b/src/core/fast_cal/internal/fast_cal.inl @@ -2,11 +2,30 @@ namespace klotski::fast_cal { -inline FCDemo::FCDemo(RawCode raw_code) : codes_(cases::GroupUnion::from_raw_code(raw_code).max_group_size(), {raw_code.unwrap()}) { +inline FastCalPro::FastCalPro(RawCode raw_code) : codes_(cases::GroupUnion::from_raw_code(raw_code).max_group_size(), {raw_code.unwrap()}) { // auto reserve = cases::GroupUnion::from_raw_code(raw_code).max_group_size(); cases_.reserve(static_cast(25955 * 1.56)); // cases_.reserve(static_cast(reserve * 1.56)); cases_.emplace(raw_code, data_t {0, 0}); // without mask } +inline KLSK_INLINE bool FastCalPro::try_emplace(uint64_t code, uint64_t mask) { + if (const auto match = cases_.find(code); match != cases_.end()) { + match->second.mask |= mask; // update mask + return false; + } + cases_.emplace(code, data_t { + .mask = mask, + .back = codes_.current(), + }); + codes_.emplace(code); + return true; +} + +inline KLSK_INLINE void FastCalPro::spawn_next(MaskMover &mover) { + auto curr = codes_.current(); + mover.next_cases(curr, cases_.find(curr)->second.mask); + codes_.next(); +} + } // namespace klotski::fast_cal