diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 49e1e6e..f05c911 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -9,6 +9,7 @@ set(KLOTSKI_CORE_SRC common_code/internal/common_code.cc common_code/internal/serialize.cc + common_code/internal/mirror.cc raw_code/internal/raw_code.cc raw_code/internal/convert.cc diff --git a/src/core/benchmark/codec.cc b/src/core/benchmark/codec.cc index b979f2f..8feff16 100644 --- a/src/core/benchmark/codec.cc +++ b/src/core/benchmark/codec.cc @@ -243,13 +243,32 @@ static void CommonCodeToShortCode(benchmark::State &state) { } } +static void IsMirrorCompare(benchmark::State &state) { + + std::vector samples; + for (auto common_code : common_code_samples(512)) { + samples.emplace_back(CommonCode::unsafe_create(common_code)); + } + + for (auto _ : state) { + for (auto code : samples) { + auto raw_code = code.to_raw_code(); + volatile auto ret = raw_code.is_horizontal_mirror(); + + // volatile auto ret = CommonCode::is_mirror(code.unwrap()); + } + } +} + // BENCHMARK(CommonCodeSerialize)->Range(8, 256); // BENCHMARK(CommonCodeDeserialize)->Range(8, 256); // BENCHMARK(CommonCodeSerializeShorten)->Range(8, 256); // BENCHMARK(CommonCodeDeserializeShorten)->Range(8, 256); -BENCHMARK(ShortCodeSerialize)->Range(8, 256); -BENCHMARK(ShortCodeDeserialize)->Range(8, 256); +// BENCHMARK(ShortCodeSerialize)->Range(8, 256); +// BENCHMARK(ShortCodeDeserialize)->Range(8, 256); + +BENCHMARK(IsMirrorCompare); // BENCHMARK(ShortCodeToCommonCode); // BENCHMARK(CommonCodeToShortCode); diff --git a/src/core/common_code/common_code.h b/src/core/common_code/common_code.h index fba9aa6..538422d 100644 --- a/src/core/common_code/common_code.h +++ b/src/core/common_code/common_code.h @@ -149,6 +149,8 @@ public: // ------------------------------------------------------------------------------------- // + static bool is_mirror(uint64_t common_code); + private: uint64_t code_; @@ -166,12 +168,6 @@ private: // ------------------------------------------------------------------------------------- // }; -// Ref: https://cplusplus.github.io/CWG/issues/1734.html - -// TODO: By definition, the default constructor is deleted, it is not trivial. -// TODO: But in clang and g++, it is legal, but in msvc it fails. -static_assert(std::is_trivial_v); - static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); diff --git a/src/core/common_code/internal/mirror.cc b/src/core/common_code/internal/mirror.cc new file mode 100644 index 0000000..03a350d --- /dev/null +++ b/src/core/common_code/internal/mirror.cc @@ -0,0 +1,154 @@ +#include +#include + +#include "common_code/common_code.h" + +using klotski::codec::CommonCode; + +bool CommonCode::is_mirror(uint64_t common_code) { + + int head = common_code >> 32; + uint32_t ranges = range_reverse(common_code); + + // std::cout << "head = " << head << std::endl; + // std::cout << "ranges = " << std::format("{:08X}", ranges) << std::endl; + + if (head % 4 != 1) { + return false; + } + + std::array state {}; // mark emtry/half-full + + if (head == 1) { + state.at(0) = true; + state.at(1) = true; + } else if (head == 5) { + state.at(1) = true; + state.at(2) = true; + } else if (head == 9) { + state.at(2) = true; + state.at(3) = true; + } else if (head == 13) { + state.at(3) = true; + state.at(4) = true; + } + + int working_line = 0; + + while (1 == 1) { + + if (working_line > 4) { + // std::cout << "reach end line" << std::endl; + break; + } + + // std::cout << std::endl; + // std::cout << "working_line: " << working_line << std::endl; + // std::cout << "state: " << std::format("{}", state) << std::endl; + + if (!state.at(working_line)) { // empty line + // std::cout << "empty working line" << std::endl; + + /// simple single line + bool is_single_line = false; + if ((ranges & 0b1111) == 0b0101) { + ranges >>= 4; + is_single_line = true; + } else { + auto tmp = ranges & 0b111111; + if (tmp == 0b110111 || tmp == 0b000100) { + ranges >>= 6; + is_single_line = true; + } else { + auto tmp_ = ranges & 0b11111111; + if (tmp_ == 0b00000000 || tmp_ == 0b11111111 || tmp_ == 0b00111100 || tmp_ == 0b11000011) { + ranges >>= 8; + is_single_line = true; + } + } + } + if (is_single_line) { + // std::cout << "simple single line" << std::endl; + ++working_line; // next line + continue; + } + + /// half-double line + bool is_half_double_line = false; + if ((ranges & 0b111111) == 0b100110) { + ranges >>= 6; + is_half_double_line = true; + } else { + auto tmp = ranges & 0b11111111; + if (tmp == 0b10111110 || tmp == 0b11101011 || tmp == 0b00101000 || tmp == 0b10000010) { + ranges >>= 8; + is_half_double_line = true; + } + } + if (is_half_double_line) { + // std::cout << "half double line" << std::endl; + if (state.at(working_line + 1)) { + working_line += 2; // next 2 lines + } else { + state.at(working_line + 1) = true; + ++working_line; // next line + } + continue; + } + + /// full-double line + if ((ranges & 0b11111111) == 0b10101010) { + // std::cout << "full double line" << std::endl; + ranges >>= 8; + working_line += 2; + continue; + } + + // std::cout << "not mirror layout" << std::endl; + return false; + + } else { // half-full line + + // std::cout << "half-full working line" << std::endl; + + /// simple single line + bool is_simple_line = false; + if ((ranges & 0b11) == 0b01) { + ranges >>= 2; + is_simple_line = true; + } else { + auto tmp = ranges & 0b1111; + + if (tmp == 0b0000 || tmp == 0b1111) { + ranges >>= 4; + is_simple_line = true; + } + } + if (is_simple_line) { + // std::cout << "simple single line" << std::endl; + ++working_line; + continue; + } + + /// half-double line + if ((ranges & 0b1111) == 0b1010) { + // std::cout << "half double line" << std::endl; + ranges >>= 4; + if (state.at(working_line + 1)) { + working_line += 2; // next 2 lines + } else { + state.at(working_line + 1) = true; + ++working_line; // next line + } + continue; + } + + // std::cout << "not mirror layout" << std::endl; + return false; + + } + + } + + return true; +} diff --git a/src/core/main.cc b/src/core/main.cc index 380e3b7..ac46434 100644 --- a/src/core/main.cc +++ b/src/core/main.cc @@ -40,7 +40,29 @@ int main() { const auto start = std::chrono::system_clock::now(); - GroupCases::from_info_t({169, 1, 7472}); + // auto ret = CommonCode::is_mirror(0x1A9BF0C00); + // auto ret = CommonCode::is_mirror(0x4FEA13400); + // auto ret = CommonCode::is_mirror(0x100AA0300); + // auto ret = CommonCode::is_mirror(0x5000A0000); + // std::cout << "ret = " << ret << std::endl; + + // auto raw_code = CommonCode::unsafe_create(0x1A9BF0C00).to_raw_code(); + // std::cout << raw_code.is_horizontal_mirror() << std::endl; + + // for (auto common_code : AllCases::instance().fetch().codes()) { + // auto raw_code = common_code.to_raw_code(); + // + // bool r1 = raw_code.is_horizontal_mirror(); + // bool r2 = CommonCode::is_mirror(common_code.unwrap()); + // + // if (r1 != r2) { + // std::cout << "found invalid" << std::endl; + // std::cout << common_code << std::endl; + // break; + // } + // } + + // GroupCases::from_info_t({169, 1, 7472}); // GroupCases::to_info_t(CommonCode::unsafe_create(0x1A9BF0C00).to_short_code());