#include #include #include #include #include #include #include #include "VoxelSpace.h" using SomaSolution = std::vector; struct Solver { std::vector* input; std::vector* offsets; std::vector* solutions; }; auto backtrack_solve_iter(std::vector *polycube_input, std::vector *offsets)-> void { auto num_inputs = offsets->size() - 1; auto solns = std::vector(); auto iter_stack = std::vector(); auto curr_soln_stack = std::vector(); auto soln_spaces_stack = std::vector(); soln_spaces_stack.push_back(0ul); auto depth = 0; while (depth >= 0) { if (depth >= iter_stack.size()) { iter_stack.push_back(offsets->at(depth)); } auto end = offsets->at(depth + 1); auto broke = false; for (; iter_stack[depth] < end; iter_stack[depth]++) { auto next_space = polycube_input->at(iter_stack[depth]); auto soln_space = soln_spaces_stack[depth]; std::cout << next_space << " " << soln_space << std::endl; auto 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++; auto 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; } auto backtrack_solve(Solver *solver, uint64_t working_solution = 0ul, int curr_piece = 0) -> void { auto input = solver->input; auto offsets = solver->offsets; auto solutions = solver->solutions; auto start = offsets->at(curr_piece); auto end = offsets->at(curr_piece + 1); auto num_pieces = offsets->size() - 1; for (int i = start; i < end; i++) { auto successful_fuse = !Voxel::collides(working_solution, input->at(i)); if (successful_fuse) { auto new_working_solution = working_solution | input->at(i); solutions->back().at(curr_piece) = input->at(i); if (curr_piece == num_pieces - 1) { auto last_soln = solutions->back(); solutions->push_back(SomaSolution(last_soln.begin(), last_soln.end())); return; } else { backtrack_solve(solver, new_working_solution, curr_piece + 1); } } } if (curr_piece == 0) { solutions->pop_back(); } } auto get_solution_rotations(SomaSolution *solution, int dims[3]) -> std::vector { auto result = std::vector(Voxel::NUM_ROTS_3D); for (int piece_i = 0; piece_i < solution->size(); piece_i++) { auto space = Voxel::Space{ .space=solution->at(piece_i), .dim_x=dims[0], .dim_y=dims[1], .dim_z=dims[2], }; auto piece_rotations = Voxel::getAllRotations(&space); for (int rot_i = 0; rot_i < piece_rotations.size(); rot_i++) { result[rot_i].push_back(piece_rotations[rot_i].space); } } return result; } auto filter_unique(std::vector *solutions, int dims[3]) -> std::vector { if (solutions->size() == 0) { return std::vector(); } auto unique_solns = std::vector{}; for (auto &solution : *solutions) { auto found_match = false; for (auto &rotation : get_solution_rotations(&solution, dims)) { for (auto &unique_soln : unique_solns) { auto is_match = true; for (int piece_i = 0; piece_i < unique_soln.size(); piece_i++) { if (rotation[piece_i] != unique_soln[piece_i]) { is_match = false; break; } } if (is_match) { found_match = true; break; } } if (found_match) { break; } } if (!found_match) { unique_solns.push_back(SomaSolution(solution)); } } return unique_solns; } auto get_dims_input(int dims[3]) -> void { std::cout << "Enter dimensions separated by newlines. (x*y*z must not exceed 64)\n"; auto 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]; auto size = dims[0]*dims[1]*dims[2]; if (size <= 64) { success = true; } else { std::cout << "That resulted in " << size << " units. Try again.\n"; } std::cin.ignore(); } } auto get_reprs_input(int units_required) -> std::vector { std::cout << "Enter bit-representations (big endian, max 64 bits, total 1s must add up to " << units_required << "). press ENTER twice to finish input.\n"; auto reprs = std::vector(); auto total_units = 0; while (true) { auto 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; } } auto bit_repr = 0ul; auto i = 0; auto good_repr = true; for (auto it = input.rbegin(); it < input.rend(); it++, i++) { if (*it == '1') { bit_repr |= 1ul << 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; } auto main() -> int { int dims[3]; get_dims_input(dims); std::cout << '\n'; auto reprs = get_reprs_input(dims[0]*dims[1]*dims[2]); /* auto reprs = std::vector{ 23ul, 30ul, 15ul, 1043ul, 24594ul, 12306ul, 11ul, }; */ std::cout << "Great. Calculating solutions...\n"; auto offsets = std::vector(); auto polycubes = std::vector(); polycubes.reserve(reprs.size() * 10); auto model_space = Voxel::Space{ .space={}, .dim_x=dims[0], .dim_y=dims[1], .dim_z=dims[2], }; offsets.push_back(0); auto space = model_space; space.space = reprs[0]; Voxel::cullEmptySpace(&space); auto positions = Voxel::getAllPositionsInPrism(&space, dims); polycubes.insert(polycubes.end(), positions.begin(), positions.end()); for (int i = 1; i < reprs.size(); i++) { offsets.push_back(polycubes.size()); auto space = model_space; space.space = reprs[i]; Voxel::cullEmptySpace(&space); auto perms = Voxel::getAllPermutationsInPrism(&space, dims); polycubes.insert(polycubes.end(), perms.begin(), perms.end()); } offsets.push_back(polycubes.size()); auto solutions = std::vector{std::vector(reprs.size())}; auto solver = Solver{ .input=&polycubes, .offsets=&offsets, .solutions=&solutions, }; backtrack_solve(&solver); auto filtered_solns = filter_unique(solver.solutions, dims); std::cout << filtered_solns.size() << std::endl; return 0; }