Skip to content
Snippets Groups Projects
Verified Commit b845870c authored by Louis's avatar Louis :fire:
Browse files

Lint + fmt

parent 5f1bdebe
No related branches found
No related tags found
No related merge requests found
use crate::output::TileOutput;
use crate::{TileLayout, TileMatcher};
use std::fmt::{Debug, Formatter};
use std::ops::Add;
use crate::{TileLayout, TileMatcher};
use crate::output::TileOutput;
/// Checks tile layouts against a matcher instance, and uses the output to produce a value
#[derive(Clone, Default)]
......@@ -19,9 +19,17 @@ impl Debug for AutoTileRule {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
// Perform grid style formatting for matcher value
write!(f, "AutoTileRule \n{:#?}output: {:?}, chance: {:.2}", self.matcher, self.output, self.chance)
write!(
f,
"AutoTileRule \n{:#?}output: {:?}, chance: {:.2}",
self.matcher, self.output, self.chance
)
} else {
write!(f, "AutoTileRule {{ matcher: {:?}, output: {:?}, chance: {:.2} }}", self.matcher, self.output, self.chance)
write!(
f,
"AutoTileRule {{ matcher: {:?}, output: {:?}, chance: {:.2} }}",
self.matcher, self.output, self.chance
)
}
}
}
......@@ -62,11 +70,7 @@ impl AutoTileRule {
/// Create a rule that will produce one of the values contained in `output_value`
/// when the target tile matches `input_value` and the selection chacne is rolled under the
/// value of `chance` (0.0 to 1.0)
pub const fn single_any_chance(
input_value: i32,
output_value: Vec<i32>,
chance: f32,
) -> Self {
pub const fn single_any_chance(input_value: i32, output_value: Vec<i32>, chance: f32) -> Self {
AutoTileRule {
matcher: TileMatcher::single_match(input_value),
output: TileOutput::any(output_value),
......@@ -141,11 +145,7 @@ impl AutoTileRule {
/// Will use the provided RNG to select from a list, if the output resolves to
/// a random selection
#[cfg(feature = "impl_fastrand")]
pub fn resolve_match_seeded(
&self,
input: &TileLayout,
seeded: &fastrand::Rng,
) -> Option<i32> {
pub fn resolve_match_seeded(&self, input: &TileLayout, seeded: &fastrand::Rng) -> Option<i32> {
self.get_match_seeded(input, seeded)
.and_then(|out| out.resolve_with(seeded))
}
......@@ -263,13 +263,8 @@ impl AutoRuleSet {
/// Will use the provided RNG to select from a list, if the output resolves to
/// a random selection
#[cfg(feature = "impl_fastrand")]
pub fn resolve_match_seeded(
&self,
input: &TileLayout,
seeded: &fastrand::Rng,
) -> Option<i32> {
pub fn resolve_match_seeded(&self, input: &TileLayout, seeded: &fastrand::Rng) -> Option<i32> {
self.get_match_seeded(input, seeded)
.and_then(|out| out.resolve_with(seeded))
}
}
use std::fmt::{Debug, Formatter};
use crate::utils::IntoTile;
use std::fmt::{Debug, Formatter};
/// The size of the grid that can be matched; equal to the length of one side of the square grid
const RULE_MAGNITUDE: usize = 7;
......@@ -37,41 +37,38 @@ impl Debug for TileStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Ignore => write!(f, "Any Or No Tile"),
Self::Nothing => write!(f, "No Tile"),
Self::Anything => write!(f, "Any Tile"),
Self::Is(value) => write!(f, "Must Match [{}]", value),
Self::IsNot(value) => write!(f, "Must Not Match [{}]", value),
Self::Nothing => write!(f, "No Tile"),
Self::Anything => write!(f, "Any Tile"),
Self::Is(value) => write!(f, "Must Match [{}]", value),
Self::IsNot(value) => write!(f, "Must Not Match [{}]", value),
}
}
}
impl PartialEq<Option<i32>> for TileStatus {
fn eq(&self, other: &Option<i32>) -> bool {
let matched = match self {
match self {
Self::Ignore => true,
Self::Nothing => other.is_none(),
Self::Anything => other.is_some(),
Self::Is(value) => &Some(*value) == other,
Self::IsNot(value) => &Some(*value) != other,
};
matched
}
}
}
impl TileStatus {
#[deprecated(since = "0.2.0", note = "Use `TileStatus::into` directly instead")]
#[deprecated(since = "0.2.0", note = "Use `TileStatus::into` directly instead")]
pub fn to_ldtk_value(self) -> i64 {
self.into_tile() as i64
self.into_tile() as i64
}
#[deprecated(since = "0.2.0", note = "Use `TileStatus::from` directly instead")]
#[deprecated(since = "0.2.0", note = "Use `TileStatus::from` directly instead")]
pub fn from_ldtk_value(value: i64) -> Self {
Self::from(value)
Self::from(value)
}
}
/// Holds a grid of raw input data, as a more ideal format for interop and storage
#[repr(transparent)]
pub struct TileLayout(pub [Option<i32>; TILE_GRID_SIZE]);
......@@ -95,19 +92,17 @@ impl TileLayout {
}
/// Filter the layout data so that it only contains the tiles surrounding the target tile. This
/// means that the array index of every entry before the center point will match the original data
/// array, but ever entry after the center point will have its index shifted down by 1
///
/// The main utility of this is to perform set operations on every tile _other_ than the target tile.
/// means that the array index of every entry before the center point will match the original data
/// array, but ever entry after the center point will have its index shifted down by 1
///
/// The main utility of this is to perform set operations on every tile _other_ than the target tile.
///
/// ## Examples
///
/// ```
/// # use micro_autotile::TileLayout;
/// let layout = TileLayout::single(123);
/// let has_any_surrounding_tiles = layout.surrounding()
/// .iter()
/// .any(|tile| tile.is_some());
/// let has_any_surrounding_tiles = layout.surrounding().iter().any(|tile| tile.is_some());
///
/// assert_eq!(has_any_surrounding_tiles, false);
/// ```
......@@ -124,12 +119,8 @@ impl Debug for TileLayout {
let lines = as_lines(&self.0);
let mut max_width = 1;
for line in lines.iter() {
for value in line.iter() {
if let Some(value) = value {
max_width = max_width.max(value.to_string().len());
}
}
for value in lines.iter().copied().flatten().flatten() {
max_width = max_width.max(value.to_string().len());
}
for line in lines {
......@@ -139,22 +130,31 @@ impl Debug for TileLayout {
} else {
write!(f, "{:^max_width$} ", "#")?;
}
}
write!(f, "\n")?;
}
writeln!(f)?;
}
write!(f, "\n")
writeln!(f)
} else {
writeln!(f, "{:?}", self.0)
}
}
}
impl <T> TryFrom<&[T]> for TileLayout where T: IntoTile + Copy + Default {
impl<T> TryFrom<&[T]> for TileLayout
where
T: IntoTile + Copy + Default,
{
type Error = NotSquareError;
fn try_from(value: &[T]) -> Result<Self, Self::Error> {
if is_square(value.len()) {
let formatted = transpose(value);
Ok(Self(formatted.map(|t| if t.into_tile() == 0 { None } else { Some(t.into_tile()) })))
Ok(Self(formatted.map(|t| {
if t.into_tile() == 0 {
None
} else {
Some(t.into_tile())
}
})))
} else {
Err(NotSquareError)
}
......@@ -174,9 +174,9 @@ impl Debug for TileMatcher {
for value in line {
write!(f, "{:?} ", value)?;
}
write!(f, "\n")?;
writeln!(f)?;
}
writeln!(f, "\n")
writeln!(f)
} else {
write!(f, "TileMatcher({:?})", self.0)
}
......@@ -185,8 +185,8 @@ impl Debug for TileMatcher {
impl Default for TileMatcher {
fn default() -> Self {
TileMatcher([TileStatus::default(); TILE_GRID_SIZE])
}
TileMatcher([TileStatus::default(); TILE_GRID_SIZE])
}
}
impl TileMatcher {
......@@ -196,7 +196,6 @@ impl TileMatcher {
TileMatcher(rules)
}
/// Create a 1x1 matcher, with any rule for the target tile
pub const fn single_match(value: i32) -> Self {
Self::single(TileStatus::Is(value))
......@@ -217,7 +216,10 @@ impl TileMatcher {
}
}
impl <T> TryFrom<&[T]> for TileMatcher where T: IntoTile + Copy + Default {
impl<T> TryFrom<&[T]> for TileMatcher
where
T: IntoTile + Copy + Default,
{
type Error = NotSquareError;
fn try_from(value: &[T]) -> Result<Self, Self::Error> {
if is_square(value.len()) {
......@@ -232,10 +234,10 @@ impl TryFrom<&[TileStatus]> for TileMatcher {
type Error = NotSquareError;
fn try_from(value: &[TileStatus]) -> Result<Self, Self::Error> {
if is_square(value.len()) {
Ok(Self(transpose(value)))
} else {
Err(NotSquareError)
}
Ok(Self(transpose(value)))
} else {
Err(NotSquareError)
}
}
}
......@@ -287,8 +289,10 @@ impl TryFrom<&[TileStatus]> for TileMatcher {
/// 1 1 1 1 1 1 1
/// 1 1 1 1 1 1 1
/// ```
///
fn transpose<Value>(input: &[Value]) -> [Value; TILE_GRID_SIZE] where Value: Default + Copy {
fn transpose<Value>(input: &[Value]) -> [Value; TILE_GRID_SIZE]
where
Value: Default + Copy,
{
if input.len() == TILE_GRID_SIZE {
match input.try_into() {
Ok(output) => return output,
......@@ -301,7 +305,7 @@ fn transpose<Value>(input: &[Value]) -> [Value; TILE_GRID_SIZE] where Value: Def
if !is_square(input.len()) {
// Length isn't square == it does not represent a square grid
panic!("Input must be a square grid");
panic!("Input must be a square grid");
}
let input_size = (input.len() as f64).sqrt() as usize;
......@@ -333,7 +337,7 @@ fn transpose<Value>(input: &[Value]) -> [Value; TILE_GRID_SIZE] where Value: Def
let output_idx = adjusted_output_y * RULE_MAGNITUDE + adjusted_output_x;
output[output_idx] = input[input_idx];
}
}
}
output
......@@ -356,15 +360,10 @@ mod tests {
fn it_transposes_odd_grids() {
let input = [2, 2, 2, 2, 2, 2, 2, 2, 2];
let expected = [
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 2, 2, 0, 0,
0, 0, 2, 2, 2, 0, 0,
0, 0, 2, 2, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0,
0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(expected, transpose(&input));
}
}
\ No newline at end of file
}
......@@ -98,33 +98,33 @@
//! const OTHER_TILE: i32 = 342;
//!
//! let wall_rules = AutoRuleSet(vec![
//! AutoTileRule::single_when(TileMatcher::try_from([ // Top Left Corner
//! TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! TileStatus::IsNot(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE),
//! TileStatus::IsNot(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE),
//! ].as_slice()).unwrap(), 54),
//! AutoTileRule::single_when(TileMatcher::try_from([ // Top Right Corner
//! TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! ].as_slice()).unwrap(), 55),
//! // ... Etc
//! AutoTileRule::single_when(TileMatcher::try_from([ // Top Left Corner
//! TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! TileStatus::IsNot(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE),
//! TileStatus::IsNot(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE),
//! ].as_slice()).unwrap(), 54),
//! AutoTileRule::single_when(TileMatcher::try_from([ // Top Right Corner
//! TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! TileStatus::Is(WALL_TILE), TileStatus::Is(WALL_TILE), TileStatus::IsNot(WALL_TILE),
//! ].as_slice()).unwrap(), 55),
//! // ... Etc
//! ]);
//!
//! let ground_rules = AutoRuleSet(vec![
//! // Use decorated tiles in 10% of cases
//! AutoTileRule::single_any_chance(GROUND_TILE, vec![45, 46, 47], 0.1),
//! // Fall back to the basic tile if we don't match previously
//! AutoTileRule::exact(GROUND_TILE, 44),
//! // Use decorated tiles in 10% of cases
//! AutoTileRule::single_any_chance(GROUND_TILE, vec![45, 46, 47], 0.1),
//! // Fall back to the basic tile if we don't match previously
//! AutoTileRule::exact(GROUND_TILE, 44),
//! ]);
//!
//! // Easily merge rule sets in an ordered way
//! let combined_rules = wall_rules + ground_rules;
//!
//! let sublayout = TileLayout::try_from([
//! Some(OTHER_TILE), Some(GROUND_TILE), Some(GROUND_TILE),
//! Some(WALL_TILE), Some(WALL_TILE), Some(OTHER_TILE),
//! Some(WALL_TILE), Some(WALL_TILE), Some(GROUND_TILE),
//! Some(OTHER_TILE), Some(GROUND_TILE), Some(GROUND_TILE),
//! Some(WALL_TILE), Some(WALL_TILE), Some(OTHER_TILE),
//! Some(WALL_TILE), Some(WALL_TILE), Some(GROUND_TILE),
//! ].as_slice()).unwrap();
//!
//! // We've got a layout that represents the top right corner of a wall, the second rule in our
......@@ -136,12 +136,11 @@
//! # }
//! ```
mod layout;
mod autotile;
mod layout;
mod output;
mod utils;
pub use layout::*;
pub use autotile::*;
pub use layout::*;
pub use output::*;
......@@ -41,4 +41,4 @@ impl TileOutput {
Self::Random(vals) => vals.get(rng.usize(0..vals.len())).copied(),
}
}
}
\ No newline at end of file
}
use crate::TileStatus;
pub trait IntoTile {
fn into_tile(self) -> i32;
fn into_tile(self) -> i32;
}
// Implementations for unsigned integer types
impl IntoTile for u8 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for u16 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for u32 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for u64 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for u128 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for usize {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
// Implementations for signed integer types
impl IntoTile for i8 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for i16 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for i32 {
fn into_tile(self) -> i32 {
self
}
fn into_tile(self) -> i32 {
self
}
}
impl IntoTile for i64 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for i128 {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
impl IntoTile for isize {
fn into_tile(self) -> i32 {
self as i32
}
fn into_tile(self) -> i32 {
self as i32
}
}
// We don't actually implement IntoTile for TileStatus, as this would conflict with a later From impl
impl TileStatus {
pub fn into_tile(self) -> i32 {
match self {
Self::Ignore => 0,
Self::Nothing => -1000001,
Self::Anything => 1000001,
Self::Is(value) => value,
Self::IsNot(value) => -(value),
}
}
pub fn into_tile(self) -> i32 {
match self {
Self::Ignore => 0,
Self::Nothing => -1000001,
Self::Anything => 1000001,
Self::Is(value) => value,
Self::IsNot(value) => -(value),
}
}
}
impl From<TileStatus> for i32 {
fn from(value: TileStatus) -> Self {
value.into_tile()
}
fn from(value: TileStatus) -> Self {
value.into_tile()
}
}
impl From<TileStatus> for i64 {
fn from(value: TileStatus) -> Self {
value.into_tile() as i64
}
}
impl <T: IntoTile> IntoTile for Option<T> {
fn into_tile(self) -> i32 {
match self {
Some(value) => value.into_tile(),
None => 0,
}
}
}
impl <T: IntoTile, E> IntoTile for Result<T, E> {
fn into_tile(self) -> i32 {
match self {
Ok(value) => value.into_tile(),
Err(_) => 0,
}
}
}
impl <I: IntoTile> From<I> for TileStatus {
fn from(value: I) -> Self {
let value = value.into_tile();
match value {
0 => Self::Ignore,
1000001 => Self::Anything,
-1000001 => Self::Nothing,
other => {
if other > 0 {
Self::Is(other.into_tile())
} else {
Self::IsNot(other.abs().into_tile())
}
}
}
}
}
\ No newline at end of file
fn from(value: TileStatus) -> Self {
value.into_tile() as i64
}
}
impl<T: IntoTile> IntoTile for Option<T> {
fn into_tile(self) -> i32 {
match self {
Some(value) => value.into_tile(),
None => 0,
}
}
}
impl<T: IntoTile, E> IntoTile for Result<T, E> {
fn into_tile(self) -> i32 {
match self {
Ok(value) => value.into_tile(),
Err(_) => 0,
}
}
}
impl<I: IntoTile> From<I> for TileStatus {
fn from(value: I) -> Self {
let value = value.into_tile();
match value {
0 => Self::Ignore,
1000001 => Self::Anything,
-1000001 => Self::Nothing,
other => {
if other > 0 {
Self::Is(other.into_tile())
} else {
Self::IsNot(other.abs().into_tile())
}
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment