use crate::fingerprint::classifier::{BpCategory, Classifier, Match, Rule};
fn rule(matcher: Match, class: &str, keep: &[&str]) -> Rule {
Rule {
matcher,
class: class.into(),
keep_props: keep.iter().map(|s| s.to_string()).collect(),
}
}
fn names(list: &[&str]) -> Match {
Match::Names(list.iter().map(|s| s.to_string()).collect())
}
pub fn structural() -> Classifier {
Classifier {
name: "structural".into(),
rules: vec![rule(Match::Category(BpCategory::Solid), "solid", &[])],
}
}
const REDSTONE_COMPONENTS: &[&str] = &[
"minecraft:redstone_wire",
"minecraft:repeater",
"minecraft:comparator",
"minecraft:redstone_torch",
"minecraft:redstone_wall_torch",
"minecraft:piston",
"minecraft:sticky_piston",
"minecraft:observer",
"minecraft:dropper",
"minecraft:hopper",
"minecraft:lever",
"minecraft:redstone_lamp",
"minecraft:target",
];
fn component_rules(keep: &[&str]) -> Vec<Rule> {
REDSTONE_COMPONENTS
.iter()
.map(|n| rule(names(&[n]), &n.replace("minecraft:", ""), keep))
.collect()
}
fn glass_match() -> Match {
Match::Any(vec![
Match::Glob("*glass".into()),
names(&["minecraft:glass"]),
])
}
fn top_slab_match() -> Match {
Match::Glob("*_slab".into()).and(Match::Prop("type".into(), "top".into()))
}
pub fn redstone_computational() -> Classifier {
let mut rules = component_rules(&["facing", "delay", "mode"]);
rules.push(rule(top_slab_match(), "transparent", &[]));
rules.push(rule(glass_match(), "transparent", &[]));
rules.push(rule(Match::Category(BpCategory::Solid), "solid", &[]));
Classifier {
name: "redstone-computational".into(),
rules,
}
}
pub fn redstone_survival() -> Classifier {
let mut rules = component_rules(&["facing", "delay", "mode"]);
rules.push(rule(top_slab_match(), "slab_top", &[]));
rules.push(rule(glass_match(), "glass", &[]));
rules.push(rule(Match::Category(BpCategory::Solid), "solid", &[]));
Classifier {
name: "redstone-survival".into(),
rules,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::block_state::BlockState;
fn bs(name: &str, props: &[(&str, &str)]) -> BlockState {
BlockState::new(name).with_properties(
props
.iter()
.map(|(k, v)| ((*k).into(), (*v).into()))
.collect(),
)
}
#[test]
fn structural_collapses_solids() {
let c = structural();
let wool = c.tokenize(&BlockState::new("minecraft:orange_wool"));
let concrete = c.tokenize(&BlockState::new("minecraft:purple_concrete"));
assert_eq!(wool, concrete);
assert_eq!(wool.as_deref(), Some("solid"));
}
#[test]
fn computational_vs_survival_glass_slab() {
let top_slab = bs("minecraft:oak_slab", &[("type", "top")]);
let glass = BlockState::new("minecraft:glass");
let comp = redstone_computational();
assert_eq!(comp.tokenize(&top_slab), comp.tokenize(&glass));
let surv = redstone_survival();
assert_ne!(surv.tokenize(&top_slab), surv.tokenize(&glass));
}
}