Skip to content

Instantly share code, notes, and snippets.

@BomBardyGamer
Created May 4, 2021 15:52
Show Gist options
  • Save BomBardyGamer/73a600cc484cb1b7d991c09967daa027 to your computer and use it in GitHub Desktop.
Save BomBardyGamer/73a600cc484cb1b7d991c09967daa027 to your computer and use it in GitHub Desktop.
Algorithm to get a chunk position in a spiral in O(1)
/**
* Calculates a chunk position from a given [id] in a spiral pattern.
*
* This algorithm was previously part of Krypton (https://github.com/KryptonMC/Krypton), however it was removed after
* it was no longer used.
*
* **Algorithm:**
*
* Given n, an index in the squared spiral
* p, the sum of a point in the inner square
* and a, the position on the current square
*
* n = p + a
*
* Credit for this algorithm goes to
* [davidonet](https://stackoverflow.com/users/1068670/davidonet) (for the original algorithm),
* and [Esophose](https://github.com/Esophose) (for the Kotlin conversion and modifications)
*
* See [here](https://stackoverflow.com/questions/398299/looping-in-a-spiral) for original
*
* @param id the id in the spiral
* @param xOffset an optional X offset
* @param zOffset an optional Z offset
* @return a [ChunkPosition] containing the calculated position in the spiral.
*/
fun chunkInSpiral(id: Int, xOffset: Int = 0, zOffset: Int = 0): ChunkPosition {
// if the id is 0 then we know we're in the centre
if (id == 0) return ChunkPosition(0 + xOffset, 0 + zOffset)
val index = id - 1
// compute radius (inverse arithmetic sum of 8 + 16 + 24 + ...)
val radius = floor((sqrt(index + 1.0) - 1) / 2) + 1
// compute total point on radius -1 (arithmetic sum of 8 + 16 + 24 + ...)
val p = (8 * radius * (radius - 1)) / 2
// points by face
val en = radius * 2
// compute de position and shift it so the first is (-r, -r) but (-r + 1, -r)
// so the square can connect
val a = (1 + index - p) % (radius * 8)
return when (floor(a / (radius * 2)).toInt()) {
// find the face (0 = top, 1 = right, 2 = bottom, 3 = left)
0 -> ChunkPosition((a - radius).toInt() + xOffset, -radius.toInt() + zOffset)
1 -> ChunkPosition(radius.toInt() + xOffset, ((a % en) - radius).toInt() + zOffset)
2 -> ChunkPosition((radius - (a % en)).toInt() + xOffset, radius.toInt() + zOffset)
3 -> ChunkPosition(-radius.toInt() + xOffset, (radius - (a % en)).toInt() + zOffset)
else -> ChunkPosition.ZERO
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment