steel_worldgen/
surface_partial.rs1#[derive(Debug)]
6pub enum PartialSurfaceRule {
7 Block(usize),
9 Sequence(&'static [Self]),
11 Condition(PartialSurfaceCondition, &'static Self),
13 Opaque,
15}
16
17#[derive(Debug)]
19pub enum PartialSurfaceCondition {
20 AbovePreliminarySurface,
22 BiomeSet(usize),
24 VerticalGradient {
27 true_at_and_below: i32,
29 false_at_and_above: i32,
31 },
32 YAtLeast(i32),
34 Not(&'static Self),
36 Opaque,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum PartialSurfaceOutcome {
43 Keep,
45 Place(usize),
47 Evaluate,
49}
50
51impl PartialSurfaceRule {
52 #[must_use]
55 pub fn resolve(&self, block_y: i32, biome_set_mask: u64) -> PartialSurfaceOutcome {
56 match self {
57 Self::Block(index) => PartialSurfaceOutcome::Place(*index),
58 Self::Sequence(rules) => rules
59 .iter()
60 .map(|rule| rule.resolve(block_y, biome_set_mask))
61 .find(|outcome| *outcome != PartialSurfaceOutcome::Keep)
62 .unwrap_or(PartialSurfaceOutcome::Keep),
63 Self::Condition(condition, then_run) => {
64 match condition.resolve(block_y, biome_set_mask) {
65 Some(false) => PartialSurfaceOutcome::Keep,
66 Some(true) => then_run.resolve(block_y, biome_set_mask),
67 None => match then_run.resolve(block_y, biome_set_mask) {
68 PartialSurfaceOutcome::Keep => PartialSurfaceOutcome::Keep,
69 _ => PartialSurfaceOutcome::Evaluate,
70 },
71 }
72 }
73 Self::Opaque => PartialSurfaceOutcome::Evaluate,
74 }
75 }
76}
77
78impl PartialSurfaceCondition {
79 #[must_use]
81 pub fn resolve(&self, block_y: i32, biome_set_mask: u64) -> Option<bool> {
82 match self {
83 Self::AbovePreliminarySurface => Some(false),
84 Self::BiomeSet(index) => Some(biome_set_mask & 1 << index != 0),
85 Self::VerticalGradient {
86 true_at_and_below,
87 false_at_and_above,
88 } => {
89 if block_y <= *true_at_and_below {
90 Some(true)
91 } else if block_y >= *false_at_and_above {
92 Some(false)
93 } else {
94 None
95 }
96 }
97 Self::YAtLeast(anchor) => Some(block_y >= *anchor),
98 Self::Not(condition) => condition
99 .resolve(block_y, biome_set_mask)
100 .map(|value| !value),
101 Self::Opaque => None,
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::{
109 PartialSurfaceCondition as C, PartialSurfaceOutcome as O, PartialSurfaceRule as R,
110 };
111
112 static RULE: R = R::Sequence(&[
114 R::Condition(
115 C::VerticalGradient {
116 true_at_and_below: -64,
117 false_at_and_above: -59,
118 },
119 &R::Block(0),
120 ),
121 R::Condition(C::AbovePreliminarySurface, &R::Block(1)),
122 R::Condition(
123 C::BiomeSet(3),
124 &R::Sequence(&[R::Condition(C::Opaque, &R::Block(2))]),
125 ),
126 R::Condition(
127 C::VerticalGradient {
128 true_at_and_below: 0,
129 false_at_and_above: 8,
130 },
131 &R::Block(4),
132 ),
133 ]);
134
135 #[test]
136 fn undecidable_branches_force_evaluation_only_when_they_could_place() {
137 let sulfur = 1 << 3;
138 assert_eq!(RULE.resolve(-64, 0), O::Place(0));
139 assert_eq!(RULE.resolve(-62, 0), O::Evaluate); assert_eq!(RULE.resolve(-30, 0), O::Place(4));
141 assert_eq!(RULE.resolve(4, 0), O::Evaluate); assert_eq!(RULE.resolve(40, 0), O::Keep);
143 assert_eq!(RULE.resolve(40, sulfur), O::Evaluate); assert_eq!(RULE.resolve(-64, sulfur), O::Place(0)); }
146}