summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt')
-rw-r--r--src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
new file mode 100644
index 0000000..1cac5f9
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
@@ -0,0 +1,67 @@
+package io.dico.parcels2.blockvisitor
+
+import io.dico.parcels2.util.Region
+import io.dico.parcels2.util.Vec3i
+import kotlin.coroutines.experimental.SequenceBuilder
+import kotlin.coroutines.experimental.buildIterator
+
+abstract class RegionTraverser {
+ fun traverseRegion(region: Region): Iterable<Vec3i> = Iterable { buildIterator { build(region) } }
+
+ protected abstract suspend fun SequenceBuilder<Vec3i>.build(region: Region)
+
+ companion object {
+ val upward = create { traverseUpward(it) }
+ val downward = create { traverseDownward(it) }
+ val forClearing get() = downward
+ val forFilling get() = upward
+
+ inline fun create(crossinline builder: suspend SequenceBuilder<Vec3i>.(Region) -> Unit) = object : RegionTraverser() {
+ override suspend fun SequenceBuilder<Vec3i>.build(region: Region) {
+ builder(region)
+ }
+ }
+
+ private suspend fun SequenceBuilder<Vec3i>.traverseDownward(region: Region) {
+ val origin = region.origin
+ val size = region.size
+ repeat(size.y) { y ->
+ repeat(size.z) { z ->
+ repeat(size.x) { x ->
+ yield(origin.add(x, size.y - y - 1, z))
+ }
+ }
+ }
+ }
+
+ private suspend fun SequenceBuilder<Vec3i>.traverseUpward(region: Region) {
+ val origin = region.origin
+ val size = region.size
+ repeat(size.y) { y ->
+ repeat(size.z) { z ->
+ repeat(size.x) { x ->
+ yield(origin.add(x, size.y - y - 1, z))
+ }
+ }
+ }
+ }
+
+ private fun slice(region: Region, atY: Int): Pair<Region, Region?> {
+ if (atY < region.size.y + 1) {
+ val first = Region(region.origin, region.size.withY(atY + 1))
+ val second = Region(region.origin.withY(atY), region.size.addY(-atY-1))
+ return first to second
+ }
+ return region to null
+ }
+
+ fun upToAndDownUntil(y: Int) = create { region ->
+ val (bottom, top) = slice(region, y)
+ traverseUpward(bottom)
+ top?.let { traverseDownward(it) }
+ }
+
+ }
+
+
+}