124 lines
3.4 KiB
Rust
124 lines
3.4 KiB
Rust
use crate::Card;
|
|
use crate::CardField;
|
|
use crate::Icon;
|
|
use crate::Painting;
|
|
|
|
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
|
pub(crate) struct IconBitfield {
|
|
circle: u8,
|
|
square: u8,
|
|
triangle: u8,
|
|
color: u8,
|
|
points: u8,
|
|
}
|
|
|
|
impl IconBitfield {
|
|
pub fn get_icon_bits(&self, icon: Icon) -> u8 {
|
|
match icon {
|
|
Icon::Circle => self.circle,
|
|
Icon::Square => self.square,
|
|
Icon::Triangle => self.triangle,
|
|
Icon::Color => self.color,
|
|
}
|
|
}
|
|
pub fn get_point_bits(&self) -> u8 {
|
|
self.points
|
|
}
|
|
|
|
fn add_icon(&mut self, icon: Icon, index: u8) {
|
|
let field = match icon {
|
|
Icon::Circle => &mut self.circle,
|
|
Icon::Square => &mut self.square,
|
|
Icon::Triangle => &mut self.triangle,
|
|
Icon::Color => &mut self.color,
|
|
};
|
|
*field |= 1 << index;
|
|
}
|
|
pub fn add_field(&mut self, field: CardField, index: u8) {
|
|
debug_assert!(index < 5);
|
|
match field {
|
|
CardField::Icon(icon) => self.add_icon(icon, index),
|
|
CardField::DoubleIcon(icon1, icon2) => {
|
|
self.add_icon(icon1, index);
|
|
self.add_icon(icon2, index);
|
|
}
|
|
CardField::PointsPer(_) => self.points |= 1 << index,
|
|
CardField::Empty => (),
|
|
}
|
|
}
|
|
|
|
pub fn new(card: &Card) -> Self {
|
|
let mut result = Self::default();
|
|
(0u8..)
|
|
.zip(card.field_iter())
|
|
.for_each(|(index, field)| result.add_field(field, index));
|
|
result
|
|
}
|
|
|
|
pub fn from_painting(painting: &Painting) -> Self {
|
|
let mut bits = Self::new(&painting[0]);
|
|
bits.layer_below(&Self::new(&painting[1]))
|
|
.layer_below(&Self::new(&painting[2]));
|
|
bits
|
|
}
|
|
|
|
pub fn all_fields(&self) -> u8 {
|
|
self.circle | self.square | self.triangle | self.color | self.points
|
|
}
|
|
|
|
/// Result of putting the other card below this one
|
|
pub fn layer_below(&mut self, other: &Self) -> &mut Self {
|
|
// 1 x 0 = 0
|
|
// 0 x 0 = 0
|
|
// 0 x 1 = 1
|
|
// 1 x 1 = 0
|
|
// Should be !a & b
|
|
|
|
let bitmask = !self.all_fields() & other.all_fields();
|
|
self.circle |= other.circle & bitmask;
|
|
self.square |= other.square & bitmask;
|
|
self.triangle |= other.triangle & bitmask;
|
|
self.color |= other.color & bitmask;
|
|
self.points |= other.points & bitmask;
|
|
self
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{Icon, icon_bitfield::IconBitfield};
|
|
|
|
#[test]
|
|
fn test_add_field() {
|
|
let mut x: IconBitfield = Default::default();
|
|
x.add_icon(Icon::Circle, 2);
|
|
let expected = IconBitfield {
|
|
circle: 0b00100,
|
|
..Default::default()
|
|
};
|
|
assert_eq!(x, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_layer_below() {
|
|
let mut a: IconBitfield = IconBitfield {
|
|
color: 0b00010,
|
|
points: 0b01000,
|
|
..Default::default()
|
|
};
|
|
let b = IconBitfield {
|
|
triangle: a.get_point_bits(),
|
|
square: 0b10000,
|
|
..Default::default()
|
|
};
|
|
let expected = IconBitfield {
|
|
color: a.get_icon_bits(Icon::Color),
|
|
points: a.get_point_bits(),
|
|
square: b.get_icon_bits(Icon::Square),
|
|
..Default::default()
|
|
};
|
|
a.layer_below(&b);
|
|
assert_eq!(a, expected);
|
|
}
|
|
}
|