1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package coffee.liz.rookery.puzzle
import kotlin.math.abs
import kotlin.math.roundToInt
/**
* Bridges [TwistyPuzzle] cubes (what the renderer draws) and [NxnCube] slots (what BLD logic and
* notation-level code use): `slotOf[i]` is the NxnCube slot of generic sticker i.
*/
class CubeMapping(val puzzle: TwistyPuzzle, val n: Int) {
val slotOf: IntArray = IntArray(puzzle.stickers.size) { i -> slotFor(puzzle.stickers[i].centroid) }
private val stickerOf: IntArray = IntArray(6 * n * n).also { inv -> slotOf.forEachIndexed { i, s -> inv[s] = i } }
fun stickerOfSlot(slot: Int): Int = stickerOf[slot]
/** Render an NxnCube colour array (indexed by slot) as a generic puzzle state. */
fun state(slotColors: IntArray): PuzzleState = PuzzleState(puzzle, IntArray(puzzle.stickers.size) { slotColors[slotOf[it]] })
// Inverse of NxnCube.slotPosition, on the unit cube ([-1, 1]^3).
private fun slotFor(c: V3): Int {
fun idx(v: Double) = ((v * n + (n - 1)) / 2).roundToInt().coerceIn(0, n - 1)
val (face, row, col) = when {
abs(c.y - 1) < 1e-6 -> Triple(0, idx(c.z), idx(c.x)) // U: a = x, b = z
abs(c.x - 1) < 1e-6 -> Triple(1, idx(-c.y), idx(-c.z)) // R: (n, -b, -a)
abs(c.z - 1) < 1e-6 -> Triple(2, idx(-c.y), idx(c.x)) // F: (a, -b, n)
abs(c.y + 1) < 1e-6 -> Triple(3, idx(-c.z), idx(c.x)) // D: (a, -n, -b)
abs(c.x + 1) < 1e-6 -> Triple(4, idx(-c.y), idx(c.z)) // L: (-n, -b, a)
else -> Triple(5, idx(-c.y), idx(-c.x)) // B: (-a, -b, -n)
}
return face * n * n + row * n + col
}
}
|