#include "common/aoc.h" namespace y2016::day11 { struct Item { int floorPos; bool generator; int id; bool operator==(const Item& item) const { return floorPos == item.floorPos && id == item.id && generator == item.generator; } }; static int FLOORS = 4; REGISTER_DAY(2016, Day11, std::vector, int); REGISTER_TEST_EXAMPLE(2016, Day11, ExampleInput, 1, 11); REGISTER_TEST(2016, Day11, Input, 1, 37); REGISTER_TEST(2016, Day11, Input, 2, 61); Item ParseItem(const std::string_view& str, int floorPos, std::map& nameToId) { size_t posDash = str.find('-'); std::string name; bool generator; if (posDash == std::string::npos) { name = str.substr(0, str.find(' ')); generator = true; } else { name = str.substr(0, posDash); generator = false; } auto it = nameToId.find(name); if (it != nameToId.end()) return Item{floorPos, generator, it->second}; int size = nameToId.size(); nameToId[name] = size; return Item{floorPos, generator, size}; } READ_INPUT(input) { std::vector vec; std::string str; std::map nameToId; for (int i = 0; i < FLOORS; i++) { getline(input, str); std::vector split = Helper::Split(str, " a "); for (size_t j = 1; j < split.size(); j++) { vec.emplace_back(ParseItem(split[j], i, nameToId)); } } return vec; } struct State { std::vector items; int elevatorPos; int amountOfPairs; std::vector> GetPairs() const { // Convert the data to a format where the pairs of generator/microchip don't matter. All that matters are their // positions std::vector> pairs(amountOfPairs); for (const auto& item : items) { if (item.generator) pairs[item.id].first = item.floorPos; else pairs[item.id].second = item.floorPos; } std::sort(pairs.begin(), pairs.end()); return pairs; } bool operator<(const State& state) const { if (elevatorPos != state.elevatorPos) return elevatorPos < state.elevatorPos; return GetPairs() < state.GetPairs(); } }; bool HasItem(const State& state, int floor, bool generator, int id) { return std::find(state.items.begin(), state.items.end(), Item{floor, generator, id}) != state.items.end(); } bool IsValidState(const State& state) { for (int i = 0; i < FLOORS; i++) { bool hasChipNotConnected = false; int generators = 0; for (const auto& item : state.items) { if (item.floorPos != i) continue; if (item.generator) { generators++; continue; } if (HasItem(state, i, true, item.id)) continue; hasChipNotConnected = true; } if (hasChipNotConnected && generators > 0) { return false; } } return true; } std::vector> Branch(const std::vector& input, const State& state) { std::vector> branches; for (int i = -1; i <= 1; i += 2) { if (state.elevatorPos + i < 0 || state.elevatorPos + i > 3) continue; State newState = state; newState.elevatorPos += i; for (auto& item : newState.items) { if (item.floorPos != state.elevatorPos) continue; item.floorPos = newState.elevatorPos; if (IsValidState(newState)) branches.emplace_back(1, newState); item.floorPos = state.elevatorPos; } for (size_t i = 0; i < newState.items.size(); i++) { if (newState.items[i].floorPos != state.elevatorPos) continue; newState.items[i].floorPos = newState.elevatorPos; for (size_t j = i + 1; j < newState.items.size(); j++) { if (newState.items[j].floorPos != state.elevatorPos) continue; newState.items[j].floorPos = newState.elevatorPos; if (IsValidState(newState)) branches.emplace_back(1, newState); newState.items[j].floorPos = state.elevatorPos; } newState.items[i].floorPos = state.elevatorPos; } } return branches; } bool Goal(const std::vector& input, const State& state) { for (size_t i = 0; i < state.items.size(); i++) { if (state.items[i].floorPos != 3) return false; } return true; } int Heuristic(const std::vector& input, const State& state) { int heuristic = 0; int moves = 0; for (size_t i = 0; i < state.items.size(); i++) { moves += (3 - state.items[i].floorPos); } heuristic += moves / 2; return heuristic; } OUTPUT1(input) { int max = 0; for (const auto& item : input) { max = std::max(max, item.id); } State state{input, 0, max + 1}; return Helper::AStar(input, state, Heuristic, Branch, Goal); } OUTPUT2(input) { std::vector items = input; int max = 0; for (const auto& item : items) { max = std::max(max, item.id); } items.emplace_back(Item{0, true, max + 1}); items.emplace_back(Item{0, false, max + 1}); items.emplace_back(Item{0, true, max + 2}); items.emplace_back(Item{0, false, max + 2}); State state{items, 0, max + 3}; return Helper::AStar(input, state, Heuristic, Branch, Goal); } }