Browse Source

feat: migrate fast cal implementation code

master
Dnomd343 2 months ago
parent
commit
3e2470c212
  1. 3
      src/core/CMakeLists.txt
  2. 65
      src/core/fast_cal/fast_cal.h
  3. 105
      src/core/fast_cal/internal/cal_core.cc
  4. 91
      src/core/fast_cal/internal/fast_cal.cc
  5. 52
      src/core/main.cc

3
src/core/CMakeLists.txt

@ -18,6 +18,9 @@ set(KLOTSKI_CORE_SRC
short_code/internal/serialize.cc
core/internal/core.cc
fast_cal/internal/cal_core.cc
fast_cal/internal/fast_cal.cc
)
add_library(klotski_core STATIC ${KLOTSKI_CORE_SRC})

65
src/core/fast_cal/fast_cal.h

@ -0,0 +1,65 @@
/// Klotski Engine by Dnomd343 @2024
// TODO: only copy from old implementation, the interfaces will change in future.
#pragma once
#include <queue>
#include <vector>
#include <cstdint>
#include <functional>
#include <unordered_map>
#include "core/core.h"
#include "raw_code/raw_code.h"
using klotski::core::Core;
using klotski::codec::RawCode;
// TODO: using prime number
const uint32_t FC_MAP_RESERVE = 65536 * 8;
/// FastCal not found -> return invalid raw code
const RawCode FC_NOT_FOUND = RawCode::unsafe_create(0);
class FastCal {
public:
typedef std::function<bool(uint64_t)> match_t;
/// setting root code
void set_root(const RawCode &code);
explicit FastCal(const RawCode &code);
/// backtrack functions
int step_num(const RawCode &code);
std::vector<RawCode> backtrack(const RawCode &code);
/// BFS search functions
void build();
RawCode solve();
std::vector<RawCode> furthest();
std::vector<RawCode> solve_multi();
RawCode target(const match_t &match);
std::vector<RawCode> target_multi(const match_t &match);
/// static BFS search functions
static std::vector<RawCode> resolve(const RawCode &start);
static std::vector<std::vector<RawCode>> to_furthest(const RawCode &start);
static std::vector<std::vector<RawCode>> resolve_multi(const RawCode &start);
static std::vector<RawCode> search(const RawCode &start, const match_t &match);
static std::vector<std::vector<RawCode>> search_multi(const RawCode &start, const match_t &match);
private:
struct fast_cal_t {
uint64_t code;
uint64_t mask;
fast_cal_t *last;
};
uint64_t root;
std::queue<fast_cal_t*> cache;
std::unordered_map<uint64_t, fast_cal_t> cases;
inline Core init(uint64_t code);
void new_case(uint64_t code, uint64_t mask);
};

105
src/core/fast_cal/internal/cal_core.cc

@ -0,0 +1,105 @@
#include "fast_cal/fast_cal.h"
Core FastCal::init(uint64_t code) { // initialize process
/// reset working data
cases.clear();
cases.reserve(FC_MAP_RESERVE); // hashmap pre-reserve
std::queue<fast_cal_t*>{}.swap(cache);
/// 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<decltype(code)>(code), std::forward<decltype(mask)>(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);
}
/// build total search tree
void FastCal::build() {
auto core = init(root);
while (!cache.empty()) {
core.next_cases(cache.front()->code, cache.front()->mask);
cache.pop();
}
}
/// found first matched target
RawCode FastCal::target(const match_t &match) {
auto core = init(root);
while (!cache.empty()) {
if (match(cache.front()->code)) {
return RawCode::unsafe_create(cache.front()->code); // match target
}
core.next_cases(cache.front()->code, cache.front()->mask);
cache.pop();
}
return FC_NOT_FOUND; // target not found
}
/// found all of the furthest cases
std::vector<RawCode> FastCal::furthest() {
auto core = init(root);
auto layer_end = cache.back();
std::vector<RawCode> layer_cases;
/// start BFS search
while (!cache.empty()) {
core.next_cases(cache.front()->code, cache.front()->mask);
layer_cases.emplace_back(
RawCode::unsafe_create(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 the latest layer cases
}
/// found multi-targets matched in first same layer
std::vector<RawCode> FastCal::target_multi(const match_t &match) {
auto core = init(root);
auto layer_end = cache.back();
std::vector<RawCode> matched; // matched list
/// start BFS search
while (!cache.empty()) {
if (match(cache.front()->code)) { // match target
matched.emplace_back(
RawCode::unsafe_create(cache.front()->code) // record matched cases
);
}
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<RawCode>{}; // no target found
}

91
src/core/fast_cal/internal/fast_cal.cc

@ -0,0 +1,91 @@
#include <algorithm>
#include "utils/common.h"
#include "fast_cal/fast_cal.h"
#include "raw_code/raw_code.h"
FastCal::FastCal(const RawCode &code) {
this->root = (uint64_t)code;
}
void FastCal::set_root(const RawCode &code) {
this->root = (uint64_t)code;
}
/// klotski resolved -> 2x2 block at address 13 (aka 0xD)
auto resolved = [](uint64_t code) {
return ((code >> (3 * 0xD)) & 0b111) == BLOCK_2x2; // check 2x2 block address
};
RawCode FastCal::solve() {
return FastCal::target(resolved);
}
std::vector<RawCode> FastCal::solve_multi() {
return FastCal::target_multi(resolved);
}
std::vector<RawCode> FastCal::resolve(const RawCode &start) {
return FastCal::search(start, resolved);
}
std::vector<std::vector<RawCode>> FastCal::resolve_multi(const RawCode &start) {
return FastCal::search_multi(start, resolved);
}
/// backtrack of FastCal tree
int FastCal::step_num(const RawCode &code) {
auto tmp = cases.find((uint64_t)code);
if (tmp == cases.end()) {
return -1; // code not exist
}
int num = 0; // step number
auto node = &tmp->second; // backtrack entry
while ((node = node->last) != nullptr) {
++num;
}
return num;
}
std::vector<RawCode> FastCal::backtrack(const RawCode &code) {
auto tmp = cases.find((uint64_t)code);
if (tmp == cases.end()) {
return std::vector<RawCode>{}; // code not exist
}
auto node = &tmp->second; // backtrack entry
std::vector<RawCode> path; // backtrack path
while (node != nullptr) {
path.emplace_back(RawCode::unsafe_create(node->code)); // record path info
node = node->last;
}
std::reverse(path.begin(), path.end()); // reverse path cases
return path;
}
/// static BFS search functions
std::vector<std::vector<RawCode>> FastCal::to_furthest(const RawCode &start) {
auto fc = FastCal(start);
std::vector<std::vector<RawCode>> result;
for (const auto &furthest : fc.furthest()) {
result.emplace_back(fc.backtrack(furthest)); // backtrack every furthest cases
}
return result;
}
std::vector<RawCode> FastCal::search(const RawCode &start, const match_t &match) {
auto fc = FastCal(start);
auto result = fc.target(match);
if (result == FC_NOT_FOUND) {
return std::vector<RawCode>{}; // target not matched
}
return fc.backtrack(result); // backtrack target path
}
std::vector<std::vector<RawCode>> FastCal::search_multi(const RawCode &start, const match_t &match) {
auto fc = FastCal(start);
std::vector<std::vector<RawCode>> result;
for (const auto &target : fc.target_multi(match)) {
result.emplace_back(fc.backtrack(target)); // backtrack every target
}
return result;
}

52
src/core/main.cc

@ -3,6 +3,7 @@
#include "core/core.h"
#include "raw_code/raw_code.h"
#include "fast_cal/fast_cal.h"
#include "all_cases/all_cases.h"
#include "short_code/short_code.h"
#include "common_code/common_code.h"
@ -21,45 +22,28 @@ using klotski::codec::SHORT_CODE_LIMIT;
int main() {
const auto start = clock();
auto core = Core([](const uint64_t code, uint64_t) {
std::cout << RawCode::unsafe_create(code);
std::cout << std::endl;
});
// auto core = Core([](const uint64_t code, uint64_t) {
// std::cout << RawCode::unsafe_create(code);
// std::cout << std::endl;
// });
// core.next_cases(RawCode::from_common_code(0x1A9BF0C00).value().unwrap(), 0x0);
core.next_cases(RawCode::from_common_code(0x1A9BF0C00).value().unwrap(), 0x0);
// auto cal = FastCal(RawCode::from_common_code(0x1A9BF0C00).value());
auto cal = FastCal(RawCode::from_common_code("25EEF04").value());
// std::vector<uint64_t> common_codes;
// common_codes.reserve(klotski::cases::ALL_CASES_NUM_);
// for (uint64_t head = 0; head < 15; ++head) {
// for (auto range : AllCases::instance().fetch()[head]) {
// common_codes.emplace_back(head << 32 | range);
// }
// }
// std::vector<std::string> common_codes_str;
// common_codes_str.reserve(klotski::cases::ALL_CASES_NUM_);
// for (auto x : common_codes) {
// common_codes_str.emplace_back(CommonCode::string_encode(x, false));
// }
// ShortCode::speed_up(true);
// auto ret = cal.solve();
//
// for (uint32_t short_code = 0; short_code < SHORT_CODE_LIMIT; ++short_code) {
// ShortCode::unsafe_create(short_code).to_common_code();
// for (auto kk : cal.backtrack(ret)) {
// std::cout << kk.to_common_code() << "," << kk.to_common_code().to_short_code() << std::endl;
// }
// for (auto common_code : common_codes) {
// printf("%llX\n", common_code);
// CommonCode::string_encode(common_code, true);
// CommonCode::string_encode(common_code, false);
// printf("%s\n", CommonCode::string_encode(common_code, false).c_str());
// std::cout << CommonCode::string_encode(common_code, false) << std::endl;
// }
// for (auto &common_code_str : common_codes_str) {
// CommonCode::string_decode(common_code_str);
// }
for (const auto solve : cal.solve_multi()) {
for (const auto raw_code : cal.backtrack(solve)) {
const auto common_code = raw_code.to_common_code();
std::cout << common_code << "/" << common_code.to_short_code() << std::endl;
}
std::cout << "----" << std::endl;
}
std::cerr << ((clock() - start) * 1000 / CLOCKS_PER_SEC) << "ms" << std::endl;

Loading…
Cancel
Save