Add solution for 2016 Day 11
This commit is contained in:
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user