diff --git a/day14/Makefile b/day14/Makefile new file mode 100644 index 0000000..a415ded --- /dev/null +++ b/day14/Makefile @@ -0,0 +1,15 @@ +CC=g++ +BIN_NAME=day14 +CCFLAGS=-o $(BIN_NAME) -g -std=c++17 +LDFLAGS=-lfolly + +.PHONY: all, clean + +all: $(BIN_NAME) + +clean: + rm -f $(BIN_NAME) + +$(BIN_NAME): day14.cpp + $(CC) $(CCFLAGS) $(LDFLAGS) day14.cpp + diff --git a/day14/day14.cpp b/day14/day14.cpp new file mode 100644 index 0000000..6562929 --- /dev/null +++ b/day14/day14.cpp @@ -0,0 +1,115 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr char IGNORE_CHAR = 'X'; +constexpr auto MASK_PATTERN = R"(mask = ([X0-9]+))"; +constexpr auto MEM_PATTERN = R"(mem\[(\d+)\] = (\d+))"; + +class InstructionBlock { + public: + InstructionBlock(std::string mask, std::vector> storeInstructions) + : mask(mask), storeInstructions(storeInstructions) { + } + + // We are dealing with a 36 bit numebr so we must use a long long to guarantee we can fit it + long long maskNumber(long long num) const { + long long res = num; + for (int i = 0; i < this->mask.size(); i++) { + char maskChar = this->mask.at(this->mask.size() - i - 1); + if (maskChar == IGNORE_CHAR) { + continue; + } else if (maskChar == '0') { + res &= ~(1LL << i); + } else if (maskChar == '1') { + res |= (1LL << i); + } + } + + return res; + } + + const std::vector> &getStoreInstructions() const { + return this->storeInstructions; + } + + private: + std::string mask; + std::vector> storeInstructions; +}; + +std::vector readInput(const std::string &filename) { + std::vector input; + std::string line; + std::ifstream file(filename); + while (std::getline(file, line)) { + input.push_back(line); + } + + return input; +} + +std::vector parseInput(const std::vector &input) { + std::vector blocks; + std::regex maskExpression(MASK_PATTERN); + std::regex memExpression(MEM_PATTERN); + std::string currentMask; + std::vector> currentStoreInstructions; + for (auto it = input.cbegin(); it != input.cend(); it++) { + auto line = *it; + std::smatch matches; + if (std::regex_match(line, matches, maskExpression)) { + // We don't want to emplace on the first mask we find + if (it != input.cbegin()) { + blocks.emplace_back(currentMask, currentStoreInstructions); + currentStoreInstructions.clear(); + } + + currentMask = matches[1]; + } else if (std::regex_match(line, matches, memExpression)) { + int address = std::stoi(matches[1]); + int value = std::stoi(matches[2]); + currentStoreInstructions.emplace_back(address, value); + } + } + + // Put in the last one we've found + blocks.emplace_back(currentMask, currentStoreInstructions); + + return blocks; +} + +long long part1(const std::vector &instructions) { + std::unordered_map memory; + for (const InstructionBlock &instruction : instructions) { + for (const std::pair &storeInstruction : instruction.getStoreInstructions()) { + auto maskedStorage = instruction.maskNumber(storeInstruction.second); + memory[storeInstruction.first] = maskedStorage; + } + } + + return std::accumulate( + memory.cbegin(), memory.cend(), 0LL, [](long long total, std::pair memoryItem) { + return total + memoryItem.second; + }); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + std::cerr << argv[0] << " " << std::endl; + return 1; + } + + auto input = readInput(argv[1]); + auto parsedInput = parseInput(input); + + std::cout << part1(parsedInput) << std::endl; +}