299 lines
10 KiB
C++
299 lines
10 KiB
C++
#include "string.h"
|
|
#include "VoxelSpace.h"
|
|
#include "SomaSolve.h"
|
|
#include "math.h"
|
|
|
|
/*
|
|
void get_dims_input(int dims[3]) {
|
|
print("Enter dimensions separated by newlines. (x*y*z must not exceed 64)\n");
|
|
bool success = false;
|
|
while (!success) {
|
|
std::cout << "x: ";
|
|
std::cin >> dims[0];
|
|
std::cout << "y: ";
|
|
std::cin >> dims[1];
|
|
std::cout << "z: ";
|
|
std::cin >> dims[2];
|
|
|
|
int size = dims[0]*dims[1]*dims[2];
|
|
if (size <= 64) {
|
|
success = true;
|
|
} else {
|
|
print("That resulted in %zu units. Try again", size);
|
|
}
|
|
std::cin.ignore();
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
std::vector<uint64> get_reprs_input(int units_required) {
|
|
print("Enter bit-representations (big endian, max 64 bits, total 1s must add up to %zu). press ENTER twice to finish input.\n", units_required );
|
|
std::vector<uint64> reprs = std::vector<uint64>();
|
|
int total_units = 0;
|
|
while (true) {
|
|
std::string input = std::string();
|
|
std::getline(std::cin, input);
|
|
if (input.size() == 0) {
|
|
if (total_units == units_required) {
|
|
break;
|
|
} else {
|
|
std::cout << "Bad number of units. You entered: " << total_units << ", but exactly " << units_required << " were required.\n";
|
|
total_units = 0;
|
|
continue;
|
|
}
|
|
}
|
|
uint64 bit_repr = 0;
|
|
int i = 0;
|
|
bool good_repr = true;
|
|
for (auto it = input.rbegin(); it < input.rend(); it++, i++) {
|
|
if (*it == '1') {
|
|
bit_repr |= 1ull << i;
|
|
total_units++;
|
|
} else if (*it != '0' || i >= 64) {
|
|
std::cout << "Input invalid. Enter a binary string only with max 64 bits." << '\n';
|
|
good_repr = false;
|
|
break;
|
|
}
|
|
}
|
|
if (good_repr) {
|
|
reprs.push_back(bit_repr);
|
|
}
|
|
}
|
|
return reprs;
|
|
}
|
|
*/
|
|
|
|
DefineList(size_t, Offset);
|
|
|
|
typedef struct Solver {
|
|
VoxelSpaceReprList *input;
|
|
OffsetList *offsets;
|
|
SomaSolutionList *solutions;
|
|
} Solver;
|
|
|
|
uint64 STD_SOMA[] = { 23ul, 30ul, 15ul, 1043ul, 24594ul, 12306ul, 11ul };
|
|
|
|
/*
|
|
void backtrack_solve_iter(std::vector<uint64> *polycube_input, std::vector<int> *offsets) {
|
|
size_t num_inputs = offsets->size() - 1;
|
|
|
|
std::vector<int> solns = std::vector<int>();
|
|
|
|
std::vector<int> iter_stack = std::vector<int>();
|
|
std::vector<int> curr_soln_stack = std::vector<int>();
|
|
std::vector<uint64> soln_spaces_stack = std::vector<uint64>();
|
|
soln_spaces_stack.push_back(0ul);
|
|
|
|
int depth = 0;
|
|
|
|
while (depth >= 0) {
|
|
if (depth >= iter_stack.size()) {
|
|
iter_stack.push_back(offsets->at(depth));
|
|
}
|
|
int end = offsets->at(depth + 1);
|
|
bool broke = false;
|
|
for (; iter_stack[depth] < end; iter_stack[depth]++) {
|
|
uint64 next_space = polycube_input->at(iter_stack[depth]);
|
|
uint64 soln_space = soln_spaces_stack[depth];
|
|
std::cout << next_space << " " << soln_space << std::endl;
|
|
bool successful_fuse = (soln_space | next_space) == (soln_space ^ next_space);
|
|
if (successful_fuse) {
|
|
soln_spaces_stack.push_back(soln_space |= next_space);
|
|
curr_soln_stack.push_back(iter_stack[depth]);
|
|
depth++;
|
|
if (curr_soln_stack.size() == num_inputs) {
|
|
solns.push_back(1);
|
|
curr_soln_stack.pop_back();
|
|
soln_spaces_stack.pop_back();
|
|
depth--;
|
|
} else {
|
|
depth++;
|
|
broke = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!broke) {
|
|
curr_soln_stack.pop_back();
|
|
soln_spaces_stack.pop_back();
|
|
depth--;
|
|
}
|
|
}
|
|
std::cout << "Done. Found " << solns.size() << " solutions." << std::endl;
|
|
}
|
|
*/
|
|
|
|
void backtrackSolve(Arena *arena, Solver *solver, uint64 working_solution, size_t curr_piece) {
|
|
VoxelSpaceReprList *input = solver->input;
|
|
OffsetList *offsets = solver->offsets;
|
|
SomaSolutionList *solutions = solver->solutions;
|
|
size_t start = offsets->data[curr_piece];
|
|
size_t end = offsets->data[curr_piece + 1];
|
|
size_t num_pieces = offsets->length - 1;
|
|
for (size_t i = start; i < end; i++) {
|
|
bool successful_fuse = !collides(working_solution, input->data[i]);
|
|
if (successful_fuse) {
|
|
uint64 new_working_solution = working_solution | input->data[i];
|
|
solutions->data[solutions->length - 1].data[curr_piece] = input->data[i];
|
|
if (curr_piece == num_pieces - 1) {
|
|
VoxelSpaceReprList last_soln = solutions->data[solutions->length - 1];
|
|
VoxelSpaceReprList last_soln_copy = PushList(arena, VoxelSpaceReprList, last_soln.length);
|
|
last_soln_copy.capacity = last_soln.length;
|
|
last_soln_copy.length = last_soln.length;
|
|
memcpy(last_soln_copy.data, last_soln.data, last_soln.length * sizeof(uint64));
|
|
AppendList(solutions, last_soln_copy);
|
|
return;
|
|
} else {
|
|
backtrackSolve(arena, solver, new_working_solution, curr_piece + 1);
|
|
}
|
|
}
|
|
}
|
|
if (curr_piece == 0) {
|
|
solutions->length -= 1;
|
|
}
|
|
}
|
|
|
|
SomaSolutionList getSolutionRotations(Arena *arena, SomaSolution *solution, int dims[3]) {
|
|
SomaSolutionList result = PushFullList(arena, SomaSolutionList, NUM_ROTS_3D);
|
|
for (EachIn(result, i)) {
|
|
result.data[i] = PushList(arena, SomaSolution, solution->length);
|
|
}
|
|
for (int piece_i = 0; piece_i < solution->length; piece_i++) {
|
|
Space space = {
|
|
solution->data[piece_i],
|
|
dims[0],
|
|
dims[1],
|
|
dims[2],
|
|
};
|
|
VoxelSpaceList pieceRotations = getAllRotations(arena, &space);
|
|
for (int rot_i = 0; rot_i < pieceRotations.length; rot_i++) {
|
|
AppendList(&result.data[rot_i], pieceRotations.data[rot_i].space);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
SomaSolutionList filterUnique(Arena *arena, SomaSolutionList *solutions, int dims[3]) {
|
|
if (solutions->length == 0) {
|
|
return (SomaSolutionList)EmptyList();
|
|
}
|
|
SomaSolutionList uniqueSolns = PushList(arena, SomaSolutionList, solutions->length);
|
|
for (EachIn(*solutions, i)) {
|
|
SomaSolution solution = solutions->data[i];
|
|
bool foundMatch = false;
|
|
Scratch temp = scratchStart(&arena, 1);
|
|
SomaSolutionList rots = getSolutionRotations(temp.arena, &solution, dims);
|
|
for (EachIn(rots, j)) {
|
|
SomaSolution rotation = rots.data[j];
|
|
for (EachIn(uniqueSolns, k)) {
|
|
SomaSolution unique_soln = uniqueSolns.data[k];
|
|
bool isMatch = true;
|
|
for (EachIn(unique_soln, piece_i)) {
|
|
if (rotation.data[piece_i] != unique_soln.data[piece_i]) {
|
|
isMatch = false;
|
|
break;
|
|
}
|
|
}
|
|
if (isMatch) {
|
|
foundMatch = true;
|
|
break;
|
|
}
|
|
}
|
|
if (foundMatch) {
|
|
break;
|
|
}
|
|
}
|
|
scratchEnd(temp);
|
|
if (!foundMatch) {
|
|
SomaSolution solutionCopy = PushList(arena, SomaSolution, solution.length);
|
|
solutionCopy.capacity = solution.length;
|
|
solutionCopy.length = solution.length;
|
|
memcpy(solutionCopy.data, solution.data, solution.length * sizeof(SomaSolutionList_underlying));
|
|
AppendList(&uniqueSolns, solutionCopy);
|
|
}
|
|
}
|
|
return uniqueSolns;
|
|
}
|
|
|
|
uint64 factorial(int n) {
|
|
uint64 result = 1;
|
|
for (int i = 1; i <= n; i++) {
|
|
result *= i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
SomaSolutionList solve(uint64 *reprs_in, uint32 reprs_in_count, int dims[3]) {
|
|
Arena *arena = arenaAlloc(Megabytes(64));
|
|
Arena *permsArena = arenaAlloc(Megabytes(128));
|
|
|
|
OffsetList offsets = PushList(arena, OffsetList, reprs_in_count + 1);
|
|
|
|
VoxelSpaceReprList polycubes = PushList(arena, VoxelSpaceReprList, 0);
|
|
|
|
Space empty_voxel_space = {
|
|
0,
|
|
dims[0],
|
|
dims[1],
|
|
dims[2],
|
|
};
|
|
|
|
AppendList(&offsets, 0);
|
|
|
|
uint64 possibleCombos = 0;
|
|
|
|
{
|
|
VoxelSpaceReprList positions = {};
|
|
Space space = empty_voxel_space;
|
|
space.space = reprs_in[0];
|
|
cullEmptySpace(&space);
|
|
positions = getAllPositionsInPrism(permsArena, &space, dims);
|
|
possibleCombos += positions.length;
|
|
VoxelSpaceReprList_underlying *insertion = PushArray(arena, uint64, positions.capacity);
|
|
polycubes.capacity += positions.capacity;
|
|
polycubes.length += positions.length;
|
|
memcpy(insertion, positions.data, positions.capacity * sizeof(VoxelSpaceReprList_underlying));
|
|
};
|
|
|
|
for (size_t i = 1; i < reprs_in_count; i++) {
|
|
AppendList(&offsets, polycubes.capacity);
|
|
Space space = empty_voxel_space;
|
|
space.space = reprs_in[i];
|
|
cullEmptySpace(&space);
|
|
VoxelSpaceReprList perms = getAllPermutationsInPrism(permsArena, &space, dims);
|
|
possibleCombos *= perms.length;
|
|
VoxelSpaceReprList_underlying *insertion = PushArray(arena, uint64, perms.capacity);
|
|
polycubes.capacity += perms.capacity;
|
|
polycubes.length += perms.length;
|
|
memcpy(insertion, perms.data, perms.capacity * sizeof(VoxelSpaceReprList_underlying));
|
|
}
|
|
|
|
AppendList(&offsets, polycubes.length);
|
|
|
|
SomaSolutionList solutions = PushList(permsArena, SomaSolutionList, (size_t)floor(sqrt(possibleCombos)));
|
|
SomaSolution initialSoln = PushFullList(permsArena, SomaSolution, reprs_in_count);
|
|
AppendList(&solutions, initialSoln);
|
|
|
|
Solver solver = {
|
|
&polycubes,
|
|
&offsets,
|
|
&solutions,
|
|
};
|
|
|
|
backtrackSolve(permsArena, &solver, 0, 0);
|
|
|
|
return filterUnique(permsArena, solver.solutions, dims);
|
|
}
|
|
|
|
|
|
void interactive_cmd_line_solve_soma() {
|
|
int dims[3] = { 3, 3, 3 };
|
|
//get_dims_input(dims);
|
|
//std::cout << '\n';
|
|
//std::vector<uint64> reprs = get_reprs_input(dims[0]*dims[1]*dims[2]);
|
|
print("Great. Calculating solutions...\n");
|
|
SomaSolutionList solutions = solve(STD_SOMA, ArrayCount(STD_SOMA), dims);
|
|
print("%zu solutions found.\n", solutions.length);
|
|
}
|