diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt index 30c7ffb..dd5ff1a 100644 --- a/src/core_test/CMakeLists.txt +++ b/src/core_test/CMakeLists.txt @@ -42,7 +42,6 @@ add_test(NAME klotski_ffi COMMAND test_klotski_ffi) # ------------------------------------------------------------------------------------ # set(KLSK_TEST_CODEC_SRC - codec/mirror.cc codec/raw_code.cc codec/short_code.cc codec/common_code.cc diff --git a/src/core_test/codec/common_code.cc b/src/core_test/codec/common_code.cc index e6daf3a..2ee4636 100644 --- a/src/core_test/codec/common_code.cc +++ b/src/core_test/codec/common_code.cc @@ -22,19 +22,18 @@ TEST(CommonCode, basic) { EXPECT_NE(CommonCode::check(0x1'A9'BF'FC'00), true); // less than 2 space EXPECT_NE(CommonCode::check(0x1'A0'BF'0C'01), true); // low bits not fill zero - EXPECT_FALSE(CommonCode::create(0x123456789).has_value()); // invalid code EXPECT_FALSE(CommonCode::from_string("0123456789").has_value()); // length > 9 EXPECT_FALSE(CommonCode::from_string("123J432A9").has_value()); // with invalid `J` - EXPECT_FALSE(CommonCode::unsafe_create(TEST_MIRROR_1).is_vertical_mirror()); - EXPECT_TRUE(CommonCode::unsafe_create(TEST_MIRROR_1).is_horizontal_mirror()); - EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_1).to_vertical_mirror(), TEST_MIRROR_1_VM); - EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_1).to_horizontal_mirror(), TEST_MIRROR_1_HM); + EXPECT_FALSE(CommonCode::unsafe_create(TEST_MIRROR_C1).is_vertical_mirror()); + EXPECT_TRUE(CommonCode::unsafe_create(TEST_MIRROR_C1).is_horizontal_mirror()); + EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_C1).to_vertical_mirror(), TEST_MIRROR_C1_VM); + EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_C1).to_horizontal_mirror(), TEST_MIRROR_C1_HM); - EXPECT_FALSE(CommonCode::unsafe_create(TEST_MIRROR_2).is_vertical_mirror()); - EXPECT_FALSE(CommonCode::unsafe_create(TEST_MIRROR_2).is_horizontal_mirror()); - EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_2).to_vertical_mirror(), TEST_MIRROR_2_VM); - EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_2).to_horizontal_mirror(), TEST_MIRROR_2_HM); + EXPECT_FALSE(CommonCode::unsafe_create(TEST_MIRROR_C2).is_vertical_mirror()); + EXPECT_FALSE(CommonCode::unsafe_create(TEST_MIRROR_C2).is_horizontal_mirror()); + EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_C2).to_vertical_mirror(), TEST_MIRROR_C2_VM); + EXPECT_EQ(CommonCode::unsafe_create(TEST_MIRROR_C2).to_horizontal_mirror(), TEST_MIRROR_C2_HM); #ifndef KLSK_NDEBUG std::ostringstream out; diff --git a/src/core_test/codec/helper/codec.cc b/src/core_test/codec/helper/codec.cc index 19a2fc4..ea5617a 100644 --- a/src/core_test/codec/helper/codec.cc +++ b/src/core_test/codec/helper/codec.cc @@ -44,3 +44,27 @@ void common_code_parallel(std::function)> &&func) { pool.wait(); } + +static std::vector convert(const std::vector &codes) { + std::vector result; + result.reserve(29334498); + for (auto code : codes) { + result.emplace_back(RawCode::from_common_code(code)); + } + return result; +} + +void raw_code_parallel(std::function)> &&func) { + + static auto codes = convert(AllCases::instance().fetch().codes()); + + BS::thread_pool pool; + pool.detach_blocks((uint64_t)0, codes.size(), [func = std::move(func)](auto start, auto end) { + + func(std::span {codes.data() + start, end - start}); + + }, 16); + + pool.wait(); + +} diff --git a/src/core_test/codec/helper/codec.h b/src/core_test/codec/helper/codec.h index e836eb0..909ebe2 100644 --- a/src/core_test/codec/helper/codec.h +++ b/src/core_test/codec/helper/codec.h @@ -3,14 +3,17 @@ #include #include +#include "raw_code/raw_code.h" #include "all_cases/all_cases.h" #include "short_code/short_code.h" #include "common_code/common_code.h" using klotski::cases::AllCases; +using klotski::cases::ALL_CASES_NUM_; + +using klotski::codec::RawCode; using klotski::codec::ShortCode; using klotski::codec::CommonCode; -using klotski::cases::ALL_CASES_NUM_; /// Build all valid CommonCodes. std::vector all_common_codes(); @@ -18,6 +21,8 @@ std::vector all_common_codes(); /// Spawn all valid klotski headers in parallel. void head_parallel(std::function &&func); +void raw_code_parallel(std::function)> &&func); + void short_code_parallel(std::function)> &&func); void common_code_parallel(std::function)> &&func); diff --git a/src/core_test/codec/helper/sample.h b/src/core_test/codec/helper/sample.h index bba6be3..20f14d6 100644 --- a/src/core_test/codec/helper/sample.h +++ b/src/core_test/codec/helper/sample.h @@ -32,13 +32,23 @@ constexpr std::string_view TEST_C_CODE_STR_ERR = "0123456789"; // ----------------------------------------------------------------------------------------- // /// CommonCode with horizontal symmetry. -constexpr uint64_t TEST_MIRROR_1 = 0x1A9BF0C00; -constexpr uint64_t TEST_MIRROR_1_VM = 0xDC3BE6800; // vertical mirror -constexpr uint64_t TEST_MIRROR_1_HM = 0x1A9BF0C00; // horizontal mirror +constexpr uint64_t TEST_MIRROR_C1 = 0x1A9BF0C00; +constexpr uint64_t TEST_MIRROR_C1_VM = 0xDC3BE6800; // vertical mirror +constexpr uint64_t TEST_MIRROR_C1_HM = 0x1A9BF0C00; // horizontal mirror + +/// RawCode with horizontal symmetry. +constexpr uint64_t TEST_MIRROR_R1 = 0x0603EDF5'CAFFF5E2; +constexpr uint64_t TEST_MIRROR_R1_VM = 0x0FFF5E2F'CF4DA603; // vertical mirror +constexpr uint64_t TEST_MIRROR_R1_HM = 0x0603EDF5'CAFFF5E2; // horizontal mirror /// CommonCode without vertical or horizontal symmetry. -constexpr uint64_t TEST_MIRROR_2 = 0x4FEA13400; -constexpr uint64_t TEST_MIRROR_2_VM = 0x8346AFC00; // vertical mirror -constexpr uint64_t TEST_MIRROR_2_HM = 0x6BFA47000; // horizontal mirror +constexpr uint64_t TEST_MIRROR_C2 = 0x4FEA13400; +constexpr uint64_t TEST_MIRROR_C2_VM = 0x8346AFC00; // vertical mirror +constexpr uint64_t TEST_MIRROR_C2_HM = 0x6BFA47000; // horizontal mirror + +/// RawCode without vertical or horizontal symmetry. +constexpr uint64_t TEST_MIRROR_R2 = 0x0E58FC85'FFEBC4DB; +constexpr uint64_t TEST_MIRROR_R2_VM = 0x0EDB5FFE'BC5C8E58; // vertical mirror +constexpr uint64_t TEST_MIRROR_R2_HM = 0x00F91CFF'FAF176DA; // horizontal mirror // ----------------------------------------------------------------------------------------- // diff --git a/src/core_test/codec/mirror.cc b/src/core_test/codec/mirror.cc deleted file mode 100644 index 0f6fe70..0000000 --- a/src/core_test/codec/mirror.cc +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include - -#include "raw_code/raw_code.h" -#include "all_cases/all_cases.h" -#include "common_code/common_code.h" - -using klotski::codec::RawCode; -using klotski::cases::AllCases; - -TEST(RawCode, vertical_mirror) { - auto raw_code_a = RawCode::unsafe_create(0x0'FC0'480'6DB'FC0'480); // invalid case for test - auto raw_code_b1 = RawCode::from_common_code(0x4FEA13400).value(); - auto raw_code_b2 = RawCode::from_common_code(0x8346AFC00).value(); - - // EXPECT_TRUE(raw_code_a.is_vertical_mirror()); - // EXPECT_TRUE(raw_code_a.is_vertical_mirror(raw_code_a)); - EXPECT_EQ(raw_code_a.to_vertical_mirror(), raw_code_a); - - EXPECT_FALSE(raw_code_b1.is_vertical_mirror()); - EXPECT_FALSE(raw_code_b2.is_vertical_mirror()); - // EXPECT_TRUE(raw_code_b1.is_vertical_mirror(raw_code_b2)); - // EXPECT_TRUE(raw_code_b2.is_vertical_mirror(raw_code_b1)); - EXPECT_EQ(raw_code_b1.to_vertical_mirror(), raw_code_b2); - EXPECT_EQ(raw_code_b2.to_vertical_mirror(), raw_code_b1); - - // EXPECT_FALSE(raw_code_a.is_vertical_mirror(raw_code_b1)); - // EXPECT_FALSE(raw_code_a.is_vertical_mirror(raw_code_b2)); - // EXPECT_FALSE(raw_code_b1.is_vertical_mirror(raw_code_a)); - // EXPECT_FALSE(raw_code_b2.is_vertical_mirror(raw_code_a)); -} - -TEST(RawCode, horizontal_mirror) { - auto raw_code_a = RawCode::from_common_code(0x1A9BF0C00).value(); - auto raw_code_b1 = RawCode::from_common_code(0x4FEA13400).value(); - auto raw_code_b2 = RawCode::from_common_code(0x6BFA47000).value(); - - EXPECT_TRUE(raw_code_a.is_horizontal_mirror()); - // EXPECT_TRUE(raw_code_a.is_horizontal_mirror(raw_code_a)); - EXPECT_EQ(raw_code_a.to_horizontal_mirror(), raw_code_a); - - EXPECT_FALSE(raw_code_b1.is_horizontal_mirror()); - EXPECT_FALSE(raw_code_b2.is_horizontal_mirror()); - // EXPECT_TRUE(raw_code_b1.is_horizontal_mirror(raw_code_b2)); - // EXPECT_TRUE(raw_code_b2.is_horizontal_mirror(raw_code_b1)); - EXPECT_EQ(raw_code_b1.to_horizontal_mirror(), raw_code_b2); - EXPECT_EQ(raw_code_b2.to_horizontal_mirror(), raw_code_b1); - - // EXPECT_FALSE(raw_code_a.is_horizontal_mirror(raw_code_b1)); - // EXPECT_FALSE(raw_code_a.is_horizontal_mirror(raw_code_b2)); - // EXPECT_FALSE(raw_code_b1.is_horizontal_mirror(raw_code_a)); - // EXPECT_FALSE(raw_code_b2.is_horizontal_mirror(raw_code_a)); -} - -TEST(RawCode, code_vertical_mirror) { - auto test_func = [](RawCode code) { - auto mirror = code.to_vertical_mirror(); - EXPECT_TRUE(RawCode::check(mirror.unwrap())); - EXPECT_EQ(mirror.to_common_code().to_raw_code(), mirror); - EXPECT_EQ(mirror.to_vertical_mirror(), code); - EXPECT_FALSE(mirror.is_vertical_mirror()); - EXPECT_NE(code, mirror); - }; - - BS::thread_pool pool; - pool.detach_sequence(0, 16, [&test_func](const uint64_t head) { - for (const auto range : AllCases::instance().fetch()[head]) { - test_func(RawCode::from_common_code(head << 32 | range).value()); - } - }); - pool.wait(); -} - -TEST(RawCode, code_horizontal_mirror) { - auto test_func = [](RawCode code) { - auto mirror = code.to_horizontal_mirror(); - EXPECT_TRUE(RawCode::check(mirror.unwrap())); - EXPECT_EQ(mirror.to_common_code().to_raw_code(), mirror); - EXPECT_EQ(mirror.to_horizontal_mirror(), code); - if (mirror.is_horizontal_mirror()) { - EXPECT_EQ(code, mirror); - } else { - EXPECT_NE(code, mirror); - } - }; - - BS::thread_pool pool; - pool.detach_sequence(0, 16, [&test_func](const uint64_t head) { - for (const auto range : AllCases::instance().fetch()[head]) { - test_func(RawCode::from_common_code(head << 32 | range).value()); - } - }); - pool.wait(); -} diff --git a/src/core_test/codec/raw_code.cc b/src/core_test/codec/raw_code.cc index 82e5f02..2004396 100644 --- a/src/core_test/codec/raw_code.cc +++ b/src/core_test/codec/raw_code.cc @@ -16,21 +16,33 @@ using klotski::codec::CommonCode; using klotski::cases::AllCases; using klotski::cases::ALL_CASES_NUM_; -TEST(RawCode, validity) { +TEST(RawCode, basic) { EXPECT_FALSE(RawCode::check(0x0A34'182B'3810'2D21)); // invalid code EXPECT_FALSE(RawCode::check(0x8603'EDF5'CAFF'F5E2)); // high 4-bits not zero - EXPECT_FALSE(RawCode::create(0x0000'0000'0000'0000).has_value()); // invalid code + EXPECT_FALSE(RawCode::unsafe_create(TEST_MIRROR_R1).is_vertical_mirror()); + EXPECT_TRUE(RawCode::unsafe_create(TEST_MIRROR_R1).is_horizontal_mirror()); + EXPECT_EQ(RawCode::unsafe_create(TEST_MIRROR_R1).to_vertical_mirror(), TEST_MIRROR_R1_VM); + EXPECT_EQ(RawCode::unsafe_create(TEST_MIRROR_R1).to_horizontal_mirror(), TEST_MIRROR_R1_HM); - // TODO: add mirror test + EXPECT_FALSE(RawCode::unsafe_create(TEST_MIRROR_R2).is_vertical_mirror()); + EXPECT_FALSE(RawCode::unsafe_create(TEST_MIRROR_R2).is_horizontal_mirror()); + EXPECT_EQ(RawCode::unsafe_create(TEST_MIRROR_R2).to_vertical_mirror(), TEST_MIRROR_R2_VM); + EXPECT_EQ(RawCode::unsafe_create(TEST_MIRROR_R2).to_horizontal_mirror(), TEST_MIRROR_R2_HM); #ifndef KLSK_NDEBUG std::ostringstream out; out << RawCode::unsafe_create(TEST_R_CODE); // ostream capture - EXPECT_TRUE(out.str().starts_with("603EDF5CAFFF5E2\n")); // TODO: using full string + EXPECT_EQ(out.str(), "603EDF5CAFFF5E2\n| @ + | \n+ + + + \n| ~ + | \n+ * * + \n* . . * \n"); #endif } +TEST(RawCode, exporter) { + auto raw_code = RawCode::unsafe_create(TEST_R_CODE); + EXPECT_EQ(raw_code.unwrap(), TEST_R_CODE); + EXPECT_EQ(raw_code.to_common_code(), TEST_C_CODE); +} + TEST(RawCode, operators) { auto raw_code = RawCode::unsafe_create(TEST_R_CODE); EXPECT_EQ((uint64_t)raw_code, TEST_R_CODE); // uint64_t cast @@ -68,13 +80,7 @@ TEST(RawCode, operators) { EXPECT_GT(RawCode::unsafe_create(TEST_R_CODE + 1), raw_code); // RawCode > RawCode } -TEST(RawCode, exporter) { - auto raw_code = RawCode::unsafe_create(TEST_R_CODE); - EXPECT_EQ(raw_code.unwrap(), TEST_R_CODE); - EXPECT_EQ(raw_code.to_common_code(), TEST_C_CODE); -} - -TEST(RawCode, initializate) { +TEST(RawCode, initialize) { auto raw_code = RawCode::unsafe_create(TEST_R_CODE); auto common_code = CommonCode::unsafe_create(TEST_C_CODE); @@ -112,27 +118,41 @@ TEST(RawCode, initializate) { EXPECT_EQ(RawCode::from_common_code(TEST_C_CODE_STR), TEST_R_CODE); } -// TODO: global check function: -// -> check -// -> compact / extract -// -> check_mirror / get_vertical_mirror / get_horizontal_mirror - TEST(RawCode, code_verify) { - BS::thread_pool pool; - pool.detach_sequence(0, 16, [](const uint64_t head) { - for (const auto range : AllCases::instance().fetch()[head]) { - const auto code = RawCode::from_common_code(head << 32 | range); - EXPECT_TRUE(code.has_value()); - EXPECT_TRUE(RawCode::check(code->unwrap())); - EXPECT_EQ(code->to_common_code(), head << 32 | range); + raw_code_parallel([](std::span codes) { + for (auto code : codes) { + EXPECT_TRUE(RawCode::check(code.unwrap())); + const auto common_code = code.to_common_code(); // RawCode::compact + EXPECT_EQ(RawCode::from_common_code(common_code), code); // RawCode::extract + } + }); +} + +TEST(RawCode, code_mirror) { + raw_code_parallel([](std::span codes) { + for (auto code : codes) { + const auto mirror_v = code.to_vertical_mirror(); + EXPECT_TRUE(RawCode::check(mirror_v.unwrap())); + EXPECT_EQ(mirror_v.to_vertical_mirror(), code); + EXPECT_FALSE(mirror_v.is_vertical_mirror()); // not exist + EXPECT_NE(mirror_v, code); + + const auto mirror_h = code.to_horizontal_mirror(); + EXPECT_TRUE(RawCode::check(mirror_h.unwrap())); + EXPECT_EQ(mirror_h.to_horizontal_mirror(), code); + if (mirror_h.is_horizontal_mirror()) { + EXPECT_EQ(mirror_h, code); + } else { + EXPECT_NE(mirror_h, code); + } } }); - pool.wait(); } TEST(RawCode, DISABLED_global_verify) { - auto force_convert = [](uint64_t common_code) -> uint64_t { - auto range = range_reverse((uint32_t)common_code); + // convert to RawCode and ignore errors + static auto force_convert = +[](uint64_t common_code) -> uint64_t { + auto range = range_reverse(static_cast(common_code)); auto raw_code = K_MASK_2x2 << (common_code >> 32) * 3; for (int addr = 0; range; range >>= 2) { while ((raw_code >> addr) & 0b111 && addr < 60) // found next space @@ -150,14 +170,14 @@ TEST(RawCode, DISABLED_global_verify) { }; BS::thread_pool pool; - auto futures = pool.submit_blocks(0ULL, 0x10'0000'0000ULL, [&force_convert](uint64_t start, uint64_t end) { - std::vector archive; + auto futures = pool.submit_blocks(0ULL, 0x10'0000'0000ULL, [](auto start, auto end) { + std::vector codes; for (uint64_t common_code = start; common_code < end; ++common_code) { if (RawCode::check(force_convert(common_code))) { - archive.emplace_back(common_code); // store valid raw code + codes.emplace_back(common_code); // store valid raw code } } - return archive; + return codes; }, 0x1000); // split as 4096 pieces std::vector result;