use std::collections::HashMap;
use std::fmt;
use arrayvec::*;
use derive_more::*;
use crate::bitlib::swap_mask_shift_u64;
use crate::bitlib::*;
#[derive(
Copy,
Clone,
Eq,
PartialEq,
Hash,
PartialOrd,
Ord,
BitAnd,
BitAndAssign,
BitOr,
BitOrAssign,
BitXor,
BitXorAssign,
)]
pub struct BitGrid8(pub u64);
impl core::ops::Shr<i32> for BitGrid8 {
type Output = Self;
fn shr(self, shift: i32) -> Self {
let positive = shift >= 0;
let shift: u32 = shift.unsigned_abs();
if positive {
Self(self.0.unbounded_shr(shift))
} else {
Self(self.0.unbounded_shl(shift))
}
}
}
impl core::ops::Shl<i32> for BitGrid8 {
type Output = Self;
fn shl(self, shift: i32) -> Self {
let positive = shift >= 0;
let shift: u32 = shift.unsigned_abs();
if positive {
Self(self.0.unbounded_shl(shift))
} else {
Self(self.0.unbounded_shr(shift))
}
}
}
impl core::ops::Not for BitGrid8 {
type Output = Self;
fn not(self) -> Self {
Self(!self.0)
}
}
impl core::ops::BitAnd<u64> for BitGrid8 {
type Output = Self;
fn bitand(self, rhs: u64) -> Self {
Self(self.0 & rhs)
}
}
impl core::ops::BitOr<u64> for BitGrid8 {
type Output = Self;
fn bitor(self, rhs: u64) -> Self {
Self(self.0 | rhs)
}
}
impl core::ops::BitXor<u64> for BitGrid8 {
type Output = Self;
fn bitxor(self, rhs: u64) -> Self {
Self(self.0 ^ rhs)
}
}
impl fmt::Debug for BitGrid8 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "BitGrid8({:#010x})", self.0)
}
}
impl fmt::Display for BitGrid8 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
(0..8)
.rev()
.map(|y| (0..8)
.map(|x| {
(if (self.0 >> (x + 8 * y)) & 0x1 == 1 {
"🟥"
} else {
"⬜"
})
.to_string()
})
.collect::<String>()
+ "\n")
.collect::<String>()
)
}
}
impl From<u64> for BitGrid8 {
fn from(raw_grid: u64) -> Self {
BitGrid8(raw_grid)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct BitGrid8PointsIter {
remaining: u64,
}
impl Iterator for BitGrid8PointsIter {
type Item = BitGrid8;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let bit = self.remaining.isolate_lowest_one();
self.remaining ^= bit;
Some(BitGrid8(bit))
}
}
impl IntoIterator for BitGrid8 {
type Item = BitGrid8;
type IntoIter = BitGrid8PointsIter;
fn into_iter(self) -> Self::IntoIter {
BitGrid8PointsIter { remaining: self.0 }
}
}
impl IntoIterator for &BitGrid8 {
type Item = BitGrid8;
type IntoIter = BitGrid8PointsIter;
fn into_iter(self) -> Self::IntoIter {
BitGrid8PointsIter { remaining: self.0 }
}
}
impl BitGrid8 {
pub fn count_ones(self) -> u32 {
self.0.count_ones()
}
pub fn pentomino_map() -> HashMap<char, BitGrid8> {
HashMap::<char, BitGrid8>::from([
('F', BitGrid8::from(0x20306)),
('I', BitGrid8::from(0x101010101)),
('L', BitGrid8::from(0x3010101)),
('N', BitGrid8::from(0xe03)),
('P', BitGrid8::from(0x10303)),
('T', BitGrid8::from(0x20207)),
('U', BitGrid8::from(0x507)),
('V', BitGrid8::from(0x10107)),
('W', BitGrid8::from(0x10306)),
('X', BitGrid8::from(0x20702)),
('Y', BitGrid8::from(0x40f)),
('Z', BitGrid8::from(0x30206)),
])
}
pub fn find_corners(self) -> BitGrid8 {
(self.shift_x(-1) | 0x8080_8080_8080_8080 | self.shift_x(1) | 0x0101_0101_0101_0101)
& (self.shift_y(-1) | 0xff00_0000_0000_0000 | self.shift_y(1) | 0xff)
& !self
}
pub fn find_corners_ne(self) -> BitGrid8 {
(self.shift_x(-1) | 0x8080_8080_8080_8080)
& (self.shift_y(-1) | 0xff00_0000_0000_0000)
& !self
}
pub fn find_corners_sw(self) -> BitGrid8 {
(self.shift_x(1) | 0x0101_0101_0101_0101) & (self.shift_y(1) | 0xff) & !self
}
pub fn find_corners_se(self) -> BitGrid8 {
(self.shift_x(-1) | 0x8080_8080_8080_8080) & (self.shift_y(1) | 0xff) & !self
}
pub fn find_corners_nw(self) -> BitGrid8 {
(self.shift_x(1) | 0x0101_0101_0101_0101)
& (self.shift_y(-1) | 0xff00_0000_0000_0000)
& !self
}
pub fn origin_rotate_all(self) -> ArrayVec<BitGrid8, 4> {
let mut vec = ArrayVec::<BitGrid8, 4>::new();
let mut x = self.shift_to_origin();
vec.push(x);
for _ in 0..3 {
x = x.rotate_cc().shift_to_origin();
vec.push(x);
}
vec.sort_unstable();
let symmetries = vec.partition_dedup().0.len(); vec.truncate(symmetries);
vec
}
pub fn border(self) -> Self {
(self
| self.shift_x(1)
| self.shift_x(-1)
| self.shift_y(1)
| self.shift_y(-1)
| BitGrid8::from(BORDER))
^ self
}
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 border8(self) -> Self {
let mut grid = self | self.shift_x(1) | self.shift_x(-1);
grid |= grid.shift_y(1) | grid.shift_y(-1) | BitGrid8::from(BORDER);
grid ^ self
}
pub fn count_components(self) -> u32 {
self.count_2x2_antimask(0x55ff_55ff_55ff_55ff_u64)
+ self.count_2x2_antimask(0x55aa_55aa_55aa_55aa_u64) - self.count_2x2_antimask(0x0055_0055_0055_0055_u64)
}
#[inline]
pub fn count_2x2_blocks(self) -> u32 {
let mut grid: u64 = self.0;
grid &= grid.unbounded_shr(8);
grid &= grid.unbounded_shr(1) & 0x0055_0055_0055_0055u64;
grid.count_ones()
}
#[inline]
pub fn count_2x2_antimask(self, antimask: u64) -> u32 {
const RIGHT: u64 = 0xfefe_fefe_fefe_fefe_u64;
BitGrid8::from((self.0.unbounded_shl(9) & RIGHT) ^ antimask).count_2x2_blocks()
+ BitGrid8::from((self.0.unbounded_shl(1) & RIGHT) ^ antimask).count_2x2_blocks()
+ BitGrid8::from(self.0.unbounded_shl(8) ^ antimask).count_2x2_blocks()
+ (self ^ BitGrid8::from(antimask)).count_2x2_blocks()
}
#[inline]
pub fn count_upper_right_2x2_blocks(self) -> u32 {
println!(
"{:}",
BitGrid8::from(
(self.0.unbounded_shl(9) & 0xfefe_fefe_fefe_fe00_u64) ^ 0x55ff_55ff_55ff_55ff_u64
)
);
BitGrid8::from(
(self.0.unbounded_shl(9) & 0xfefe_fefe_fefe_fe00_u64) ^ 0x55ff_55ff_55ff_55ff_u64,
)
.count_2x2_blocks()
+ BitGrid8::from(
(self.0.unbounded_shl(1) & 0xfefe_fefe_fefe_fefe_u64) ^ 0x55ff_55ff_55ff_55ff_u64,
)
.count_2x2_blocks()
+ BitGrid8::from(self.0.unbounded_shl(8) ^ 0x55ff_55ff_55ff_55ff_u64).count_2x2_blocks()
+ (self ^ BitGrid8::from(0x55ff_55ff_55ff_55ff_u64)).count_2x2_blocks()
}
#[inline]
pub fn count_lower_left_2x2_blocks(self) -> u32 {
const ANTIMASK: u64 = 0x0055_0055_0055_0055_u64;
BitGrid8::from((self.0.unbounded_shl(9) & 0xfefe_fefe_fefe_fe00_u64) ^ ANTIMASK)
.count_2x2_blocks()
+ BitGrid8::from((self.0.unbounded_shl(1) & 0xfefe_fefe_fefe_fefe_u64) ^ ANTIMASK)
.count_2x2_blocks()
+ BitGrid8::from(self.0.unbounded_shl(8) ^ ANTIMASK).count_2x2_blocks()
+ (self ^ BitGrid8::from(ANTIMASK)).count_2x2_blocks()
}
#[inline]
pub fn count_antidiagonal_2x2_blocks(self) -> u32 {
const ANTIMASK: u64 = 0x55aa_55aa_55aa_55aa_u64;
BitGrid8::from((self.0.unbounded_shl(9) & 0xfefe_fefe_fefe_fe00_u64) ^ ANTIMASK)
.count_2x2_blocks()
+ BitGrid8::from((self.0.unbounded_shl(1) & 0xfefe_fefe_fefe_fefe_u64) ^ ANTIMASK)
.count_2x2_blocks()
+ BitGrid8::from(self.0.unbounded_shl(8) ^ ANTIMASK).count_2x2_blocks()
+ (self ^ BitGrid8::from(ANTIMASK)).count_2x2_blocks()
}
pub fn origin_dihedral_all(self) -> ArrayVec<BitGrid8, 8> {
let mut vec = ArrayVec::<BitGrid8, 8>::new();
let mut x = self.shift_to_origin();
vec.push(x);
for _ in 0..3 {
x = x.rotate_cc().shift_to_origin();
vec.push(x);
}
x = x.flip_x().shift_to_origin();
vec.push(x);
for _ in 0..3 {
x = x.rotate_cc().shift_to_origin();
vec.push(x);
}
vec.sort_unstable();
let symmetries = vec.partition_dedup().0.len(); vec.truncate(symmetries);
vec
}
pub fn origin_dihedral_all_vec(self) -> Vec<BitGrid8> {
let mut vec = Vec::<BitGrid8>::new();
let mut x = self.shift_to_origin();
vec.push(x);
for _ in 0..3 {
x = x.rotate_cc().shift_to_origin();
vec.push(x);
}
x = x.flip_x().shift_to_origin();
vec.push(x);
for _ in 0..3 {
x = x.rotate_cc().shift_to_origin();
vec.push(x);
}
vec.sort_unstable();
let symmetries = vec.partition_dedup().0.len(); vec.truncate(symmetries);
vec
}
pub fn rotate_all_vec(self) -> ArrayVec<BitGrid8, 4> {
let mut vec = ArrayVec::<BitGrid8, 4>::new();
let mut x = self;
vec.push(x);
for _ in 0..3 {
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 square = self.0;
swap_mask_shift_u64(&mut square, 0x0f0f_0f0f_u64, 36);
swap_mask_shift_u64(&mut square, 0xffff_ffff_u64, 32);
swap_mask_shift_u64(&mut square, 0x0000_3333_0000_3333_u64, 18);
swap_mask_shift_u64(&mut square, 0xffff_0000_ffff_u64, 16);
swap_mask_shift_u64(&mut square, 0x0055_0055_0055_0055_u64, 9);
swap_mask_shift_u64(&mut square, 0x00ff_00ff_00ff_00ff_u64, 8);
BitGrid8::from(square)
}
pub fn rotate(self) -> Self {
let mut square = self.0;
swap_mask_shift_u64(&mut square, 0xffff_ffff_u64, 32);
swap_mask_shift_u64(&mut square, 0x0f0f_0f0f_u64, 36);
swap_mask_shift_u64(&mut square, 0xffff_0000_ffff_u64, 16);
swap_mask_shift_u64(&mut square, 0x0000_3333_0000_3333_u64, 18);
swap_mask_shift_u64(&mut square, 0x00ff_00ff_00ff_00ff_u64, 8);
swap_mask_shift_u64(&mut square, 0x0055_0055_0055_0055_u64, 9);
BitGrid8::from(square)
}
pub fn flip_x(self) -> Self {
let mut square = self.0;
swap_mask_shift_u64(&mut square, 0xffff_ffff_u64, 32);
swap_mask_shift_u64(&mut square, 0xffff_0000_ffff_u64, 16);
swap_mask_shift_u64(&mut square, 0x00ff_00ff_00ff_00ff_u64, 8);
BitGrid8::from(square)
}
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, len_y)
}
pub fn shift_x(self, shift: i32) -> Self {
if !(-7..=7).contains(&shift) {
return Self(0);
};
if shift == 0 {
return self;
};
let sign = shift > 0;
let shift: u32 = shift.unsigned_abs();
let mask: u64 = ((1_u64 << (8_u32 - shift)) - 1_u64) * 0x0101_0101_0101_0101_u64;
if sign {
BitGrid8::from((mask & self.0).unbounded_shl(shift))
} else {
BitGrid8::from(mask & self.0.unbounded_shr(shift))
}
}
pub fn checked_shift_x(self, shift: i32) -> Option<Self> {
let shifted = self.shift_x(shift);
if self.0.count_ones() == shifted.0.count_ones() {
Some(shifted)
} else {
None
}
}
pub fn shift_y(self, shift: i32) -> Self {
if !(-7..=7).contains(&shift) {
return Self(0);
};
if shift == 0 {
return self;
};
let sign = shift > 0;
let shift: u32 = shift.unsigned_abs().unbounded_shl(3); let mask: u64 = 0xffff_ffff_ffff_ffff_u64.unbounded_shr(shift);
if sign {
BitGrid8::from((mask & self.0).unbounded_shl(shift))
} else {
BitGrid8::from(mask & self.0.unbounded_shr(shift))
}
}
pub fn checked_shift_y(self, shift: i32) -> Option<Self> {
let shifted = self.shift_y(shift);
if self.0.count_ones() == shifted.0.count_ones() {
Some(shifted)
} else {
None
}
}
pub fn shift_xy(self, x_shift: i32, y_shift: i32) -> Self {
self.shift_x(x_shift).shift_y(y_shift)
}
pub fn checked_shift_xy(self, x_shift: i32, y_shift: i32) -> Option<Self> {
let shifted = self.shift_xy(x_shift, y_shift);
if self.0.count_ones() == shifted.0.count_ones() {
Some(shifted)
} else {
None
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_bitgrid8_display() {
assert_eq!(format!("{}", BitGrid8::from(BACKSLASH)),
"🟥⬜⬜⬜⬜⬜⬜⬜\n⬜🟥⬜⬜⬜⬜⬜⬜\n⬜⬜🟥⬜⬜⬜⬜⬜\n⬜⬜⬜🟥⬜⬜⬜⬜\n⬜⬜⬜⬜🟥⬜⬜⬜\n⬜⬜⬜⬜⬜🟥⬜⬜\n⬜⬜⬜⬜⬜⬜🟥⬜\n⬜⬜⬜⬜⬜⬜⬜🟥\n");
assert_eq!(format!("{}", BitGrid8::from(0x1)),
"⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n⬜⬜⬜⬜⬜⬜⬜⬜\n🟥⬜⬜⬜⬜⬜⬜⬜\n");
}
#[test]
fn test_shift_to_origin() {
assert_eq!(BitGrid8::from(FULL).shift_to_origin(), BitGrid8::from(FULL));
assert_eq!(
BitGrid8::from(UPPER_RIGHT).shift_to_origin(),
BitGrid8::from(LOWER_LEFT)
);
assert_eq!(
BitGrid8::from(BACKSLASH).shift_to_origin(),
BitGrid8::from(BACKSLASH)
);
assert_eq!(
BitGrid8::from(CENTER_XY).shift_to_origin(),
BitGrid8::from(CENTER_XY)
);
assert_eq!(
BitGrid8::from(0xf00f00).shift_to_origin(),
BitGrid8::from(0xf00f)
);
let pentomino = BitGrid8::pentomino_map();
assert_eq!((pentomino[&'F'] << 24).shift_to_origin(), pentomino[&'F']);
}
#[test]
fn test_find_corners() {
assert_eq!(BitGrid8::from(FULL).find_corners(), BitGrid8::from(0));
println!("{}", BitGrid8::from(BACKSLASH).find_corners());
assert_eq!(
BitGrid8::from(UPPER_RIGHT).find_corners(),
BitGrid8::from(0x900000080000081)
);
assert_eq!(
BitGrid8::from(BACKSLASH).find_corners(),
BitGrid8::from(0x82050a142850a041)
);
assert_eq!(
BitGrid8::from(CENTER_XY).find_corners(),
BitGrid8::from(0xa500a50000a500a5)
);
let pentomino = BitGrid8::pentomino_map();
println!("{:}", pentomino[&'F'].find_corners());
println!("{:}", pentomino[&'F']);
assert_eq!(
(pentomino[&'F']).find_corners(),
BitGrid8::from(0x8100000000010489)
);
}
#[test]
fn test_find_corner_sw() {
assert_eq!(BitGrid8::from(FULL).find_corners_sw(), BitGrid8::from(0));
println!("{}", BitGrid8::from(UPPER_RIGHT).find_corners_sw());
assert_eq!(
BitGrid8::from(UPPER_RIGHT).find_corners_sw(),
BitGrid8::from(0x1)
);
assert_eq!(
BitGrid8::from(BACKSLASH).find_corners_sw(),
BitGrid8::from(0x204081020408001)
);
assert_eq!(
BitGrid8::from(CENTER_XY).find_corners_sw(),
BitGrid8::from(0x210000000021)
);
let pentomino = BitGrid8::pentomino_map();
println!("{:}", pentomino[&'F'].find_corners_sw());
println!("{:}", pentomino[&'F']);
assert_eq!(
(pentomino[&'F']).find_corners_sw(),
BitGrid8::from(0x00010409)
);
}
#[test]
fn test_find_corner_nw() {
assert_eq!(BitGrid8::from(FULL).find_corners_nw(), BitGrid8::from(0));
println!("{}", BitGrid8::from(UPPER_RIGHT));
println!("{}", BitGrid8::from(UPPER_RIGHT).find_corners_nw());
assert_eq!(
BitGrid8::from(UPPER_RIGHT).find_corners_nw(),
BitGrid8::from(0x0100_0000_0000_0000)
);
assert_eq!(
BitGrid8::from(BACKSLASH).find_corners_nw(),
BitGrid8::from(0x201000000000000)
);
println!("{}", BitGrid8::from(CENTER_XY).find_corners_nw());
assert_eq!(
BitGrid8::from(CENTER_XY).find_corners_nw(),
BitGrid8::from(0x2100_0000_0021_0000)
);
let pentomino = BitGrid8::pentomino_map();
println!("{:}", pentomino[&'F'].find_corners_nw());
println!("{:}", pentomino[&'F']);
assert_eq!(
(pentomino[&'F']).find_corners_nw(),
BitGrid8::from(0x100000000000001)
);
}
#[test]
fn test_find_corner_se() {
assert_eq!(BitGrid8::from(FULL).find_corners_se(), BitGrid8::from(0));
println!("{}", BitGrid8::from(UPPER_RIGHT).find_corners_se());
assert_eq!(
BitGrid8::from(UPPER_RIGHT).find_corners_se(),
BitGrid8::from(0x80)
);
assert_eq!(
BitGrid8::from(BACKSLASH).find_corners_se(),
BitGrid8::from(0x08040)
);
assert_eq!(
BitGrid8::from(CENTER_XY).find_corners_se(),
BitGrid8::from(0x840000000084)
);
let pentomino = BitGrid8::pentomino_map();
println!("{:}", pentomino[&'F'].find_corners_se());
println!("{:}", pentomino[&'F']);
assert_eq!(
(pentomino[&'F']).find_corners_se(),
BitGrid8::from(0x00010081)
);
}
#[test]
fn test_find_corner_ne() {
assert_eq!(BitGrid8::from(FULL).find_corners_ne(), BitGrid8::from(0));
assert_eq!(
BitGrid8::from(UPPER_RIGHT).find_corners_ne(),
BitGrid8::from(0x800000080000000)
);
assert_eq!(
BitGrid8::from(BACKSLASH).find_corners_ne(),
BitGrid8::from(0x8001020408102040)
);
println!("{}", BitGrid8::from(CENTER_XY).find_corners_ne());
assert_eq!(
BitGrid8::from(CENTER_XY).find_corners_ne(),
BitGrid8::from(0x8400000000840000)
);
let pentomino = BitGrid8::pentomino_map();
println!("{:}", pentomino[&'F'].find_corners_ne());
println!("{:}", pentomino[&'F']);
assert_eq!(
(pentomino[&'F']).find_corners_ne(),
BitGrid8::from(0x8000000000000001)
);
}
#[test]
fn test_border() {
assert_eq!(BitGrid8::from(FULL).border(), BitGrid8::from(0));
assert_eq!(
BitGrid8::from(UPPER_RIGHT).border(),
BitGrid8::from(0xf090909f18181ff)
);
assert_eq!(
BitGrid8::from(BACKSLASH).border(),
BitGrid8::from(0xfe858b95a9d1a17f)
);
assert_eq!(
BitGrid8::from(CENTER_XY).border(),
BitGrid8::from(0xe7a5e70000e7a5e7)
);
assert_eq!(
BitGrid8::from(0x1818000000).border(),
BitGrid8::from(0xff8199a5a59981ff)
);
let pentomino = BitGrid8::pentomino_map();
println!("{:}", pentomino[&'F'].border());
assert_eq!(
(pentomino[&'F']).border(),
BitGrid8::from(0xff818181838584f9)
);
}
#[test]
fn test_border_connected() {
assert_eq!(BitGrid8::from(FULL).border8(), BitGrid8::from(0));
assert_eq!(
BitGrid8::from(UPPER_RIGHT).border8(),
BitGrid8::from(0xf090909f98181ff)
);
assert_eq!(
BitGrid8::from(BACKSLASH).border8(),
BitGrid8::from(0xfe8d9bb7edd9b17f)
);
assert_eq!(
BitGrid8::from(CENTER_XY).border8(),
BitGrid8::from(0xe7a5e70000e7a5e7)
);
assert_eq!(
BitGrid8::from(0x1818000000).border8(),
BitGrid8::from(0xff81bda5a5bd81ff)
);
let pentomino = BitGrid8::pentomino_map();
println!("{:}", pentomino[&'F'].border8());
assert_eq!(
(pentomino[&'F']).border8(),
BitGrid8::from(0xff81818187858cf9)
);
}
#[test]
fn test_count_2x2_blocks() {
assert_eq!(BitGrid8::from(FULL).count_2x2_blocks(), 16);
assert_eq!(BitGrid8::from(UPPER_RIGHT).count_2x2_blocks(), 4);
assert_eq!(BitGrid8::from(BACKSLASH).count_2x2_blocks(), 0);
assert_eq!(BitGrid8::from(CENTER_XY).count_2x2_blocks(), 0);
}
#[test]
fn test_count_upper_right_2x2_blocks_all() {
assert_eq!(BitGrid8::from(FULL).count_upper_right_2x2_blocks(), 1);
assert_eq!(BitGrid8::from(CENTER_XY).count_upper_right_2x2_blocks(), 2);
assert_eq!(BitGrid8::from(HIGHFIVE).count_upper_right_2x2_blocks(), 2);
assert_eq!(BitGrid8::from(BACKSLASH).count_upper_right_2x2_blocks(), 8);
}
#[test]
fn test_count_lower_left_2x2_blocks_all() {
assert_eq!(BitGrid8::from(FULL).count_lower_left_2x2_blocks(), 0);
assert_eq!(BitGrid8::from(CENTER_XY).count_lower_left_2x2_blocks(), 1);
assert_eq!(BitGrid8::from(HIGHFIVE).count_lower_left_2x2_blocks(), 1);
assert_eq!(BitGrid8::from(BACKSLASH).count_lower_left_2x2_blocks(), 0);
}
#[test]
fn test_count_components() {
assert_eq!(BitGrid8::from(FULL).count_components(), 1);
assert_eq!(BitGrid8::from(CENTER_XY).count_components(), 1);
assert_eq!(BitGrid8::from(HIGHFIVE).count_components(), 1);
assert_eq!(BitGrid8::from(BACKSLASH).count_components(), 8);
assert_eq!(BitGrid8::from(SLASH).count_components(), 8);
}
#[test]
fn test_shift_x() {
assert_eq!(
BitGrid8::from(FULL).shift_x(1),
BitGrid8::from(0xfefe_fefe_fefe_fefe_u64)
);
assert_eq!(
BitGrid8::from(FULL).shift_x(4),
BitGrid8::from(0xf0f0_f0f0_f0f0_f0f0_u64)
);
assert_eq!(
BitGrid8::from(FULL).shift_x(-1),
BitGrid8::from(0x7f7f_7f7f_7f7f_7f7f_u64)
);
assert_eq!(
BitGrid8::from(FULL).shift_x(-4),
BitGrid8::from(0x0f0f_0f0f_0f0f_0f0f_u64)
);
assert_eq!(BitGrid8::from(FULL).shift_x(-8), BitGrid8::from(0));
assert_eq!(BitGrid8::from(FULL).shift_x(8), BitGrid8::from(0));
let pentomino = BitGrid8::pentomino_map();
assert_eq!(pentomino[&'F'].shift_x(1), BitGrid8::from(0x4060c));
assert_eq!(pentomino[&'F'].shift_x(-1), BitGrid8::from(0x10103));
}
#[test]
fn test_checked_shift_x() {
assert_eq!(BitGrid8::from(FULL).checked_shift_x(1), None);
assert_eq!(BitGrid8::from(FULL).checked_shift_x(-1), None);
let pentomino = BitGrid8::pentomino_map();
assert_eq!(
pentomino[&'F'].checked_shift_x(1),
Some(BitGrid8::from(0x4060c))
);
assert_eq!(pentomino[&'F'].checked_shift_x(-1), None);
}
#[test]
fn test_shift_y() {
assert_eq!(
BitGrid8::from(FULL).shift_y(1),
BitGrid8::from(0xffff_ffff_ffff_ff00_u64)
);
assert_eq!(
BitGrid8::from(FULL).shift_y(-1),
BitGrid8::from(0x00ff_ffff_ffff_ffff_u64)
);
assert_eq!(
BitGrid8::from(FULL).shift_y(4),
BitGrid8::from(0xffff_ffff_0000_0000_u64)
);
assert_eq!(
BitGrid8::from(FULL).shift_y(-4),
BitGrid8::from(0x0000_0000_ffff_ffff_u64)
);
assert_eq!(BitGrid8::from(FULL).shift_y(8), BitGrid8::from(0));
assert_eq!(BitGrid8::from(FULL).shift_y(-8), BitGrid8::from(0));
assert_eq!(BitGrid8::from(0xf00f).shift_y(-1), BitGrid8::from(0xf0));
assert_eq!(BitGrid8::from(0xf00f00).shift_y(-1), BitGrid8::from(0xf00f));
let pentomino = BitGrid8::pentomino_map();
assert_eq!(pentomino[&'F'].shift_y(1), BitGrid8::from(0x2030600));
assert_eq!(pentomino[&'F'].shift_y(-1), BitGrid8::from(0x203));
}
#[test]
fn test_checked_shift_y() {
assert_eq!(BitGrid8::from(FULL).checked_shift_y(1), None);
assert_eq!(BitGrid8::from(FULL).checked_shift_y(-1), None);
assert_eq!(BitGrid8::from(0xf00f).checked_shift_y(-1), None);
assert_eq!(
BitGrid8::from(0xf00f00).checked_shift_y(-1),
Some(BitGrid8::from(0xf00f))
);
let pentomino = BitGrid8::pentomino_map();
assert_eq!(
pentomino[&'F'].checked_shift_y(1),
Some(BitGrid8::from(0x2030600))
);
assert_eq!(pentomino[&'F'].checked_shift_y(-1), None);
}
#[test]
fn test_shift_xy() {
assert_eq!(
BitGrid8::from(FULL).shift_xy(1, 1),
BitGrid8::from(0xfefe_fefe_fefe_fe00_u64)
);
assert_eq!(
BitGrid8::from(FULL).shift_xy(1, -1),
BitGrid8::from(0x00fe_fefe_fefe_fefe_u64)
);
assert_eq!(BitGrid8::from(FULL).shift_xy(-8, 1), BitGrid8::from(0));
assert_eq!(BitGrid8::from(FULL).shift_xy(1, 8), BitGrid8::from(0));
let pentomino = BitGrid8::pentomino_map();
assert_eq!(pentomino[&'F'].shift_xy(1, 1), BitGrid8::from(0x4060c00));
assert_eq!(pentomino[&'F'].shift_xy(1, -1), BitGrid8::from(0x406));
assert_eq!(pentomino[&'F'].shift_xy(-1, 1), BitGrid8::from(0x1010300));
assert_eq!(pentomino[&'F'].shift_xy(-1, -1), BitGrid8::from(0x101));
}
#[test]
fn test_checked_shift_xy() {
assert_eq!(BitGrid8::from(FULL).checked_shift_xy(1, 1), None);
assert_eq!(BitGrid8::from(FULL).checked_shift_xy(-1, -1), None);
let pentomino = BitGrid8::pentomino_map();
assert_eq!(
pentomino[&'F'].checked_shift_xy(1, 1),
Some(BitGrid8::from(0x4060c00))
);
assert_eq!(pentomino[&'F'].checked_shift_xy(1, -1), None);
assert_eq!(pentomino[&'F'].checked_shift_xy(-1, 1), None);
assert_eq!(pentomino[&'F'].checked_shift_xy(-1, -1), None);
}
#[test]
fn test_bitgrid8_iterator() {
let pentomino = BitGrid8::pentomino_map();
let pent_i_points = pentomino[&'I'].into_iter();
assert_eq!(
pent_i_points.collect::<Vec<_>>(),
[
BitGrid8::from(0x00000001),
BitGrid8::from(0x00000100),
BitGrid8::from(0x00010000),
BitGrid8::from(0x01000000),
BitGrid8::from(0x100000000)
]
);
assert_eq!(
pent_i_points.collect::<Vec<_>>(),
[
BitGrid8::from(0x00000001),
BitGrid8::from(0x00000100),
BitGrid8::from(0x00010000),
BitGrid8::from(0x01000000),
BitGrid8::from(0x100000000)
]
);
let pent_i_points_rotate = pentomino[&'I'].rotate_cc().into_iter();
assert_eq!(
pent_i_points_rotate.collect::<Vec<_>>(),
[
BitGrid8::from(0x00000008),
BitGrid8::from(0x00000010),
BitGrid8::from(0x00000020),
BitGrid8::from(0x00000040),
BitGrid8::from(0x00000080)
]
);
assert_eq!(
pent_i_points_rotate.collect::<Vec<_>>(),
[
BitGrid8::from(0x00000008),
BitGrid8::from(0x00000010),
BitGrid8::from(0x00000020),
BitGrid8::from(0x00000040),
BitGrid8::from(0x00000080)
]
);
}
#[test]
fn test_bounding_box_pentomino() {
let pentomino = BitGrid8::pentomino_map();
assert_eq!(pentomino[&'F'].bounding_box(), (3, 3));
assert_eq!(pentomino[&'I'].bounding_box(), (1, 5));
assert_eq!(pentomino[&'L'].bounding_box(), (2, 4));
assert_eq!(pentomino[&'P'].bounding_box(), (2, 3));
assert_eq!(pentomino[&'W'].bounding_box(), (3, 3));
}
#[test]
fn test_bounding_box() {
assert_eq!(BitGrid8::from(FULL).bounding_box(), (8, 8));
assert_eq!(BitGrid8::from(LOWER_LEFT).bounding_box(), (4, 4));
assert_eq!(BitGrid8::from(BACKSLASH).bounding_box(), (8, 8));
assert_eq!(BitGrid8::from(HIGHFIVE).bounding_box(), (8, 5));
assert_eq!(BitGrid8::from(SMALL_FIVE).bounding_box(), (4, 5));
assert_eq!(BitGrid8::from(0).bounding_box(), (0, 0));
assert_eq!(BitGrid8::from(1).bounding_box(), (1, 1));
}
#[test]
fn test_origin_bounding_box_pentomino() {
let pentomino = BitGrid8::pentomino_map();
assert_eq!(pentomino[&'F'].bounding_box(), (3, 3));
assert_eq!(pentomino[&'I'].bounding_box(), (1, 5));
assert_eq!(pentomino[&'L'].bounding_box(), (2, 4));
assert_eq!(pentomino[&'P'].bounding_box(), (2, 3));
assert_eq!(pentomino[&'W'].bounding_box(), (3, 3));
}
#[test]
fn test_rotate_cc() {
assert_eq!(
BitGrid8::from(0x171515151515151d).rotate_cc(),
BitGrid8::from(HIGHFIVE)
);
assert_eq!(
BitGrid8::from(0x1715151d00000000).rotate_cc(),
BitGrid8::from(SMALL_FIVE)
);
assert_eq!(BitGrid8::from(FULL).rotate_cc(), BitGrid8::from(FULL));
println!("{}", BitGrid8::from(UPPER_LEFT));
println!("{}", BitGrid8::from(UPPER_LEFT).rotate_cc());
assert_eq!(
BitGrid8::from(LOWER_LEFT),
BitGrid8::from(UPPER_LEFT).rotate_cc()
);
assert_eq!(BitGrid8::from(BACKSLASH), BitGrid8::from(SLASH).rotate_cc());
}
#[test]
fn test_rotate() {
assert_eq!(
BitGrid8::from(HIGHFIVE).rotate(),
BitGrid8::from(0x171515151515151d)
);
assert_eq!(
BitGrid8::from(SMALL_FIVE).rotate(),
BitGrid8::from(0x1715151d00000000)
);
assert_eq!(BitGrid8::from(BACKSLASH), BitGrid8::from(SLASH).rotate());
assert_eq!(BitGrid8::from(FULL).rotate(), BitGrid8::from(FULL));
assert_eq!(
BitGrid8::from(LOWER_LEFT).rotate(),
BitGrid8::from(UPPER_LEFT)
);
}
#[test]
fn test_rotate_composition() {
assert_eq!(
BitGrid8::from(0x9288_7746_3521_0076).rotate().rotate_cc(),
BitGrid8::from(0x9288_7746_3521_0076)
);
assert_eq!(
BitGrid8::from(0x9288_7746_3521_0076).rotate_cc().rotate(),
BitGrid8::from(0x9288_7746_3521_0076)
);
}
#[test]
fn test_flip_x() {
assert_eq!(BitGrid8::from(BACKSLASH), BitGrid8::from(SLASH).flip_x());
assert_eq!(BitGrid8::from(FULL).flip_x(), BitGrid8::from(FULL));
println!("{}", BitGrid8::from(UPPER_LEFT));
println!("{}", BitGrid8::from(UPPER_LEFT).flip_x());
assert_eq!(
BitGrid8::from(UPPER_LEFT).flip_x(),
BitGrid8::from(LOWER_LEFT)
);
assert_eq!(
BitGrid8::from(HIGHFIVE).flip_x(),
BitGrid8::from(0xff01_ff80_ff00_0000)
);
}
#[test]
fn test_rotate_all_vec() {
assert_eq!(
BitGrid8::rotate_all_vec(BitGrid8::from(CENTER_XY)).as_slice(),
&[BitGrid8::from(CENTER_XY)]
);
assert_eq!(
BitGrid8::rotate_all_vec(BitGrid8::from(UPPER_LEFT)).as_slice(),
&[
BitGrid8::from(LOWER_LEFT),
BitGrid8::from(LOWER_RIGHT),
BitGrid8::from(UPPER_LEFT),
BitGrid8::from(UPPER_RIGHT),
]
);
assert_eq!(BitGrid8::rotate_all_vec(BitGrid8::from(SLASH)).len(), 2);
assert_eq!(BitGrid8::rotate_all_vec(BitGrid8::from(CHECKER2)).len(), 4);
}
#[test]
fn test_origin_rotate_all() {
assert_eq!(
BitGrid8::origin_rotate_all(BitGrid8::from(CENTER_XY)).as_slice(),
&[BitGrid8::from(CENTER_XY)]
);
assert_eq!(
BitGrid8::origin_rotate_all(BitGrid8::from(UPPER_LEFT)).len(),
1
);
assert_eq!(
BitGrid8::origin_rotate_all(BitGrid8::from(HIGHFIVE)).len(),
2
);
assert_eq!(
BitGrid8::origin_rotate_all(BitGrid8::from(CHECKER2)).len(),
2
);
assert_eq!(BitGrid8::origin_rotate_all(BitGrid8::from(0x103)).len(), 4);
}
#[test]
fn test_origin_dihedral_all() {
assert_eq!(
BitGrid8::origin_dihedral_all(BitGrid8::from(CENTER_XY)).as_slice(),
&[BitGrid8::from(CENTER_XY)]
);
assert_eq!(
BitGrid8::origin_dihedral_all(BitGrid8::from(UPPER_LEFT)).len(),
1
);
assert_eq!(
BitGrid8::origin_dihedral_all(BitGrid8::from(HIGHFIVE)).len(),
4
);
assert_eq!(
BitGrid8::origin_dihedral_all(BitGrid8::from(CHECKER2)).len(),
2
);
assert_eq!(
BitGrid8::origin_dihedral_all(BitGrid8::from(0x103)).len(),
4
);
}
#[test]
fn test_origin_dihedral_all_pentomino() {
let pentomino = BitGrid8::pentomino_map();
assert_eq!(pentomino[&'F'].origin_dihedral_all().len(), 8);
assert_eq!(pentomino[&'N'].origin_dihedral_all().len(), 8);
assert_eq!(pentomino[&'P'].origin_dihedral_all().len(), 8);
assert_eq!(pentomino[&'Y'].origin_dihedral_all().len(), 8);
assert_eq!(pentomino[&'V'].origin_dihedral_all().len(), 4);
assert_eq!(pentomino[&'W'].origin_dihedral_all().len(), 4);
}
#[test]
fn test_pentomino_map() {
let pentomino = BitGrid8::pentomino_map();
assert_eq!(
&pentomino[&'X'],
&pentomino[&'X'].rotate_cc().shift_to_origin()
);
assert_eq!(
&pentomino[&'X'],
&pentomino[&'X'].rotate().shift_to_origin()
);
assert_eq!(pentomino[&'X'].origin_rotate_all().len(), 1);
assert_eq!(pentomino[&'F'].origin_rotate_all().len(), 4);
assert_eq!(pentomino[&'Z'].origin_rotate_all().len(), 2);
}
#[test]
fn test_blsi() {
let n: u64 = 0b_01100100;
assert_eq!(n.isolate_lowest_one(), 0b_00000100);
assert_eq!(0_u64.isolate_lowest_one(), 0);
}
}