283 lines
9.6 KiB
C++
283 lines
9.6 KiB
C++
#include <vector>
|
|
#include <bitset>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <cstdint>
|
|
#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<Space> *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<Space> *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<Space> {
|
|
auto rotations = std::vector<Space>();
|
|
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<Space> {
|
|
auto rotations = std::vector<Space>();
|
|
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<uint64_t> {
|
|
auto cubePositions = std::vector<uint64_t>();
|
|
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<uint64_t> {
|
|
auto rotations = getUniqueRotations(space);
|
|
auto result = std::vector<uint64_t>();
|
|
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;
|
|
}
|
|
}
|