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
|
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);
|
bool operator==(const Item& item) const
|
||||||
REGISTER_TEST(2016, Day11, Input, 1, 0);
|
{
|
||||||
REGISTER_TEST_EXAMPLE(2016, Day11, ExampleInput, 2, 0);
|
return floorPos == item.floorPos && id == item.id && generator == item.generator;
|
||||||
REGISTER_TEST(2016, Day11, Input, 2, 0);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
READ_INPUT(input)
|
||||||
{
|
{
|
||||||
std::vector<int> vec;
|
std::vector<Item> vec;
|
||||||
std::string str;
|
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;
|
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)
|
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)
|
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());
|
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)
|
static bool StartsWith(const std::string_view& str, const std::string& prefix, size_t offset = 0)
|
||||||
{
|
{
|
||||||
return str.substr(offset, prefix.size()) == prefix;
|
return str.substr(offset, prefix.size()) == prefix;
|
||||||
|
|||||||
Reference in New Issue
Block a user