#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 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 reprs = std::vector(); 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 *polycube_input, std::vector *offsets) { size_t num_inputs = offsets->size() - 1; std::vector solns = std::vector(); std::vector iter_stack = std::vector(); std::vector curr_soln_stack = std::vector(); std::vector soln_spaces_stack = std::vector(); 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 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); }