diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e7ebcd8..c24ee9e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -11,10 +11,10 @@ set(KLOTSKI_CORE_SRC common_code/internal/serialize.cc common_code/internal/sundry.cc - raw_code/raw_code.cc - raw_code/convert.cc - raw_code/sundry.cc - raw_code/mirror.cc + raw_code/internal/raw_code.cc + raw_code/internal/convert.cc + raw_code/internal/sundry.cc + raw_code/internal/mirror.cc short_code/convert.cc short_code/serialize.cc diff --git a/src/core/raw_code/inline_impl.h b/src/core/raw_code/inline_impl.h deleted file mode 100644 index ca6d9a6..0000000 --- a/src/core/raw_code/inline_impl.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -namespace klotski { -namespace codec { - -/// Get the original 64-bit code. -inline uint64_t RawCode::unwrap() const noexcept { - return code_; -} - -/// Implicit conversion to 64-bit code. -inline RawCode::operator uint64_t() const noexcept { - return code_; -} - -/// Equality comparison between RawCode and numbers. -inline bool operator==(RawCode r1, uint64_t r2) noexcept { - return r1.unwrap() == r2; -} - -/// RawCode equal comparison implement. -inline bool operator==(RawCode r1, RawCode r2) noexcept { - return r1.unwrap() == r2.unwrap(); -} - -/// RawCode create without any check. -inline RawCode RawCode::unsafe_create(uint64_t raw_code) noexcept { - return *reinterpret_cast(&raw_code); // init directly -} - -/// RawCode create with valid check. -inline std::optional RawCode::create(uint64_t raw_code) noexcept { - if (!RawCode::check(raw_code)) { - return std::nullopt; // invalid raw code - } - return RawCode::unsafe_create(raw_code); -} - -/// Calculate vertically symmetrical case. -inline RawCode RawCode::to_vertical_mirror() const noexcept { - return RawCode::unsafe_create(get_vertical_mirror(code_)); -} - -/// Calculate horizontally symmetrical case. -inline RawCode RawCode::to_horizontal_mirror() const noexcept { - return RawCode::unsafe_create(get_horizontal_mirror(code_)); -} - -/// Determine whether the case is vertically symmetrical. -inline bool RawCode::is_vertical_mirror() const noexcept { - return check_vertical_mirror(code_); -} - -/// Determine whether the case is horizontally symmetrical. -inline bool RawCode::is_horizontal_mirror() const noexcept { - return check_horizontal_mirror(code_); -} - -/// Determine whether two cases are vertically symmetrical to each other. -inline bool RawCode::is_vertical_mirror(RawCode raw_code) const noexcept { - return raw_code.code_ == get_vertical_mirror(code_); -} - -/// Determine whether two cases are horizontally symmetrical to each other. -inline bool RawCode::is_horizontal_mirror(RawCode raw_code) const noexcept { - return raw_code.code_ == get_horizontal_mirror(code_); -} - -} // namespace codec -} // namespace klotski diff --git a/src/core/raw_code/convert.cc b/src/core/raw_code/internal/convert.cc similarity index 84% rename from src/core/raw_code/convert.cc rename to src/core/raw_code/internal/convert.cc index e5c05e3..1b39f4a 100644 --- a/src/core/raw_code/convert.cc +++ b/src/core/raw_code/internal/convert.cc @@ -1,12 +1,10 @@ -#include "common.h" -#include "utility.h" -#include "raw_code.h" +#include "utils/common.h" +#include "utils/utility.h" +#include "raw_code/raw_code.h" -namespace klotski { -namespace codec { +namespace klotski::codec { -/// Convert RawCode to CommonCode. -uint64_t RawCode::compact(uint64_t raw_code) noexcept { +uint64_t RawCode::compact(uint64_t raw_code) { int unfilled = 16; uint64_t head = 0; // 2x2 block address uint32_t range = 0; @@ -34,8 +32,7 @@ uint64_t RawCode::compact(uint64_t raw_code) noexcept { return head | (range << (unfilled << 1)); // fill low bits as zero } -/// Convert CommonCode to RawCode. -uint64_t RawCode::extract(uint64_t common_code) noexcept { +uint64_t RawCode::extract(uint64_t common_code) { auto code = K_MASK_2x2 << (common_code >> 32) * 3; // flag for 2x2 block auto range = range_reverse((uint32_t)common_code); // reversed range @@ -61,5 +58,4 @@ uint64_t RawCode::extract(uint64_t common_code) noexcept { return code; } -} // namespace codec -} // namespace klotski +} // namespace klotski::codec diff --git a/src/core/raw_code/mirror.cc b/src/core/raw_code/internal/mirror.cc similarity index 91% rename from src/core/raw_code/mirror.cc rename to src/core/raw_code/internal/mirror.cc index 06a7aaf..e3615b0 100644 --- a/src/core/raw_code/mirror.cc +++ b/src/core/raw_code/internal/mirror.cc @@ -1,8 +1,7 @@ -#include "common.h" -#include "raw_code.h" +#include "utils/common.h" +#include "raw_code/raw_code.h" -namespace klotski { -namespace codec { +namespace klotski::codec { // ----------------------------------------------------------------------------------------- // @@ -87,7 +86,7 @@ inline static void horizontal_clear(uint64_t &raw_code) { // ----------------------------------------------------------------------------------------- // -uint64_t RawCode::get_vertical_mirror(uint64_t raw_code) noexcept { +uint64_t RawCode::get_vertical_mirror(uint64_t raw_code) { vertical_fill(raw_code); raw_code = (raw_code & MASK_MIRROR_V3) | ((raw_code >> 48) & MASK_MIRROR_V1) | ((raw_code >> 24) & MASK_MIRROR_V2) @@ -96,7 +95,7 @@ uint64_t RawCode::get_vertical_mirror(uint64_t raw_code) noexcept { return raw_code; } -uint64_t RawCode::get_horizontal_mirror(uint64_t raw_code) noexcept { +uint64_t RawCode::get_horizontal_mirror(uint64_t raw_code) { horizontal_fill(raw_code); raw_code = ((raw_code >> 9) & MASK_MIRROR_H1) | ((raw_code >> 3) & MASK_MIRROR_H2) | ((raw_code & MASK_MIRROR_H2) << 3) | ((raw_code & MASK_MIRROR_H1) << 9); // flip raw code @@ -104,13 +103,13 @@ uint64_t RawCode::get_horizontal_mirror(uint64_t raw_code) noexcept { return raw_code; } -bool RawCode::check_vertical_mirror(uint64_t raw_code) noexcept { +bool RawCode::check_vertical_mirror(uint64_t raw_code) { vertical_fill(raw_code); return !(MASK_MIRROR_V1 & ((raw_code >> 48) ^ raw_code)) && !(MASK_MIRROR_V2 & ((raw_code >> 24) ^ raw_code)); } -bool RawCode::check_horizontal_mirror(uint64_t raw_code) noexcept { +bool RawCode::check_horizontal_mirror(uint64_t raw_code) { horizontal_fill(raw_code); return !(MASK_MIRROR_H1 & ((raw_code >> 9) ^ raw_code)) && !(MASK_MIRROR_H2 & ((raw_code >> 3) ^ raw_code)); @@ -118,5 +117,4 @@ bool RawCode::check_horizontal_mirror(uint64_t raw_code) noexcept { // ----------------------------------------------------------------------------------------- // -} // namespace codec -} // namespace klotski +} // namespace klotski::codec diff --git a/src/core/raw_code/raw_code.cc b/src/core/raw_code/internal/raw_code.cc similarity index 84% rename from src/core/raw_code/raw_code.cc rename to src/core/raw_code/internal/raw_code.cc index d1ec6ea..06d8eaf 100644 --- a/src/core/raw_code/raw_code.cc +++ b/src/core/raw_code/internal/raw_code.cc @@ -1,18 +1,18 @@ -#include "common.h" -#include "raw_code.h" +#include "utils/common.h" +#include "raw_code/raw_code.h" -namespace klotski { -namespace codec { +namespace klotski::codec { -// TODO: only for debug usage. -std::ostream& operator<<(std::ostream &out, RawCode self) { +std::ostream& operator<<(std::ostream &out, const RawCode self) { char *code; asprintf(&code, "%015llX\n", self.code_); // code length -> 15 out << code; free(code); - /// 0x0 1x2 2x1 1x1 2x2 b101 b110 fill - char map[] = {'.', '~', '|', '*', '@', '?', '?', '+'}; + constexpr char map[] = { + // 0x0 1x2 2x1 1x1 2x2 b101 b110 fill + '.', '~', '|', '*', '@', '?', '?', '+' + }; for (int addr = 0; addr < 60; addr += 3) { out << map[(self.code_ >> addr) & 0b111]; out << " " << &"\n"[(addr & 0b11) != 0b01]; @@ -20,8 +20,7 @@ std::ostream& operator<<(std::ostream &out, RawCode self) { return out; } -/// Check the validity of the original RawCode. -bool RawCode::check(uint64_t raw_code) noexcept { +bool RawCode::check(uint64_t raw_code) { /// MASK_1x1 | MASK_1x2 | MASK_2x1 | MASK_2x2 /// 100 000 000 000 | 000 100 000 000 | 000 000 000 000 | 000 100 000 000 /// 000 000 000 000 | 000 000 000 000 | 100 000 000 000 | 100 100 000 000 @@ -70,5 +69,4 @@ bool RawCode::check(uint64_t raw_code) noexcept { return head_num == 1 && space_num >= 2; // one head and at least 2 space } -} // namespace codec -} // namespace klotski +} // namespace klotski::codec diff --git a/src/core/raw_code/internal/raw_code.inl b/src/core/raw_code/internal/raw_code.inl new file mode 100644 index 0000000..c7b2934 --- /dev/null +++ b/src/core/raw_code/internal/raw_code.inl @@ -0,0 +1,76 @@ +#pragma once + +#include + +namespace klotski::codec { + +// ------------------------------------------------------------------------------------- // + +inline uint64_t RawCode::unwrap() const { + return code_; +} + +inline RawCode::operator uint64_t() const { + return code_; +} + +// ------------------------------------------------------------------------------------- // + +constexpr auto operator==(const RawCode &lhs, const uint64_t rhs) { + return lhs.code_ == rhs; +} + +constexpr auto operator<=>(const RawCode &lhs, const uint64_t rhs) { + return lhs.code_ <=> rhs; +} + +constexpr auto operator==(const RawCode &lhs, const RawCode &rhs) { + return lhs.code_ == rhs.code_; +} + +constexpr auto operator<=>(const RawCode &lhs, const RawCode &rhs) { + return lhs.code_ <=> rhs.code_; +} + +// ------------------------------------------------------------------------------------- // + +inline RawCode RawCode::unsafe_create(const uint64_t raw_code) { + return std::bit_cast(raw_code); // init directly +} + +inline std::optional RawCode::create(const uint64_t raw_code) { + if (!check(raw_code)) { + return std::nullopt; // invalid raw code + } + return unsafe_create(raw_code); +} + +// ------------------------------------------------------------------------------------- // + +inline bool RawCode::is_vertical_mirror() const { + return check_vertical_mirror(code_); +} + +inline bool RawCode::is_horizontal_mirror() const { + return check_horizontal_mirror(code_); +} + +inline RawCode RawCode::to_vertical_mirror() const { + return unsafe_create(get_vertical_mirror(code_)); +} + +inline RawCode RawCode::to_horizontal_mirror() const { + return unsafe_create(get_horizontal_mirror(code_)); +} + +inline bool RawCode::is_vertical_mirror(const RawCode raw_code) const { + return raw_code.code_ == get_vertical_mirror(code_); +} + +inline bool RawCode::is_horizontal_mirror(const RawCode raw_code) const { + return raw_code.code_ == get_horizontal_mirror(code_); +} + +// ------------------------------------------------------------------------------------- // + +} // namespace klotski::codec diff --git a/src/core/raw_code/internal/sundry.cc b/src/core/raw_code/internal/sundry.cc new file mode 100644 index 0000000..376cd60 --- /dev/null +++ b/src/core/raw_code/internal/sundry.cc @@ -0,0 +1,40 @@ +#include "raw_code.h" +#include "common_code.h" + +namespace klotski::codec { + +// ----------------------------------------------------------------------------------------- // + +RawCode::RawCode(const CommonCode common_code) { + code_ = extract(common_code.unwrap()); +} + +// ----------------------------------------------------------------------------------------- // + +CommonCode RawCode::to_common_code() const { + return CommonCode::unsafe_create(compact(code_)); +} + +// ----------------------------------------------------------------------------------------- // + +RawCode RawCode::from_common_code(const CommonCode common_code) { + return common_code.to_raw_code(); +} + +std::optional RawCode::from_common_code(const uint64_t common_code) { + auto convert = [](const CommonCode code) { + return code.to_raw_code(); + }; + return CommonCode::create(common_code).transform(convert); +} + +std::optional RawCode::from_common_code(const std::string &common_code) { + auto convert = [](const CommonCode code) { + return code.to_raw_code(); + }; + return CommonCode::from_string(common_code).transform(convert); +} + +// ----------------------------------------------------------------------------------------- // + +} // namespace klotski::codec diff --git a/src/core/raw_code/raw_code.h b/src/core/raw_code/raw_code.h index 71f87b9..3fc1877 100644 --- a/src/core/raw_code/raw_code.h +++ b/src/core/raw_code/raw_code.h @@ -1,4 +1,4 @@ -#pragma once +/// Klotski Engine by Dnomd343 @2024 /// RawCode is an uncompressed klotski coding scheme, which is used for program /// calculation. It encodes the `5x4` chessboard as 0 ~ 19, and using 3-bit to @@ -59,59 +59,125 @@ /// RawCode => 0x0E58'FC85'FFEB'C4DB /// /// -------------------------------------------------------------------------------------------------- /// +#pragma once + #include #include #include #include -namespace klotski { -namespace codec { +namespace klotski::codec { class CommonCode; + class RawCode { public: - explicit operator uint64_t() const noexcept; - static bool check(uint64_t raw_code) noexcept; + // ------------------------------------------------------------------------------------- // + + /// Explicit conversion to u64 code. + explicit operator uint64_t() const; + + /// Check the validity of the original RawCode. + static bool check(uint64_t raw_code); + + // TODO: add macro check here + /// Output string encoding of RawCode only for debug. friend std::ostream& operator<<(std::ostream &out, RawCode self); - [[nodiscard]] uint64_t unwrap() const noexcept; - [[nodiscard]] CommonCode to_common_code() const noexcept; + // ------------------------------------------------------------------------------------- // + + /// Get the original u64 code. + [[nodiscard]] uint64_t unwrap() const; + + /// Convert RawCode to CommonCode. + [[nodiscard]] CommonCode to_common_code() const; + + // ------------------------------------------------------------------------------------- // -public: RawCode() = delete; - explicit RawCode(CommonCode common_code) noexcept; - static RawCode unsafe_create(uint64_t raw_code) noexcept; - static std::optional create(uint64_t raw_code) noexcept; + /// Construct RawCode from CommonCode. + explicit RawCode(CommonCode common_code); + + /// Create RawCode without any check. + static RawCode unsafe_create(uint64_t raw_code); + + /// Create RawCode with validity check. + static std::optional create(uint64_t raw_code); + + // ------------------------------------------------------------------------------------- // + + /// Create RawCode from CommonCode. + static RawCode from_common_code(CommonCode common_code); + + /// Create RawCode from CommonCode in u64. + static std::optional from_common_code(uint64_t common_code); + + /// Create RawCode from CommonCode in string form. + static std::optional from_common_code(const std::string &common_code); + + // ------------------------------------------------------------------------------------- // - static RawCode from_common_code(CommonCode common_code) noexcept; - static std::optional from_common_code(uint64_t common_code) noexcept; - static std::optional from_common_code(std::string &&common_code) noexcept; - static std::optional from_common_code(const std::string &common_code) noexcept; + /// Compare RawCode with u64 values. + friend constexpr auto operator==(const RawCode &lhs, uint64_t rhs); + friend constexpr auto operator<=>(const RawCode &lhs, uint64_t rhs); + + /// Compare the original values of two RawCodes. + friend constexpr auto operator==(const RawCode &lhs, const RawCode &rhs); + friend constexpr auto operator<=>(const RawCode &lhs, const RawCode &rhs); + + // ------------------------------------------------------------------------------------- // + + /// Calculate vertically symmetrical layout. + [[nodiscard]] RawCode to_vertical_mirror() const; + + /// Calculate horizontally symmetrical layout. + [[nodiscard]] RawCode to_horizontal_mirror() const; + + // ------------------------------------------------------------------------------------- // + + /// Determine whether the layout is vertically symmetrical. + [[nodiscard]] bool is_vertical_mirror() const; + + /// Determine whether the layout is horizontally symmetrical. + [[nodiscard]] bool is_horizontal_mirror() const; + + /// Determine whether two layouts are vertically symmetrical to each other. + [[nodiscard]] bool is_vertical_mirror(RawCode raw_code) const; + + /// Determine whether two layouts are horizontally symmetrical to each other. + [[nodiscard]] bool is_horizontal_mirror(RawCode raw_code) const; + + // ------------------------------------------------------------------------------------- // private: uint64_t code_; - static uint64_t compact(uint64_t raw_code) noexcept; - static uint64_t extract(uint64_t common_code) noexcept; -public: - [[nodiscard]] RawCode to_vertical_mirror() const noexcept; - [[nodiscard]] RawCode to_horizontal_mirror() const noexcept; + // ------------------------------------------------------------------------------------- // - [[nodiscard]] bool is_vertical_mirror() const noexcept; - [[nodiscard]] bool is_horizontal_mirror() const noexcept; - [[nodiscard]] bool is_vertical_mirror(RawCode raw_code) const noexcept; - [[nodiscard]] bool is_horizontal_mirror(RawCode raw_code) const noexcept; + /// Compact RawCode as CommonCode. + static uint64_t compact(uint64_t raw_code); -private: - static bool check_vertical_mirror(uint64_t raw_code) noexcept; - static bool check_horizontal_mirror(uint64_t raw_code) noexcept; + /// Extract CommonCode as RawCode. + static uint64_t extract(uint64_t common_code); + + // ------------------------------------------------------------------------------------- // + + /// Check whether the layout is vertically symmetrical. + static bool check_vertical_mirror(uint64_t raw_code); + + /// Check whether the layout is horizontally symmetrical. + static bool check_horizontal_mirror(uint64_t raw_code); + + /// Get the vertically symmetrical layout. + static uint64_t get_vertical_mirror(uint64_t raw_code); + + /// Get the horizontally symmetrical layout. + static uint64_t get_horizontal_mirror(uint64_t raw_code); - static uint64_t get_vertical_mirror(uint64_t raw_code) noexcept; - static uint64_t get_horizontal_mirror(uint64_t raw_code) noexcept; + // ------------------------------------------------------------------------------------- // }; -} // namespace codec -} // namespace klotski +} // namespace klotski::codec -#include "inline_impl.h" +#include "internal/raw_code.inl" diff --git a/src/core/raw_code/sundry.cc b/src/core/raw_code/sundry.cc deleted file mode 100644 index ddabc76..0000000 --- a/src/core/raw_code/sundry.cc +++ /dev/null @@ -1,46 +0,0 @@ -#include "raw_code.h" -#include "common_code.h" - -namespace klotski { -namespace codec { - -// ----------------------------------------------------------------------------------------- // - -RawCode::RawCode(CommonCode common_code) noexcept { - code_ = RawCode::extract(common_code.unwrap()); -} - -// ----------------------------------------------------------------------------------------- // - -CommonCode RawCode::to_common_code() const noexcept { - return CommonCode::unsafe_create(RawCode::compact(code_)); -} - -// ----------------------------------------------------------------------------------------- // - -RawCode RawCode::from_common_code(CommonCode common_code) noexcept { - return common_code.to_raw_code(); -} - -std::optional RawCode::from_common_code(uint64_t common_code) noexcept { - return CommonCode::create(common_code).transform([](auto common_code) { - return common_code.to_raw_code(); - }); -} - -std::optional RawCode::from_common_code(std::string &&common_code) noexcept { - return CommonCode::from_string(std::move(common_code)).transform([](auto common_code) { - return common_code.to_raw_code(); - }); -} - -std::optional RawCode::from_common_code(const std::string &common_code) noexcept { - return CommonCode::from_string(common_code).transform([](auto common_code) { - return common_code.to_raw_code(); - }); -} - -// ----------------------------------------------------------------------------------------- // - -} // namespace codec -} // namespace klotski