#include #include #include #include #include #include "VoxelSpace.h" namespace Voxel { auto index(int dim_y, int dim_z, int x, int y, int z) -> int { return dim_y * dim_z * x + dim_z * y + z; } // [1, 0, 0] [x] [ x] // [0, 0, -1] * [y] = [-z] // [0, 1, 0] [z] [ y] auto newIndexRotX(Space *space, int x, int y, int z) -> int { return space->dim_z * space->dim_y * x + space->dim_y * (space->dim_z - 1 - z) + y; } // [ 0, 0, 1] [x] [ z] // [ 0, 1, 0] * [y] = [ y] // [-1, 0, 0] [z] [-x] auto newIndexRotY(Space *space, int x, int y, int z) -> int { return space->dim_y * space->dim_x * z + space->dim_x * y + (space->dim_x - 1 - x); } // [0, -1, 0] [x] [-y] // [1, 0, 0] * [y] = [ x] // [0, 0, 1] [z] [ z] auto newIndexRotZ(Space *space, int x, int y, int z) -> int { return space->dim_x * space->dim_z * (space->dim_y - 1 - y) + space->dim_z * x + z; } auto toggle(uint64_t space, int index) -> uint64_t { space ^= 1ul << index; return space; } auto set(uint64_t space, int index, bool val) -> uint64_t { if (val) { space |= 1ul << index; } else { space &= ~(1ul << index); } return space; } auto collides(uint64_t a, uint64_t b) -> bool { return (a | b) != (a ^ b); } auto collides(Space *a, Space *b) -> bool { return (a->space | b->space) != (a->space ^ b->space); } auto filledAt(Space *space, int x, int y, int z) -> bool { auto mask = 1ul << (space->dim_y * space->dim_z * x + space->dim_z * y + z); return (space->space & mask) != 0ul; } auto getExtrema(Space *space) -> Extrema { auto extrema = Extrema{ .xMax=0, .xMin=space->dim_x, .yMax=0, .yMin=space->dim_y, .zMax=0, .zMin=space->dim_z, }; for (int x = 0; x < space->dim_x; x++) { for (int y = 0; y < space->dim_y; y++) { for (int z = 0; z < space->dim_z; z++) { if (filledAt(space, x, y, z)) { if (x > extrema.xMax) extrema.xMax = x; if (x < extrema.xMin) extrema.xMin = x; if (y > extrema.yMax) extrema.yMax = y; if (y < extrema.yMin) extrema.yMin = y; if (z > extrema.zMax) extrema.zMax = z; if (z < extrema.zMin) extrema.zMin = z; } } } } return extrema; } auto cullEmptySpace(Space *space) -> void { auto extrema = getExtrema(space); auto space_index = 0; auto newSpace = 0ul; for (int x = extrema.xMin; x <= extrema.xMax; x++) { for (int y = extrema.yMin; y <= extrema.yMax; y++) { for (int z = extrema.zMin; z <= extrema.zMax; z++) { if (filledAt(space, x, y, z)) { newSpace |= 1ul << space_index; } space_index++; } } } space->dim_x = extrema.xMax - extrema.xMin + 1; space->dim_y = extrema.yMax - extrema.yMin + 1; space->dim_z = extrema.zMax - extrema.zMin + 1; space->space = newSpace; } auto rotate90X(Space *space) -> void { auto new_space = 0ul; for (int x = 0; x < space->dim_x; x++) { for (int y = 0; y < space->dim_y; y++) { for (int z = 0; z < space->dim_z; z++) { if (filledAt(space, x, y, z)) { new_space |= 1 << newIndexRotX(space, x, y, z); } } } } auto temp = space->dim_y; space->dim_y = space->dim_z; space->dim_z = temp; space->space = new_space; } auto rotate90Y(Space *space) -> void { auto new_space = 0ul; for (int x = 0; x < space->dim_x; x++) { for (int y = 0; y < space->dim_y; y++) { for (int z = 0; z < space->dim_z; z++) { if (filledAt(space, x, y, z)) { new_space |= 1 << newIndexRotY(space, x, y, z); } } } } auto temp = space->dim_x; space->dim_x = space->dim_z; space->dim_z = temp; space->space = new_space; } auto rotate90Z(Space *space) -> void { auto new_space = 0ul; for (int x = 0; x < space->dim_x; x++) { for (int y = 0; y < space->dim_y; y++) { for (int z = 0; z < space->dim_z; z++) { if (filledAt(space, x, y, z)) { new_space |= 1 << newIndexRotZ(space, x, y, z); } } } } auto temp = space->dim_x; space->dim_x = space->dim_y; space->dim_y = temp; space->space = new_space; } auto isMatch(Space *a, Space *b) -> bool { return a->space == b->space && a->dim_x == b->dim_x && a->dim_y == b->dim_y && a->dim_z == b->dim_z; } auto pushNewUniqueSpins(std::vector *existingSpaces, Space* spaceToSpin) -> void { Space spins[4] = {}; spins[0] = *spaceToSpin; for (int i = 0; i < 3; i++) { spins[i + 1] = spins[i]; rotate90X(&spins[i + 1]); } for (int i = 0; i < 4; i++) { auto matchFound = false; for (auto &existingSpace : *existingSpaces) { if (isMatch(&existingSpace, &spins[i])) { matchFound = true; break; } } if (!matchFound) { existingSpaces->push_back(spins[i]); } } } auto pushXAxisSpins(std::vector *existingSpaces, Space* spaceToSpin) -> void { auto refSpace = *spaceToSpin; for (int i = 0; i < 4; i++) { rotate90X(&refSpace); existingSpaces->push_back(refSpace); } } auto getUniqueRotations(Space *space) -> std::vector { auto rotations = std::vector(); rotations.reserve(24); auto refSpace = *space; cullEmptySpace(&refSpace); pushNewUniqueSpins(&rotations, &refSpace); rotate90Y(&refSpace); pushNewUniqueSpins(&rotations, &refSpace); rotate90Y(&refSpace); pushNewUniqueSpins(&rotations, &refSpace); rotate90Y(&refSpace); pushNewUniqueSpins(&rotations, &refSpace); rotate90Z(&refSpace); pushNewUniqueSpins(&rotations, &refSpace); rotate90Z(&refSpace); rotate90Z(&refSpace); pushNewUniqueSpins(&rotations, &refSpace); return rotations; } auto getAllRotations(Space *space) -> std::vector { auto rotations = std::vector(); rotations.reserve(24); auto refSpace = *space; pushXAxisSpins(&rotations, &refSpace); rotate90Y(&refSpace); pushXAxisSpins(&rotations, &refSpace); rotate90Y(&refSpace); pushXAxisSpins(&rotations, &refSpace); rotate90Y(&refSpace); pushXAxisSpins(&rotations, &refSpace); rotate90Z(&refSpace); pushXAxisSpins(&rotations, &refSpace); rotate90Z(&refSpace); rotate90Z(&refSpace); pushXAxisSpins(&rotations, &refSpace); return rotations; } auto getAllPositionsInPrism(Space *space, int prism_dims[3]) -> std::vector { auto cubePositions = std::vector(); if (space->dim_x > prism_dims[0] || space->dim_y > prism_dims[1] || space->dim_z > prism_dims[2]) { return cubePositions; } auto xPositionCount = prism_dims[0] - space->dim_x + 1; auto yPositionCount = prism_dims[1] - space->dim_y + 1; auto zPositionCount = prism_dims[2] - space->dim_z + 1; for (int x = 0; x < xPositionCount; x++) { for (int y = 0; y < yPositionCount; y++) { for (int z = 0; z < zPositionCount; z++) { auto new_space = 0ul; for (int posX = 0; posX < space->dim_x; posX++) { for (int posY = 0; posY < space->dim_y; posY++) { for (int posZ = 0; posZ < space->dim_z; posZ++) { auto set_val = filledAt(space, posX, posY, posZ); auto index_to_set = index(prism_dims[1], prism_dims[2], x + posX, y + posY, z + posZ); new_space = set(new_space, index_to_set, set_val); } } } cubePositions.push_back(new_space); } } } return cubePositions; } auto getAllPermutationsInPrism(Space *space, int prism_dims[3]) -> std::vector { auto rotations = getUniqueRotations(space); auto result = std::vector(); for (auto &rotation : rotations) { auto positions = getAllPositionsInPrism(&rotation, prism_dims); result.insert(result.end(), positions.begin(), positions.end()); } return result; } auto size(uint64_t space) -> int { auto size = 0; for (int i = 0; i < 64; i++) { if ((space & (1ul << i)) != 0) { size++; } } return size; } }