use crate::output::TileOutput;
use crate::{TileLayout, TileMatcher};
use std::fmt::{Debug, Formatter};
use std::ops::Add;
#[derive(Clone, Default)]
pub struct AutoTileRule {
pub matcher: TileMatcher,
pub output: TileOutput,
pub chance: f32,
}
impl Debug for AutoTileRule {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
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
)
}
}
}
impl AutoTileRule {
pub const fn exact(input_value: i32, output_value: i32) -> Self {
Self::exact_chance(input_value, output_value, 1.0)
}
pub const fn exact_chance(input_value: i32, output_value: i32, chance: f32) -> Self {
AutoTileRule {
matcher: TileMatcher::single_match(input_value),
output: TileOutput::single(output_value),
chance,
}
}
pub const fn single_when(matcher: TileMatcher, output_value: i32) -> Self {
AutoTileRule {
matcher,
output: TileOutput::single(output_value),
chance: 1.0,
}
}
pub const fn single_any(input_value: i32, output_value: Vec<i32>) -> Self {
Self::single_any_chance(input_value, output_value, 1.0)
}
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),
chance,
}
}
pub const fn any_any_chance(
input_value: TileMatcher,
output_value: Vec<i32>,
chance: f32,
) -> Self {
AutoTileRule {
matcher: input_value,
output: TileOutput::any(output_value),
chance,
}
}
#[cfg(feature = "impl_fastrand")]
pub fn get_match(&self, input: &TileLayout) -> Option<&TileOutput> {
let chance = fastrand::f32();
if chance <= self.chance && self.matcher.matches(input) {
Some(&self.output)
} else {
None
}
}
#[cfg(feature = "impl_fastrand")]
pub fn get_match_seeded(
&self,
input: &TileLayout,
seeded: &fastrand::Rng,
) -> Option<&TileOutput> {
let chance = seeded.f32();
if chance <= self.chance && self.matcher.matches(input) {
Some(&self.output)
} else {
None
}
}
#[cfg(feature = "impl_fastrand")]
pub fn resolve_match(&self, input: &TileLayout) -> Option<i32> {
self.get_match(input).and_then(|out| out.resolve())
}
#[cfg(feature = "impl_fastrand")]
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))
}
}
#[derive(Clone, Debug, Default)]
pub struct AutoRuleSet(pub Vec<AutoTileRule>);
impl Add<AutoRuleSet> for AutoRuleSet {
type Output = AutoRuleSet;
fn add(self, rhs: AutoRuleSet) -> Self::Output {
AutoRuleSet([self.0.as_slice(), rhs.0.as_slice()].concat())
}
}
impl From<AutoTileRule> for AutoRuleSet {
fn from(value: AutoTileRule) -> Self {
Self(vec![value])
}
}
impl From<Vec<AutoTileRule>> for AutoRuleSet {
fn from(value: Vec<AutoTileRule>) -> Self {
Self(value)
}
}
impl AutoRuleSet {
#[cfg(feature = "impl_fastrand")]
pub fn get_match(&self, input: &TileLayout) -> Option<&TileOutput> {
for rule in self.0.iter() {
let result = rule.get_match(input);
if result.is_some() {
return result;
}
}
None
}
#[cfg(feature = "impl_fastrand")]
pub fn get_match_seeded(
&self,
input: &TileLayout,
seeded: &fastrand::Rng,
) -> Option<&TileOutput> {
for rule in self.0.iter() {
let result = rule.get_match_seeded(input, seeded);
if result.is_some() {
return result;
}
}
None
}
#[cfg(feature = "impl_fastrand")]
pub fn resolve_match(&self, input: &TileLayout) -> Option<i32> {
self.get_match(input).and_then(|out| out.resolve())
}
#[cfg(feature = "impl_fastrand")]
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))
}
}