mirror of https://github.com/dnomd343/klotski.git
Dnomd343
2 years ago
6 changed files with 0 additions and 359 deletions
@ -1,4 +0,0 @@ |
|||
cmake_minimum_required(VERSION 3.0) |
|||
set(CMAKE_CXX_STANDARD 14) |
|||
|
|||
add_executable(klotski main.cc common.cc all_cases.cc short_code.cc common_code.cc) |
@ -1,39 +0,0 @@ |
|||
#include "common.h" |
|||
|
|||
uint32_t Common::range_reverse(uint32_t bin) { // reverse binary every 2-bits
|
|||
bin = ((bin << 16) & 0xFFFF0000) | ((bin >> 16) & 0x0000FFFF); |
|||
bin = ((bin << 8) & 0xFF00FF00) | ((bin >> 8) & 0x00FF00FF); |
|||
bin = ((bin << 4) & 0xF0F0F0F0) | ((bin >> 4) & 0x0F0F0F0F); |
|||
return ((bin << 2) & 0xCCCCCCCC) | ((bin >> 2) & 0x33333333); |
|||
} |
|||
|
|||
bool Common::check_case(uint32_t head, uint32_t range) { // whether the head and range is valid
|
|||
uint32_t mask = 0b110011 << head; // fill 2x2 block
|
|||
for (int addr = 0; range; range >>= 2) { // traverse every 2-bits
|
|||
while (mask >> addr & 0b1) { |
|||
++addr; // search next not filled block
|
|||
} |
|||
switch (range & 0b11) { |
|||
case 0b00: // space block
|
|||
case 0b11: // 1x1 block
|
|||
if (addr > 19) { // invalid address
|
|||
return false; |
|||
} |
|||
mask |= 0b1 << addr; // fill 1x1 block
|
|||
break; |
|||
case 0b10: // 2x1 block
|
|||
if (addr > 15 || mask >> (addr + 4) & 0b1) { // invalid address
|
|||
return false; |
|||
} |
|||
mask |= 0b10001 << addr; // fill 2x1 block
|
|||
break; |
|||
case 0b01: // 1x2 block
|
|||
if (addr > 18 || (addr & 0b11) == 0b11 || mask >> (addr + 1) & 0b1) { // invalid address
|
|||
return false; |
|||
} |
|||
mask |= 0b11 << addr; // fill 1x2 block
|
|||
break; |
|||
} |
|||
} |
|||
return true; // valid case
|
|||
} |
@ -1,9 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
|
|||
class Common { |
|||
public: |
|||
static uint32_t range_reverse(uint32_t bin); |
|||
static bool check_case(uint32_t head, uint32_t range); |
|||
}; |
@ -1,70 +0,0 @@ |
|||
#include <iostream> |
|||
#include "all_cases.h" |
|||
#include "short_code.h" |
|||
#include "common_code.h" |
|||
|
|||
int main() { |
|||
|
|||
// auto a = AllCases();
|
|||
// auto a = AllCases(AllCases::Build::BASIC_RANGES);
|
|||
// auto a = AllCases(AllCases::Build::ALL_CASES);
|
|||
|
|||
// std::cout << "start getting basic ranges" << std::endl;
|
|||
// std::cout << "basic range: " << a.get_basic_ranges()->size() << std::endl;
|
|||
|
|||
// std::cout << "start getting all cases" << std::endl;
|
|||
// for (const auto &temp : *a.get_all_cases()) {
|
|||
// std::cout << " " << temp.size() << std::endl;
|
|||
// }
|
|||
|
|||
|
|||
// auto s = ShortCode();
|
|||
// auto s = ShortCode(ShortCode::Mode::NORMAL);
|
|||
// auto s = ShortCode(ShortCode::Mode::FAST);
|
|||
|
|||
// s.speed_up(ShortCode::Mode::NORMAL);
|
|||
// s.speed_up(ShortCode::Mode::FAST);
|
|||
|
|||
// printf("%d\n", s.zip_short_code(0x6EC0F8800));
|
|||
// printf("%09lX\n", s.unzip_short_code(14323231));
|
|||
|
|||
// std::cout << ShortCode::code_to_string(14323231) << std::endl;
|
|||
// std::cout << ShortCode::code_from_string("EP4HZ") << std::endl;
|
|||
|
|||
|
|||
// std::cout << CommonCode::code_to_string(0x4FEA13400, true) << std::endl;
|
|||
// std::cout << CommonCode::code_to_string(0x4FEA13400) << std::endl;
|
|||
|
|||
// printf("%09lX\n", CommonCode::code_from_string("4FEa134"));
|
|||
// printf("%09lX\n", CommonCode::code_from_string("1A9bf0C0"));
|
|||
|
|||
|
|||
// std::cout << (int)last_zero_num(0b1) << std::endl;
|
|||
// std::cout << (int)last_zero_num(0b1000) << std::endl;
|
|||
// std::cout << (int)last_zero_num(0) << std::endl;
|
|||
// std::cout << CommonCode::code_to_string(0, true) << std::endl;
|
|||
|
|||
auto a = AllCases(); |
|||
std::vector<uint64_t> all_cases; |
|||
for (int head = 0; head < 16; ++head) { |
|||
auto prefix = (uint64_t)head << 32; |
|||
for (auto const &range : (*a.get_all_cases())[head]) { |
|||
all_cases.emplace_back(prefix | range); |
|||
} |
|||
} |
|||
// std::cout << all_cases.size() << std::endl;
|
|||
for (auto const &code : all_cases) { |
|||
// printf("%s\n", CommonCode::code_to_string(code).c_str());
|
|||
std::string code_str = CommonCode::code_to_string(code); |
|||
if (CommonCode::code_from_string(code_str) != code) { |
|||
std::cout << "ERROR: " << code_str << std::endl; |
|||
} |
|||
|
|||
code_str = CommonCode::code_to_string(code, true); |
|||
if (CommonCode::code_from_string(code_str) != code) { |
|||
std::cout << "ERROR: " << code_str << std::endl; |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
@ -1,169 +0,0 @@ |
|||
#include <stdexcept> |
|||
#include "common.h" |
|||
#include "all_cases.h" |
|||
#include "short_code.h" |
|||
#include "short_code_mark.h" |
|||
#include "common_code.h" |
|||
|
|||
ShortCode::ShortCode(ShortCode::Mode mode) { // class initialize
|
|||
speed_up(mode); |
|||
} |
|||
|
|||
bool ShortCode::check(uint32_t short_code) { |
|||
return short_code < ShortCode::SHORT_CODE_LIMIT; // 0 ~ (SHORT_CODE_LIMIT - 1)
|
|||
} |
|||
|
|||
std::string ShortCode::code_to_string(uint32_t short_code) { // encode as 5-bits string
|
|||
if (!ShortCode::check(short_code)) { |
|||
throw std::range_error("short code out of range"); |
|||
} |
|||
std::string result(5, '\0'); // short code length 5
|
|||
for (int n = 0; n < 5; ++n) { |
|||
uint8_t bit = short_code % 32; |
|||
short_code = (short_code - bit) / 32; |
|||
result[4 - n] = SHORT_CODE_TABLE[bit]; |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
uint32_t ShortCode::code_from_string(const std::string &short_code) { // 5-bits string decode as number
|
|||
if (short_code.length() != 5) { |
|||
throw std::runtime_error("invalid short code"); |
|||
} |
|||
uint32_t result = 0; |
|||
for (auto bit : short_code) { |
|||
result *= 32; |
|||
if (bit >= 'a' && bit <= 'z') { |
|||
bit -= 32; // convert to uppercase
|
|||
} |
|||
if (bit >= '1' && bit <= 'Z') { |
|||
result += (bit = SHORT_CODE_TABLE_REV[bit - 49]); // table convert
|
|||
if (bit != -1) { |
|||
continue; // pass check
|
|||
} |
|||
} |
|||
throw std::runtime_error("invalid short code"); |
|||
} |
|||
if (!ShortCode::check(result)) { |
|||
throw std::range_error("short code out of range"); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
void ShortCode::speed_up(enum Mode mode) { // speed up handle short code
|
|||
switch (mode) { |
|||
case Mode::NORMAL: // speed up into normal mode
|
|||
if (basic_ranges.empty()) { |
|||
build_base_ranges(); // basic ranges initialize
|
|||
} |
|||
break; |
|||
case Mode::FAST: // speed up into fast mode
|
|||
if (all_cases_list.empty()) { |
|||
build_mappings(); // all cases mapping initialize
|
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void ShortCode::build_base_ranges() { // build basic ranges
|
|||
auto all = AllCases(AllCases::Build::BASIC_RANGES); |
|||
basic_ranges = *all.get_basic_ranges(); |
|||
} |
|||
|
|||
void ShortCode::build_mappings() { // build fast search mappings
|
|||
auto all = AllCases(AllCases::Build::ALL_CASES); |
|||
for (int head = 0; head < 16; ++head) { |
|||
uint64_t prefix = (uint64_t)head << 32; |
|||
for (const auto &range : (*all.get_all_cases())[head]) { |
|||
all_cases_list.emplace_back(prefix | range); // short_code => common_code
|
|||
} |
|||
} |
|||
for (int n = 0; n < all_cases_list.size(); ++n) { |
|||
all_cases_dict[all_cases_list[n]] = n; // common_code => short_code
|
|||
} |
|||
} |
|||
|
|||
enum ShortCode::Mode ShortCode::check_mode() { // ensure speed up enabled and return current mode
|
|||
if (!all_cases_list.empty()) { |
|||
return ShortCode::Mode::FAST; // fast mode already enabled
|
|||
} |
|||
if (!basic_ranges.empty()) { |
|||
return ShortCode::Mode::NORMAL; // normal mode already enabled
|
|||
} |
|||
speed_up(ShortCode::Mode::NORMAL); // class without initialized -> enter normal mode
|
|||
return ShortCode::Mode::NORMAL; // use normal mode
|
|||
} |
|||
|
|||
uint32_t ShortCode::zip_short_code(uint64_t common_code) { // common_code --zip--> short_code
|
|||
if (!CommonCode::check(common_code)) { |
|||
throw std::runtime_error("invalid common code"); |
|||
} |
|||
switch (check_mode()) { |
|||
case ShortCode::Mode::NORMAL: |
|||
return tiny_encode(common_code); |
|||
case ShortCode::Mode::FAST: |
|||
return all_cases_dict[common_code]; |
|||
default: |
|||
throw std::runtime_error("unknown error"); |
|||
} |
|||
} |
|||
|
|||
uint64_t ShortCode::unzip_short_code(uint32_t short_code) { // short_code --unzip--> common_code
|
|||
if (!ShortCode::check(short_code)) { |
|||
throw std::runtime_error("invalid short code"); |
|||
} |
|||
switch (check_mode()) { |
|||
case ShortCode::Mode::NORMAL: |
|||
return tiny_decode(short_code); |
|||
case ShortCode::Mode::FAST: |
|||
return all_cases_list[short_code]; |
|||
default: |
|||
throw std::runtime_error("unknown error"); |
|||
} |
|||
} |
|||
|
|||
uint32_t ShortCode::tiny_encode(uint64_t common_code) { // common_code --low-memory--> short_code
|
|||
uint32_t offset = 0; |
|||
uint32_t head = common_code >> 32; // common code head
|
|||
uint32_t prefix = (common_code >> 24) & 0xFF; // common code range prefix
|
|||
auto target = Common::range_reverse((uint32_t)common_code); // target range
|
|||
|
|||
for (int index = 0; index < BASIC_RANGES_INDEX[prefix]; ++index) { // traverse basic ranges
|
|||
uint32_t range = basic_ranges[index + BASIC_RANGES_OFFSET[prefix]]; |
|||
if (range == target) { |
|||
break; // found target range
|
|||
} |
|||
if (Common::check_case(head, range)) { // search for valid cases
|
|||
++offset; // record sub offset
|
|||
} |
|||
} |
|||
return ALL_CASES_OFFSET[head] + RANGE_PREFIX_OFFSET[head][prefix] + offset; |
|||
} |
|||
|
|||
uint64_t ShortCode::tiny_decode(uint32_t short_code) { // short_code --low-memory--> common_code
|
|||
uint32_t head = 0, prefix = 0; |
|||
for (; head < 16; ++head) { |
|||
if (short_code < ALL_CASES_INDEX[head]) { // match head
|
|||
break; |
|||
} |
|||
short_code -= ALL_CASES_INDEX[head]; // short code approximate
|
|||
} |
|||
for (; prefix < 256; ++prefix) { |
|||
if (short_code < RANGE_PREFIX_INDEX[head][prefix]) { // match range prefix
|
|||
break; |
|||
} |
|||
short_code -= RANGE_PREFIX_INDEX[head][prefix]; // short code approximate
|
|||
} |
|||
|
|||
uint32_t range; |
|||
for (int index = 0; index < BASIC_RANGES_INDEX[prefix]; ++index) { // traverse basic ranges
|
|||
range = basic_ranges[index + BASIC_RANGES_OFFSET[prefix]]; |
|||
if (Common::check_case(head, range)) { // search for valid cases
|
|||
if (short_code == 0) { |
|||
break; // found target range
|
|||
} |
|||
--short_code; // short code approximate
|
|||
} |
|||
} |
|||
return (uint64_t)head << 32 | Common::range_reverse(range); // release common code
|
|||
} |
@ -1,68 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include <string> |
|||
#include <cstdint> |
|||
#include <unordered_map> |
|||
|
|||
/// ok
|
|||
const char SHORT_CODE_TABLE[32] = { |
|||
'1', '2', '3', '4', '5', '6', '7', '8', '9', // skip `0`
|
|||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // skip `I`
|
|||
'J', 'K', // skip `L`
|
|||
'M', 'N', // skip `O`
|
|||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
|||
}; |
|||
|
|||
/// ok
|
|||
const char SHORT_CODE_TABLE_REV[42] = { |
|||
// 00 01 02 03 04 05 06 07 08
|
|||
0, 1, 2, 3, 4, 5, 6, 7, 8, |
|||
// 09 10 11 12 13 14 15
|
|||
-1, -1, -1, -1, -1, -1, -1, |
|||
// 16 17 18 19 20 21 22 23 24 25
|
|||
9, 10, 11, 12, 13, 14, 15, 16, -1, 17, |
|||
// 26 27 28 29 30 31 32 33 34 35
|
|||
18, -1, 19, 20, -1, 21, 22, 23, 24, 25, |
|||
// 36 37 38 39 40 41
|
|||
26, 27, 28, 29, 30, 31, |
|||
}; |
|||
|
|||
class ShortCode { |
|||
public: |
|||
/// ok
|
|||
enum Mode {NORMAL, FAST}; |
|||
|
|||
/// ok
|
|||
ShortCode() = default; |
|||
void speed_up(enum Mode mode); |
|||
explicit ShortCode(enum Mode mode); |
|||
static bool check(uint32_t short_code); |
|||
|
|||
/// ok
|
|||
uint32_t zip_short_code(uint64_t common_code); |
|||
/// ok
|
|||
uint64_t unzip_short_code(uint32_t short_code); |
|||
|
|||
/// ok
|
|||
static std::string code_to_string(uint32_t short_code); |
|||
static uint32_t code_from_string(const std::string &short_code); |
|||
|
|||
private: |
|||
/// ok
|
|||
static const uint32_t SHORT_CODE_LIMIT = 29334498; |
|||
|
|||
/// ok
|
|||
std::vector<uint32_t> basic_ranges; |
|||
std::vector<uint64_t> all_cases_list; // short_code -> common_code
|
|||
std::unordered_map<uint64_t, uint32_t> all_cases_dict; // common_code -> short_code
|
|||
|
|||
/// ok
|
|||
void build_mappings(); |
|||
enum Mode check_mode(); |
|||
void build_base_ranges(); |
|||
|
|||
/// ok
|
|||
uint64_t tiny_decode(uint32_t short_code); |
|||
uint32_t tiny_encode(uint64_t common_code); |
|||
}; |
Loading…
Reference in new issue