diff --git a/src/core_ffi/rust_ffi/adapter/layout.cc b/src/core_ffi/rust_ffi/adapter/layout.cc index 28b44bf..e1948f9 100644 --- a/src/core_ffi/rust_ffi/adapter/layout.cc +++ b/src/core_ffi/rust_ffi/adapter/layout.cc @@ -30,6 +30,90 @@ bool klotski::ffi::layout_check(const uint64_t val) { return CommonCode::check(val); } +rust::String klotski::ffi::layout_to_str(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.to_string(); +} + +rust::String klotski::ffi::layout_to_shorten_str(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.to_shorten_string(); +} + +uint32_t klotski::ffi::layout_to_short_code(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.to_short_code().code; +} + +bool klotski::ffi::layout_is_horizontal_mirror(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.is_horizontal_mirror(); +} + +bool klotski::ffi::layout_is_vertical_mirror(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.is_vertical_mirror(); +} + +uint64_t klotski::ffi::layout_to_horizontal_mirror(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.to_horizontal_mirror().code; +} + +uint64_t klotski::ffi::layout_to_vertical_mirror(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.to_vertical_mirror().code; +} + +uint8_t klotski::ffi::layout_n_1x1(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.n_1x1(); +} + +uint8_t klotski::ffi::layout_n_1x2(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.n_1x2(); +} + +uint8_t klotski::ffi::layout_n_2x1(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.n_2x1(); +} + +uint8_t klotski::ffi::layout_type_id(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.type_id(); +} + +uint16_t klotski::ffi::layout_pattern_id(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.pattern_id(); +} + +uint8_t klotski::ffi::layout_toward_char(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.toward_char(); +} + +uint32_t klotski::ffi::layout_case_id(uint64_t val) { + const auto layout = RsLayout {val}; + return layout.case_id(); +} + +rust::Vec klotski::ffi::layout_next_cases(uint64_t val) { + std::vector result; + auto mover = MaskMover([&result](const RawCode code, uint64_t) { + result.emplace_back(code.to_common_code()); + }); + mover.next_cases(CommonCode::unsafe_create(val).to_raw_code(), 0); + + rust::Vec vec; + for (auto x : result) { + vec.emplace_back(x.unwrap()); + } + return vec; +} + rust::String RsLayout::to_string() const noexcept { return CommonCode::unsafe_create(code).to_string(); } diff --git a/src/core_ffi/rust_ffi/examples/demo.rs b/src/core_ffi/rust_ffi/examples/demo.rs index 58e273d..aff77aa 100644 --- a/src/core_ffi/rust_ffi/examples/demo.rs +++ b/src/core_ffi/rust_ffi/examples/demo.rs @@ -2,25 +2,25 @@ use klotski::Layout; use klotski::ShortCode; fn short_code_demo() { - ShortCode::speed_up(false); - ShortCode::speed_up(true); - - assert!(ShortCode::check(4091296)); - let code = ShortCode::create(4091296).unwrap(); - assert_eq!(code, ShortCode::from_string("4WVE1").unwrap()); - assert_eq!(code, ShortCode::create(4091296).unwrap()); - - println!("code: {:?}", code.unwrap()); - println!("string: {}", code.to_string()); - - println!("layout: {:?}", code.to_layout()); + // ShortCode::speed_up(false); + // ShortCode::speed_up(true); + // + // assert!(ShortCode::check(4091296)); + // let code = ShortCode::create(4091296).unwrap(); + // assert_eq!(code, ShortCode::from_string("4WVE1").unwrap()); + // assert_eq!(code, ShortCode::create(4091296).unwrap()); + // + // println!("code: {:?}", code.unwrap()); + // println!("string: {}", code.to_string()); + // + // println!("layout: {:?}", code.to_layout()); } fn layout_demo() { assert!(Layout::check(0x1A9BF0C00)); - let code = Layout::create(0x1A9BF0C00).unwrap(); - assert_eq!(code, Layout::from_string("1A9BF0C").unwrap()); - assert_eq!(code, Layout::create(0x1A9BF0C00).unwrap()); + let code = Layout::new(0x1A9BF0C00).unwrap(); + assert_eq!(code, Layout::from_str("1A9BF0C").unwrap()); + assert_eq!(code, Layout::new(0x1A9BF0C00).unwrap()); println!("code: {:?}", code.unwrap()); diff --git a/src/core_ffi/rust_ffi/include/interface.h b/src/core_ffi/rust_ffi/include/interface.h index db4e8e4..9c6d781 100644 --- a/src/core_ffi/rust_ffi/include/interface.h +++ b/src/core_ffi/rust_ffi/include/interface.h @@ -14,4 +14,34 @@ uint64_t layout_from_str(rust::Str s); void short_code_speed_up(bool fast_mode); +rust::String layout_to_str(uint64_t val); + +rust::String layout_to_shorten_str(uint64_t val); + +uint32_t layout_to_short_code(uint64_t val); + +bool layout_is_horizontal_mirror(uint64_t val); + +bool layout_is_vertical_mirror(uint64_t val); + +uint64_t layout_to_horizontal_mirror(uint64_t val); + +uint64_t layout_to_vertical_mirror(uint64_t val); + +uint8_t layout_n_1x1(uint64_t val); + +uint8_t layout_n_1x2(uint64_t val); + +uint8_t layout_n_2x1(uint64_t val); + +uint8_t layout_type_id(uint64_t val); + +uint16_t layout_pattern_id(uint64_t val); + +uint8_t layout_toward_char(uint64_t val); + +uint32_t layout_case_id(uint64_t val); + +rust::Vec layout_next_cases(uint64_t val); + } // namespace klotski::ffi diff --git a/src/core_ffi/rust_ffi/src/bridge.rs b/src/core_ffi/rust_ffi/src/bridge.rs index ec4388d..1183482 100644 --- a/src/core_ffi/rust_ffi/src/bridge.rs +++ b/src/core_ffi/rust_ffi/src/bridge.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "klotski::ffi")] -mod ffi { +pub(crate) mod ffi { #[derive(Debug)] struct RsLayout { code: u64 @@ -19,6 +19,36 @@ mod ffi { /// only for internal use fn layout_from_str(s: &str) -> u64; + fn layout_to_str(val: u64) -> String; + + fn layout_to_shorten_str(val: u64) -> String; + + fn layout_to_short_code(val: u64) -> u32; + + fn layout_is_horizontal_mirror(val: u64) -> bool; + + fn layout_is_vertical_mirror(val: u64) -> bool; + + fn layout_to_horizontal_mirror(val: u64) -> u64; + + fn layout_to_vertical_mirror(val: u64) -> u64; + + fn layout_n_1x1(val: u64) -> u8; + + fn layout_n_1x2(val: u64) -> u8; + + fn layout_n_2x1(val: u64) -> u8; + + fn layout_type_id(val: u64) -> u8; + + fn layout_pattern_id(val: u64) -> u16; + + fn layout_toward_char(val: u64) -> u8; + + fn layout_case_id(val: u64) -> u32; + + fn layout_next_cases(val: u64) -> Vec; + /// Convert Layout to string form. fn to_string(self: &RsLayout) -> String; diff --git a/src/core_ffi/rust_ffi/src/layout.rs b/src/core_ffi/rust_ffi/src/layout.rs new file mode 100644 index 0000000..00e2782 --- /dev/null +++ b/src/core_ffi/rust_ffi/src/layout.rs @@ -0,0 +1,153 @@ +use crate::ffi; +use crate::ShortCode; + +/// Layout represents a valid klotski situation, which fills single `2x2` block +/// and any number of `1x1` / `1x2` / `2x1` blocks without overlapping within +/// the range of `5x4`, and ensures that at least two spaces need to remain. +/// These layout information will be stored in a 36-bit value (u64), which can +/// uniquely mark a valid klotski situation, and any valid situation can also +/// be represented by a unique value. +#[derive(Debug)] +pub struct Layout { + value: u64 +} + +impl Layout { + /// Check whether the klotski layout value is a valid. + pub fn check(val: u64) -> bool { + ffi::layout_check(val) + } + + /// Create klotski layout without any check. Note that if an invalid value + /// is passed, unpredictable behavior may occur. + pub fn unsafe_new(val: u64) -> Self { + Self { value: val } + } + + /// Create klotski layout with validity check. + pub fn new(val: u64) -> Option { + if !Self::check(val) { + return None + } + Some(Self::unsafe_new(val)) + } + + /// Create klotski layout from string form. + pub fn from_str(msg: &str) -> Option { + let val = ffi::layout_from_str(msg); + if val == 0x10_FFFF_FFFF { + return None; + } + Some(Self::unsafe_new(val)) + } +} + +impl Layout { + /// Get the original value of klotski layout. + pub fn unwrap(&self) -> u64 { + self.value + } + + pub fn to_string(&self) -> String { + ffi::layout_to_str(self.value) + } + + pub fn to_shorten_string(&self) -> String { + ffi::layout_to_shorten_str(self.value) + } + + pub fn to_short_code(&self) -> ShortCode { + ShortCode::unsafe_new(ffi::layout_to_short_code(self.value)) + } +} + +impl Into for Layout { + fn into(self) -> u64 { + self.unwrap() + } +} + +impl Into for Layout { + fn into(self) -> String { + self.to_string() + } +} + +impl Into for Layout { + fn into(self) -> ShortCode { + self.to_short_code() + } +} + +impl Layout { + pub fn is_horizontal_mirror(&self) -> bool { + ffi::layout_is_horizontal_mirror(self.value) + } + + pub fn is_vertical_mirror(&self) -> bool { + ffi::layout_is_vertical_mirror(self.value) + } + + pub fn to_vertical_mirror(&self) -> Layout { + let val = ffi::layout_to_vertical_mirror(self.value); + Layout::unsafe_new(val) + } + + pub fn to_horizontal_mirror(&self) -> Layout { + let val = ffi::layout_to_horizontal_mirror(self.value); + Layout::unsafe_new(val) + } +} + +impl Layout { + pub fn n_1x1(&self) -> u8 { + ffi::layout_n_1x1(self.value) + } + + pub fn n_1x2(&self) -> u8 { + ffi::layout_n_1x2(self.value) + } + + pub fn n_2x1(&self) -> u8 { + ffi::layout_n_2x1(self.value) + } + + pub fn n_2x2(&self) -> u8 { + 1 + } +} + +impl Layout { + pub fn type_id(&self) -> u8 { + ffi::layout_type_id(self.value) + } + + pub fn pattern_id(&self) -> u16 { + ffi::layout_pattern_id(self.value) + } + + pub fn toward_char(&self) -> u8 { + ffi::layout_toward_char(self.value) + } + + pub fn case_id(&self) -> u32 { + ffi::layout_case_id(self.value) + } +} + +impl Layout { + pub fn next_cases(&self) -> Vec { + ffi::layout_next_cases(self.value) + .iter() + .map(|val| Layout::unsafe_new(*val)) + .collect() + } +} + +impl PartialEq for Layout { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} + +// TODO: add `Display` trait support diff --git a/src/core_ffi/rust_ffi/src/lib.rs b/src/core_ffi/rust_ffi/src/lib.rs index 9f0a1f7..c7a0697 100644 --- a/src/core_ffi/rust_ffi/src/lib.rs +++ b/src/core_ffi/rust_ffi/src/lib.rs @@ -1,4 +1,11 @@ mod bridge; +mod layout; +mod short_code; -pub use bridge::Layout; -pub use bridge::ShortCode; +// pub use bridge::Layout; +// pub use bridge::ShortCode; + +use bridge::ffi; + +pub use layout::Layout; +pub use short_code::ShortCode; diff --git a/src/core_ffi/rust_ffi/src/short_code.rs b/src/core_ffi/rust_ffi/src/short_code.rs new file mode 100644 index 0000000..2139c04 --- /dev/null +++ b/src/core_ffi/rust_ffi/src/short_code.rs @@ -0,0 +1,23 @@ +use crate::ffi; + +#[derive(Debug)] +pub struct ShortCode { + code: u32 +} + +impl ShortCode { + // fn new(code: u32) -> Option { + // if !Self::check(code) { + // return None + // } + // Some(Self::unsafe_new(code)) + // } + + pub fn unsafe_new(code: u32) -> ShortCode { + Self {code} + } + + fn check(code: u32) -> bool { + ffi::short_code_check(code) + } +}