use std::fmt;
use std::collections::HashMap;
use crate::bitgrid8::BitGrid8;
use derive_more::*;
use arrayvec::*;
use crate::bitlib::swap_mask_shift_u64;
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord,
BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign,
)]
pub struct BitHex8(pub u64);
impl fmt::Debug for BitHex8 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "BitGrid8({:#010x})", self.0)
}
}
impl fmt::Display for BitHex8 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}",
(0..8).rev().map(|y|
(0..8)
.map(|x| format!("{}", if (self.0 >> (x + 8*y)) & 0x1 == 1 { "🟥" } else { "⬜" }))
.collect::<String>()
+"\n")
.collect::<String>()
)
}
}
pub const HEX4: u64 = 0x78_7c7e_7f3f_1f0f;
pub const FULL: BitHex8 = BitHex8(0x78_7c7e_7f3f_1f0f);
pub const ASTERISK: BitHex8 = BitHex8(0x4828187f0c0a09);
pub const THREE_HEX: BitHex8 = BitHex8(0x6c7e360c0e06);
pub const LARGE_Z: BitHex8 = BitHex8(0x78_0808_0808_080f);
impl BitHex8 {
pub fn has_overlap(self, other: Self) -> bool {
self.0 & other.0 != 0
}
#[inline(always)]
pub fn is_empty(self) -> bool {
self.0 == 0
}
pub fn rotate_all_vec(self) -> ArrayVec::<Self, 4> {
let mut vec = ArrayVec::<Self, 4>::new();
let mut x = self;
vec.push(x);
for _ in 0..2 { x = x.rotate_cc(); vec.push(x); }
vec.sort_unstable();
let symmetries = vec.partition_dedup().0.len(); vec.truncate(symmetries);
vec
}
pub fn rotate_cc(self) -> Self {
let mut grid: u64 = BitGrid8(self.0).rotate_cc().0.unbounded_shr(4);
grid = (grid & 0x0fff_ffff) ^ (grid.unbounded_shl(4) & 0x00ff_ffff_0000_0000);
grid = (grid & 0xffff_0000_0fff) ^ (grid.unbounded_shl(2) & 0x00ff_0000_ffff_0000);
grid = (grid & 0xff_00ff_003f_000f) ^ (grid.unbounded_shl(1) & 0x0000_ff00_ff00_ff00);
Self(grid)
}
pub fn rotate(self) -> Self {
todo!();
}
pub fn flip_x(self) -> Self {
let mut grid = self.0;
swap_mask_shift_u64(&mut grid, 0xf, 51);
swap_mask_shift_u64(&mut grid, 0x1f00, 34);
swap_mask_shift_u64(&mut grid, 0x3f0000, 17);
Self(grid)
}
pub fn shift_to_origin(self) -> Self {
let mut shape = self.0;
let y_shift = (shape.trailing_zeros() / 8) * 8;
shape = shape.unbounded_shr(y_shift);
let mut x_shift = shape | shape.unbounded_shr(32);
x_shift |= x_shift.unbounded_shr(32);
x_shift |= x_shift.unbounded_shr(16);
x_shift |= x_shift.unbounded_shr(8);
shape = shape.unbounded_shr(x_shift.trailing_zeros());
Self(shape)
}
pub fn bounding_box(self) -> (u32, u32) {
let mut shape = self.0;
shape |= ((shape >> 1) & 0x7f7f7f7f7f7f7f7f) | shape >> 8;
shape |= ((shape >> 2) & 0x3f3f3f3f3f3f3f3f) | shape >> 16;
shape |= ((shape >> 4) & 0x0f0f0f0f0f0f0f0f) | shape >> 32;
let len_x = (shape & 0xff).count_ones();
let len_y = (shape & 0x0101010101010101).count_ones();
(len_x as u32, len_y as u32)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_bithex8_display() {
println!("{}", FULL);
assert_eq!(format!("{}", FULL),
"⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜🟥🟥🟥🟥⬜\n⬜⬜🟥🟥🟥🟥🟥⬜\n⬜🟥🟥🟥🟥🟥🟥⬜\n🟥🟥🟥🟥🟥🟥🟥⬜\n🟥🟥🟥🟥🟥🟥⬜⬜\n🟥🟥🟥🟥🟥⬜⬜⬜\n🟥🟥🟥🟥⬜⬜⬜⬜\n");
assert_eq!(format!("{}", BitHex8(0x1)),
"⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n🟥⬜⬜⬜⬜⬜⬜⬜\n");
assert_eq!(format!("{}", FULL.rotate_cc()),
"⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜🟥🟥🟥🟥⬜\n⬜⬜🟥🟥🟥🟥🟥⬜\n⬜🟥🟥🟥🟥🟥🟥⬜\n🟥🟥🟥🟥🟥🟥🟥⬜\n🟥🟥🟥🟥🟥🟥⬜⬜\n🟥🟥🟥🟥🟥⬜⬜⬜\n🟥🟥🟥🟥⬜⬜⬜⬜\n");
}
#[test]
fn test_bithex8_rotate_cc() {
assert_eq!(FULL, FULL.rotate_cc());
assert_eq!(ASTERISK, ASTERISK.rotate_cc());
assert_ne!(THREE_HEX, THREE_HEX.rotate_cc());
assert_eq!(THREE_HEX, THREE_HEX.rotate_cc().rotate_cc());
println!("{}", LARGE_Z);
assert_ne!(LARGE_Z, LARGE_Z.rotate_cc());
assert_ne!(LARGE_Z, LARGE_Z.rotate_cc().rotate_cc());
assert_eq!(LARGE_Z, LARGE_Z.rotate_cc().rotate_cc().rotate_cc());
}
#[test]
fn test_bithex8_flip_x() {
println!("{}", ASTERISK);
println!("{}", ASTERISK.flip_x());
assert_eq!(ASTERISK, ASTERISK.flip_x());
}
}