mirror of
https://github.com/kristoferssolo/hexlab.git
synced 2025-10-21 19:40:34 +00:00
feat(walls): add more methods
This commit is contained in:
parent
cb52be461a
commit
7d5d0743b9
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1,6 +1,6 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ab_glyph"
|
name = "ab_glyph"
|
||||||
@ -2063,7 +2063,7 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hexlab"
|
name = "hexlab"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"hexx",
|
"hexx",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "hexlab"
|
name = "hexlab"
|
||||||
authors = ["Kristofers Solo <dev@kristofers.xyz>"]
|
authors = ["Kristofers Solo <dev@kristofers.xyz>"]
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A hexagonal maze generation and manipulation library"
|
description = "A hexagonal maze generation and manipulation library"
|
||||||
repository = "https://github.com/kristoferssolo/hexlab"
|
repository = "https://github.com/kristoferssolo/hexlab"
|
||||||
|
|||||||
724
src/walls.rs
724
src/walls.rs
@ -1,13 +1,47 @@
|
|||||||
use std::{
|
|
||||||
fmt::Debug,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "bevy")]
|
#[cfg(feature = "bevy")]
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::{Component, Reflect, ReflectComponent};
|
||||||
use hexx::EdgeDirection;
|
use hexx::EdgeDirection;
|
||||||
|
|
||||||
/// Represents the walls of a hexagonal tile using bit flags
|
/// A bit-flag representation of walls in a hexagonal tile.
|
||||||
|
///
|
||||||
|
/// `Walls` uses an efficient bit-flag system to track the presence or absence of walls
|
||||||
|
/// along each edge of a hexagonal tile. Each of the six possible walls is represented
|
||||||
|
/// by a single bit in an 8-bit integer, allowing for fast operations and minimal memory usage.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Creating and manipulating walls:
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// // Create a hexagon with all walls
|
||||||
|
/// let walls = Walls::new();
|
||||||
|
/// assert!(walls.is_closed());
|
||||||
|
///
|
||||||
|
/// // Create a hexagon with no walls
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
/// assert!(walls.is_empty());
|
||||||
|
///
|
||||||
|
/// // Add specific walls
|
||||||
|
/// walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
/// walls.add(EdgeDirection::FLAT_SOUTH);
|
||||||
|
/// assert_eq!(walls.count(), 2);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using walls in game logic:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
///
|
||||||
|
/// // Add walls to create a corner
|
||||||
|
/// walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
/// walls.add(EdgeDirection::FLAT_SOUTH_EAST);
|
||||||
|
///
|
||||||
|
/// // Check if a specific direction has a wall
|
||||||
|
/// assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
/// assert!(!walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "bevy", derive(Reflect, Component))]
|
#[cfg_attr(feature = "bevy", derive(Reflect, Component))]
|
||||||
@ -15,38 +49,279 @@ use hexx::EdgeDirection;
|
|||||||
pub struct Walls(u8);
|
pub struct Walls(u8);
|
||||||
|
|
||||||
impl Walls {
|
impl Walls {
|
||||||
|
/// Creates a new set of walls with all edges closed.
|
||||||
|
///
|
||||||
|
/// This is the default state where all six edges of the hexagon have walls.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let walls = Walls::new();
|
||||||
|
/// assert!(walls.is_closed());
|
||||||
|
/// assert_eq!(walls.count(), 6);
|
||||||
|
/// ```
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new set of walls with no edges (completely open).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let walls = Walls::empty();
|
||||||
|
/// assert!(walls.is_empty());
|
||||||
|
/// assert_eq!(walls.count(), 0);
|
||||||
|
/// ```
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the walls are currently empty
|
||||||
|
///
|
||||||
|
/// Returns `true` if all directions have no walls set.
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let walls = Walls::empty();
|
||||||
|
/// assert!(walls.is_empty());
|
||||||
|
///
|
||||||
|
/// let walls = Walls::new();
|
||||||
|
/// assert!(!walls.is_empty());
|
||||||
|
/// ```
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0 == 0
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a wall in the specified direction
|
/// Adds a wall in the specified direction
|
||||||
|
///
|
||||||
|
/// This method uses bitwise operations to efficiently set the wall flag
|
||||||
|
/// for the given direction. Multiple walls can be added to the same hexagon.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
/// walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
/// assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
/// assert!(!walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
///
|
||||||
|
/// walls.add(EdgeDirection::FLAT_SOUTH);
|
||||||
|
/// assert!(walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
/// assert_eq!(walls.count(), 2);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add<T>(&mut self, direction: T)
|
pub fn add<T>(&mut self, direction: T)
|
||||||
where
|
where
|
||||||
T: Into<Self>,
|
T: Into<Self> + Copy,
|
||||||
{
|
{
|
||||||
self.0 |= direction.into().0;
|
self.0 |= direction.into().0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a wall in the specified direction
|
/// Removes a wall in the specified direction
|
||||||
|
///
|
||||||
|
/// Returns `true` if a wall was actually removed, `false` if there was no wall
|
||||||
|
/// in the specified direction.
|
||||||
|
///
|
||||||
|
/// # Exmaples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::new();
|
||||||
|
/// assert!(walls.remove(EdgeDirection::FLAT_NORTH));
|
||||||
|
/// assert!(!walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
///
|
||||||
|
/// // Removing a non-existent wall returns false
|
||||||
|
/// assert!(!walls.remove(EdgeDirection::FLAT_NORTH));
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove<T>(&mut self, direction: T)
|
pub fn remove<T>(&mut self, direction: T) -> bool
|
||||||
where
|
where
|
||||||
T: Into<Self>,
|
T: Into<Self> + Copy,
|
||||||
{
|
{
|
||||||
self.0 &= !direction.into().0;
|
let was_removed = self.contains(direction);
|
||||||
|
if was_removed {
|
||||||
|
self.0 &= !direction.into().0;
|
||||||
|
}
|
||||||
|
was_removed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if there is a wall in the specified direction
|
/// Returns true if there is a wall in the specified direction
|
||||||
|
///
|
||||||
|
/// Uses efficient bitwise operations to check for the presence of a wall.
|
||||||
|
///
|
||||||
|
/// # Exmaples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
///
|
||||||
|
/// walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
/// assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
/// assert!(!walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains<T>(&self, other: T) -> bool
|
pub fn contains<T>(&self, other: T) -> bool
|
||||||
where
|
where
|
||||||
T: Into<Self>,
|
T: Into<Self> + Copy,
|
||||||
{
|
{
|
||||||
self.0 & other.into().0 != 0
|
self.0 & other.into().0 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the raw bit representation of the walls
|
/// Returns the raw bit representation of the walls
|
||||||
|
///
|
||||||
|
/// This method provides access to the underlying bit flags for advanced usage.
|
||||||
|
/// The bits are ordered according to the `EdgeDirection` indices.
|
||||||
|
///
|
||||||
|
/// # Exmaples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::new();
|
||||||
|
///
|
||||||
|
/// assert_eq!(walls.as_bits(), 0b111111);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_bits(&self) -> u8 {
|
pub fn as_bits(&self) -> u8 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the total number of walls present
|
||||||
|
///
|
||||||
|
/// Efficiently counts the number of set bits in the internal representation.
|
||||||
|
///
|
||||||
|
/// # Exmaples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
///
|
||||||
|
/// assert_eq!(walls.count(), 0);
|
||||||
|
///
|
||||||
|
/// walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
/// walls.add(EdgeDirection::FLAT_SOUTH);
|
||||||
|
/// assert_eq!(walls.count(), 2);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn count(&self) -> u8 {
|
||||||
|
self.0.count_ones() as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns all possible directions as a `Walls` value
|
||||||
|
///
|
||||||
|
/// This represents a hexagon with walls in all six directions.
|
||||||
|
///
|
||||||
|
/// # Exmaples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let all_walls = Walls::all_directions();
|
||||||
|
///
|
||||||
|
/// assert_eq!(all_walls.count(), 6);
|
||||||
|
/// assert!(all_walls.is_closed());
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn all_directions() -> Self {
|
||||||
|
Self(0b111111)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggles a wall in the specified direction.
|
||||||
|
///
|
||||||
|
/// If a wall exists in the given direction, it will be removed.
|
||||||
|
/// If no wall exists, one will be added.
|
||||||
|
/// Returns the previous state (`true` if a wall was present).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
///
|
||||||
|
/// assert!(!walls.toggle(EdgeDirection::FLAT_NORTH)); // Returns false, wall was not present
|
||||||
|
/// assert!(walls.contains(EdgeDirection::FLAT_NORTH)); // Wall is now present
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::new();
|
||||||
|
///
|
||||||
|
/// assert!(walls.toggle(EdgeDirection::FLAT_NORTH)); // Returns true, wall was present
|
||||||
|
/// assert!(!walls.contains(EdgeDirection::FLAT_NORTH)); // Wall is now removed
|
||||||
|
/// ```
|
||||||
|
pub fn toggle<T>(&mut self, direction: T) -> bool
|
||||||
|
where
|
||||||
|
T: Into<Self> + Copy,
|
||||||
|
{
|
||||||
|
let is_present = self.contains(direction);
|
||||||
|
if is_present {
|
||||||
|
self.remove(direction);
|
||||||
|
} else {
|
||||||
|
self.add(direction);
|
||||||
|
}
|
||||||
|
is_present
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if walls are present in all six directions.
|
||||||
|
///
|
||||||
|
/// Returns `true` if the hexagon has all possible walls, making it completely enclosed.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let walls = Walls::new();
|
||||||
|
/// assert!(walls.is_closed());
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
/// assert!(!walls.is_closed());
|
||||||
|
/// // Add all walls manually
|
||||||
|
/// for direction in EdgeDirection::iter() {
|
||||||
|
/// walls.add(direction);
|
||||||
|
/// }
|
||||||
|
/// assert!(walls.is_closed());
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn is_closed(&self) -> bool {
|
||||||
|
self.count() == 6
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets walls for multiple directions at once.
|
||||||
|
///
|
||||||
|
/// This method efficiently adds multiple walls in a single operation while
|
||||||
|
/// preserving any existing walls not specified in the input.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use hexlab::prelude::*;
|
||||||
|
///
|
||||||
|
/// let mut walls = Walls::empty();
|
||||||
|
/// walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
///
|
||||||
|
/// walls.fill([EdgeDirection::FLAT_SOUTH, EdgeDirection::FLAT_SOUTH_EAST]);
|
||||||
|
///
|
||||||
|
/// assert!(walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
/// assert_eq!(walls.count(), 3);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn fill<T>(&mut self, other: T)
|
||||||
|
where
|
||||||
|
T: Into<Self>,
|
||||||
|
{
|
||||||
|
self.0 |= other.into().0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EdgeDirection> for Walls {
|
impl From<EdgeDirection> for Walls {
|
||||||
@ -55,33 +330,25 @@ impl From<EdgeDirection> for Walls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<[EdgeDirection; 6]> for Walls {
|
|
||||||
fn from(value: [EdgeDirection; 6]) -> Self {
|
|
||||||
let mut walls = 0u8;
|
|
||||||
for direction in value {
|
|
||||||
walls |= 1 << direction.index();
|
|
||||||
}
|
|
||||||
Self(walls)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for Walls {
|
impl From<u8> for Walls {
|
||||||
fn from(value: u8) -> Self {
|
fn from(value: u8) -> Self {
|
||||||
Self(1 << value)
|
Self(1 << value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Walls {
|
impl FromIterator<EdgeDirection> for Walls {
|
||||||
type Target = u8;
|
fn from_iter<T: IntoIterator<Item = EdgeDirection>>(iter: T) -> Self {
|
||||||
|
let mut walls = 0u8;
|
||||||
fn deref(&self) -> &Self::Target {
|
for direction in iter {
|
||||||
&self.0
|
walls |= 1 << direction.index();
|
||||||
|
}
|
||||||
|
Self(walls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for Walls {
|
impl<const N: usize> From<[EdgeDirection; N]> for Walls {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn from(value: [EdgeDirection; N]) -> Self {
|
||||||
&mut self.0
|
value.into_iter().collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,119 +362,308 @@ impl Default for Walls {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// all_directions
|
||||||
#[test]
|
#[test]
|
||||||
fn new_walls() {
|
fn all_directions_creates_closed_walls() {
|
||||||
let walls = Walls::default();
|
let walls = Walls::all_directions();
|
||||||
// All walls should be present by default
|
assert!(walls.is_closed());
|
||||||
for direction in EdgeDirection::iter() {
|
assert!(!walls.is_empty());
|
||||||
assert!(
|
assert_eq!(walls.as_bits(), 0b111111);
|
||||||
walls.contains(direction),
|
|
||||||
"Wall should exist in direction {:?}",
|
|
||||||
direction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// as_bits
|
||||||
#[test]
|
#[test]
|
||||||
fn add_remove_single_wall() {
|
fn as_bits_empty() {
|
||||||
let mut walls = Walls::default();
|
let walls = Walls::empty();
|
||||||
|
|
||||||
// Remove and verify each wall
|
|
||||||
walls.remove(EdgeDirection::FLAT_TOP);
|
|
||||||
assert!(!walls.contains(EdgeDirection::FLAT_TOP));
|
|
||||||
|
|
||||||
// Add back and verify
|
|
||||||
walls.add(EdgeDirection::FLAT_TOP);
|
|
||||||
assert!(walls.contains(EdgeDirection::FLAT_TOP));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multiple_operations() {
|
|
||||||
let mut walls = Walls::default();
|
|
||||||
|
|
||||||
// Remove multiple walls
|
|
||||||
walls.remove(EdgeDirection::FLAT_TOP);
|
|
||||||
walls.remove(EdgeDirection::FLAT_BOTTOM);
|
|
||||||
|
|
||||||
// Verify removed walls
|
|
||||||
assert!(!walls.contains(EdgeDirection::FLAT_TOP));
|
|
||||||
assert!(!walls.contains(EdgeDirection::FLAT_BOTTOM));
|
|
||||||
|
|
||||||
// Verify other walls still exist
|
|
||||||
assert!(walls.contains(EdgeDirection::FLAT_TOP_RIGHT));
|
|
||||||
assert!(walls.contains(EdgeDirection::FLAT_TOP_LEFT));
|
|
||||||
|
|
||||||
// Add back one wall
|
|
||||||
walls.add(EdgeDirection::FLAT_TOP);
|
|
||||||
assert!(walls.contains(EdgeDirection::FLAT_TOP));
|
|
||||||
assert!(!walls.contains(EdgeDirection::FLAT_BOTTOM));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn bit_patterns() {
|
|
||||||
let mut walls = Walls::default();
|
|
||||||
assert_eq!(
|
|
||||||
walls.as_bits(),
|
|
||||||
0b111111,
|
|
||||||
"Initial state should have all walls"
|
|
||||||
);
|
|
||||||
|
|
||||||
walls.remove(EdgeDirection::FLAT_BOTTOM_RIGHT);
|
|
||||||
assert_eq!(walls.as_bits() & 0b000001, 0, "First bit should be cleared");
|
|
||||||
|
|
||||||
walls.add(EdgeDirection::FLAT_BOTTOM_RIGHT);
|
|
||||||
assert_eq!(walls.as_bits() & 0b000001, 1, "First bit should be set");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn remove_all_walls() {
|
|
||||||
let mut walls = Walls::default();
|
|
||||||
|
|
||||||
// Remove all walls
|
|
||||||
for direction in EdgeDirection::iter() {
|
|
||||||
walls.remove(direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify all walls are removed
|
|
||||||
assert_eq!(walls.as_bits(), 0, "All walls should be removed");
|
|
||||||
|
|
||||||
// Verify each direction
|
|
||||||
for direction in EdgeDirection::iter() {
|
|
||||||
assert!(
|
|
||||||
!walls.contains(direction),
|
|
||||||
"No wall should exist in direction {:?}",
|
|
||||||
direction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deref_operations() {
|
|
||||||
let mut walls = Walls::default();
|
|
||||||
|
|
||||||
// Test Deref
|
|
||||||
let bits: &u8 = walls.deref();
|
|
||||||
assert_eq!(*bits, 0b111111);
|
|
||||||
|
|
||||||
// Test DerefMut
|
|
||||||
*walls.deref_mut() = 0;
|
|
||||||
assert_eq!(walls.as_bits(), 0);
|
assert_eq!(walls.as_bits(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn idempotent_operations() {
|
fn as_bits_single_wall() {
|
||||||
let mut walls = Walls::default();
|
let mut walls = Walls::empty();
|
||||||
|
walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010000);
|
||||||
|
}
|
||||||
|
|
||||||
// Adding twice shouldn't change the result
|
#[test]
|
||||||
walls.add(EdgeDirection::FLAT_TOP);
|
fn as_bits_multiple_walls() {
|
||||||
let first_add = walls.as_bits();
|
let mut walls = Walls::empty();
|
||||||
walls.add(EdgeDirection::FLAT_TOP);
|
walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
assert_eq!(walls.as_bits(), first_add);
|
walls.add(EdgeDirection::FLAT_SOUTH);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010010);
|
||||||
|
}
|
||||||
|
|
||||||
// Removing twice shouldn't change the result
|
#[test]
|
||||||
walls.remove(EdgeDirection::FLAT_TOP);
|
fn as_bits_all_walls() {
|
||||||
let first_remove = walls.as_bits();
|
let walls = Walls::new();
|
||||||
walls.remove(EdgeDirection::FLAT_TOP);
|
assert_eq!(walls.as_bits(), 0b111111);
|
||||||
assert_eq!(walls.as_bits(), first_remove);
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
#[test]
|
||||||
|
fn new_created_closed_walls() {
|
||||||
|
let walls = Walls::new();
|
||||||
|
assert!(walls.is_closed());
|
||||||
|
assert_eq!(walls.as_bits(), 0b111111);
|
||||||
|
}
|
||||||
|
|
||||||
|
// empty
|
||||||
|
#[test]
|
||||||
|
fn empty_creates_no_walls() {
|
||||||
|
let walls = Walls::empty();
|
||||||
|
assert!(walls.is_empty());
|
||||||
|
assert_eq!(walls.as_bits(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add
|
||||||
|
#[test]
|
||||||
|
fn add_single_wall() {
|
||||||
|
let mut walls = Walls::empty();
|
||||||
|
walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert_eq!(walls.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove
|
||||||
|
#[test]
|
||||||
|
fn remove_existing_wall() {
|
||||||
|
let mut walls = Walls::new();
|
||||||
|
assert!(walls.remove(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert!(!walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_nonexistent_wall() {
|
||||||
|
let mut walls = Walls::empty();
|
||||||
|
assert!(!walls.remove(EdgeDirection::FLAT_NORTH));
|
||||||
|
walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
assert!(walls.remove(EdgeDirection::FLAT_NORTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
// toggle
|
||||||
|
#[test]
|
||||||
|
fn toggle_adds_wall() {
|
||||||
|
let mut walls = Walls::empty();
|
||||||
|
assert!(!walls.toggle(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn toggle_removes_wall() {
|
||||||
|
let mut walls = Walls::new();
|
||||||
|
assert!(walls.toggle(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert!(!walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill
|
||||||
|
#[test]
|
||||||
|
fn fill_adds_multiple_walls() {
|
||||||
|
let mut walls = Walls::empty();
|
||||||
|
walls.fill([EdgeDirection::FLAT_NORTH, EdgeDirection::FLAT_SOUTH]);
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
assert_eq!(walls.count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fill_preserves_existing_walls() {
|
||||||
|
let mut walls = Walls::empty();
|
||||||
|
walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
walls.fill([EdgeDirection::FLAT_SOUTH, EdgeDirection::FLAT_SOUTH_EAST]);
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_SOUTH_EAST));
|
||||||
|
assert_eq!(walls.count(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_edge_direction_conversion() {
|
||||||
|
let walls: Walls = EdgeDirection::FLAT_NORTH.into();
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert_eq!(walls.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_u8_conversion() {
|
||||||
|
let walls: Walls = 0u8.into();
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_SOUTH_EAST));
|
||||||
|
assert_eq!(walls.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_array_conversion() {
|
||||||
|
let walls: Walls = [EdgeDirection::FLAT_NORTH, EdgeDirection::FLAT_SOUTH].into();
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
assert_eq!(walls.count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_iterator_handles_duplicates() {
|
||||||
|
let directions = vec![
|
||||||
|
EdgeDirection::FLAT_NORTH,
|
||||||
|
EdgeDirection::FLAT_SOUTH,
|
||||||
|
EdgeDirection::FLAT_NORTH, // Duplicate
|
||||||
|
];
|
||||||
|
let walls: Walls = directions.into_iter().collect();
|
||||||
|
assert_eq!(walls.count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_creates_closed_walls() {
|
||||||
|
let walls = Walls::default();
|
||||||
|
assert!(walls.is_closed());
|
||||||
|
assert_eq!(walls.as_bits(), 0b111111);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_iterator() {
|
||||||
|
let directions = vec![
|
||||||
|
EdgeDirection::FLAT_NORTH,
|
||||||
|
EdgeDirection::FLAT_SOUTH,
|
||||||
|
EdgeDirection::FLAT_NORTH, // Duplicate should not affect result
|
||||||
|
];
|
||||||
|
let walls: Walls = directions.into_iter().collect();
|
||||||
|
assert_eq!(walls.count(), 2);
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_NORTH));
|
||||||
|
assert!(walls.contains(EdgeDirection::FLAT_SOUTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bit_manipulation() {
|
||||||
|
let mut walls = Walls::empty();
|
||||||
|
|
||||||
|
// Test single bit operations
|
||||||
|
walls.add(EdgeDirection::FLAT_NORTH);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010000);
|
||||||
|
|
||||||
|
walls.add(EdgeDirection::FLAT_SOUTH);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010010);
|
||||||
|
|
||||||
|
// Test removing middle bit
|
||||||
|
walls.add(EdgeDirection::FLAT_SOUTH_EAST);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010011);
|
||||||
|
walls.remove(EdgeDirection::FLAT_SOUTH);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010001);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From<EdgeDirection> tests
|
||||||
|
#[test]
|
||||||
|
fn from_edge_direction_flat_south_east() {
|
||||||
|
let walls = Walls::from(EdgeDirection::FLAT_SOUTH_EAST);
|
||||||
|
assert_eq!(walls.as_bits(), 0b000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_edge_direction_flat_south() {
|
||||||
|
let walls = Walls::from(EdgeDirection::FLAT_SOUTH);
|
||||||
|
assert_eq!(walls.as_bits(), 0b000010);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_edge_direction_flat_south_west() {
|
||||||
|
let walls = Walls::from(EdgeDirection::FLAT_SOUTH_WEST);
|
||||||
|
assert_eq!(walls.as_bits(), 0b000100);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_edge_direction_flat_north_west() {
|
||||||
|
let walls = Walls::from(EdgeDirection::FLAT_NORTH_WEST);
|
||||||
|
assert_eq!(walls.as_bits(), 0b001000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_edge_direction_flat_north() {
|
||||||
|
let walls = Walls::from(EdgeDirection::FLAT_NORTH);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_edge_direction_flat_east() {
|
||||||
|
let walls = Walls::from(EdgeDirection::FLAT_NORTH_EAST);
|
||||||
|
assert_eq!(walls.as_bits(), 0b100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromIterator tests
|
||||||
|
#[test]
|
||||||
|
fn from_iterator_empty() {
|
||||||
|
let walls = Vec::new().into_iter().collect::<Walls>();
|
||||||
|
assert!(walls.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_iterator_single() {
|
||||||
|
let walls = vec![EdgeDirection::FLAT_SOUTH]
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Walls>();
|
||||||
|
assert_eq!(walls.as_bits(), 0b000010);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_iterator_multiple() {
|
||||||
|
let walls = vec![EdgeDirection::FLAT_NORTH, EdgeDirection::FLAT_SOUTH]
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Walls>();
|
||||||
|
assert_eq!(walls.as_bits(), 0b010010);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_iterator_duplicates() {
|
||||||
|
let walls = vec![
|
||||||
|
EdgeDirection::FLAT_NORTH,
|
||||||
|
EdgeDirection::FLAT_NORTH,
|
||||||
|
EdgeDirection::FLAT_SOUTH,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Walls>();
|
||||||
|
assert_eq!(walls.as_bits(), 0b010010);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_iterator_all_directions() {
|
||||||
|
let walls = EdgeDirection::iter().collect::<Walls>();
|
||||||
|
assert_eq!(walls.as_bits(), 0b111111);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From<[EdgeDirection; N]> tests
|
||||||
|
#[test]
|
||||||
|
fn from_array_empty() {
|
||||||
|
let walls = Walls::from([]);
|
||||||
|
assert!(walls.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_array_single() {
|
||||||
|
let walls = Walls::from([EdgeDirection::FLAT_NORTH]);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_array_multiple() {
|
||||||
|
let walls = Walls::from([EdgeDirection::FLAT_NORTH, EdgeDirection::FLAT_SOUTH]);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010010);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_array_duplicates() {
|
||||||
|
let walls = Walls::from([
|
||||||
|
EdgeDirection::FLAT_NORTH,
|
||||||
|
EdgeDirection::FLAT_NORTH,
|
||||||
|
EdgeDirection::FLAT_SOUTH,
|
||||||
|
]);
|
||||||
|
assert_eq!(walls.as_bits(), 0b010010);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_array_all_directions() {
|
||||||
|
let walls = Walls::from([
|
||||||
|
EdgeDirection::FLAT_NORTH,
|
||||||
|
EdgeDirection::FLAT_NORTH_EAST,
|
||||||
|
EdgeDirection::FLAT_SOUTH_EAST,
|
||||||
|
EdgeDirection::FLAT_SOUTH,
|
||||||
|
EdgeDirection::FLAT_SOUTH_WEST,
|
||||||
|
EdgeDirection::FLAT_NORTH_WEST,
|
||||||
|
]);
|
||||||
|
assert_eq!(walls.as_bits(), 0b111111);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user