Add solution for 2016 Day 11

This commit is contained in:
Thraix
2026-08-22 14:33:45 +02:00
parent fc16b73a01
commit 5d44b9484f
3 changed files with 217 additions and 9 deletions
+4
View File
@@ -0,0 +1,4 @@
The first floor contains a hydrogen-compatible microchip and a lithium-compatible microchip.
The second floor contains a hydrogen generator.
The third floor contains a lithium generator.
The fourth floor contains nothing relevant.
+198 -9
View File
@@ -2,30 +2,219 @@
namespace y2016::day11
{
REGISTER_DAY(2016, Day11, std::vector<int>, int);
struct Item
{
int floorPos;
bool generator;
int id;
REGISTER_TEST_EXAMPLE(2016, Day11, ExampleInput, 1, 0);
REGISTER_TEST(2016, Day11, Input, 1, 0);
REGISTER_TEST_EXAMPLE(2016, Day11, ExampleInput, 2, 0);
REGISTER_TEST(2016, Day11, Input, 2, 0);
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<Item>, 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<std::string, int>& 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<int> vec;
std::vector<Item> vec;
std::string str;
while (getline(input, str))
std::map<std::string, int> nameToId;
for (int i = 0; i < FLOORS; i++)
{
getline(input, str);
std::vector<std::string_view> 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<Item> items;
int elevatorPos;
int amountOfPairs;
std::vector<std::pair<int, int>> 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<std::pair<int, int>> 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<std::pair<int, State>> Branch(const std::vector<Item>& input, const State& state)
{
std::vector<std::pair<int, State>> 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<Item>& 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<Item>& 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)
{
return 0;
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)
{
return 0;
std::vector<Item> 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);
}
}
+15
View File
@@ -51,6 +51,21 @@ struct Helper
t.erase(std::remove_if(t.begin(), t.end(), func), t.end());
}
static std::vector<std::string_view> Split(const std::string& str, const std::string& delim)
{
std::vector<std::string_view> split;
size_t pos = str.find(delim);
size_t lastPos = 0;
while (pos != std::string::npos)
{
split.emplace_back(std::string_view{str.c_str() + lastPos, pos - lastPos});
lastPos = pos + delim.size();
pos = str.find(delim, pos + delim.size());
}
split.emplace_back(std::string_view{str.c_str() + lastPos, str.size() - lastPos});
return split;
}
static bool StartsWith(const std::string_view& str, const std::string& prefix, size_t offset = 0)
{
return str.substr(offset, prefix.size()) == prefix;