added tests, expanding solution algorithm
This commit is contained in:
@@ -13,3 +13,26 @@ add_executable(somaesque
|
|||||||
)
|
)
|
||||||
#target_link_libraries(somaesque glfw GL X11 pthread Xrandr dl SDL2 glm::glm)
|
#target_link_libraries(somaesque glfw GL X11 pthread Xrandr dl SDL2 glm::glm)
|
||||||
#target_include_directories(somaesque PRIVATE src/KHR src/glad)
|
#target_include_directories(somaesque PRIVATE src/KHR src/glad)
|
||||||
|
|
||||||
|
# TESTING
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
googletest
|
||||||
|
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
add_executable(tests
|
||||||
|
tests.cpp
|
||||||
|
VoxelSpace.cpp
|
||||||
|
VoxelSpace.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
tests
|
||||||
|
GTest::gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(tests)
|
||||||
|
|||||||
@@ -43,11 +43,11 @@ namespace Voxel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto collides(uint64_t a, uint64_t b) -> bool {
|
auto collides(uint64_t a, uint64_t b) -> bool {
|
||||||
return (a | b) != (a ^ b);
|
return (a | b) != (a ^ b);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto collides(Space *a, Space *b) -> bool {
|
auto collides(Space *a, Space *b) -> bool {
|
||||||
return (a->space | b->space) != (a->space ^ b->space);
|
return (a->space | b->space) != (a->space ^ b->space);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,11 +105,12 @@ namespace Voxel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto rotate90X(Space *space) -> void {
|
auto rotate90X(Space *space) -> void {
|
||||||
|
auto new_space = 0ull;
|
||||||
for (int x = 0; x < space->dims[0]; x++) {
|
for (int x = 0; x < space->dims[0]; x++) {
|
||||||
for (int y = 0; y < space->dims[1]; y++) {
|
for (int y = 0; y < space->dims[1]; y++) {
|
||||||
for (int z = 0; z < space->dims[2]; z++) {
|
for (int z = 0; z < space->dims[2]; z++) {
|
||||||
if (filledAt(space->space, space->dims, x, y, z)) {
|
if (filledAt(space->space, space->dims, x, y, z)) {
|
||||||
space->space |= 1 << newIndexRotX(space->dims, x, y, z);
|
new_space |= 1 << newIndexRotX(space->dims, x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,14 +118,16 @@ namespace Voxel {
|
|||||||
auto temp = space->dims[1];
|
auto temp = space->dims[1];
|
||||||
space->dims[1] = space->dims[2];
|
space->dims[1] = space->dims[2];
|
||||||
space->dims[2] = temp;
|
space->dims[2] = temp;
|
||||||
|
space->space = new_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rotate90Y(Space *space) -> void {
|
auto rotate90Y(Space *space) -> void {
|
||||||
|
auto new_space = 0ull;
|
||||||
for (int x = 0; x < space->dims[0]; x++) {
|
for (int x = 0; x < space->dims[0]; x++) {
|
||||||
for (int y = 0; y < space->dims[1]; y++) {
|
for (int y = 0; y < space->dims[1]; y++) {
|
||||||
for (int z = 0; z < space->dims[2]; z++) {
|
for (int z = 0; z < space->dims[2]; z++) {
|
||||||
if (filledAt(space->space, space->dims, x, y, z)) {
|
if (filledAt(space->space, space->dims, x, y, z)) {
|
||||||
space->space |= 1 << newIndexRotY(space->dims, x, y, z);
|
new_space |= 1 << newIndexRotY(space->dims, x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,14 +135,16 @@ namespace Voxel {
|
|||||||
auto temp = space->dims[0];
|
auto temp = space->dims[0];
|
||||||
space->dims[0] = space->dims[2];
|
space->dims[0] = space->dims[2];
|
||||||
space->dims[2] = temp;
|
space->dims[2] = temp;
|
||||||
|
space->space = new_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rotate90Z(Space *space) -> void {
|
auto rotate90Z(Space *space) -> void {
|
||||||
|
auto new_space = 0ull;
|
||||||
for (int x = 0; x < space->dims[0]; x++) {
|
for (int x = 0; x < space->dims[0]; x++) {
|
||||||
for (int y = 0; y < space->dims[1]; y++) {
|
for (int y = 0; y < space->dims[1]; y++) {
|
||||||
for (int z = 0; z < space->dims[2]; z++) {
|
for (int z = 0; z < space->dims[2]; z++) {
|
||||||
if (filledAt(space->space, space->dims, x, y, z)) {
|
if (filledAt(space->space, space->dims, x, y, z)) {
|
||||||
space->space |= 1 << newIndexRotZ(space->dims, x, y, z);
|
new_space |= 1 << newIndexRotZ(space->dims, x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,6 +152,7 @@ namespace Voxel {
|
|||||||
auto temp = space->dims[0];
|
auto temp = space->dims[0];
|
||||||
space->dims[0] = space->dims[1];
|
space->dims[0] = space->dims[1];
|
||||||
space->dims[1] = temp;
|
space->dims[1] = temp;
|
||||||
|
space->space = new_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto isMatch(Space *a, Space *b) -> bool {
|
inline auto isMatch(Space *a, Space *b) -> bool {
|
||||||
@@ -203,6 +209,24 @@ namespace Voxel {
|
|||||||
return rotations;
|
return rotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto getUniqueRotations(Space *space) -> std::vector<Space> {
|
||||||
|
auto rotations = std::vector<Space>();
|
||||||
|
rotations.reserve(6*24);
|
||||||
|
auto dims = space->dims;
|
||||||
|
auto refSpace = *space;
|
||||||
|
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 getAllRotations(Space *space) -> std::vector<Space> {
|
||||||
auto rotations = std::vector<Space>();
|
auto rotations = std::vector<Space>();
|
||||||
rotations.reserve(6*24);
|
rotations.reserve(6*24);
|
||||||
@@ -212,12 +236,12 @@ namespace Voxel {
|
|||||||
rotate90Y(&refSpace);
|
rotate90Y(&refSpace);
|
||||||
pushXAxisSpins(&rotations, &refSpace);
|
pushXAxisSpins(&rotations, &refSpace);
|
||||||
rotate90Y(&refSpace);
|
rotate90Y(&refSpace);
|
||||||
pushXAxisSpins(&rotations, &refSpace);
|
pushNewUniqueSpins(&rotations, &refSpace);
|
||||||
rotate90Z(&refSpace);
|
rotate90Z(&refSpace);
|
||||||
pushXAxisSpins(&rotations, &refSpace);
|
pushNewUniqueSpins(&rotations, &refSpace);
|
||||||
rotate90Z(&refSpace);
|
rotate90Z(&refSpace);
|
||||||
rotate90Z(&refSpace);
|
rotate90Z(&refSpace);
|
||||||
pushXAxisSpins(&rotations, &refSpace);
|
pushNewUniqueSpins(&rotations, &refSpace);
|
||||||
return rotations;
|
return rotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
VoxelSpace.h
20
VoxelSpace.h
@@ -19,24 +19,24 @@ namespace Voxel {
|
|||||||
int dims[3];
|
int dims[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto index(int dims[3], int x, int y, int z) -> int;
|
auto index(int dims[3], int x, int y, int z) -> int;
|
||||||
|
|
||||||
inline auto newIndexRotX(int dims[3], int x, int y, int z) -> int;
|
auto newIndexRotX(int dims[3], int x, int y, int z) -> int;
|
||||||
|
|
||||||
inline auto newIndexRotY(int dims[3], int x, int y, int z) -> int;
|
auto newIndexRotY(int dims[3], int x, int y, int z) -> int;
|
||||||
|
|
||||||
inline auto newIndexRotZ(int dims[3], int x, int y, int z) -> int;
|
auto newIndexRotZ(int dims[3], int x, int y, int z) -> int;
|
||||||
|
|
||||||
inline auto toggle(uint64_t space, int index) -> uint64_t;
|
auto toggle(uint64_t space, int index) -> uint64_t;
|
||||||
|
|
||||||
inline auto set(uint64_t space, int index, bool val) -> uint64_t;
|
auto set(uint64_t space, int index, bool val) -> uint64_t;
|
||||||
|
|
||||||
inline auto collides(Space *a, Space *b) -> bool;
|
auto collides(Space *a, Space *b) -> bool;
|
||||||
inline auto collides(uint64_t a, uint64_t b) -> bool;
|
auto collides(uint64_t a, uint64_t b) -> bool;
|
||||||
|
|
||||||
inline auto add(Space *a, Space *b) -> Space;
|
auto add(Space *a, Space *b) -> Space;
|
||||||
|
|
||||||
inline auto filledAt(Space *space, int index) -> bool;
|
auto filledAt(uint64_t space, int dims[3], int x, int y, int z) -> bool;
|
||||||
|
|
||||||
auto getExtrema(uint64_t space, int dims[3]) -> Extrema;
|
auto getExtrema(uint64_t space, int dims[3]) -> Extrema;
|
||||||
|
|
||||||
|
|||||||
43
main.cpp
43
main.cpp
@@ -1,4 +1,5 @@
|
|||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -57,7 +58,6 @@ auto backtrack_solve(std::vector<uint64_t> *polycube_input, std::vector<int> *of
|
|||||||
auto solns = 0;
|
auto solns = 0;
|
||||||
auto start = offsets->at(set);
|
auto start = offsets->at(set);
|
||||||
auto end = offsets->at(set + 1);
|
auto end = offsets->at(set + 1);
|
||||||
std::cout << start << " " << end << "\n";
|
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
auto successful_fuse = !Voxel::collides(working_solution, polycube_input->at(i));
|
auto successful_fuse = !Voxel::collides(working_solution, polycube_input->at(i));
|
||||||
if (successful_fuse) {
|
if (successful_fuse) {
|
||||||
@@ -72,6 +72,34 @@ auto backtrack_solve(std::vector<uint64_t> *polycube_input, std::vector<int> *of
|
|||||||
return solns;
|
return solns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto filter_unique(std::vector<std::vector<uint64_t>> *solutions, int dims[3]) -> std::vector<std::vector<uint64_t>> {
|
||||||
|
if (solutions->size() == 0) {
|
||||||
|
return std::vector<std::vector<uint64_t>>();
|
||||||
|
}
|
||||||
|
auto unique_solns = std::vector<std::vector<uint64_t>>();
|
||||||
|
for (auto &solution : unique_solns) {
|
||||||
|
auto foundMatch = false;
|
||||||
|
auto soln_rotations = std::vector<std::vector<uint64_t>>();
|
||||||
|
for (auto &piece : solution) {
|
||||||
|
auto space = Voxel::Space{ .space=solution.at(0), .dims={ dims[0], dims[1], dims[2] } };
|
||||||
|
auto unique_rots = Voxel::getUniqueRotations(&space);
|
||||||
|
soln_rotations.insert(soln_rotations.end(), unique_rots.begin(), unique_rots.end());
|
||||||
|
}
|
||||||
|
for (auto &rotation : soln_rotations) {
|
||||||
|
auto end = unique_solns.size();
|
||||||
|
for (int i = 0; i < end; i++) {
|
||||||
|
if (rotation == unique_solns[i]) {
|
||||||
|
foundMatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundMatch) {
|
||||||
|
unique_solns.push_back(solution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unique_solns;
|
||||||
|
}
|
||||||
|
|
||||||
auto get_dims_input(int dims[3]) -> void {
|
auto get_dims_input(int dims[3]) -> void {
|
||||||
std::cout << "Enter dimensions separated by newlines. (x*y*z must not exceed 64)\n";
|
std::cout << "Enter dimensions separated by newlines. (x*y*z must not exceed 64)\n";
|
||||||
auto success = false;
|
auto success = false;
|
||||||
@@ -146,19 +174,19 @@ auto main() -> int {
|
|||||||
std::cout << "Great. Calculating solutions...\n";
|
std::cout << "Great. Calculating solutions...\n";
|
||||||
|
|
||||||
auto offsets = std::vector<int>();
|
auto offsets = std::vector<int>();
|
||||||
auto polycubes = std::vector<Voxel::Space>();
|
auto polycubes = std::vector<uint64_t>();
|
||||||
polycubes.reserve(reprs.size() * 10);
|
polycubes.reserve(reprs.size() * 10);
|
||||||
|
|
||||||
auto model_space = Voxel::Space{
|
auto model_space = Voxel::Space{
|
||||||
.space={},
|
.space={},
|
||||||
.dims={dims[0], dims[1], dims[2]},
|
.dims={dims[0], dims[1], dims[2]},
|
||||||
};
|
};
|
||||||
|
|
||||||
offsets.push_back(polycubes.size());
|
offsets.push_back(polycubes.size());
|
||||||
auto space = model_space;
|
auto space = model_space;
|
||||||
space.space = reprs[0];
|
space.space = reprs[0];
|
||||||
Voxel::cullEmptySpace(&space);
|
Voxel::cullEmptySpace(&space);
|
||||||
auto positions = Voxel::getUniqueRotations(&space);
|
auto positions = Voxel::getAllPositionsInPrism(space.space, space.dims, dims);
|
||||||
polycubes.insert(polycubes.end(), positions.begin(), positions.end());
|
polycubes.insert(polycubes.end(), positions.begin(), positions.end());
|
||||||
|
|
||||||
for (int i = 1; i < reprs.size(); i++) {
|
for (int i = 1; i < reprs.size(); i++) {
|
||||||
@@ -166,16 +194,13 @@ auto main() -> int {
|
|||||||
auto space = model_space;
|
auto space = model_space;
|
||||||
space.space = reprs[i];
|
space.space = reprs[i];
|
||||||
Voxel::cullEmptySpace(&space);
|
Voxel::cullEmptySpace(&space);
|
||||||
auto perms = Voxel::getUniqueRotations(&space);
|
auto perms = Voxel::getAllPermutationsInPrism(&space, dims);
|
||||||
polycubes.insert(polycubes.end(), perms.begin(), perms.end());
|
polycubes.insert(polycubes.end(), perms.begin(), perms.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
offsets.push_back(polycubes.size());
|
offsets.push_back(polycubes.size());
|
||||||
|
|
||||||
auto spaces = std::vector<uint64_t>(polycubes.size());
|
auto solns = backtrack_solve(&polycubes, &offsets);
|
||||||
std::transform(polycubes.begin(), polycubes.end(), spaces.begin(), [](auto i) { return i.space; });
|
|
||||||
|
|
||||||
auto solns = backtrack_solve(&spaces, &offsets);
|
|
||||||
|
|
||||||
std::cout << solns << std::endl;
|
std::cout << solns << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
63
tests.cpp
Normal file
63
tests.cpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "VoxelSpace.h"
|
||||||
|
|
||||||
|
TEST(VoxelSpaces, BasicPositions) {
|
||||||
|
auto space = Voxel::Space{ .space=23ull, .dims={3, 3, 3}};
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 1), true);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 0, 0), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 1, 2), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 2, 1), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 0), true);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 2, 1), false);
|
||||||
|
|
||||||
|
space = Voxel::Space{ .space=30ull, .dims={3, 3, 3}};
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 1), true);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 0, 0), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 1, 2), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 2, 1), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 0), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 2, 1), false);
|
||||||
|
|
||||||
|
space = Voxel::Space{ .space=15ull, .dims={3, 3, 3}};
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 1), true);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 0, 0), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 1, 2), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 2, 1), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 0), true);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 2, 1), false);
|
||||||
|
|
||||||
|
space = Voxel::Space{ .space=23ull, .dims={3, 3, 3}};
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 1), true);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 0, 0), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 1, 2), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 1, 2, 1), false);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 0, 0, 0), true);
|
||||||
|
EXPECT_EQ(Voxel::filledAt(space.space, space.dims, 2, 2, 1), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VoxelSpaces, RotatedIndices) {
|
||||||
|
auto space1 = Voxel::Space{ .space=172ull, .dims={3, 3, 3}};
|
||||||
|
|
||||||
|
EXPECT_EQ(Voxel::newIndexRotX(space1.dims, 0, 0, 0), 6);
|
||||||
|
EXPECT_EQ(Voxel::newIndexRotX(space1.dims, 1, 0, 1), 12);
|
||||||
|
|
||||||
|
EXPECT_EQ(Voxel::newIndexRotY(space1.dims, 0, 1, 0), 5);
|
||||||
|
EXPECT_EQ(Voxel::newIndexRotY(space1.dims, 1, 2, 0), 7);
|
||||||
|
|
||||||
|
EXPECT_EQ(Voxel::newIndexRotZ(space1.dims, 1, 0, 2), 23);
|
||||||
|
EXPECT_EQ(Voxel::newIndexRotZ(space1.dims, 0, 0, 0), 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VoxelSpaces, RotateXYZ) {
|
||||||
|
auto space1 = Voxel::Space{ .space=30ull, .dims={3, 3, 3}};
|
||||||
|
auto space2 = Voxel::Space{ .space=30ull, .dims={3, 3, 3}};
|
||||||
|
auto space3 = Voxel::Space{ .space=30ull, .dims={3, 3, 3}};
|
||||||
|
Voxel::rotate90X(&space1);
|
||||||
|
Voxel::rotate90Y(&space2);
|
||||||
|
Voxel::rotate90Z(&space3);
|
||||||
|
EXPECT_EQ(space1.space, 153ull);
|
||||||
|
EXPECT_EQ(space2.space, 1067040ull);
|
||||||
|
EXPECT_EQ(space3.space, 1574400ull);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user