diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d25c18..cdafd10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,4 +3,4 @@ project(klotski) set(CMAKE_CXX_STANDARD 14) -add_executable(klotski main.cpp) +add_executable(klotski main.cc case.cc common.cc klotski.cc) diff --git a/case.cpp b/case.cc similarity index 76% rename from case.cpp rename to case.cc index e685da8..83502e1 100644 --- a/case.cpp +++ b/case.cc @@ -1,66 +1,43 @@ -#include -#include +#include "case.h" +#include "common.h" #include -typedef __uint32_t uint32_t; -typedef __uint64_t uint64_t; +bool check_case(int head, uint32_t range); +void build_base_range(std::vector &base_range); +void gen_range(std::vector &release, int n1, int n2, int n3, int n4); -inline int binary_num(uint32_t binary, int length) { // get number of non-zero bit - int num = 0; - for (int i = 0; i < length; ++i) { - num += int((binary >> i) & 0x1); - } - return num; -} - -inline void binary_reverse(uint32_t &range) { // reverse binary every 2 bits - range = ((range << 16) & 0xFFFF0000) | ((range >> 16) & 0x0000FFFF); - range = ((range << 8) & 0xFF00FF00) | ((range >> 8) & 0x00FF00FF); - range = ((range << 4) & 0xF0F0F0F0) | ((range >> 4) & 0x0F0F0F0F); - range = ((range << 2) & 0xCCCCCCCC) | ((range >> 2) & 0x33333333); -} - -inline void binary_to_str(uint64_t binary, char *string) { - for (int i = 0; i < 9; ++i, ++string) { // only read low 9 * 4 bits - *string = int8_t(binary >> (8 - i) * 4 & 0xF); - if (*string < 10) { - *string += 48; // 0 -> 48 - } else { - *string += 55; // A -> 65 +void find_all_case(std::vector *all_case) { + all_case->clear(); + std::vector base_range; + build_base_range(base_range); + for (int head = 0; head < 16; ++head) { // address for 2x2 block + if (head % 4 != 3) { + uint64_t prefix = int64_t(head) << 32; + for (auto range : base_range) { // combine 2x2 address and range + if (check_case(head, range)) { + binary_reverse(range); + all_case->emplace_back(prefix | range); + } + } } } - string[9] = 0x0; // string ending } -bool check_case(int head, uint32_t range) { // whether case is valid - uint32_t status = 0x33 << head; - for (int addr = 0; range; range >>= 2) { - while (status >> addr & 0x1) { - ++addr; - } - switch (range & 0x3) { - case 0x0: // space - case 0x3: // 1x1 - if (addr > 19) { - return false; - } - status |= 0x1 << addr; - break; - case 0x1: // 1x2 - if (addr % 4 == 3 || addr > 18 || status >> (addr + 1) & 0x1) { - return false; - } - status |= 0x3 << addr; - break; - case 0x2: // 2x1 - if (addr > 15 || status >> (addr + 4) & 0x1) { - return false; - } - status |= 0x11 << addr; - break; +void build_base_range(std::vector &base_range) { + for (int n = 0; n <= 7; ++n) { // number of 1x2 and 2x1 block -> 0 ~ (20 - 4 - 2) / 2 + for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) { // number of 1x2 block + for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) { // number of 1x1 block + gen_range(base_range, (16 - n * 2 - n_1x1), (n - n_2x1), n_2x1, n_1x1); + } } } - return true; + for (auto &bin : base_range) { + binary_reverse(bin); + } + std::sort(base_range.begin(), base_range.end()); + for (auto &bin : base_range) { + binary_reverse(bin); + } } void gen_range(std::vector &release, int n1, int n2, int n3, int n4) { @@ -114,51 +91,33 @@ void gen_range(std::vector &release, int n1, int n2, int n3, int n4) { } } -void build_base_range(std::vector &base_range) { - for (int n = 0; n <= 7; ++n) { // number of 1x2 and 2x1 block -> 0 ~ (20 - 4 - 2) / 2 - for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) { // number of 1x2 block - for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) { // number of 1x1 block - gen_range(base_range, (16 - n * 2 - n_1x1), (n - n_2x1), n_2x1, n_1x1); - } +bool check_case(int head, uint32_t range) { // whether case is valid + uint32_t status = 0x33 << head; + for (int addr = 0; range; range >>= 2) { + while (status >> addr & 0x1) { + ++addr; } - } - for (auto &bin : base_range) { - binary_reverse(bin); - } - std::sort(base_range.begin(), base_range.end()); - for (auto &bin : base_range) { - binary_reverse(bin); - } -} - -void find_all_case(std::vector *all_case) { - all_case->clear(); - std::vector base_range; - build_base_range(base_range); - for (int head = 0; head < 16; ++head) { // address for 2x2 block - if (head % 4 != 3) { - uint64_t prefix = int64_t(head) << 32; - for (auto range : base_range) { // combine 2x2 address and range - if (check_case(head, range)) { - binary_reverse(range); - all_case->emplace_back(prefix | range); + switch (range & 0x3) { + case 0x0: // space + case 0x3: // 1x1 + if (addr > 19) { + return false; } - } + status |= 0x1 << addr; + break; + case 0x1: // 1x2 + if (addr % 4 == 3 || addr > 18 || status >> (addr + 1) & 0x1) { + return false; + } + status |= 0x3 << addr; + break; + case 0x2: // 2x1 + if (addr > 15 || status >> (addr + 4) & 0x1) { + return false; + } + status |= 0x11 << addr; + break; } } -} - -int main() { - std::vector all_case; - find_all_case(&all_case); - -// printf("count -> %lu\n", all_case.size()); - - for (auto code : all_case) { - char str[10]; - binary_to_str(code, str); - printf("%s\n", str); - } - - return 0; + return true; } diff --git a/case.h b/case.h new file mode 100644 index 0000000..8c65854 --- /dev/null +++ b/case.h @@ -0,0 +1,9 @@ +#ifndef _CASE_H_ +#define _CASE_H_ + +#include +#include + +void find_all_case(std::vector *all_case); + +#endif diff --git a/common.cc b/common.cc new file mode 100644 index 0000000..a009e0c --- /dev/null +++ b/common.cc @@ -0,0 +1,31 @@ +#include "common.h" + +//inline int binary_num(uint32_t binary, int length) { // get number of non-zero bit +int binary_num(uint32_t binary, int length) { // get number of non-zero bit + int num = 0; + for (int i = 0; i < length; ++i) { + num += int((binary >> i) & 0x1); + } + return num; +} + +//inline void binary_reverse(uint32_t &range) { // reverse binary every 2 bits +void binary_reverse(uint32_t &range) { // reverse binary every 2 bits + range = ((range << 16) & 0xFFFF0000) | ((range >> 16) & 0x0000FFFF); + range = ((range << 8) & 0xFF00FF00) | ((range >> 8) & 0x00FF00FF); + range = ((range << 4) & 0xF0F0F0F0) | ((range >> 4) & 0x0F0F0F0F); + range = ((range << 2) & 0xCCCCCCCC) | ((range >> 2) & 0x33333333); +} + +//inline void binary_to_str(uint64_t binary, char *string) { +void binary_to_str(uint64_t binary, char *string) { + for (int i = 0; i < 9; ++i, ++string) { // only read low 9 * 4 bits + *string = int8_t(binary >> (8 - i) * 4 & 0xF); + if (*string < 10) { + *string += 48; // 0 -> 48 + } else { + *string += 55; // A -> 65 + } + } + string[9] = 0x0; // string ending +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..0b2ad51 --- /dev/null +++ b/common.h @@ -0,0 +1,10 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include + +void binary_reverse(uint32_t &range); +int binary_num(uint32_t binary, int length); +void binary_to_str(uint64_t binary, char *string); + +#endif diff --git a/klotski b/klotski new file mode 100755 index 0000000..0a56628 Binary files /dev/null and b/klotski differ diff --git a/klotski.cc b/klotski.cc new file mode 100644 index 0000000..29f6746 --- /dev/null +++ b/klotski.cc @@ -0,0 +1,55 @@ +#include "common.h" +#include "klotski.h" + +uint64_t compact_code(uint64_t code) { + int block_num = 0; + uint64_t ret = 0; + uint32_t range = 0; + for (int addr = 0; code; ++addr, code >>= 3) { + switch (code & 0x7) { + case B_space: + range <<= 2; + break; + case B_1x2: + (range <<= 2) |= 0x1; + break; + case B_2x1: + (range <<= 2) |= 0x2; + break; + case B_1x1: + (range <<= 2) |= 0x3; + break; + case B_2x2: + ret |= uint64_t(addr) << 32; + default: + continue; + } + ++block_num; + } + return ret | range << (16 - block_num) * 2; +} + +uint64_t extract_code(uint64_t code) { + uint64_t ret = C_2x2 << (code >> 32) * 3; + auto range = uint32_t(code); + binary_reverse(range); + for (int addr = 0; range; range >>= 2) { + while (0x7 & ret >> addr) { + addr += 3; + } + switch (range & 0x3) { + case 0x1: + ret |= C_1x2 << addr; + break; + case 0x2: + ret |= C_2x1 << addr; + break; + case 0x3: + ret |= C_1x1 << addr; + break; + case 0x0: + addr += 3; + } + } + return ret; +} diff --git a/klotski.h b/klotski.h new file mode 100644 index 0000000..19c1230 --- /dev/null +++ b/klotski.h @@ -0,0 +1,73 @@ +#ifndef _KLOTSKI_H_ +#define _KLOTSKI_H_ + +#include + +#define B_space 0x0 +#define B_fill 0x7 +#define B_1x2 0x1 +#define B_2x1 0x2 +#define B_1x1 0x3 +#define B_2x2 0x4 + +#define C_1x1 int64_t(0x3) +#define C_1x2 int64_t(0x39) +#define C_2x1 int64_t(0x7002) +#define C_2x2 int64_t(0x3F03C) + +#define F_1x1 int64_t(0x7) +#define F_1x2 int64_t(0x3F) +#define F_2x1 int64_t(0x7007) +#define F_2x2 int64_t(0x3F03F) + +uint64_t compact_code(uint64_t code); +uint64_t extract_code(uint64_t code); + +#endif + +/* + + uint64_t -> 0000 + [xxx] * 20 + + 2x2 2x1 1x2 1x1 + # # # # # # + # # # + + 00 01 02 03 + 04 05 06 07 + 08 09 10 11 + 12 13 14 15 + 16 17 18 19 + + x1 (%4) => 0 1 2 3 + x3 (%4) => 0 3 2 1 + +*/ + +/* +====================================================== + + 1x1 -> 011 000 000 000 -> 0000 0000 0011 -> 0x3 + + 1x2 -> 001 111 000 000 -> 0000 0011 1001 -> 0x39 + + 2x1 -> 010 000 000 000 -> 0000 0000 0010 -> 0x7002 + 111 000 000 000 -> 0000 0000 0111 + + 2x2 -> 100 111 000 000 -> 0000 0011 1100 -> 0x3F03C + 111 111 000 000 -> 0000 0011 1111 + +====================================================== + + 1x1 -> 111 000 000 000 -> 0000 0000 0111 -> 0x7 + + 1x2 -> 111 111 000 000 -> 0000 0011 1111 -> 0x3F + + 2x1 -> 111 000 000 000 -> 0000 0000 0111 -> 0x7007 + 111 000 000 000 -> 0000 0000 0111 + + 2x2 -> 111 111 000 000 -> 0000 0011 1111 -> 0x3F03F + 111 111 000 000 -> 0000 0011 1111 + +====================================================== +*/ diff --git a/main.cc b/main.cc new file mode 100644 index 0000000..93eaa20 --- /dev/null +++ b/main.cc @@ -0,0 +1,84 @@ +#include "case.h" +#include "klotski.h" +#include +#include +#include + +void graph_output(uint64_t code) { + for (int i = 0; i < 20; ++i) { + switch (code & 0x7) { + case B_1x1: + printf("# "); + break; + case B_1x2: + printf("& "); + break; + case B_2x1: + printf("$ "); + break; + case B_2x2: + printf("@ "); + break; + case B_fill: + printf("* "); + break; + case B_space: + printf(". "); + break; + default: + printf("? "); + } + if ((i & 0x3) == 0x3) { + printf("\n"); + } + code >>= 3; + } +} + +int main() { + printf("Klotski engine\n"); + +// printf("%lx\n", compact_code(0x0E58FC85FFEBC4DB)); +// printf("%lx\n", compact_code(0x0603EDF5CAFFF5E2)); + +// graph_output(extract_code(0x4FEA13400)); +// printf("\n"); +// graph_output(extract_code(0x1A9BF0C00)); +// printf("\n"); + + std::vector all_case; + find_all_case(&all_case); + printf("count -> %lu\n", all_case.size()); + + for (auto code : all_case) { + if (code != compact_code(extract_code(code))) { + printf("error -> %lx\n", code); + } + } + + return 0; + + // 0x4FEA13400 + // # # # @ | 011 011 011 010 => 0100 1101 1011 -> 4DB + // * * & @ | 100 111 010 111 => 1110 1011 1100 -> EBC + // * * & $ | 111 111 111 010 => 0101 1111 1111 -> 5FF + // . + + $ | 000 001 111 111 => 1111 1100 1000 -> FC8 + // . # ~ ~ | 000 011 001 111 => 1110 0101 1000 -> E58 + // 0x0E58FC85FFEBC4DB + + graph_output(0x0E58FC85FFEBC4DB); + printf("\n"); + + // 0x1A9BF0C00 + // @ * * @ | 010 100 111 010 => 0101 1110 0010 -> 5E2 + // @ * * @ | 111 111 111 111 => 1111 1111 1111 -> FFF + // $ ~ ~ $ | 010 001 111 010 => 0101 1100 1010 -> 5CA + // $ # # $ | 111 011 011 111 => 1110 1101 1111 -> EDF + // # . . # | 011 000 000 011 => 0110 0000 0011 -> 603 + // 0x0603EDF5CAFFF5E2 + + graph_output(0x0603EDF5CAFFF5E2); + printf("\n"); + + return 0; +} diff --git a/main.cpp b/main.cpp deleted file mode 100644 index a1e349d..0000000 --- a/main.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include - -#define B_space 0x0 -#define B_fill 0x7 -#define B_1x2 0x1 -#define B_2x1 0x2 -#define B_1x1 0x3 -#define B_2x2 0x4 - -#define C_1x1 int64_t(0x3) -#define C_1x2 int64_t(0x39) -#define C_2x1 int64_t(0x7002) -#define C_2x2 int64_t(0x3F03C) - -#define F_1x1 int64_t(0x7) -#define F_1x2 int64_t(0x3F) -#define F_2x1 int64_t(0x7007) -#define F_2x2 int64_t(0x3F03F) - -/* - - uint64_t -> 0000 + [xxx] * 20 - - 2x2 2x1 1x2 1x1 - # # # # # # - # # # - - 00 01 02 03 - 04 05 06 07 - 08 09 10 11 - 12 13 14 15 - 16 17 18 19 - - x1 (%4) => 0 1 2 3 - x3 (%4) => 0 3 2 1 - -*/ - -/* -====================================================== - - 1x1 -> 011 000 000 000 -> 0000 0000 0011 -> 0x3 - - 1x2 -> 001 111 000 000 -> 0000 0011 1001 -> 0x39 - - 2x1 -> 010 000 000 000 -> 0000 0000 0010 -> 0x7002 - 111 000 000 000 -> 0000 0000 0111 - - 2x2 -> 100 111 000 000 -> 0000 0011 1100 -> 0x3F03C - 111 111 000 000 -> 0000 0011 1111 - -====================================================== - - 1x1 -> 111 000 000 000 -> 0000 0000 0111 -> 0x7 - - 1x2 -> 111 111 000 000 -> 0000 0011 1111 -> 0x3F - - 2x1 -> 111 000 000 000 -> 0000 0000 0111 -> 0x7007 - 111 000 000 000 -> 0000 0000 0111 - - 2x2 -> 111 111 000 000 -> 0000 0011 1111 -> 0x3F03F - 111 111 000 000 -> 0000 0011 1111 - -====================================================== -*/ - -void graph_output(uint64_t code) { - for (int i = 0; i < 20; ++i) { - switch (code & 0x7) { - case B_1x1: - printf("# "); - break; - case B_1x2: - printf("& "); - break; - case B_2x1: - printf("$ "); - break; - case B_2x2: - printf("@ "); - break; - case B_fill: - printf("* "); - break; - case B_space: - printf(". "); - break; - default: - printf("? "); - } - if ((i & 0x3) == 0x3) { - printf("\n"); - } - code >>= 3; - } -} - -uint64_t compact_code(uint64_t code) { - int block_num = 0; - uint64_t ret = 0; - uint32_t range = 0; - for (int addr = 0; code; ++addr, code >>= 3) { - switch (code & 0x7) { - case B_space: - range <<= 2; - break; - case B_1x2: - (range <<= 2) |= 0x1; - break; - case B_2x1: - (range <<= 2) |= 0x2; - break; - case B_1x1: - (range <<= 2) |= 0x3; - break; - case B_2x2: - ret |= uint64_t(addr) << 32; - default: - continue; - } - ++block_num; - } - return ret | range << (16 - block_num) * 2; -} - -inline void binary_reverse(uint32_t &range) { // reverse binary every 2 bits - range = ((range << 16) & 0xFFFF0000) | ((range >> 16) & 0x0000FFFF); - range = ((range << 8) & 0xFF00FF00) | ((range >> 8) & 0x00FF00FF); - range = ((range << 4) & 0xF0F0F0F0) | ((range >> 4) & 0x0F0F0F0F); - range = ((range << 2) & 0xCCCCCCCC) | ((range >> 2) & 0x33333333); -} - -uint64_t extract_code(uint64_t code) { - uint64_t ret = C_2x2 << (code >> 32) * 3; - auto range = uint32_t(code); - binary_reverse(range); - for (int addr = 0; range; range >>= 2) { - while (0x7 & ret >> addr) { - addr += 3; - } - switch (range & 0x3) { - case 0x1: - ret |= C_1x2 << addr; - break; - case 0x2: - ret |= C_2x1 << addr; - break; - case 0x3: - ret |= C_1x1 << addr; - break; - case 0x0: - addr += 3; - } - } - return ret; -} - -int main() { - printf("Klotski engine\n"); - -// printf("%lx\n", compact_code(0x0E58FC85FFEBC4DB)); -// printf("%lx\n", compact_code(0x0603EDF5CAFFF5E2)); - - graph_output(extract_code(0x4FEA13400)); - printf("\n"); - graph_output(extract_code(0x1A9BF0C00)); - printf("\n"); - - return 0; - - // 0x4FEA13400 - // # # # @ | 011 011 011 010 => 0100 1101 1011 -> 4DB - // * * & @ | 100 111 010 111 => 1110 1011 1100 -> EBC - // * * & $ | 111 111 111 010 => 0101 1111 1111 -> 5FF - // . + + $ | 000 001 111 111 => 1111 1100 1000 -> FC8 - // . # ~ ~ | 000 011 001 111 => 1110 0101 1000 -> E58 - // 0x0E58FC85FFEBC4DB - - graph_output(0x0E58FC85FFEBC4DB); - printf("\n"); - - // 0x1A9BF0C00 - // @ * * @ | 010 100 111 010 => 0101 1110 0010 -> 5E2 - // @ * * @ | 111 111 111 111 => 1111 1111 1111 -> FFF - // $ ~ ~ $ | 010 001 111 010 => 0101 1100 1010 -> 5CA - // $ # # $ | 111 011 011 111 => 1110 1101 1111 -> EDF - // # . . # | 011 000 000 011 => 0110 0000 0011 -> 603 - // 0x0603EDF5CAFFF5E2 - - graph_output(0x0603EDF5CAFFF5E2); - printf("\n"); - - return 0; -}